1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Primitive restart tests.
22 *//*--------------------------------------------------------------------*/
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"
46 static const int MAX_RENDER_WIDTH = 256;
47 static const int MAX_RENDER_HEIGHT = 256;
49 static const deUint32 MAX_UNSIGNED_BYTE = (1<<8) - 1;
50 static const deUint32 MAX_UNSIGNED_SHORT = (1<<16) - 1;
51 static const deUint32 MAX_UNSIGNED_INT = (deUint32)((1ULL << 32) - 1);
53 static const deUint8 RESTART_INDEX_UNSIGNED_BYTE = (deUint8)MAX_UNSIGNED_BYTE;
54 static const deUint16 RESTART_INDEX_UNSIGNED_SHORT = (deUint16)MAX_UNSIGNED_SHORT;
55 static const deUint32 RESTART_INDEX_UNSIGNED_INT = MAX_UNSIGNED_INT;
57 class PrimitiveRestartCase : public TestCase
66 PRIMITIVE_TRIANGLE_STRIP,
67 PRIMITIVE_TRIANGLE_FAN,
75 INDEX_UNSIGNED_BYTE = 0,
84 FUNCTION_DRAW_ELEMENTS = 0,
85 FUNCTION_DRAW_ELEMENTS_INSTANCED,
86 FUNCTION_DRAW_RANGE_ELEMENTS,
91 PrimitiveRestartCase (Context& context, const char* name, const char* description, PrimitiveType primType, IndexType indexType, Function function, bool beginWithRestart, bool endWithRestart, bool duplicateRestarts);
92 ~PrimitiveRestartCase (void);
96 IterateResult iterate (void);
99 PrimitiveRestartCase (const PrimitiveRestartCase& other);
100 PrimitiveRestartCase& operator= (const PrimitiveRestartCase& other);
102 void draw (int startNdx, int count);
104 void renderWithRestart (void);
105 void renderWithoutRestart (void);
107 // Helper functions for handling the appropriate index vector (according to m_indexType).
108 void addIndex (deUint32 index);
109 deUint32 getIndex (int indexNdx);
110 int getNumIndices (void);
111 void* getIndexPtr (int indexNdx);
113 // \note Only one of the following index vectors is used (according to m_indexType).
114 std::vector<deUint8> m_indicesUB;
115 std::vector<deUint16> m_indicesUS;
116 std::vector<deUint32> m_indicesUI;
118 std::vector<float> m_positions;
120 PrimitiveType m_primType;
121 IndexType m_indexType;
124 bool m_beginWithRestart; // Whether there will be restart indices at the beginning of the index array.
125 bool m_endWithRestart; // Whether there will be restart indices at the end of the index array.
126 bool m_duplicateRestarts; // Whether two consecutive restarts are used instead of one.
128 glu::ShaderProgram* m_program;
131 PrimitiveRestartCase::PrimitiveRestartCase (Context& context, const char* name, const char* description, PrimitiveType primType, IndexType indexType, Function function, bool beginWithRestart, bool endWithRestart, bool duplicateRestarts)
132 : TestCase (context, name, description)
133 , m_primType (primType)
134 , m_indexType (indexType)
135 , m_function (function)
136 , m_beginWithRestart (beginWithRestart)
137 , m_endWithRestart (endWithRestart)
138 , m_duplicateRestarts (duplicateRestarts)
139 , m_program (DE_NULL)
143 PrimitiveRestartCase::~PrimitiveRestartCase (void)
145 PrimitiveRestartCase::deinit();
148 void PrimitiveRestartCase::deinit (void)
154 void PrimitiveRestartCase::addIndex (deUint32 index)
156 if (m_indexType == INDEX_UNSIGNED_BYTE)
158 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_BYTE));
159 m_indicesUB.push_back((deUint8)index);
161 else if (m_indexType == INDEX_UNSIGNED_SHORT)
163 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_SHORT));
164 m_indicesUS.push_back((deUint16)index);
166 else if (m_indexType == INDEX_UNSIGNED_INT)
168 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_INT));
169 m_indicesUI.push_back((deUint32)index);
175 deUint32 PrimitiveRestartCase::getIndex (int indexNdx)
179 case INDEX_UNSIGNED_BYTE: return (deUint32)m_indicesUB[indexNdx];
180 case INDEX_UNSIGNED_SHORT: return (deUint32)m_indicesUS[indexNdx];
181 case INDEX_UNSIGNED_INT: return m_indicesUI[indexNdx];
188 int PrimitiveRestartCase::getNumIndices (void)
192 case INDEX_UNSIGNED_BYTE: return (int)m_indicesUB.size();
193 case INDEX_UNSIGNED_SHORT: return (int)m_indicesUS.size();
194 case INDEX_UNSIGNED_INT: return (int)m_indicesUI.size();
201 // Pointer to the index value at index indexNdx.
202 void* PrimitiveRestartCase::getIndexPtr (int indexNdx)
206 case INDEX_UNSIGNED_BYTE: return (void*)&m_indicesUB[indexNdx];
207 case INDEX_UNSIGNED_SHORT: return (void*)&m_indicesUS[indexNdx];
208 case INDEX_UNSIGNED_INT: return (void*)&m_indicesUI[indexNdx];
215 void PrimitiveRestartCase::init (void)
217 // Create shader program.
219 static const char* vertShaderSource =
221 "in highp vec4 a_position;\n"
225 " gl_Position = a_position;\n"
228 static const char* fragShaderSource =
230 "layout(location = 0) out mediump vec4 o_color;\n"
234 " o_color = vec4(1.0f);\n"
237 DE_ASSERT(!m_program);
238 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
240 if(!m_program->isOk())
242 m_testCtx.getLog() << *m_program;
243 TCU_FAIL("Failed to compile shader");
246 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE
247 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT
248 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT
251 DE_ASSERT(restartIndex != 0);
253 DE_ASSERT(getNumIndices() == 0);
255 // If testing a case with restart at beginning, add it there.
256 if (m_beginWithRestart)
258 addIndex(restartIndex);
259 if (m_duplicateRestarts)
260 addIndex(restartIndex);
263 // Generate vertex positions and indices depending on primitive type.
264 // \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.
266 if (m_primType == PRIMITIVE_POINTS)
268 // Generate rows with different numbers of points.
270 deUint32 curIndex = 0;
271 const int numRows = 20;
273 for (int row = 0; row < numRows; row++)
275 for (int col = 0; col < row + 1; col++)
277 float fx = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numRows;
278 float fy = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
280 m_positions.push_back(fx);
281 m_positions.push_back(fy);
283 addIndex(curIndex++);
286 if (row < numRows - 1) // Add a restart after all but last row.
288 addIndex(restartIndex);
289 if (m_duplicateRestarts)
290 addIndex(restartIndex);
294 else if (m_primType == PRIMITIVE_LINE_STRIP || m_primType == PRIMITIVE_LINE_LOOP || m_primType == PRIMITIVE_LINES)
296 // Generate a numRows x numCols arrangement of line polygons of different vertex counts.
298 deUint32 curIndex = 0;
299 const int numRows = 4;
300 const int numCols = 4;
302 for (int row = 0; row < numRows; row++)
304 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
306 for (int col = 0; col < numCols; col++)
308 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
309 int numVertices = row*numCols + col + 1;
311 for (int i = 0; i < numVertices; i++)
313 float fx = centerX + 0.9f * deFloatCos((float)i*2.0f*DE_PI / (float)numVertices) / (float)numCols;
314 float fy = centerY + 0.9f * deFloatSin((float)i*2.0f*DE_PI / (float)numVertices) / (float)numRows;
316 m_positions.push_back(fx);
317 m_positions.push_back(fy);
319 addIndex(curIndex++);
322 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
324 addIndex(restartIndex);
325 if (m_duplicateRestarts)
326 addIndex(restartIndex);
331 else if (m_primType == PRIMITIVE_TRIANGLE_STRIP)
333 // Generate a number of horizontal triangle strips of different lengths.
335 deUint32 curIndex = 0;
336 const int numStrips = 20;
338 for (int stripNdx = 0; stripNdx < numStrips; stripNdx++)
340 int numVertices = stripNdx + 1;
342 for (int i = 0; i < numVertices; i++)
344 float fx = -0.9f + 1.8f * (float)(i/2*2) / numStrips;
345 float fy = -0.9f + 1.8f * ((float)stripNdx + (i%2 == 0 ? 0.0f : 0.8f)) / numStrips;
347 m_positions.push_back(fx);
348 m_positions.push_back(fy);
350 addIndex(curIndex++);
353 if (stripNdx < numStrips - 1) // Add a restart after all but last strip.
355 addIndex(restartIndex);
356 if (m_duplicateRestarts)
357 addIndex(restartIndex);
361 else if (m_primType == PRIMITIVE_TRIANGLE_FAN)
363 // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts.
365 deUint32 curIndex = 0;
366 const int numRows = 4;
367 const int numCols = 4;
369 for (int row = 0; row < numRows; row++)
371 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
373 for (int col = 0; col < numCols; col++)
375 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
376 int numArcVertices = row*numCols + col;
378 m_positions.push_back(centerX);
379 m_positions.push_back(centerY);
381 addIndex(curIndex++);
383 for (int i = 0; i < numArcVertices; i++)
385 float fx = centerX + 0.9f * deFloatCos((float)i*2.0f*DE_PI / (float)numArcVertices) / (float)numCols;
386 float fy = centerY + 0.9f * deFloatSin((float)i*2.0f*DE_PI / (float)numArcVertices) / (float)numRows;
388 m_positions.push_back(fx);
389 m_positions.push_back(fy);
391 addIndex(curIndex++);
394 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
396 addIndex(restartIndex);
397 if (m_duplicateRestarts)
398 addIndex(restartIndex);
403 else if (m_primType == PRIMITIVE_TRIANGLES)
405 // Generate a number of rows with (potentially incomplete) triangles.
407 deUint32 curIndex = 0;
408 const int numRows = 3*7;
410 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
412 int numVertices = rowNdx + 1;
414 for (int i = 0; i < numVertices; i++)
416 float fx = -0.9f + 1.8f * ((float)(i/3) + (i%3 == 2 ? 0.8f : 0.0f)) * 3 / numRows;
417 float fy = -0.9f + 1.8f * ((float)rowNdx + (i%3 == 0 ? 0.0f : 0.8f)) / numRows;
419 m_positions.push_back(fx);
420 m_positions.push_back(fy);
422 addIndex(curIndex++);
425 if (rowNdx < numRows - 1) // Add a restart after all but last row.
427 addIndex(restartIndex);
428 if (m_duplicateRestarts)
429 addIndex(restartIndex);
436 // If testing a case with restart at end, add it there.
437 if (m_endWithRestart)
439 addIndex(restartIndex);
440 if (m_duplicateRestarts)
441 addIndex(restartIndex);
444 // Special case assertions.
446 int numIndices = getNumIndices();
448 DE_ASSERT(numIndices > 0);
449 DE_ASSERT(m_beginWithRestart || getIndex(0) != restartIndex); // We don't want restarts at beginning unless the case is a special case.
450 DE_ASSERT(m_endWithRestart || getIndex(numIndices-1) != restartIndex); // We don't want restarts at end unless the case is a special case.
452 if (!m_duplicateRestarts)
453 for (int i = 1; i < numIndices; i++)
454 DE_ASSERT(getIndex(i) != restartIndex || getIndex(i-1) != restartIndex); // We don't want duplicate restarts unless the case is a special case.
457 PrimitiveRestartCase::IterateResult PrimitiveRestartCase::iterate (void)
459 int width = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
460 int height = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
462 int xOffsetMax = m_context.getRenderTarget().getWidth() - width;
463 int yOffsetMax = m_context.getRenderTarget().getHeight() - height;
465 de::Random rnd (deStringHash(getName()));
467 int xOffset = rnd.getInt(0, xOffsetMax);
468 int yOffset = rnd.getInt(0, yOffsetMax);
469 tcu::Surface referenceImg (width, height);
470 tcu::Surface resultImg (width, height);
472 glViewport(xOffset, yOffset, width, height);
473 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
475 deUint32 program = m_program->getProgram();
476 glUseProgram(program);
478 // Setup position attribute.
480 int loc = glGetAttribLocation(program, "a_position");
481 glEnableVertexAttribArray(loc);
482 glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, &m_positions[0]);
487 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess());
489 // Render reference (same scene as the real deal, but emulate primitive restart without actually using it).
491 renderWithoutRestart();
492 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, referenceImg.getAccess());
496 bool testOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
498 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
499 testOk ? "Pass" : "Fail");
506 // Draw with the appropriate GLES3 draw function.
507 void PrimitiveRestartCase::draw (int startNdx, int count)
513 case PRIMITIVE_POINTS: primTypeGL = GL_POINTS; break;
514 case PRIMITIVE_LINE_STRIP: primTypeGL = GL_LINE_STRIP; break;
515 case PRIMITIVE_LINE_LOOP: primTypeGL = GL_LINE_LOOP; break;
516 case PRIMITIVE_LINES: primTypeGL = GL_LINES; break;
517 case PRIMITIVE_TRIANGLE_STRIP: primTypeGL = GL_TRIANGLE_STRIP; break;
518 case PRIMITIVE_TRIANGLE_FAN: primTypeGL = GL_TRIANGLE_FAN; break;
519 case PRIMITIVE_TRIANGLES: primTypeGL = GL_TRIANGLES; break;
529 case INDEX_UNSIGNED_BYTE: indexTypeGL = GL_UNSIGNED_BYTE; break;
530 case INDEX_UNSIGNED_SHORT: indexTypeGL = GL_UNSIGNED_SHORT; break;
531 case INDEX_UNSIGNED_INT: indexTypeGL = GL_UNSIGNED_INT; break;
537 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE
538 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT
539 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT
542 DE_ASSERT(restartIndex != 0);
544 if (m_function == FUNCTION_DRAW_ELEMENTS)
545 glDrawElements(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx));
546 else if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED)
547 glDrawElementsInstanced(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx), 1);
550 DE_ASSERT(m_function == FUNCTION_DRAW_RANGE_ELEMENTS);
552 // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter).
556 int numIndices = getNumIndices();
557 for (int i = 0; i < numIndices; i++)
559 deUint32 index = getIndex(i);
560 if (index != restartIndex && index > max)
564 glDrawRangeElements(primTypeGL, 0, (GLuint)max, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx));
568 void PrimitiveRestartCase::renderWithRestart (void)
570 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() begin");
572 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
573 GLU_CHECK_MSG("Enable primitive restart");
574 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
575 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithRestart()");
577 draw(0, getNumIndices());
579 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithRestart()");
581 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() end");
584 void PrimitiveRestartCase::renderWithoutRestart (void)
586 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() begin");
588 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE
589 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT
590 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT
593 DE_ASSERT(restartIndex != 0);
595 glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
596 GLU_CHECK_MSG("Disable primitive restart");
597 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
598 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithoutRestart()");
600 // Draw, emulating primitive restart.
602 int numIndices = getNumIndices();
604 DE_ASSERT(numIndices >= 0);
606 int indexArrayStartNdx = 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether.
608 for (int indexArrayNdx = 0; indexArrayNdx <= numIndices; indexArrayNdx++) // \note Goes one "too far" in order to detect end of array as well.
610 if (indexArrayNdx >= numIndices || getIndex(indexArrayNdx) == restartIndex) // \note Handle end of array the same way as a restart index encounter.
612 if (indexArrayStartNdx < numIndices)
614 // Draw from index indexArrayStartNdx to index indexArrayNdx-1 .
616 draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx);
617 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithoutRestart()");
620 indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
624 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() end");
627 PrimitiveRestartTests::PrimitiveRestartTests (Context& context)
628 : TestCaseGroup(context, "primitive_restart", "Primitive restart tests")
632 PrimitiveRestartTests::~PrimitiveRestartTests (void)
636 void PrimitiveRestartTests::init (void)
638 for (int isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++)
639 for (int isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++)
640 for (int isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++)
642 bool isRestartBeginCase = isRestartBeginCaseI != 0;
643 bool isRestartEndCase = isRestartEndCaseI != 0;
644 bool isDuplicateRestartCase = isDuplicateRestartCaseI != 0;
646 std::string specialCaseGroupName;
648 if (isRestartBeginCase) specialCaseGroupName = "begin_restart";
649 if (isRestartEndCase) specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "end_restart";
650 if (isDuplicateRestartCase) specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "duplicate_restarts";
652 if (specialCaseGroupName.empty())
653 specialCaseGroupName = "basic";
655 TestCaseGroup* specialCaseGroup = new TestCaseGroup(m_context, specialCaseGroupName.c_str(), "");
656 addChild(specialCaseGroup);
658 for (int primType = 0; primType < (int)PrimitiveRestartCase::PRIMITIVE_LAST; primType++)
660 const char* primTypeName = primType == (int)PrimitiveRestartCase::PRIMITIVE_POINTS ? "points"
661 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_STRIP ? "line_strip"
662 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_LOOP ? "line_loop"
663 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINES ? "lines"
664 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_STRIP ? "triangle_strip"
665 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_FAN ? "triangle_fan"
666 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLES ? "triangles"
669 DE_ASSERT(primTypeName != DE_NULL);
671 TestCaseGroup* primTypeGroup = new TestCaseGroup(m_context, primTypeName, "");
672 specialCaseGroup->addChild(primTypeGroup);
674 for (int indexType = 0; indexType < (int)PrimitiveRestartCase::INDEX_LAST; indexType++)
676 const char *indexTypeName = indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_BYTE ? "unsigned_byte"
677 : indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_SHORT ? "unsigned_short"
678 : indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_INT ? "unsigned_int"
681 DE_ASSERT(indexTypeName != DE_NULL);
683 TestCaseGroup* indexTypeGroup = new TestCaseGroup(m_context, indexTypeName, "");
684 primTypeGroup->addChild(indexTypeGroup);
686 for (int function = 0; function < (int)PrimitiveRestartCase::FUNCTION_LAST; function++)
688 const char* functionName = function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS ? "draw_elements"
689 : function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "draw_elements_instanced"
690 : function == (int)PrimitiveRestartCase::FUNCTION_DRAW_RANGE_ELEMENTS ? "draw_range_elements"
693 DE_ASSERT(functionName != DE_NULL);
695 indexTypeGroup->addChild(new PrimitiveRestartCase(m_context,
698 (PrimitiveRestartCase::PrimitiveType)primType,
699 (PrimitiveRestartCase::IndexType)indexType,
700 (PrimitiveRestartCase::Function)function,
703 isDuplicateRestartCase));