Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fPrimitiveRestartTests.cpp
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 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);
52
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;
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, IndexType indexType, Function function, bool beginWithRestart, bool endWithRestart, bool duplicateRestarts);
92                                                         ~PrimitiveRestartCase   (void);
93
94         void                                    init                                    (void);
95         void                                    deinit                                  (void);
96         IterateResult                   iterate                                 (void);
97
98 private:
99                                                         PrimitiveRestartCase    (const PrimitiveRestartCase& other);
100         PrimitiveRestartCase&   operator=                               (const PrimitiveRestartCase& other);
101
102         void                                    draw                                    (int startNdx, int count);
103
104         void                                    renderWithRestart               (void);
105         void                                    renderWithoutRestart    (void);
106
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);
112
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;
117
118         std::vector<float>              m_positions;
119
120         PrimitiveType                   m_primType;
121         IndexType                               m_indexType;
122         Function                                m_function;
123
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.
127
128         glu::ShaderProgram*             m_program;
129 };
130
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)
140 {
141 }
142
143 PrimitiveRestartCase::~PrimitiveRestartCase (void)
144 {
145         PrimitiveRestartCase::deinit();
146 }
147
148 void PrimitiveRestartCase::deinit (void)
149 {
150         delete m_program;
151         m_program = DE_NULL;
152 }
153
154 void PrimitiveRestartCase::addIndex (deUint32 index)
155 {
156         if (m_indexType == INDEX_UNSIGNED_BYTE)
157         {
158                 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_BYTE));
159                 m_indicesUB.push_back((deUint8)index);
160         }
161         else if (m_indexType == INDEX_UNSIGNED_SHORT)
162         {
163                 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_SHORT));
164                 m_indicesUS.push_back((deUint16)index);
165         }
166         else if (m_indexType == INDEX_UNSIGNED_INT)
167         {
168                 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_INT));
169                 m_indicesUI.push_back((deUint32)index);
170         }
171         else
172                 DE_ASSERT(DE_FALSE);
173 }
174
175 deUint32 PrimitiveRestartCase::getIndex (int indexNdx)
176 {
177         switch (m_indexType)
178         {
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];
182                 default:
183                         DE_ASSERT(DE_FALSE);
184                         return 0;
185         }
186 }
187
188 int PrimitiveRestartCase::getNumIndices (void)
189 {
190         switch (m_indexType)
191         {
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();
195                 default:
196                         DE_ASSERT(DE_FALSE);
197                         return 0;
198         }
199 }
200
201 // Pointer to the index value at index indexNdx.
202 void* PrimitiveRestartCase::getIndexPtr (int indexNdx)
203 {
204         switch (m_indexType)
205         {
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];
209                 default:
210                         DE_ASSERT(DE_FALSE);
211                         return DE_NULL;
212         }
213 }
214
215 void PrimitiveRestartCase::init (void)
216 {
217         // Create shader program.
218
219         static const char* vertShaderSource =
220                 "#version 300 es\n"
221                 "in highp vec4 a_position;\n"
222                 "\n"
223                 "void main()\n"
224                 "{\n"
225                 "       gl_Position = a_position;\n"
226                 "}\n";
227
228         static const char* fragShaderSource =
229                 "#version 300 es\n"
230                 "layout(location = 0) out mediump vec4 o_color;\n"
231                 "\n"
232                 "void main()\n"
233                 "{\n"
234                 "       o_color = vec4(1.0f);\n"
235                 "}\n";
236
237         DE_ASSERT(!m_program);
238         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
239
240         if(!m_program->isOk())
241         {
242                 m_testCtx.getLog() << *m_program;
243                 TCU_FAIL("Failed to compile shader");
244         }
245
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
249                                                   : 0;
250
251         DE_ASSERT(restartIndex != 0);
252
253         DE_ASSERT(getNumIndices() == 0);
254
255         // If testing a case with restart at beginning, add it there.
256         if (m_beginWithRestart)
257         {
258                 addIndex(restartIndex);
259                 if (m_duplicateRestarts)
260                         addIndex(restartIndex);
261         }
262
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.
265
266         if (m_primType == PRIMITIVE_POINTS)
267         {
268                 // Generate rows with different numbers of points.
269
270                 deUint32        curIndex                        = 0;
271                 const int       numRows                         = 20;
272
273                 for (int row = 0; row < numRows; row++)
274                 {
275                         for (int col = 0; col < row + 1; col++)
276                         {
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;
279
280                                 m_positions.push_back(fx);
281                                 m_positions.push_back(fy);
282
283                                 addIndex(curIndex++);
284                         }
285
286                         if (row < numRows - 1) // Add a restart after all but last row.
287                         {
288                                 addIndex(restartIndex);
289                                 if (m_duplicateRestarts)
290                                         addIndex(restartIndex);
291                         }
292                 }
293         }
294         else if (m_primType == PRIMITIVE_LINE_STRIP || m_primType == PRIMITIVE_LINE_LOOP || m_primType == PRIMITIVE_LINES)
295         {
296                 // Generate a numRows x numCols arrangement of line polygons of different vertex counts.
297
298                 deUint32        curIndex        = 0;
299                 const int       numRows         = 4;
300                 const int       numCols         = 4;
301
302                 for (int row = 0; row < numRows; row++)
303                 {
304                         float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
305
306                         for (int col = 0; col < numCols; col++)
307                         {
308                                 float   centerX         = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
309                                 int             numVertices     = row*numCols + col + 1;
310
311                                 for (int i = 0; i < numVertices; i++)
312                                 {
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;
315
316                                         m_positions.push_back(fx);
317                                         m_positions.push_back(fy);
318
319                                         addIndex(curIndex++);
320                                 }
321
322                                 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
323                                 {
324                                         addIndex(restartIndex);
325                                         if (m_duplicateRestarts)
326                                                 addIndex(restartIndex);
327                                 }
328                         }
329                 }
330         }
331         else if (m_primType == PRIMITIVE_TRIANGLE_STRIP)
332         {
333                 // Generate a number of horizontal triangle strips of different lengths.
334
335                 deUint32        curIndex        = 0;
336                 const int       numStrips       = 20;
337
338                 for (int stripNdx = 0; stripNdx < numStrips; stripNdx++)
339                 {
340                         int numVertices = stripNdx + 1;
341
342                         for (int i = 0; i < numVertices; i++)
343                         {
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;
346
347                                 m_positions.push_back(fx);
348                                 m_positions.push_back(fy);
349
350                                 addIndex(curIndex++);
351                         }
352
353                         if (stripNdx < numStrips - 1) // Add a restart after all but last strip.
354                         {
355                                 addIndex(restartIndex);
356                                 if (m_duplicateRestarts)
357                                         addIndex(restartIndex);
358                         }
359                 }
360         }
361         else if (m_primType == PRIMITIVE_TRIANGLE_FAN)
362         {
363                 // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts.
364
365                 deUint32        curIndex        = 0;
366                 const int       numRows         = 4;
367                 const int       numCols         = 4;
368
369                 for (int row = 0; row < numRows; row++)
370                 {
371                         float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
372
373                         for (int col = 0; col < numCols; col++)
374                         {
375                                 float   centerX                 = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
376                                 int             numArcVertices  = row*numCols + col;
377
378                                 m_positions.push_back(centerX);
379                                 m_positions.push_back(centerY);
380
381                                 addIndex(curIndex++);
382
383                                 for (int i = 0; i < numArcVertices; i++)
384                                 {
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;
387
388                                         m_positions.push_back(fx);
389                                         m_positions.push_back(fy);
390
391                                         addIndex(curIndex++);
392                                 }
393
394                                 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
395                                 {
396                                         addIndex(restartIndex);
397                                         if (m_duplicateRestarts)
398                                                 addIndex(restartIndex);
399                                 }
400                         }
401                 }
402         }
403         else if (m_primType == PRIMITIVE_TRIANGLES)
404         {
405                 // Generate a number of rows with (potentially incomplete) triangles.
406
407                 deUint32        curIndex        = 0;
408                 const int       numRows         = 3*7;
409
410                 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
411                 {
412                         int numVertices = rowNdx + 1;
413
414                         for (int i = 0; i < numVertices; i++)
415                         {
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;
418
419                                 m_positions.push_back(fx);
420                                 m_positions.push_back(fy);
421
422                                 addIndex(curIndex++);
423                         }
424
425                         if (rowNdx < numRows - 1) // Add a restart after all but last row.
426                         {
427                                 addIndex(restartIndex);
428                                 if (m_duplicateRestarts)
429                                         addIndex(restartIndex);
430                         }
431                 }
432         }
433         else
434                 DE_ASSERT(DE_FALSE);
435
436         // If testing a case with restart at end, add it there.
437         if (m_endWithRestart)
438         {
439                 addIndex(restartIndex);
440                 if (m_duplicateRestarts)
441                         addIndex(restartIndex);
442         }
443
444         // Special case assertions.
445
446         int numIndices = getNumIndices();
447
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.
451
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.
455 }
456
457 PrimitiveRestartCase::IterateResult PrimitiveRestartCase::iterate (void)
458 {
459         int                                                     width                   = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
460         int                                                     height                  = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
461
462         int                                                     xOffsetMax              = m_context.getRenderTarget().getWidth() - width;
463         int                                                     yOffsetMax              = m_context.getRenderTarget().getHeight() - height;
464
465         de::Random                                      rnd                             (deStringHash(getName()));
466
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);
471
472         glViewport(xOffset, yOffset, width, height);
473         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
474
475         deUint32 program = m_program->getProgram();
476         glUseProgram(program);
477
478         // Setup position attribute.
479
480         int loc = glGetAttribLocation(program, "a_position");
481         glEnableVertexAttribArray(loc);
482         glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, &m_positions[0]);
483
484         // Render result.
485
486         renderWithRestart();
487         glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess());
488
489         // Render reference (same scene as the real deal, but emulate primitive restart without actually using it).
490
491         renderWithoutRestart();
492         glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, referenceImg.getAccess());
493
494         // Compare.
495
496         bool testOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
497
498         m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
499                                                         testOk ? "Pass"                                 : "Fail");
500
501         glUseProgram(0);
502
503         return STOP;
504 }
505
506 // Draw with the appropriate GLES3 draw function.
507 void PrimitiveRestartCase::draw (int startNdx, int count)
508 {
509         GLenum primTypeGL;
510
511         switch (m_primType)
512         {
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;
520                 default:
521                         DE_ASSERT(DE_FALSE);
522                         primTypeGL = 0;
523         }
524
525         GLenum indexTypeGL;
526
527         switch (m_indexType)
528         {
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;
532                 default:
533                         DE_ASSERT(DE_FALSE);
534                         indexTypeGL = 0;
535         }
536
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
540                                                   : 0;
541
542         DE_ASSERT(restartIndex != 0);
543
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);
548         else
549         {
550                 DE_ASSERT(m_function == FUNCTION_DRAW_RANGE_ELEMENTS);
551
552                 // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter).
553
554                 deUint32 max = 0;
555
556                 int numIndices = getNumIndices();
557                 for (int i = 0; i < numIndices; i++)
558                 {
559                         deUint32 index = getIndex(i);
560                         if (index != restartIndex && index > max)
561                                 max = index;
562                 }
563
564                 glDrawRangeElements(primTypeGL, 0, (GLuint)max, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx));
565         }
566 }
567
568 void PrimitiveRestartCase::renderWithRestart (void)
569 {
570         GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() begin");
571
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()");
576
577         draw(0, getNumIndices());
578
579         GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithRestart()");
580
581         GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() end");
582 }
583
584 void PrimitiveRestartCase::renderWithoutRestart (void)
585 {
586         GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() begin");
587
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
591                                                   : 0;
592
593         DE_ASSERT(restartIndex != 0);
594
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()");
599
600         // Draw, emulating primitive restart.
601
602         int numIndices = getNumIndices();
603
604         DE_ASSERT(numIndices >= 0);
605
606         int indexArrayStartNdx = 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether.
607
608         for (int indexArrayNdx = 0; indexArrayNdx <= numIndices; indexArrayNdx++) // \note Goes one "too far" in order to detect end of array as well.
609         {
610                 if (indexArrayNdx >= numIndices || getIndex(indexArrayNdx) == restartIndex) // \note Handle end of array the same way as a restart index encounter.
611                 {
612                         if (indexArrayStartNdx < numIndices)
613                         {
614                                 // Draw from index indexArrayStartNdx to index indexArrayNdx-1 .
615
616                                 draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx);
617                                 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithoutRestart()");
618                         }
619
620                         indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
621                 }
622         }
623
624         GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() end");
625 }
626
627 PrimitiveRestartTests::PrimitiveRestartTests (Context& context)
628         : TestCaseGroup(context, "primitive_restart", "Primitive restart tests")
629 {
630 }
631
632 PrimitiveRestartTests::~PrimitiveRestartTests (void)
633 {
634 }
635
636 void PrimitiveRestartTests::init (void)
637 {
638         for (int isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++)
639         for (int isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++)
640         for (int isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++)
641         {
642                 bool                    isRestartBeginCase              = isRestartBeginCaseI != 0;
643                 bool                    isRestartEndCase                = isRestartEndCaseI != 0;
644                 bool                    isDuplicateRestartCase  = isDuplicateRestartCaseI != 0;
645
646                 std::string             specialCaseGroupName;
647
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";
651
652                 if (specialCaseGroupName.empty())
653                         specialCaseGroupName = "basic";
654
655                 TestCaseGroup* specialCaseGroup = new TestCaseGroup(m_context, specialCaseGroupName.c_str(), "");
656                 addChild(specialCaseGroup);
657
658                 for (int primType = 0; primType < (int)PrimitiveRestartCase::PRIMITIVE_LAST; primType++)
659                 {
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"
667                                                                          : DE_NULL;
668
669                         DE_ASSERT(primTypeName != DE_NULL);
670
671                         TestCaseGroup* primTypeGroup = new TestCaseGroup(m_context, primTypeName, "");
672                         specialCaseGroup->addChild(primTypeGroup);
673
674                         for (int indexType = 0; indexType < (int)PrimitiveRestartCase::INDEX_LAST; indexType++)
675                         {
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"
679                                                                                   : DE_NULL;
680
681                                 DE_ASSERT(indexTypeName != DE_NULL);
682
683                                 TestCaseGroup* indexTypeGroup = new TestCaseGroup(m_context, indexTypeName, "");
684                                 primTypeGroup->addChild(indexTypeGroup);
685
686                                 for (int function = 0; function < (int)PrimitiveRestartCase::FUNCTION_LAST; function++)
687                                 {
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"
691                                                                                          : DE_NULL;
692
693                                         DE_ASSERT(functionName != DE_NULL);
694
695                                         indexTypeGroup->addChild(new PrimitiveRestartCase(m_context,
696                                                                                                                                           functionName,
697                                                                                                                                           "",
698                                                                                                                                           (PrimitiveRestartCase::PrimitiveType)primType,
699                                                                                                                                           (PrimitiveRestartCase::IndexType)indexType,
700                                                                                                                                           (PrimitiveRestartCase::Function)function,
701                                                                                                                                           isRestartBeginCase,
702                                                                                                                                           isRestartEndCase,
703                                                                                                                                           isDuplicateRestartCase));
704                                 }
705                         }
706                 }
707         }
708 }
709
710 } // Functional
711 } // gles3
712 } // deqp