1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Primitive restart tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fPrimitiveRestartTests.hpp"
25 #include "gluShaderProgram.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "deRandom.hpp"
32 #include "deMath.h"
33 #include "deString.h"
34
35 #include "glw.h"
36
37 using tcu::Vec4;
38
39 namespace deqp
40 {
41 namespace gles3
42 {
43 namespace Functional
44 {
45
46 static const int MAX_RENDER_WIDTH = 256;
47 static const int MAX_RENDER_HEIGHT = 256;
48
49 static const uint32_t MAX_UNSIGNED_BYTE = (1 << 8) - 1;
50 static const uint32_t MAX_UNSIGNED_SHORT = (1 << 16) - 1;
51 static const uint32_t MAX_UNSIGNED_INT = (uint32_t)((1ULL << 32) - 1);
52
53 static const uint8_t RESTART_INDEX_UNSIGNED_BYTE = (uint8_t)MAX_UNSIGNED_BYTE;
54 static const uint16_t RESTART_INDEX_UNSIGNED_SHORT = (uint16_t)MAX_UNSIGNED_SHORT;
55 static const uint32_t RESTART_INDEX_UNSIGNED_INT = MAX_UNSIGNED_INT;
56
57 class PrimitiveRestartCase : public TestCase
58 {
59 public:
60 enum PrimitiveType
61 {
62 PRIMITIVE_POINTS = 0,
63 PRIMITIVE_LINE_STRIP,
64 PRIMITIVE_LINE_LOOP,
65 PRIMITIVE_LINES,
66 PRIMITIVE_TRIANGLE_STRIP,
67 PRIMITIVE_TRIANGLE_FAN,
68 PRIMITIVE_TRIANGLES,
69
70 PRIMITIVE_LAST
71 };
72
73 enum IndexType
74 {
75 INDEX_UNSIGNED_BYTE = 0,
76 INDEX_UNSIGNED_SHORT,
77 INDEX_UNSIGNED_INT,
78
79 INDEX_LAST
80 };
81
82 enum Function
83 {
84 FUNCTION_DRAW_ELEMENTS = 0,
85 FUNCTION_DRAW_ELEMENTS_INSTANCED,
86 FUNCTION_DRAW_RANGE_ELEMENTS,
87
88 FUNCTION_LAST
89 };
90
91 PrimitiveRestartCase(Context &context, const char *name, const char *description, PrimitiveType primType,
92 IndexType indexType, Function function, bool beginWithRestart, bool endWithRestart,
93 bool duplicateRestarts);
94 ~PrimitiveRestartCase(void);
95
96 void init(void);
97 void deinit(void);
98 IterateResult iterate(void);
99
100 private:
101 PrimitiveRestartCase(const PrimitiveRestartCase &other);
102 PrimitiveRestartCase &operator=(const PrimitiveRestartCase &other);
103
104 void draw(int startNdx, int count);
105
106 void renderWithRestart(void);
107 void renderWithoutRestart(void);
108
109 // Helper functions for handling the appropriate index vector (according to m_indexType).
110 void addIndex(uint32_t index);
111 uint32_t getIndex(int indexNdx);
112 int getNumIndices(void);
113 void *getIndexPtr(int indexNdx);
114
115 // \note Only one of the following index vectors is used (according to m_indexType).
116 std::vector<uint8_t> m_indicesUB;
117 std::vector<uint16_t> m_indicesUS;
118 std::vector<uint32_t> m_indicesUI;
119
120 std::vector<float> m_positions;
121
122 PrimitiveType m_primType;
123 IndexType m_indexType;
124 Function m_function;
125
126 bool m_beginWithRestart; // Whether there will be restart indices at the beginning of the index array.
127 bool m_endWithRestart; // Whether there will be restart indices at the end of the index array.
128 bool m_duplicateRestarts; // Whether two consecutive restarts are used instead of one.
129
130 glu::ShaderProgram *m_program;
131 };
132
PrimitiveRestartCase(Context & context,const char * name,const char * description,PrimitiveType primType,IndexType indexType,Function function,bool beginWithRestart,bool endWithRestart,bool duplicateRestarts)133 PrimitiveRestartCase::PrimitiveRestartCase(Context &context, const char *name, const char *description,
134 PrimitiveType primType, IndexType indexType, Function function,
135 bool beginWithRestart, bool endWithRestart, bool duplicateRestarts)
136 : TestCase(context, name, description)
137 , m_primType(primType)
138 , m_indexType(indexType)
139 , m_function(function)
140 , m_beginWithRestart(beginWithRestart)
141 , m_endWithRestart(endWithRestart)
142 , m_duplicateRestarts(duplicateRestarts)
143 , m_program(DE_NULL)
144 {
145 }
146
~PrimitiveRestartCase(void)147 PrimitiveRestartCase::~PrimitiveRestartCase(void)
148 {
149 PrimitiveRestartCase::deinit();
150 }
151
deinit(void)152 void PrimitiveRestartCase::deinit(void)
153 {
154 delete m_program;
155 m_program = DE_NULL;
156 }
157
addIndex(uint32_t index)158 void PrimitiveRestartCase::addIndex(uint32_t index)
159 {
160 if (m_indexType == INDEX_UNSIGNED_BYTE)
161 {
162 DE_ASSERT(de::inRange(index, (uint32_t)0, MAX_UNSIGNED_BYTE));
163 m_indicesUB.push_back((uint8_t)index);
164 }
165 else if (m_indexType == INDEX_UNSIGNED_SHORT)
166 {
167 DE_ASSERT(de::inRange(index, (uint32_t)0, MAX_UNSIGNED_SHORT));
168 m_indicesUS.push_back((uint16_t)index);
169 }
170 else if (m_indexType == INDEX_UNSIGNED_INT)
171 {
172 DE_ASSERT(de::inRange(index, (uint32_t)0, MAX_UNSIGNED_INT));
173 m_indicesUI.push_back((uint32_t)index);
174 }
175 else
176 DE_ASSERT(false);
177 }
178
getIndex(int indexNdx)179 uint32_t PrimitiveRestartCase::getIndex(int indexNdx)
180 {
181 switch (m_indexType)
182 {
183 case INDEX_UNSIGNED_BYTE:
184 return (uint32_t)m_indicesUB[indexNdx];
185 case INDEX_UNSIGNED_SHORT:
186 return (uint32_t)m_indicesUS[indexNdx];
187 case INDEX_UNSIGNED_INT:
188 return m_indicesUI[indexNdx];
189 default:
190 DE_ASSERT(false);
191 return 0;
192 }
193 }
194
getNumIndices(void)195 int PrimitiveRestartCase::getNumIndices(void)
196 {
197 switch (m_indexType)
198 {
199 case INDEX_UNSIGNED_BYTE:
200 return (int)m_indicesUB.size();
201 case INDEX_UNSIGNED_SHORT:
202 return (int)m_indicesUS.size();
203 case INDEX_UNSIGNED_INT:
204 return (int)m_indicesUI.size();
205 default:
206 DE_ASSERT(false);
207 return 0;
208 }
209 }
210
211 // Pointer to the index value at index indexNdx.
getIndexPtr(int indexNdx)212 void *PrimitiveRestartCase::getIndexPtr(int indexNdx)
213 {
214 switch (m_indexType)
215 {
216 case INDEX_UNSIGNED_BYTE:
217 return (void *)&m_indicesUB[indexNdx];
218 case INDEX_UNSIGNED_SHORT:
219 return (void *)&m_indicesUS[indexNdx];
220 case INDEX_UNSIGNED_INT:
221 return (void *)&m_indicesUI[indexNdx];
222 default:
223 DE_ASSERT(false);
224 return DE_NULL;
225 }
226 }
227
init(void)228 void PrimitiveRestartCase::init(void)
229 {
230 // Create shader program.
231 std::string vertShaderSource;
232 if (m_primType == PRIMITIVE_POINTS)
233 {
234 vertShaderSource = "#version 300 es\n"
235 "in highp vec4 a_position;\n"
236 "\n"
237 "void main()\n"
238 "{\n"
239 " gl_Position = a_position;\n"
240 " gl_PointSize = 1.0f;\n"
241 "}\n";
242 }
243 else
244 {
245 vertShaderSource = "#version 300 es\n"
246 "in highp vec4 a_position;\n"
247 "\n"
248 "void main()\n"
249 "{\n"
250 " gl_Position = a_position;\n"
251 "}\n";
252 }
253
254 static const char *fragShaderSource = "#version 300 es\n"
255 "layout(location = 0) out mediump vec4 o_color;\n"
256 "\n"
257 "void main()\n"
258 "{\n"
259 " o_color = vec4(1.0f);\n"
260 "}\n";
261
262 DE_ASSERT(!m_program);
263 m_program = new glu::ShaderProgram(m_context.getRenderContext(),
264 glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
265
266 if (!m_program->isOk())
267 {
268 m_testCtx.getLog() << *m_program;
269 TCU_FAIL("Failed to compile shader");
270 }
271
272 uint32_t restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE :
273 m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT :
274 m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT :
275 0;
276
277 DE_ASSERT(restartIndex != 0);
278
279 DE_ASSERT(getNumIndices() == 0);
280
281 // If testing a case with restart at beginning, add it there.
282 if (m_beginWithRestart)
283 {
284 addIndex(restartIndex);
285 if (m_duplicateRestarts)
286 addIndex(restartIndex);
287 }
288
289 // Generate vertex positions and indices depending on primitive type.
290 // \note At this point, restarts shall not be added to the start or the end of the index vector. Those are special cases, and are done above and after the following if-else chain, respectively.
291
292 if (m_primType == PRIMITIVE_POINTS)
293 {
294 // Generate rows with different numbers of points.
295
296 uint32_t curIndex = 0;
297 const int numRows = 20;
298
299 for (int row = 0; row < numRows; row++)
300 {
301 for (int col = 0; col < row + 1; col++)
302 {
303 float fx = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numRows;
304 float fy = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
305
306 m_positions.push_back(fx);
307 m_positions.push_back(fy);
308
309 addIndex(curIndex++);
310 }
311
312 if (row < numRows - 1) // Add a restart after all but last row.
313 {
314 addIndex(restartIndex);
315 if (m_duplicateRestarts)
316 addIndex(restartIndex);
317 }
318 }
319 }
320 else if (m_primType == PRIMITIVE_LINE_STRIP || m_primType == PRIMITIVE_LINE_LOOP || m_primType == PRIMITIVE_LINES)
321 {
322 // Generate a numRows x numCols arrangement of line polygons of different vertex counts.
323
324 uint32_t curIndex = 0;
325 const int numRows = 4;
326 const int numCols = 4;
327
328 for (int row = 0; row < numRows; row++)
329 {
330 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
331
332 for (int col = 0; col < numCols; col++)
333 {
334 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
335 int numVertices = row * numCols + col + 1;
336
337 for (int i = 0; i < numVertices; i++)
338 {
339 float fx =
340 centerX + 0.9f * deFloatCos((float)i * 2.0f * DE_PI / (float)numVertices) / (float)numCols;
341 float fy =
342 centerY + 0.9f * deFloatSin((float)i * 2.0f * DE_PI / (float)numVertices) / (float)numRows;
343
344 m_positions.push_back(fx);
345 m_positions.push_back(fy);
346
347 addIndex(curIndex++);
348 }
349
350 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
351 {
352 addIndex(restartIndex);
353 if (m_duplicateRestarts)
354 addIndex(restartIndex);
355 }
356 }
357 }
358 }
359 else if (m_primType == PRIMITIVE_TRIANGLE_STRIP)
360 {
361 // Generate a number of horizontal triangle strips of different lengths.
362
363 uint32_t curIndex = 0;
364 const int numStrips = 20;
365
366 for (int stripNdx = 0; stripNdx < numStrips; stripNdx++)
367 {
368 int numVertices = stripNdx + 1;
369
370 for (int i = 0; i < numVertices; i++)
371 {
372 float fx = -0.9f + 1.8f * (float)(i / 2 * 2) / numStrips;
373 float fy = -0.9f + 1.8f * ((float)stripNdx + (i % 2 == 0 ? 0.0f : 0.8f)) / numStrips;
374
375 m_positions.push_back(fx);
376 m_positions.push_back(fy);
377
378 addIndex(curIndex++);
379 }
380
381 if (stripNdx < numStrips - 1) // Add a restart after all but last strip.
382 {
383 addIndex(restartIndex);
384 if (m_duplicateRestarts)
385 addIndex(restartIndex);
386 }
387 }
388 }
389 else if (m_primType == PRIMITIVE_TRIANGLE_FAN)
390 {
391 // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts.
392
393 uint32_t curIndex = 0;
394 const int numRows = 4;
395 const int numCols = 4;
396
397 for (int row = 0; row < numRows; row++)
398 {
399 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
400
401 for (int col = 0; col < numCols; col++)
402 {
403 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
404 int numArcVertices = row * numCols + col;
405
406 m_positions.push_back(centerX);
407 m_positions.push_back(centerY);
408
409 addIndex(curIndex++);
410
411 for (int i = 0; i < numArcVertices; i++)
412 {
413 float fx =
414 centerX + 0.9f * deFloatCos((float)i * 2.0f * DE_PI / (float)numArcVertices) / (float)numCols;
415 float fy =
416 centerY + 0.9f * deFloatSin((float)i * 2.0f * DE_PI / (float)numArcVertices) / (float)numRows;
417
418 m_positions.push_back(fx);
419 m_positions.push_back(fy);
420
421 addIndex(curIndex++);
422 }
423
424 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
425 {
426 addIndex(restartIndex);
427 if (m_duplicateRestarts)
428 addIndex(restartIndex);
429 }
430 }
431 }
432 }
433 else if (m_primType == PRIMITIVE_TRIANGLES)
434 {
435 // Generate a number of rows with (potentially incomplete) triangles.
436
437 uint32_t curIndex = 0;
438 const int numRows = 3 * 7;
439
440 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
441 {
442 int numVertices = rowNdx + 1;
443
444 for (int i = 0; i < numVertices; i++)
445 {
446 float fx = -0.9f + 1.8f * ((float)(i / 3) + (i % 3 == 2 ? 0.8f : 0.0f)) * 3 / numRows;
447 float fy = -0.9f + 1.8f * ((float)rowNdx + (i % 3 == 0 ? 0.0f : 0.8f)) / numRows;
448
449 m_positions.push_back(fx);
450 m_positions.push_back(fy);
451
452 addIndex(curIndex++);
453 }
454
455 if (rowNdx < numRows - 1) // Add a restart after all but last row.
456 {
457 addIndex(restartIndex);
458 if (m_duplicateRestarts)
459 addIndex(restartIndex);
460 }
461 }
462 }
463 else
464 DE_ASSERT(false);
465
466 // If testing a case with restart at end, add it there.
467 if (m_endWithRestart)
468 {
469 addIndex(restartIndex);
470 if (m_duplicateRestarts)
471 addIndex(restartIndex);
472 }
473
474 // Special case assertions.
475
476 int numIndices = getNumIndices();
477
478 DE_ASSERT(numIndices > 0);
479 DE_ASSERT(m_beginWithRestart ||
480 getIndex(0) != restartIndex); // We don't want restarts at beginning unless the case is a special case.
481 DE_ASSERT(m_endWithRestart || getIndex(numIndices - 1) !=
482 restartIndex); // We don't want restarts at end unless the case is a special case.
483
484 if (!m_duplicateRestarts)
485 for (int i = 1; i < numIndices; i++)
486 DE_ASSERT(getIndex(i) != restartIndex ||
487 getIndex(i - 1) !=
488 restartIndex); // We don't want duplicate restarts unless the case is a special case.
489 }
490
iterate(void)491 PrimitiveRestartCase::IterateResult PrimitiveRestartCase::iterate(void)
492 {
493 int width = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
494 int height = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
495
496 int xOffsetMax = m_context.getRenderTarget().getWidth() - width;
497 int yOffsetMax = m_context.getRenderTarget().getHeight() - height;
498
499 de::Random rnd(deStringHash(getName()));
500
501 int xOffset = rnd.getInt(0, xOffsetMax);
502 int yOffset = rnd.getInt(0, yOffsetMax);
503 tcu::Surface referenceImg(width, height);
504 tcu::Surface resultImg(width, height);
505
506 glViewport(xOffset, yOffset, width, height);
507 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
508
509 uint32_t program = m_program->getProgram();
510 glUseProgram(program);
511
512 // Setup position attribute.
513
514 int loc = glGetAttribLocation(program, "a_position");
515 glEnableVertexAttribArray(loc);
516 glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, &m_positions[0]);
517
518 // Render result.
519
520 renderWithRestart();
521 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess());
522
523 // Render reference (same scene as the real deal, but emulate primitive restart without actually using it).
524
525 renderWithoutRestart();
526 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, referenceImg.getAccess());
527
528 // Compare.
529
530 bool testOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result",
531 referenceImg, resultImg, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
532
533 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, testOk ? "Pass" : "Fail");
534
535 glUseProgram(0);
536
537 return STOP;
538 }
539
540 // Draw with the appropriate GLES3 draw function.
draw(int startNdx,int count)541 void PrimitiveRestartCase::draw(int startNdx, int count)
542 {
543 GLenum primTypeGL;
544
545 switch (m_primType)
546 {
547 case PRIMITIVE_POINTS:
548 primTypeGL = GL_POINTS;
549 break;
550 case PRIMITIVE_LINE_STRIP:
551 primTypeGL = GL_LINE_STRIP;
552 break;
553 case PRIMITIVE_LINE_LOOP:
554 primTypeGL = GL_LINE_LOOP;
555 break;
556 case PRIMITIVE_LINES:
557 primTypeGL = GL_LINES;
558 break;
559 case PRIMITIVE_TRIANGLE_STRIP:
560 primTypeGL = GL_TRIANGLE_STRIP;
561 break;
562 case PRIMITIVE_TRIANGLE_FAN:
563 primTypeGL = GL_TRIANGLE_FAN;
564 break;
565 case PRIMITIVE_TRIANGLES:
566 primTypeGL = GL_TRIANGLES;
567 break;
568 default:
569 DE_ASSERT(false);
570 primTypeGL = 0;
571 }
572
573 GLenum indexTypeGL;
574
575 switch (m_indexType)
576 {
577 case INDEX_UNSIGNED_BYTE:
578 indexTypeGL = GL_UNSIGNED_BYTE;
579 break;
580 case INDEX_UNSIGNED_SHORT:
581 indexTypeGL = GL_UNSIGNED_SHORT;
582 break;
583 case INDEX_UNSIGNED_INT:
584 indexTypeGL = GL_UNSIGNED_INT;
585 break;
586 default:
587 DE_ASSERT(false);
588 indexTypeGL = 0;
589 }
590
591 uint32_t restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE :
592 m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT :
593 m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT :
594 0;
595
596 DE_ASSERT(restartIndex != 0);
597
598 if (m_function == FUNCTION_DRAW_ELEMENTS)
599 glDrawElements(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid *)getIndexPtr(startNdx));
600 else if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED)
601 glDrawElementsInstanced(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid *)getIndexPtr(startNdx), 1);
602 else
603 {
604 DE_ASSERT(m_function == FUNCTION_DRAW_RANGE_ELEMENTS);
605
606 // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter).
607
608 uint32_t max = 0;
609
610 int numIndices = getNumIndices();
611 for (int i = 0; i < numIndices; i++)
612 {
613 uint32_t index = getIndex(i);
614 if (index != restartIndex && index > max)
615 max = index;
616 }
617
618 glDrawRangeElements(primTypeGL, 0, (GLuint)max, (GLsizei)count, indexTypeGL, (GLvoid *)getIndexPtr(startNdx));
619 }
620 }
621
renderWithRestart(void)622 void PrimitiveRestartCase::renderWithRestart(void)
623 {
624 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() begin");
625
626 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
627 GLU_CHECK_MSG("Enable primitive restart");
628 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
629 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithRestart()");
630
631 draw(0, getNumIndices());
632
633 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithRestart()");
634
635 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() end");
636 }
637
renderWithoutRestart(void)638 void PrimitiveRestartCase::renderWithoutRestart(void)
639 {
640 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() begin");
641
642 uint32_t restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE :
643 m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT :
644 m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT :
645 0;
646
647 DE_ASSERT(restartIndex != 0);
648
649 glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
650 GLU_CHECK_MSG("Disable primitive restart");
651 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
652 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithoutRestart()");
653
654 // Draw, emulating primitive restart.
655
656 int numIndices = getNumIndices();
657
658 DE_ASSERT(numIndices >= 0);
659
660 int indexArrayStartNdx =
661 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether.
662
663 for (int indexArrayNdx = 0; indexArrayNdx <= numIndices;
664 indexArrayNdx++) // \note Goes one "too far" in order to detect end of array as well.
665 {
666 if (indexArrayNdx >= numIndices ||
667 getIndex(indexArrayNdx) ==
668 restartIndex) // \note Handle end of array the same way as a restart index encounter.
669 {
670 if (indexArrayStartNdx < numIndices)
671 {
672 // Draw from index indexArrayStartNdx to index indexArrayNdx-1 .
673
674 draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx);
675 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithoutRestart()");
676 }
677
678 indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
679 }
680 }
681
682 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() end");
683 }
684
PrimitiveRestartTests(Context & context)685 PrimitiveRestartTests::PrimitiveRestartTests(Context &context)
686 : TestCaseGroup(context, "primitive_restart", "Primitive restart tests")
687 {
688 }
689
~PrimitiveRestartTests(void)690 PrimitiveRestartTests::~PrimitiveRestartTests(void)
691 {
692 }
693
init(void)694 void PrimitiveRestartTests::init(void)
695 {
696 for (int isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++)
697 for (int isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++)
698 for (int isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++)
699 {
700 bool isRestartBeginCase = isRestartBeginCaseI != 0;
701 bool isRestartEndCase = isRestartEndCaseI != 0;
702 bool isDuplicateRestartCase = isDuplicateRestartCaseI != 0;
703
704 std::string specialCaseGroupName;
705
706 if (isRestartBeginCase)
707 specialCaseGroupName = "begin_restart";
708 if (isRestartEndCase)
709 specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "end_restart";
710 if (isDuplicateRestartCase)
711 specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "duplicate_restarts";
712
713 if (specialCaseGroupName.empty())
714 specialCaseGroupName = "basic";
715
716 TestCaseGroup *specialCaseGroup = new TestCaseGroup(m_context, specialCaseGroupName.c_str(), "");
717 addChild(specialCaseGroup);
718
719 for (int primType = 0; primType < (int)PrimitiveRestartCase::PRIMITIVE_LAST; primType++)
720 {
721 const char *primTypeName =
722 primType == (int)PrimitiveRestartCase::PRIMITIVE_POINTS ? "points" :
723 primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_STRIP ? "line_strip" :
724 primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_LOOP ? "line_loop" :
725 primType == (int)PrimitiveRestartCase::PRIMITIVE_LINES ? "lines" :
726 primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_STRIP ? "triangle_strip" :
727 primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_FAN ? "triangle_fan" :
728 primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLES ? "triangles" :
729 DE_NULL;
730
731 DE_ASSERT(primTypeName != DE_NULL);
732
733 TestCaseGroup *primTypeGroup = new TestCaseGroup(m_context, primTypeName, "");
734 specialCaseGroup->addChild(primTypeGroup);
735
736 for (int indexType = 0; indexType < (int)PrimitiveRestartCase::INDEX_LAST; indexType++)
737 {
738 const char *indexTypeName =
739 indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_BYTE ? "unsigned_byte" :
740 indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_SHORT ? "unsigned_short" :
741 indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_INT ? "unsigned_int" :
742 DE_NULL;
743
744 DE_ASSERT(indexTypeName != DE_NULL);
745
746 TestCaseGroup *indexTypeGroup = new TestCaseGroup(m_context, indexTypeName, "");
747 primTypeGroup->addChild(indexTypeGroup);
748
749 for (int function = 0; function < (int)PrimitiveRestartCase::FUNCTION_LAST; function++)
750 {
751 const char *functionName =
752 function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS ?
753 "draw_elements" :
754 function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ?
755 "draw_elements_instanced" :
756 function == (int)PrimitiveRestartCase::FUNCTION_DRAW_RANGE_ELEMENTS ?
757 "draw_range_elements" :
758 DE_NULL;
759
760 DE_ASSERT(functionName != DE_NULL);
761
762 indexTypeGroup->addChild(new PrimitiveRestartCase(
763 m_context, functionName, "", (PrimitiveRestartCase::PrimitiveType)primType,
764 (PrimitiveRestartCase::IndexType)indexType, (PrimitiveRestartCase::Function)function,
765 isRestartBeginCase, isRestartEndCase, isDuplicateRestartCase));
766 }
767 }
768 }
769 }
770 }
771
772 } // namespace Functional
773 } // namespace gles3
774 } // namespace deqp
775