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
PrimitiveRestartCase(Context & context,const char * name,const char * description,PrimitiveType primType,IndexType indexType,Function function,bool beginWithRestart,bool endWithRestart,bool duplicateRestarts)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
~PrimitiveRestartCase(void)143 PrimitiveRestartCase::~PrimitiveRestartCase (void)
144 {
145 PrimitiveRestartCase::deinit();
146 }
147
deinit(void)148 void PrimitiveRestartCase::deinit (void)
149 {
150 delete m_program;
151 m_program = DE_NULL;
152 }
153
addIndex(deUint32 index)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
getIndex(int indexNdx)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
getNumIndices(void)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.
getIndexPtr(int 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
init(void)215 void PrimitiveRestartCase::init (void)
216 {
217 // Create shader program.
218 std::string vertShaderSource;
219 if (m_primType == PRIMITIVE_POINTS)
220 {
221 vertShaderSource =
222 "#version 300 es\n"
223 "in highp vec4 a_position;\n"
224 "\n"
225 "void main()\n"
226 "{\n"
227 " gl_Position = a_position;\n"
228 " gl_PointSize = 1.0f;\n"
229 "}\n";
230 }
231 else
232 {
233 vertShaderSource =
234 "#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 "}\n";
241 }
242
243 static const char* fragShaderSource =
244 "#version 300 es\n"
245 "layout(location = 0) out mediump vec4 o_color;\n"
246 "\n"
247 "void main()\n"
248 "{\n"
249 " o_color = vec4(1.0f);\n"
250 "}\n";
251
252 DE_ASSERT(!m_program);
253 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
254
255 if(!m_program->isOk())
256 {
257 m_testCtx.getLog() << *m_program;
258 TCU_FAIL("Failed to compile shader");
259 }
260
261 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE
262 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT
263 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT
264 : 0;
265
266 DE_ASSERT(restartIndex != 0);
267
268 DE_ASSERT(getNumIndices() == 0);
269
270 // If testing a case with restart at beginning, add it there.
271 if (m_beginWithRestart)
272 {
273 addIndex(restartIndex);
274 if (m_duplicateRestarts)
275 addIndex(restartIndex);
276 }
277
278 // Generate vertex positions and indices depending on primitive type.
279 // \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.
280
281 if (m_primType == PRIMITIVE_POINTS)
282 {
283 // Generate rows with different numbers of points.
284
285 deUint32 curIndex = 0;
286 const int numRows = 20;
287
288 for (int row = 0; row < numRows; row++)
289 {
290 for (int col = 0; col < row + 1; col++)
291 {
292 float fx = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numRows;
293 float fy = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
294
295 m_positions.push_back(fx);
296 m_positions.push_back(fy);
297
298 addIndex(curIndex++);
299 }
300
301 if (row < numRows - 1) // Add a restart after all but last row.
302 {
303 addIndex(restartIndex);
304 if (m_duplicateRestarts)
305 addIndex(restartIndex);
306 }
307 }
308 }
309 else if (m_primType == PRIMITIVE_LINE_STRIP || m_primType == PRIMITIVE_LINE_LOOP || m_primType == PRIMITIVE_LINES)
310 {
311 // Generate a numRows x numCols arrangement of line polygons of different vertex counts.
312
313 deUint32 curIndex = 0;
314 const int numRows = 4;
315 const int numCols = 4;
316
317 for (int row = 0; row < numRows; row++)
318 {
319 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
320
321 for (int col = 0; col < numCols; col++)
322 {
323 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
324 int numVertices = row*numCols + col + 1;
325
326 for (int i = 0; i < numVertices; i++)
327 {
328 float fx = centerX + 0.9f * deFloatCos((float)i*2.0f*DE_PI / (float)numVertices) / (float)numCols;
329 float fy = centerY + 0.9f * deFloatSin((float)i*2.0f*DE_PI / (float)numVertices) / (float)numRows;
330
331 m_positions.push_back(fx);
332 m_positions.push_back(fy);
333
334 addIndex(curIndex++);
335 }
336
337 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
338 {
339 addIndex(restartIndex);
340 if (m_duplicateRestarts)
341 addIndex(restartIndex);
342 }
343 }
344 }
345 }
346 else if (m_primType == PRIMITIVE_TRIANGLE_STRIP)
347 {
348 // Generate a number of horizontal triangle strips of different lengths.
349
350 deUint32 curIndex = 0;
351 const int numStrips = 20;
352
353 for (int stripNdx = 0; stripNdx < numStrips; stripNdx++)
354 {
355 int numVertices = stripNdx + 1;
356
357 for (int i = 0; i < numVertices; i++)
358 {
359 float fx = -0.9f + 1.8f * (float)(i/2*2) / numStrips;
360 float fy = -0.9f + 1.8f * ((float)stripNdx + (i%2 == 0 ? 0.0f : 0.8f)) / numStrips;
361
362 m_positions.push_back(fx);
363 m_positions.push_back(fy);
364
365 addIndex(curIndex++);
366 }
367
368 if (stripNdx < numStrips - 1) // Add a restart after all but last strip.
369 {
370 addIndex(restartIndex);
371 if (m_duplicateRestarts)
372 addIndex(restartIndex);
373 }
374 }
375 }
376 else if (m_primType == PRIMITIVE_TRIANGLE_FAN)
377 {
378 // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts.
379
380 deUint32 curIndex = 0;
381 const int numRows = 4;
382 const int numCols = 4;
383
384 for (int row = 0; row < numRows; row++)
385 {
386 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows;
387
388 for (int col = 0; col < numCols; col++)
389 {
390 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols;
391 int numArcVertices = row*numCols + col;
392
393 m_positions.push_back(centerX);
394 m_positions.push_back(centerY);
395
396 addIndex(curIndex++);
397
398 for (int i = 0; i < numArcVertices; i++)
399 {
400 float fx = centerX + 0.9f * deFloatCos((float)i*2.0f*DE_PI / (float)numArcVertices) / (float)numCols;
401 float fy = centerY + 0.9f * deFloatSin((float)i*2.0f*DE_PI / (float)numArcVertices) / (float)numRows;
402
403 m_positions.push_back(fx);
404 m_positions.push_back(fy);
405
406 addIndex(curIndex++);
407 }
408
409 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon.
410 {
411 addIndex(restartIndex);
412 if (m_duplicateRestarts)
413 addIndex(restartIndex);
414 }
415 }
416 }
417 }
418 else if (m_primType == PRIMITIVE_TRIANGLES)
419 {
420 // Generate a number of rows with (potentially incomplete) triangles.
421
422 deUint32 curIndex = 0;
423 const int numRows = 3*7;
424
425 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
426 {
427 int numVertices = rowNdx + 1;
428
429 for (int i = 0; i < numVertices; i++)
430 {
431 float fx = -0.9f + 1.8f * ((float)(i/3) + (i%3 == 2 ? 0.8f : 0.0f)) * 3 / numRows;
432 float fy = -0.9f + 1.8f * ((float)rowNdx + (i%3 == 0 ? 0.0f : 0.8f)) / numRows;
433
434 m_positions.push_back(fx);
435 m_positions.push_back(fy);
436
437 addIndex(curIndex++);
438 }
439
440 if (rowNdx < numRows - 1) // Add a restart after all but last row.
441 {
442 addIndex(restartIndex);
443 if (m_duplicateRestarts)
444 addIndex(restartIndex);
445 }
446 }
447 }
448 else
449 DE_ASSERT(DE_FALSE);
450
451 // If testing a case with restart at end, add it there.
452 if (m_endWithRestart)
453 {
454 addIndex(restartIndex);
455 if (m_duplicateRestarts)
456 addIndex(restartIndex);
457 }
458
459 // Special case assertions.
460
461 int numIndices = getNumIndices();
462
463 DE_ASSERT(numIndices > 0);
464 DE_ASSERT(m_beginWithRestart || getIndex(0) != restartIndex); // We don't want restarts at beginning unless the case is a special case.
465 DE_ASSERT(m_endWithRestart || getIndex(numIndices-1) != restartIndex); // We don't want restarts at end unless the case is a special case.
466
467 if (!m_duplicateRestarts)
468 for (int i = 1; i < numIndices; i++)
469 DE_ASSERT(getIndex(i) != restartIndex || getIndex(i-1) != restartIndex); // We don't want duplicate restarts unless the case is a special case.
470 }
471
iterate(void)472 PrimitiveRestartCase::IterateResult PrimitiveRestartCase::iterate (void)
473 {
474 int width = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
475 int height = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
476
477 int xOffsetMax = m_context.getRenderTarget().getWidth() - width;
478 int yOffsetMax = m_context.getRenderTarget().getHeight() - height;
479
480 de::Random rnd (deStringHash(getName()));
481
482 int xOffset = rnd.getInt(0, xOffsetMax);
483 int yOffset = rnd.getInt(0, yOffsetMax);
484 tcu::Surface referenceImg (width, height);
485 tcu::Surface resultImg (width, height);
486
487 glViewport(xOffset, yOffset, width, height);
488 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
489
490 deUint32 program = m_program->getProgram();
491 glUseProgram(program);
492
493 // Setup position attribute.
494
495 int loc = glGetAttribLocation(program, "a_position");
496 glEnableVertexAttribArray(loc);
497 glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, &m_positions[0]);
498
499 // Render result.
500
501 renderWithRestart();
502 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess());
503
504 // Render reference (same scene as the real deal, but emulate primitive restart without actually using it).
505
506 renderWithoutRestart();
507 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, referenceImg.getAccess());
508
509 // Compare.
510
511 bool testOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
512
513 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
514 testOk ? "Pass" : "Fail");
515
516 glUseProgram(0);
517
518 return STOP;
519 }
520
521 // Draw with the appropriate GLES3 draw function.
draw(int startNdx,int count)522 void PrimitiveRestartCase::draw (int startNdx, int count)
523 {
524 GLenum primTypeGL;
525
526 switch (m_primType)
527 {
528 case PRIMITIVE_POINTS: primTypeGL = GL_POINTS; break;
529 case PRIMITIVE_LINE_STRIP: primTypeGL = GL_LINE_STRIP; break;
530 case PRIMITIVE_LINE_LOOP: primTypeGL = GL_LINE_LOOP; break;
531 case PRIMITIVE_LINES: primTypeGL = GL_LINES; break;
532 case PRIMITIVE_TRIANGLE_STRIP: primTypeGL = GL_TRIANGLE_STRIP; break;
533 case PRIMITIVE_TRIANGLE_FAN: primTypeGL = GL_TRIANGLE_FAN; break;
534 case PRIMITIVE_TRIANGLES: primTypeGL = GL_TRIANGLES; break;
535 default:
536 DE_ASSERT(DE_FALSE);
537 primTypeGL = 0;
538 }
539
540 GLenum indexTypeGL;
541
542 switch (m_indexType)
543 {
544 case INDEX_UNSIGNED_BYTE: indexTypeGL = GL_UNSIGNED_BYTE; break;
545 case INDEX_UNSIGNED_SHORT: indexTypeGL = GL_UNSIGNED_SHORT; break;
546 case INDEX_UNSIGNED_INT: indexTypeGL = GL_UNSIGNED_INT; break;
547 default:
548 DE_ASSERT(DE_FALSE);
549 indexTypeGL = 0;
550 }
551
552 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE
553 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT
554 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT
555 : 0;
556
557 DE_ASSERT(restartIndex != 0);
558
559 if (m_function == FUNCTION_DRAW_ELEMENTS)
560 glDrawElements(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx));
561 else if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED)
562 glDrawElementsInstanced(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx), 1);
563 else
564 {
565 DE_ASSERT(m_function == FUNCTION_DRAW_RANGE_ELEMENTS);
566
567 // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter).
568
569 deUint32 max = 0;
570
571 int numIndices = getNumIndices();
572 for (int i = 0; i < numIndices; i++)
573 {
574 deUint32 index = getIndex(i);
575 if (index != restartIndex && index > max)
576 max = index;
577 }
578
579 glDrawRangeElements(primTypeGL, 0, (GLuint)max, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx));
580 }
581 }
582
renderWithRestart(void)583 void PrimitiveRestartCase::renderWithRestart (void)
584 {
585 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() begin");
586
587 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
588 GLU_CHECK_MSG("Enable primitive restart");
589 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
590 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithRestart()");
591
592 draw(0, getNumIndices());
593
594 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithRestart()");
595
596 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() end");
597 }
598
renderWithoutRestart(void)599 void PrimitiveRestartCase::renderWithoutRestart (void)
600 {
601 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() begin");
602
603 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE
604 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT
605 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT
606 : 0;
607
608 DE_ASSERT(restartIndex != 0);
609
610 glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
611 GLU_CHECK_MSG("Disable primitive restart");
612 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
613 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithoutRestart()");
614
615 // Draw, emulating primitive restart.
616
617 int numIndices = getNumIndices();
618
619 DE_ASSERT(numIndices >= 0);
620
621 int indexArrayStartNdx = 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether.
622
623 for (int indexArrayNdx = 0; indexArrayNdx <= numIndices; indexArrayNdx++) // \note Goes one "too far" in order to detect end of array as well.
624 {
625 if (indexArrayNdx >= numIndices || getIndex(indexArrayNdx) == restartIndex) // \note Handle end of array the same way as a restart index encounter.
626 {
627 if (indexArrayStartNdx < numIndices)
628 {
629 // Draw from index indexArrayStartNdx to index indexArrayNdx-1 .
630
631 draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx);
632 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithoutRestart()");
633 }
634
635 indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
636 }
637 }
638
639 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() end");
640 }
641
PrimitiveRestartTests(Context & context)642 PrimitiveRestartTests::PrimitiveRestartTests (Context& context)
643 : TestCaseGroup(context, "primitive_restart", "Primitive restart tests")
644 {
645 }
646
~PrimitiveRestartTests(void)647 PrimitiveRestartTests::~PrimitiveRestartTests (void)
648 {
649 }
650
init(void)651 void PrimitiveRestartTests::init (void)
652 {
653 for (int isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++)
654 for (int isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++)
655 for (int isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++)
656 {
657 bool isRestartBeginCase = isRestartBeginCaseI != 0;
658 bool isRestartEndCase = isRestartEndCaseI != 0;
659 bool isDuplicateRestartCase = isDuplicateRestartCaseI != 0;
660
661 std::string specialCaseGroupName;
662
663 if (isRestartBeginCase) specialCaseGroupName = "begin_restart";
664 if (isRestartEndCase) specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "end_restart";
665 if (isDuplicateRestartCase) specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "duplicate_restarts";
666
667 if (specialCaseGroupName.empty())
668 specialCaseGroupName = "basic";
669
670 TestCaseGroup* specialCaseGroup = new TestCaseGroup(m_context, specialCaseGroupName.c_str(), "");
671 addChild(specialCaseGroup);
672
673 for (int primType = 0; primType < (int)PrimitiveRestartCase::PRIMITIVE_LAST; primType++)
674 {
675 const char* primTypeName = primType == (int)PrimitiveRestartCase::PRIMITIVE_POINTS ? "points"
676 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_STRIP ? "line_strip"
677 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_LOOP ? "line_loop"
678 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINES ? "lines"
679 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_STRIP ? "triangle_strip"
680 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_FAN ? "triangle_fan"
681 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLES ? "triangles"
682 : DE_NULL;
683
684 DE_ASSERT(primTypeName != DE_NULL);
685
686 TestCaseGroup* primTypeGroup = new TestCaseGroup(m_context, primTypeName, "");
687 specialCaseGroup->addChild(primTypeGroup);
688
689 for (int indexType = 0; indexType < (int)PrimitiveRestartCase::INDEX_LAST; indexType++)
690 {
691 const char *indexTypeName = indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_BYTE ? "unsigned_byte"
692 : indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_SHORT ? "unsigned_short"
693 : indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_INT ? "unsigned_int"
694 : DE_NULL;
695
696 DE_ASSERT(indexTypeName != DE_NULL);
697
698 TestCaseGroup* indexTypeGroup = new TestCaseGroup(m_context, indexTypeName, "");
699 primTypeGroup->addChild(indexTypeGroup);
700
701 for (int function = 0; function < (int)PrimitiveRestartCase::FUNCTION_LAST; function++)
702 {
703 const char* functionName = function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS ? "draw_elements"
704 : function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "draw_elements_instanced"
705 : function == (int)PrimitiveRestartCase::FUNCTION_DRAW_RANGE_ELEMENTS ? "draw_range_elements"
706 : DE_NULL;
707
708 DE_ASSERT(functionName != DE_NULL);
709
710 indexTypeGroup->addChild(new PrimitiveRestartCase(m_context,
711 functionName,
712 "",
713 (PrimitiveRestartCase::PrimitiveType)primType,
714 (PrimitiveRestartCase::IndexType)indexType,
715 (PrimitiveRestartCase::Function)function,
716 isRestartBeginCase,
717 isRestartEndCase,
718 isDuplicateRestartCase));
719 }
720 }
721 }
722 }
723 }
724
725 } // Functional
726 } // gles3
727 } // deqp
728