xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fPrimitiveRestartTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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