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 
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 
iterate(void)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.
draw(int startNdx,int count)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 
renderWithRestart(void)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 
renderWithoutRestart(void)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 
PrimitiveRestartTests(Context & context)627 PrimitiveRestartTests::PrimitiveRestartTests (Context& context)
628 	: TestCaseGroup(context, "primitive_restart", "Primitive restart tests")
629 {
630 }
631 
~PrimitiveRestartTests(void)632 PrimitiveRestartTests::~PrimitiveRestartTests (void)
633 {
634 }
635 
init(void)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
713