• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Drawing tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fDrawTests.hpp"
25 #include "deRandom.hpp"
26 #include "deStringUtil.hpp"
27 #include "deMemory.h"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuVectorUtil.hpp"
30 #include "sglrGLContext.hpp"
31 #include "glsDrawTest.hpp"
32 #include "gluStrUtil.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluCallLogWrapper.hpp"
35 
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 
39 #include <set>
40 
41 namespace deqp
42 {
43 namespace gles31
44 {
45 namespace Functional
46 {
47 namespace
48 {
49 
50 enum TestIterationType
51 {
52 	TYPE_DRAW_COUNT,		// !< test with 1, 5, and 25 primitives
53 	TYPE_INSTANCE_COUNT,	// !< test with 1, 4, and 11 instances
54 
55 	TYPE_LAST
56 };
57 
58 static const char* s_commonVertexShaderSource =		"#version 310 es\n"
59 													"in highp vec4 a_position;\n"
60 													"void main (void)\n"
61 													"{\n"
62 													"	gl_Position = a_position;\n"
63 													"}\n";
64 static const char* s_commonFragmentShaderSource	=	"#version 310 es\n"
65 													"layout(location = 0) out highp vec4 fragColor;\n"
66 													"void main (void)\n"
67 													"{\n"
68 													"	fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
69 													"}\n";
70 
71 static const char* s_colorVertexShaderSource =		"#version 310 es\n"
72 													"in highp vec4 a_position;\n"
73 													"in highp vec4 a_color;\n"
74 													"out highp vec4 v_color;\n"
75 													"void main (void)\n"
76 													"{\n"
77 													"	gl_Position = a_position;\n"
78 													"	v_color = a_color;\n"
79 													"}\n";
80 static const char* s_colorFragmentShaderSource	=	"#version 310 es\n"
81 													"layout(location = 0) out highp vec4 fragColor;\n"
82 													"in highp vec4 v_color;\n"
83 													"void main (void)\n"
84 													"{\n"
85 													"	fragColor = v_color;\n"
86 													"}\n";
87 struct DrawElementsCommand
88 {
89 	deUint32 count;
90 	deUint32 primCount;
91 	deUint32 firstIndex;
92 	deInt32  baseVertex;
93 	deUint32 reservedMustBeZero;
94 };
95 DE_STATIC_ASSERT(5 * sizeof(deUint32) == sizeof(DrawElementsCommand)); // tight packing
96 
97 struct DrawArraysCommand
98 {
99 	deUint32 count;
100 	deUint32 primCount;
101 	deUint32 first;
102 	deUint32 reservedMustBeZero;
103 };
104 DE_STATIC_ASSERT(4 * sizeof(deUint32) == sizeof(DrawArraysCommand)); // tight packing
105 
106 // Verifies image contains only yellow or greeen, or a linear combination
107 // of these colors.
verifyImageYellowGreen(const tcu::Surface & image,tcu::TestLog & log)108 static bool verifyImageYellowGreen (const tcu::Surface& image, tcu::TestLog& log)
109 {
110 	using tcu::TestLog;
111 
112 	const tcu::RGBA green		(0, 255, 0, 255);
113 	const tcu::RGBA yellow		(255, 255, 0, 255);
114 	const int colorThreshold	= 20;
115 
116 	tcu::Surface error			(image.getWidth(), image.getHeight());
117 	bool isOk					= true;
118 
119 	for (int y = 0; y < image.getHeight(); y++)
120 	for (int x = 0; x < image.getWidth(); x++)
121 	{
122 		const tcu::RGBA pixel = image.getPixel(x, y);
123 		bool pixelOk = true;
124 
125 		// Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
126 		if (de::abs(pixel.getGreen() - 255) > colorThreshold)
127 			pixelOk = false;
128 
129 		// Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
130 		if (de::abs(pixel.getBlue() - 0) > colorThreshold)
131 			pixelOk = false;
132 
133 		error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
134 		isOk = isOk && pixelOk;
135 	}
136 
137 	if (!isOk)
138 	{
139 		log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
140 		log << TestLog::ImageSet("Verfication result", "Result of rendering")
141 			<< TestLog::Image("Result",		"Result",		image)
142 			<< TestLog::Image("ErrorMask",	"Error mask",	error)
143 			<< TestLog::EndImageSet;
144 	}
145 	else
146 	{
147 		log << TestLog::ImageSet("Verfication result", "Result of rendering")
148 			<< TestLog::Image("Result", "Result", image)
149 			<< TestLog::EndImageSet;
150 	}
151 
152 	return isOk;
153 }
154 
addTestIterations(gls::DrawTest * test,gls::DrawTestSpec & spec,TestIterationType type)155 static void addTestIterations (gls::DrawTest* test, gls::DrawTestSpec& spec, TestIterationType type)
156 {
157 	if (type == TYPE_DRAW_COUNT)
158 	{
159 		spec.primitiveCount = 1;
160 		test->addIteration(spec, "draw count = 1");
161 
162 		spec.primitiveCount = 5;
163 		test->addIteration(spec, "draw count = 5");
164 
165 		spec.primitiveCount = 25;
166 		test->addIteration(spec, "draw count = 25");
167 	}
168 	else if (type == TYPE_INSTANCE_COUNT)
169 	{
170 		spec.instanceCount = 1;
171 		test->addIteration(spec, "instance count = 1");
172 
173 		spec.instanceCount = 4;
174 		test->addIteration(spec, "instance count = 4");
175 
176 		spec.instanceCount = 11;
177 		test->addIteration(spec, "instance count = 11");
178 	}
179 	else
180 		DE_ASSERT(false);
181 }
182 
genBasicSpec(gls::DrawTestSpec & spec,gls::DrawTestSpec::DrawMethod method)183 static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method)
184 {
185 	spec.apiType							= glu::ApiType::es(3,1);
186 	spec.primitive							= gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
187 	spec.primitiveCount						= 5;
188 	spec.drawMethod							= method;
189 	spec.indexType							= gls::DrawTestSpec::INDEXTYPE_LAST;
190 	spec.indexPointerOffset					= 0;
191 	spec.indexStorage						= gls::DrawTestSpec::STORAGE_LAST;
192 	spec.first								= 0;
193 	spec.indexMin							= 0;
194 	spec.indexMax							= 0;
195 	spec.instanceCount						= 1;
196 	spec.indirectOffset						= 0;
197 
198 	spec.attribs.resize(2);
199 
200 	spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
201 	spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
202 	spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
203 	spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
204 	spec.attribs[0].componentCount			= 4;
205 	spec.attribs[0].offset					= 0;
206 	spec.attribs[0].stride					= 0;
207 	spec.attribs[0].normalize				= false;
208 	spec.attribs[0].instanceDivisor			= 0;
209 	spec.attribs[0].useDefaultAttribute		= false;
210 
211 	spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
212 	spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
213 	spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
214 	spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
215 	spec.attribs[1].componentCount			= 2;
216 	spec.attribs[1].offset					= 0;
217 	spec.attribs[1].stride					= 0;
218 	spec.attribs[1].normalize				= false;
219 	spec.attribs[1].instanceDivisor			= 0;
220 	spec.attribs[1].useDefaultAttribute		= false;
221 }
222 
sizeToString(int size)223 static std::string sizeToString (int size)
224 {
225 	if (size < 1024)
226 		return de::toString(size) + " byte(s)";
227 	if (size < 1024*1024)
228 		return de::toString(size / 1024) + " KB";
229 	return de::toString(size / 1024 / 1024) + " MB";
230 }
231 
232 class AttributeGroup : public TestCaseGroup
233 {
234 public:
235 									AttributeGroup	(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage);
236 									~AttributeGroup	(void);
237 
238 	void							init			(void);
239 
240 private:
241 	gls::DrawTestSpec::DrawMethod	m_method;
242 	gls::DrawTestSpec::Primitive	m_primitive;
243 	gls::DrawTestSpec::IndexType	m_indexType;
244 	gls::DrawTestSpec::Storage		m_indexStorage;
245 };
246 
AttributeGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod,gls::DrawTestSpec::Primitive primitive,gls::DrawTestSpec::IndexType indexType,gls::DrawTestSpec::Storage indexStorage)247 AttributeGroup::AttributeGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage)
248 	: TestCaseGroup		(context, name, descr)
249 	, m_method			(drawMethod)
250 	, m_primitive		(primitive)
251 	, m_indexType		(indexType)
252 	, m_indexStorage	(indexStorage)
253 {
254 }
255 
~AttributeGroup(void)256 AttributeGroup::~AttributeGroup (void)
257 {
258 }
259 
init(void)260 void AttributeGroup::init (void)
261 {
262 	// Single attribute
263 	{
264 		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array.");
265 		gls::DrawTestSpec	spec;
266 
267 		spec.apiType							= glu::ApiType::es(3,1);
268 		spec.primitive							= m_primitive;
269 		spec.primitiveCount						= 5;
270 		spec.drawMethod							= m_method;
271 		spec.indexType							= m_indexType;
272 		spec.indexPointerOffset					= 0;
273 		spec.indexStorage						= m_indexStorage;
274 		spec.first								= 0;
275 		spec.indexMin							= 0;
276 		spec.indexMax							= 0;
277 		spec.instanceCount						= 1;
278 		spec.indirectOffset						= 0;
279 
280 		spec.attribs.resize(1);
281 
282 		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
283 		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
284 		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
285 		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
286 		spec.attribs[0].componentCount			= 2;
287 		spec.attribs[0].offset					= 0;
288 		spec.attribs[0].stride					= 0;
289 		spec.attribs[0].normalize				= false;
290 		spec.attribs[0].instanceDivisor			= 0;
291 		spec.attribs[0].useDefaultAttribute		= false;
292 
293 		addTestIterations(test, spec, TYPE_DRAW_COUNT);
294 
295 		this->addChild(test);
296 	}
297 
298 	// Multiple attribute
299 	{
300 		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes", "Multiple attribute arrays.");
301 		gls::DrawTestSpec	spec;
302 
303 		spec.apiType							= glu::ApiType::es(3,1);
304 		spec.primitive							= m_primitive;
305 		spec.primitiveCount						= 5;
306 		spec.drawMethod							= m_method;
307 		spec.indexType							= m_indexType;
308 		spec.indexPointerOffset					= 0;
309 		spec.indexStorage						= m_indexStorage;
310 		spec.first								= 0;
311 		spec.indexMin							= 0;
312 		spec.indexMax							= 0;
313 		spec.instanceCount						= 1;
314 		spec.indirectOffset						= 0;
315 
316 		spec.attribs.resize(2);
317 
318 		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
319 		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
320 		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
321 		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
322 		spec.attribs[0].componentCount			= 4;
323 		spec.attribs[0].offset					= 0;
324 		spec.attribs[0].stride					= 0;
325 		spec.attribs[0].normalize				= false;
326 		spec.attribs[0].instanceDivisor			= 0;
327 		spec.attribs[0].useDefaultAttribute		= false;
328 
329 		spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
330 		spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
331 		spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
332 		spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
333 		spec.attribs[1].componentCount			= 2;
334 		spec.attribs[1].offset					= 0;
335 		spec.attribs[1].stride					= 0;
336 		spec.attribs[1].normalize				= false;
337 		spec.attribs[1].instanceDivisor			= 0;
338 		spec.attribs[1].useDefaultAttribute		= false;
339 
340 		addTestIterations(test, spec, TYPE_DRAW_COUNT);
341 
342 		this->addChild(test);
343 	}
344 
345 	// Multiple attribute, second one divided
346 	{
347 		gls::DrawTest*		test					= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes", "Instanced attribute array.");
348 		gls::DrawTestSpec	spec;
349 
350 		spec.apiType								= glu::ApiType::es(3,1);
351 		spec.primitive								= m_primitive;
352 		spec.primitiveCount							= 5;
353 		spec.drawMethod								= m_method;
354 		spec.indexType								= m_indexType;
355 		spec.indexPointerOffset						= 0;
356 		spec.indexStorage							= m_indexStorage;
357 		spec.first									= 0;
358 		spec.indexMin								= 0;
359 		spec.indexMax								= 0;
360 		spec.instanceCount							= 1;
361 		spec.indirectOffset							= 0;
362 
363 		spec.attribs.resize(3);
364 
365 		spec.attribs[0].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
366 		spec.attribs[0].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
367 		spec.attribs[0].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
368 		spec.attribs[0].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
369 		spec.attribs[0].componentCount				= 4;
370 		spec.attribs[0].offset						= 0;
371 		spec.attribs[0].stride						= 0;
372 		spec.attribs[0].normalize					= false;
373 		spec.attribs[0].instanceDivisor				= 0;
374 		spec.attribs[0].useDefaultAttribute			= false;
375 
376 		// Add another position component so the instances wont be drawn on each other
377 		spec.attribs[1].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
378 		spec.attribs[1].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
379 		spec.attribs[1].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
380 		spec.attribs[1].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
381 		spec.attribs[1].componentCount				= 2;
382 		spec.attribs[1].offset						= 0;
383 		spec.attribs[1].stride						= 0;
384 		spec.attribs[1].normalize					= false;
385 		spec.attribs[1].instanceDivisor				= 1;
386 		spec.attribs[1].useDefaultAttribute			= false;
387 		spec.attribs[1].additionalPositionAttribute	= true;
388 
389 		// Instanced color
390 		spec.attribs[2].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
391 		spec.attribs[2].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
392 		spec.attribs[2].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
393 		spec.attribs[2].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
394 		spec.attribs[2].componentCount				= 3;
395 		spec.attribs[2].offset						= 0;
396 		spec.attribs[2].stride						= 0;
397 		spec.attribs[2].normalize					= false;
398 		spec.attribs[2].instanceDivisor				= 1;
399 		spec.attribs[2].useDefaultAttribute			= false;
400 
401 		addTestIterations(test, spec, TYPE_INSTANCE_COUNT);
402 
403 		this->addChild(test);
404 	}
405 
406 	// Multiple attribute, second one default
407 	{
408 		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute", "Attribute specified with glVertexAttrib*.");
409 		gls::DrawTestSpec	spec;
410 
411 		spec.apiType							= glu::ApiType::es(3,1);
412 		spec.primitive							= m_primitive;
413 		spec.primitiveCount						= 5;
414 		spec.drawMethod							= m_method;
415 		spec.indexType							= m_indexType;
416 		spec.indexPointerOffset					= 0;
417 		spec.indexStorage						= m_indexStorage;
418 		spec.first								= 0;
419 		spec.indexMin							= 0;
420 		spec.indexMax							= 0;
421 		spec.instanceCount						= 1;
422 		spec.indirectOffset						= 0;
423 
424 		spec.attribs.resize(2);
425 
426 		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
427 		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
428 		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
429 		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
430 		spec.attribs[0].componentCount			= 2;
431 		spec.attribs[0].offset					= 0;
432 		spec.attribs[0].stride					= 0;
433 		spec.attribs[0].normalize				= false;
434 		spec.attribs[0].instanceDivisor			= 0;
435 		spec.attribs[0].useDefaultAttribute		= false;
436 
437 		struct IOPair
438 		{
439 			gls::DrawTestSpec::InputType  input;
440 			gls::DrawTestSpec::OutputType output;
441 			int							  componentCount;
442 		} iopairs[] =
443 		{
444 			{ gls::DrawTestSpec::INPUTTYPE_FLOAT,        gls::DrawTestSpec::OUTPUTTYPE_VEC2,  4 },
445 			{ gls::DrawTestSpec::INPUTTYPE_FLOAT,        gls::DrawTestSpec::OUTPUTTYPE_VEC4,  2 },
446 			{ gls::DrawTestSpec::INPUTTYPE_INT,          gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4 },
447 			{ gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4 },
448 		};
449 
450 		for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx)
451 		{
452 			const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) + de::toString(iopairs[ioNdx].componentCount) + " to " + gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output);
453 
454 			spec.attribs[1].inputType			= iopairs[ioNdx].input;
455 			spec.attribs[1].outputType			= iopairs[ioNdx].output;
456 			spec.attribs[1].storage				= gls::DrawTestSpec::STORAGE_BUFFER;
457 			spec.attribs[1].usage				= gls::DrawTestSpec::USAGE_STATIC_DRAW;
458 			spec.attribs[1].componentCount		= iopairs[ioNdx].componentCount;
459 			spec.attribs[1].offset				= 0;
460 			spec.attribs[1].stride				= 0;
461 			spec.attribs[1].normalize			= false;
462 			spec.attribs[1].instanceDivisor		= 0;
463 			spec.attribs[1].useDefaultAttribute	= true;
464 
465 			test->addIteration(spec, desc.c_str());
466 		}
467 
468 		this->addChild(test);
469 	}
470 }
471 
472 class IndexGroup : public TestCaseGroup
473 {
474 public:
475 									IndexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
476 									~IndexGroup		(void);
477 
478 	void							init			(void);
479 
480 private:
481 	gls::DrawTestSpec::DrawMethod	m_method;
482 };
483 
IndexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)484 IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
485 	: TestCaseGroup		(context, name, descr)
486 	, m_method			(drawMethod)
487 {
488 }
489 
~IndexGroup(void)490 IndexGroup::~IndexGroup (void)
491 {
492 }
493 
init(void)494 void IndexGroup::init (void)
495 {
496 	struct IndexTest
497 	{
498 		gls::DrawTestSpec::IndexType	type;
499 		int								offsets[3];
500 	};
501 
502 	const IndexTest tests[] =
503 	{
504 		{ gls::DrawTestSpec::INDEXTYPE_BYTE,	{ 0, 1, -1 } },
505 		{ gls::DrawTestSpec::INDEXTYPE_SHORT,	{ 0, 2, -1 } },
506 		{ gls::DrawTestSpec::INDEXTYPE_INT,		{ 0, 4, -1 } },
507 	};
508 
509 	gls::DrawTestSpec spec;
510 	genBasicSpec(spec, m_method);
511 
512 	spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
513 
514 	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
515 	{
516 		const IndexTest&	indexTest	= tests[testNdx];
517 
518 		const std::string	name		= std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
519 		const std::string	desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
520 		gls::DrawTest*		test		= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
521 
522 		spec.indexType			= indexTest.type;
523 
524 		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx)
525 		{
526 			const std::string iterationDesc = std::string("first vertex ") + de::toString(indexTest.offsets[iterationNdx] / gls::DrawTestSpec::indexTypeSize(indexTest.type));
527 			spec.indexPointerOffset	= indexTest.offsets[iterationNdx];
528 			test->addIteration(spec, iterationDesc.c_str());
529 		}
530 
531 		addChild(test);
532 	}
533 }
534 
535 class BaseVertexGroup : public TestCaseGroup
536 {
537 public:
538 									BaseVertexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
539 									~BaseVertexGroup	(void);
540 
541 	void							init				(void);
542 
543 private:
544 	gls::DrawTestSpec::DrawMethod	m_method;
545 };
546 
BaseVertexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)547 BaseVertexGroup::BaseVertexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
548 	: TestCaseGroup		(context, name, descr)
549 	, m_method			(drawMethod)
550 {
551 }
552 
~BaseVertexGroup(void)553 BaseVertexGroup::~BaseVertexGroup (void)
554 {
555 }
556 
init(void)557 void BaseVertexGroup::init (void)
558 {
559 	struct IndexTest
560 	{
561 		bool							positiveBase;
562 		gls::DrawTestSpec::IndexType	type;
563 		int								baseVertex[2];
564 	};
565 
566 	const IndexTest tests[] =
567 	{
568 		{ true,  gls::DrawTestSpec::INDEXTYPE_BYTE,		{  1,  2 } },
569 		{ true,  gls::DrawTestSpec::INDEXTYPE_SHORT,	{  1,  2 } },
570 		{ true,  gls::DrawTestSpec::INDEXTYPE_INT,		{  1,  2 } },
571 		{ false, gls::DrawTestSpec::INDEXTYPE_BYTE,		{ -1, -2 } },
572 		{ false, gls::DrawTestSpec::INDEXTYPE_SHORT,	{ -1, -2 } },
573 		{ false, gls::DrawTestSpec::INDEXTYPE_INT,		{ -1, -2 } },
574 	};
575 
576 	gls::DrawTestSpec spec;
577 	genBasicSpec(spec, m_method);
578 
579 	spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
580 
581 	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
582 	{
583 		const IndexTest&	indexTest	= tests[testNdx];
584 
585 		const std::string	name		= std::string("index_") + (indexTest.positiveBase ? "" : "neg_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
586 		const std::string	desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
587 		gls::DrawTest*		test		= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
588 
589 		spec.indexType			= indexTest.type;
590 
591 		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.baseVertex); ++iterationNdx)
592 		{
593 			const std::string iterationDesc = std::string("base vertex ") + de::toString(indexTest.baseVertex[iterationNdx]);
594 			spec.baseVertex	= indexTest.baseVertex[iterationNdx];
595 			test->addIteration(spec, iterationDesc.c_str());
596 		}
597 
598 		addChild(test);
599 	}
600 }
601 
602 class FirstGroup : public TestCaseGroup
603 {
604 public:
605 									FirstGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
606 									~FirstGroup		(void);
607 
608 	void							init			(void);
609 
610 private:
611 	gls::DrawTestSpec::DrawMethod	m_method;
612 };
613 
FirstGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)614 FirstGroup::FirstGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
615 	: TestCaseGroup		(context, name, descr)
616 	, m_method			(drawMethod)
617 {
618 }
619 
~FirstGroup(void)620 FirstGroup::~FirstGroup (void)
621 {
622 }
623 
init(void)624 void FirstGroup::init (void)
625 {
626 	const int firsts[] =
627 	{
628 		1, 3, 17
629 	};
630 
631 	gls::DrawTestSpec spec;
632 	genBasicSpec(spec, m_method);
633 
634 	for (int firstNdx = 0; firstNdx < DE_LENGTH_OF_ARRAY(firsts); ++firstNdx)
635 	{
636 		const std::string	name = std::string("first_") + de::toString(firsts[firstNdx]);
637 		const std::string	desc = std::string("first ") + de::toString(firsts[firstNdx]);
638 		gls::DrawTest*		test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
639 
640 		spec.first = firsts[firstNdx];
641 
642 		addTestIterations(test, spec, TYPE_DRAW_COUNT);
643 
644 		this->addChild(test);
645 	}
646 }
647 
648 class MethodGroup : public TestCaseGroup
649 {
650 public:
651 									MethodGroup			(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
652 									~MethodGroup		(void);
653 
654 	void							init				(void);
655 
656 private:
657 	gls::DrawTestSpec::DrawMethod	m_method;
658 };
659 
MethodGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)660 MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
661 	: TestCaseGroup		(context, name, descr)
662 	, m_method			(drawMethod)
663 {
664 }
665 
~MethodGroup(void)666 MethodGroup::~MethodGroup (void)
667 {
668 }
669 
init(void)670 void MethodGroup::init (void)
671 {
672 	const bool indexed		= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT);
673 	const bool hasFirst		= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT);
674 
675 	const gls::DrawTestSpec::Primitive primitive[] =
676 	{
677 		gls::DrawTestSpec::PRIMITIVE_POINTS,
678 		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
679 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
680 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
681 		gls::DrawTestSpec::PRIMITIVE_LINES,
682 		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
683 		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
684 	};
685 
686 	if (hasFirst)
687 	{
688 		// First-tests
689 		this->addChild(new FirstGroup(m_context, "first", "First tests", m_method));
690 	}
691 
692 	if (indexed)
693 	{
694 		// Index-tests
695 		this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
696 		this->addChild(new BaseVertexGroup(m_context, "base_vertex", "Base vertex tests", m_method));
697 	}
698 
699 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx)
700 	{
701 		const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
702 		const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
703 
704 		this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx], gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER));
705 	}
706 }
707 
708 class GridProgram : public sglr::ShaderProgram
709 {
710 public:
711 			GridProgram		(void);
712 
713 	void	shadeVertices	(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
714 	void	shadeFragments	(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
715 };
716 
GridProgram(void)717 GridProgram::GridProgram (void)
718 	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
719 							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
720 							<< sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
721 							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
722 							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
723 							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
724 							<< sglr::pdec::VertexSource("#version 310 es\n"
725 														"in highp vec4 a_position;\n"
726 														"in highp vec4 a_offset;\n"
727 														"in highp vec4 a_color;\n"
728 														"out highp vec4 v_color;\n"
729 														"void main(void)\n"
730 														"{\n"
731 														"	gl_Position = a_position + a_offset;\n"
732 														"	v_color = a_color;\n"
733 														"}\n")
734 							<< sglr::pdec::FragmentSource(
735 														"#version 310 es\n"
736 														"layout(location = 0) out highp vec4 dEQP_FragColor;\n"
737 														"in highp vec4 v_color;\n"
738 														"void main(void)\n"
739 														"{\n"
740 														"	dEQP_FragColor = v_color;\n"
741 														"}\n"))
742 {
743 }
744 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const745 void GridProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
746 {
747 	for (int ndx = 0; ndx < numPackets; ++ndx)
748 	{
749 		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) + rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
750 		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[2], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
751 	}
752 }
753 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const754 void GridProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
755 {
756 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
757 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
758 		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
759 }
760 
761 class InstancedGridRenderTest : public TestCase
762 {
763 public:
764 					InstancedGridRenderTest		(Context& context, const char* name, const char* desc, int gridSide, bool useIndices);
765 					~InstancedGridRenderTest	(void);
766 
767 	IterateResult	iterate						(void);
768 
769 private:
770 	void			renderTo					(sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dst);
771 
772 	const int		m_gridSide;
773 	const bool		m_useIndices;
774 };
775 
InstancedGridRenderTest(Context & context,const char * name,const char * desc,int gridSide,bool useIndices)776 InstancedGridRenderTest::InstancedGridRenderTest (Context& context, const char* name, const char* desc, int gridSide, bool useIndices)
777 	: TestCase		(context, name, desc)
778 	, m_gridSide	(gridSide)
779 	, m_useIndices	(useIndices)
780 {
781 }
782 
~InstancedGridRenderTest(void)783 InstancedGridRenderTest::~InstancedGridRenderTest (void)
784 {
785 }
786 
iterate(void)787 InstancedGridRenderTest::IterateResult InstancedGridRenderTest::iterate (void)
788 {
789 	const int renderTargetWidth  = de::min(1024, m_context.getRenderTarget().getWidth());
790 	const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight());
791 
792 	sglr::GLContext ctx		(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
793 	tcu::Surface	surface	(renderTargetWidth, renderTargetHeight);
794 	GridProgram		program;
795 
796 	// render
797 
798 	renderTo(ctx, program, surface);
799 
800 	// verify image
801 	// \note the green/yellow pattern is only for clarity. The test will only verify that all instances were drawn by looking for anything non-green/yellow.
802 	if (verifyImageYellowGreen(surface, m_testCtx.getLog()))
803 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
804 	else
805 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid");
806 	return STOP;
807 }
808 
renderTo(sglr::Context & ctx,sglr::ShaderProgram & program,tcu::Surface & dst)809 void InstancedGridRenderTest::renderTo (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dst)
810 {
811 	const tcu::Vec4 green	(0, 1, 0, 1);
812 	const tcu::Vec4 yellow	(1, 1, 0, 1);
813 
814 	deUint32 vaoID			= 0;
815 	deUint32 positionBuf	= 0;
816 	deUint32 offsetBuf		= 0;
817 	deUint32 colorBuf		= 0;
818 	deUint32 indexBuf		= 0;
819 	deUint32 drawIndirectBuf= 0;
820 	deUint32 programID		= ctx.createProgram(&program);
821 	deInt32 posLocation		= ctx.getAttribLocation(programID, "a_position");
822 	deInt32 offsetLocation	= ctx.getAttribLocation(programID, "a_offset");
823 	deInt32 colorLocation	= ctx.getAttribLocation(programID, "a_color");
824 
825 	float cellW	= 2.0f / m_gridSide;
826 	float cellH	= 2.0f / m_gridSide;
827 	const tcu::Vec4 vertexPositions[] =
828 	{
829 		tcu::Vec4(0,		0,		0, 1),
830 		tcu::Vec4(cellW,	0,		0, 1),
831 		tcu::Vec4(0,		cellH,	0, 1),
832 
833 		tcu::Vec4(0,		cellH,	0, 1),
834 		tcu::Vec4(cellW,	0,		0, 1),
835 		tcu::Vec4(cellW,	cellH,	0, 1),
836 	};
837 
838 	const deUint16 indices[] =
839 	{
840 		0, 4, 3,
841 		2, 1, 5
842 	};
843 
844 	std::vector<tcu::Vec4> offsets;
845 	for (int x = 0; x < m_gridSide; ++x)
846 	for (int y = 0; y < m_gridSide; ++y)
847 		offsets.push_back(tcu::Vec4(x * cellW - 1.0f, y * cellW - 1.0f, 0, 0));
848 
849 	std::vector<tcu::Vec4> colors;
850 	for (int x = 0; x < m_gridSide; ++x)
851 	for (int y = 0; y < m_gridSide; ++y)
852 		colors.push_back(((x + y) % 2 == 0) ? (green) : (yellow));
853 
854 	ctx.genVertexArrays(1, &vaoID);
855 	ctx.bindVertexArray(vaoID);
856 
857 	ctx.genBuffers(1, &positionBuf);
858 	ctx.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
859 	ctx.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
860 	ctx.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
861 	ctx.vertexAttribDivisor(posLocation, 0);
862 	ctx.enableVertexAttribArray(posLocation);
863 
864 	ctx.genBuffers(1, &offsetBuf);
865 	ctx.bindBuffer(GL_ARRAY_BUFFER, offsetBuf);
866 	ctx.bufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(tcu::Vec4), &offsets[0], GL_STATIC_DRAW);
867 	ctx.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
868 	ctx.vertexAttribDivisor(offsetLocation, 1);
869 	ctx.enableVertexAttribArray(offsetLocation);
870 
871 	ctx.genBuffers(1, &colorBuf);
872 	ctx.bindBuffer(GL_ARRAY_BUFFER, colorBuf);
873 	ctx.bufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(tcu::Vec4), &colors[0], GL_STATIC_DRAW);
874 	ctx.vertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
875 	ctx.vertexAttribDivisor(colorLocation, 1);
876 	ctx.enableVertexAttribArray(colorLocation);
877 
878 	if (m_useIndices)
879 	{
880 		ctx.genBuffers(1, &indexBuf);
881 		ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
882 		ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
883 	}
884 
885 	ctx.genBuffers(1, &drawIndirectBuf);
886 	ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf);
887 
888 	if (m_useIndices)
889 	{
890 		DrawElementsCommand command;
891 		command.count				= 6;
892 		command.primCount			= m_gridSide * m_gridSide;
893 		command.firstIndex			= 0;
894 		command.baseVertex			= 0;
895 		command.reservedMustBeZero	= 0;
896 
897 		ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(command), &command, GL_STATIC_DRAW);
898 	}
899 	else
900 	{
901 		DrawArraysCommand command;
902 		command.count				= 6;
903 		command.primCount			= m_gridSide * m_gridSide;
904 		command.first				= 0;
905 		command.reservedMustBeZero	= 0;
906 
907 		ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(command), &command, GL_STATIC_DRAW);
908 	}
909 
910 	ctx.clearColor(0, 0, 0, 1);
911 	ctx.clear(GL_COLOR_BUFFER_BIT);
912 
913 	ctx.viewport(0, 0, dst.getWidth(), dst.getHeight());
914 
915 	ctx.useProgram(programID);
916 	if (m_useIndices)
917 		ctx.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, DE_NULL);
918 	else
919 		ctx.drawArraysIndirect(GL_TRIANGLES, DE_NULL);
920 	ctx.useProgram(0);
921 
922 	glu::checkError(ctx.getError(), "", __FILE__, __LINE__);
923 
924 	ctx.deleteBuffers(1, &drawIndirectBuf);
925 	if (m_useIndices)
926 		ctx.deleteBuffers(1, &indexBuf);
927 	ctx.deleteBuffers(1, &colorBuf);
928 	ctx.deleteBuffers(1, &offsetBuf);
929 	ctx.deleteBuffers(1, &positionBuf);
930 	ctx.deleteVertexArrays(1, &vaoID);
931 	ctx.deleteProgram(programID);
932 
933 	ctx.finish();
934 	ctx.readPixels(dst, 0, 0, dst.getWidth(), dst.getHeight());
935 
936 	glu::checkError(ctx.getError(), "", __FILE__, __LINE__);
937 }
938 
939 class InstancingGroup : public TestCaseGroup
940 {
941 public:
942 			InstancingGroup		(Context& context, const char* name, const char* descr);
943 			~InstancingGroup	(void);
944 
945 	void	init				(void);
946 };
947 
InstancingGroup(Context & context,const char * name,const char * descr)948 InstancingGroup::InstancingGroup (Context& context, const char* name, const char* descr)
949 	: TestCaseGroup	(context, name, descr)
950 {
951 }
952 
~InstancingGroup(void)953 InstancingGroup::~InstancingGroup (void)
954 {
955 }
956 
init(void)957 void InstancingGroup::init (void)
958 {
959 	const int gridWidths[] =
960 	{
961 		2,
962 		5,
963 		10,
964 		32,
965 		100,
966 	};
967 
968 	// drawArrays
969 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
970 	{
971 		const std::string name = std::string("draw_arrays_indirect_grid_") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
972 		const std::string desc = std::string("DrawArraysIndirect, Grid size ") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
973 
974 		this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], false));
975 	}
976 
977 	// drawElements
978 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
979 	{
980 		const std::string name = std::string("draw_elements_indirect_grid_") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
981 		const std::string desc = std::string("DrawElementsIndirect, Grid size ") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
982 
983 		this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], true));
984 	}
985 }
986 
987 class ComputeShaderGeneratedCase : public TestCase
988 {
989 public:
990 	enum DrawMethod
991 	{
992 		DRAWMETHOD_DRAWARRAYS,
993 		DRAWMETHOD_DRAWELEMENTS,
994 		DRAWMETHOD_LAST
995 	};
996 
997 						ComputeShaderGeneratedCase	(Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int drawCallCount);
998 						~ComputeShaderGeneratedCase	(void);
999 	void				init						(void);
1000 	void				deinit						(void);
1001 
1002 	IterateResult		iterate						(void);
1003 	std::string			genComputeSource			(bool computeCmd, bool computeData, bool computeIndices) const;
1004 
1005 private:
1006 	void				createDrawCommand			(void);
1007 	void				createDrawData				(void);
1008 	void				createDrawIndices			(void);
1009 
1010 	virtual void		runComputeShader			(void) = 0;
1011 	void				renderTo					(tcu::Surface& image);
1012 
1013 protected:
1014 	deUint32			calcDrawBufferSize			(void) const;
1015 	deUint32			calcIndexBufferSize			(void) const;
1016 
1017 	const DrawMethod	m_drawMethod;
1018 	const bool			m_computeCmd;
1019 	const bool			m_computeData;
1020 	const bool			m_computeIndices;
1021 	const int			m_commandSize;
1022 	const int			m_numDrawCmds;
1023 	const int			m_gridSize;
1024 
1025 	glw::GLuint			m_cmdBufferID;
1026 	glw::GLuint			m_dataBufferID;
1027 	glw::GLuint			m_indexBufferID;
1028 
1029 private:
1030 	glu::ShaderProgram*	m_shaderProgram;
1031 };
1032 
ComputeShaderGeneratedCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int drawCallCount)1033 ComputeShaderGeneratedCase::ComputeShaderGeneratedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int drawCallCount)
1034 	: TestCase			(context, name, desc)
1035 	, m_drawMethod		(method)
1036 	, m_computeCmd		(computeCmd)
1037 	, m_computeData		(computeData)
1038 	, m_computeIndices	(computeIndices)
1039 	, m_commandSize		((method==DRAWMETHOD_DRAWARRAYS) ? (sizeof(DrawArraysCommand)) : (sizeof(DrawElementsCommand)))
1040 	, m_numDrawCmds		(drawCallCount)
1041 	, m_gridSize		(gridSize)
1042 	, m_cmdBufferID		(0)
1043 	, m_dataBufferID	(0)
1044 	, m_indexBufferID	(0)
1045 	, m_shaderProgram	(DE_NULL)
1046 {
1047     const int triangleCount	= m_gridSize * m_gridSize * 2;
1048 
1049 	DE_ASSERT(method < DRAWMETHOD_LAST);
1050 	DE_ASSERT(!computeIndices || method == DRAWMETHOD_DRAWELEMENTS);
1051 	DE_ASSERT(triangleCount % m_numDrawCmds == 0);
1052 	DE_UNREF(triangleCount);
1053 }
1054 
~ComputeShaderGeneratedCase(void)1055 ComputeShaderGeneratedCase::~ComputeShaderGeneratedCase (void)
1056 {
1057 	deinit();
1058 }
1059 
init(void)1060 void ComputeShaderGeneratedCase::init (void)
1061 {
1062 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1063 
1064 	// generate basic shader
1065 
1066 	m_shaderProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_colorVertexShaderSource) << glu::FragmentSource(s_colorFragmentShaderSource));
1067 	m_testCtx.getLog() << *m_shaderProgram;
1068 
1069 	if (!m_shaderProgram->isOk())
1070 		throw tcu::TestError("Failed to compile shader.");
1071 
1072 	// gen buffers
1073 	gl.genBuffers(1, &m_cmdBufferID);
1074 	gl.genBuffers(1, &m_dataBufferID);
1075 	gl.genBuffers(1, &m_indexBufferID);
1076 
1077 	// check the SSBO buffers are of legal size
1078 	{
1079 		const deUint64	drawBufferElementSize	= sizeof(tcu::Vec4);
1080 		const deUint64	indexBufferElementSize	= sizeof(deUint32);
1081 		const int		commandBufferSize		= m_commandSize * m_numDrawCmds;
1082 		deInt64			maxSSBOSize				= 0;
1083 
1084 		gl.getInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxSSBOSize);
1085 
1086 		if (m_computeData && (deUint64)calcDrawBufferSize()*drawBufferElementSize > (deUint64)maxSSBOSize)
1087 			throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for vertex attrib buffers");
1088 		if (m_computeIndices && (deUint64)calcIndexBufferSize()*indexBufferElementSize > (deUint64)maxSSBOSize)
1089 			throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for index buffers");
1090 		if (m_computeCmd && (deUint64)commandBufferSize > (deUint64)maxSSBOSize)
1091 			throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for command buffers");
1092 	}
1093 }
1094 
deinit(void)1095 void ComputeShaderGeneratedCase::deinit (void)
1096 {
1097 	if (m_cmdBufferID)
1098 	{
1099 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_cmdBufferID);
1100 		m_cmdBufferID = 0;
1101 	}
1102 	if (m_dataBufferID)
1103 	{
1104 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBufferID);
1105 		m_dataBufferID = 0;
1106 	}
1107 	if (m_indexBufferID)
1108 	{
1109 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBufferID);
1110 		m_indexBufferID = 0;
1111 	}
1112 
1113 	if (m_shaderProgram)
1114 	{
1115 		delete m_shaderProgram;
1116 		m_shaderProgram = DE_NULL;
1117 	}
1118 }
1119 
iterate(void)1120 ComputeShaderGeneratedCase::IterateResult ComputeShaderGeneratedCase::iterate (void)
1121 {
1122 	const int				renderTargetWidth	= de::min(1024, m_context.getRenderTarget().getWidth());
1123 	const int				renderTargetHeight	= de::min(1024, m_context.getRenderTarget().getHeight());
1124 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1125 	tcu::Surface			surface				(renderTargetWidth, renderTargetHeight);
1126 
1127 	m_testCtx.getLog() << tcu::TestLog::Message << "Preparing to draw " << m_gridSize << " x " << m_gridSize << " grid." << tcu::TestLog::EndMessage;
1128 
1129 	try
1130 	{
1131 		// Gen command buffer
1132 		if (!m_computeCmd)
1133 		{
1134 			m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw command buffer." << tcu::TestLog::EndMessage;
1135 			createDrawCommand();
1136 		}
1137 
1138 		// Gen data buffer
1139 		if (!m_computeData)
1140 		{
1141 			m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw data buffer." << tcu::TestLog::EndMessage;
1142 			createDrawData();
1143 		}
1144 
1145 		// Gen index buffer
1146 		if (!m_computeIndices && m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1147 		{
1148 			m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw index buffer." << tcu::TestLog::EndMessage;
1149 			createDrawIndices();
1150 		}
1151 
1152 		// Run compute shader
1153 		{
1154 			m_testCtx.getLog()
1155 				<< tcu::TestLog::Message << "Filling following buffers using compute shader:\n"
1156 				<< ((m_computeCmd)		? ("\tcommand buffer\n")	: (""))
1157 				<< ((m_computeData)		? ("\tdata buffer\n")		: (""))
1158 				<< ((m_computeIndices)	? ("\tindex buffer\n")		: (""))
1159 				<< tcu::TestLog::EndMessage;
1160 			runComputeShader();
1161 		}
1162 
1163 		// Ensure data is written to the buffers before we try to read it
1164 		{
1165 			const glw::GLuint barriers = ((m_computeCmd)     ? (GL_COMMAND_BARRIER_BIT)             : (0)) |
1166 										 ((m_computeData)    ? (GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) : (0)) |
1167 										 ((m_computeIndices) ? (GL_ELEMENT_ARRAY_BARRIER_BIT)       : (0));
1168 
1169 			m_testCtx.getLog() << tcu::TestLog::Message << "Memory barrier. Barriers = " << glu::getMemoryBarrierFlagsStr(barriers) << tcu::TestLog::EndMessage;
1170 			gl.memoryBarrier(barriers);
1171 		}
1172 
1173 		// Draw from buffers
1174 
1175 		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing from buffers with " << m_numDrawCmds << " draw call(s)." << tcu::TestLog::EndMessage;
1176 		renderTo(surface);
1177 	}
1178 	catch (glu::OutOfMemoryError&)
1179 	{
1180 		m_testCtx.getLog() << tcu::TestLog::Message << "Got GL_OUT_OF_MEMORY." << tcu::TestLog::EndMessage;
1181 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Got GL_OUT_OF_MEMORY");
1182 		m_testCtx.setTerminateAfter(true); // Do not rely on implementation to be able to recover from OOM
1183 		return STOP;
1184 	}
1185 
1186 
1187 	// verify image
1188 	// \note the green/yellow pattern is only for clarity. The test will only verify that all grid cells were drawn by looking for anything non-green/yellow.
1189 	if (verifyImageYellowGreen(surface, m_testCtx.getLog()))
1190 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1191 	else
1192 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid");
1193 	return STOP;
1194 }
1195 
genComputeSource(bool computeCmd,bool computeData,bool computeIndices) const1196 std::string ComputeShaderGeneratedCase::genComputeSource (bool computeCmd, bool computeData, bool computeIndices) const
1197 {
1198 	const int cmdLayoutBinding				= 0;
1199 	const int dataLayoutBinding				= (computeCmd) ? (1) : (0);
1200 	const int indexLayoutBinding			= (computeCmd && computeData) ? (2) : (computeCmd || computeData) ? (1) : (0);
1201 
1202 	std::ostringstream buf;
1203 
1204 	buf << "#version 310 es\n\n"
1205 		<< "precision highp int;\n"
1206 		<< "precision highp float;\n\n";
1207 
1208 	if (computeCmd && m_drawMethod==DRAWMETHOD_DRAWARRAYS)
1209 		buf	<< "struct DrawArraysIndirectCommand {\n"
1210 			<< "    uint count;\n"
1211 			<< "    uint primCount;\n"
1212 			<< "    uint first;\n"
1213 			<< "    uint reservedMustBeZero;\n"
1214 			<< "};\n\n";
1215 	else if (computeCmd && m_drawMethod==DRAWMETHOD_DRAWELEMENTS)
1216 		buf	<< "struct DrawElementsIndirectCommand {\n"
1217 			<< "    uint count;\n"
1218 			<< "    uint primCount;\n"
1219 			<< "    uint firstIndex;\n"
1220 			<< "    int  baseVertex;\n"
1221 			<< "    uint reservedMustBeZero;\n"
1222 			<< "};\n\n";
1223 
1224 	buf << "layout(local_size_x = 1, local_size_y = 1) in;\n"
1225 		<< "layout(std430) buffer;\n\n";
1226 
1227 	if (computeCmd)
1228 		buf	<< "layout(binding = " << cmdLayoutBinding << ") writeonly buffer CommandBuffer {\n"
1229 			<< "    " << ((m_drawMethod==DRAWMETHOD_DRAWARRAYS) ? ("DrawArraysIndirectCommand") : ("DrawElementsIndirectCommand")) << " commands[];\n"
1230 			<< "};\n";
1231 	if (computeData)
1232 		buf	<< "layout(binding = " << dataLayoutBinding << ") writeonly buffer DataBuffer {\n"
1233 			<< "    vec4 attribs[];\n"
1234 			<< "};\n";
1235 	if (computeIndices)
1236 		buf	<< "layout(binding = " << indexLayoutBinding << ") writeonly buffer IndexBuffer {\n"
1237 			<< "    uint indices[];\n"
1238 			<< "};\n";
1239 
1240 	buf	<< "\n"
1241 		<< "void main() {\n"
1242 		<< "    const uint gridSize      = " << m_gridSize << "u;\n"
1243 		<< "    const uint triangleCount = gridSize * gridSize * 2u;\n"
1244 		<< "\n";
1245 
1246 	if (computeCmd)
1247 	{
1248 		buf	<< "    // command\n"
1249 			<< "    if (gl_GlobalInvocationID.x < " << m_numDrawCmds << "u && gl_GlobalInvocationID.y == 0u && gl_GlobalInvocationID.z == 0u) {\n"
1250 			<< "        const uint numDrawCallTris = triangleCount / " << m_numDrawCmds << "u;\n"
1251 			<< "        uint firstTri              = gl_GlobalInvocationID.x * numDrawCallTris;\n\n"
1252 			<< "        commands[gl_GlobalInvocationID.x].count                 = numDrawCallTris*3u;\n"
1253 			<< "        commands[gl_GlobalInvocationID.x].primCount             = 1u;\n";
1254 
1255 		if (m_drawMethod==DRAWMETHOD_DRAWARRAYS)
1256 		{
1257 			buf	<< "        commands[gl_GlobalInvocationID.x].first                 = firstTri*3u;\n";
1258 		}
1259 		else if (m_drawMethod==DRAWMETHOD_DRAWELEMENTS)
1260 		{
1261 			buf	<< "        commands[gl_GlobalInvocationID.x].firstIndex            = firstTri*3u;\n";
1262 			buf	<< "        commands[gl_GlobalInvocationID.x].baseVertex            = 0;\n";
1263 		}
1264 
1265 		buf	<< "        commands[gl_GlobalInvocationID.x].reservedMustBeZero    = 0u;\n"
1266 			<< "    }\n"
1267 			<< "\n";
1268 	}
1269 
1270 	if (computeData)
1271 	{
1272 		buf	<< "    // vertex attribs\n"
1273 			<< "    const vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1274 			<< "    const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n";
1275 
1276 		if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1277 		{
1278 			buf	<< "    if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && gl_GlobalInvocationID.z == 0u) {\n"
1279 				<< "        uint        y           = gl_GlobalInvocationID.x;\n"
1280 				<< "        uint        x           = gl_GlobalInvocationID.y;\n"
1281 				<< "        float       posX        = (float(x) / float(gridSize)) * 2.0 - 1.0;\n"
1282 				<< "        float       posY        = (float(y) / float(gridSize)) * 2.0 - 1.0;\n"
1283 				<< "        const float cellSize    = 2.0 / float(gridSize);\n"
1284 				<< "        vec4        color       = ((x + y)%2u != 0u) ? (yellow) : (green);\n"
1285 				<< "\n"
1286 				<< "        attribs[((y * gridSize + x) * 6u + 0u) * 2u + 0u] = vec4(posX,            posY,            0.0, 1.0);\n"
1287 				<< "        attribs[((y * gridSize + x) * 6u + 1u) * 2u + 0u] = vec4(posX + cellSize, posY,            0.0, 1.0);\n"
1288 				<< "        attribs[((y * gridSize + x) * 6u + 2u) * 2u + 0u] = vec4(posX + cellSize, posY + cellSize, 0.0, 1.0);\n"
1289 				<< "        attribs[((y * gridSize + x) * 6u + 3u) * 2u + 0u] = vec4(posX,            posY,            0.0, 1.0);\n"
1290 				<< "        attribs[((y * gridSize + x) * 6u + 4u) * 2u + 0u] = vec4(posX + cellSize, posY + cellSize, 0.0, 1.0);\n"
1291 				<< "        attribs[((y * gridSize + x) * 6u + 5u) * 2u + 0u] = vec4(posX,            posY + cellSize, 0.0, 1.0);\n"
1292 				<< "\n"
1293 				<< "        attribs[((y * gridSize + x) * 6u + 0u) * 2u + 1u] = color;\n"
1294 				<< "        attribs[((y * gridSize + x) * 6u + 1u) * 2u + 1u] = color;\n"
1295 				<< "        attribs[((y * gridSize + x) * 6u + 2u) * 2u + 1u] = color;\n"
1296 				<< "        attribs[((y * gridSize + x) * 6u + 3u) * 2u + 1u] = color;\n"
1297 				<< "        attribs[((y * gridSize + x) * 6u + 4u) * 2u + 1u] = color;\n"
1298 				<< "        attribs[((y * gridSize + x) * 6u + 5u) * 2u + 1u] = color;\n"
1299 				<< "    }\n";
1300 		}
1301 		else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1302 		{
1303 			buf	<< "    if (gl_GlobalInvocationID.x < gridSize+1u && gl_GlobalInvocationID.y < gridSize+1u && gl_GlobalInvocationID.z == 0u) {\n"
1304 				<< "        uint        y           = gl_GlobalInvocationID.x;\n"
1305 				<< "        uint        x           = gl_GlobalInvocationID.y;\n"
1306 				<< "        float       posX        = (float(x) / float(gridSize)) * 2.0 - 1.0;\n"
1307 				<< "        float       posY        = (float(y) / float(gridSize)) * 2.0 - 1.0;\n"
1308 				<< "\n"
1309 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 0u] = vec4(posX, posY, 0.0, 1.0);\n"
1310 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 1u] = green;\n"
1311 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 2u] = vec4(posX, posY, 0.0, 1.0);\n"
1312 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 3u] = yellow;\n"
1313 				<< "    }\n";
1314 		}
1315 
1316 		buf << "\n";
1317 	}
1318 
1319 	if (computeIndices)
1320 	{
1321 		buf	<< "    // indices\n"
1322 			<< "    if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && gl_GlobalInvocationID.z == 0u) {\n"
1323 			<< "        uint    y       = gl_GlobalInvocationID.x;\n"
1324 			<< "        uint    x       = gl_GlobalInvocationID.y;\n"
1325 			<< "        uint    color   = ((x + y)%2u);\n"
1326 			<< "\n"
1327 			<< "        indices[(y * gridSize + x) * 6u + 0u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1328 			<< "        indices[(y * gridSize + x) * 6u + 1u] = ((y+1u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1329 			<< "        indices[(y * gridSize + x) * 6u + 2u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1330 			<< "        indices[(y * gridSize + x) * 6u + 3u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1331 			<< "        indices[(y * gridSize + x) * 6u + 4u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1332 			<< "        indices[(y * gridSize + x) * 6u + 5u] = ((y+0u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1333 			<< "    }\n"
1334 			<< "\n";
1335 	}
1336 
1337 	buf	<< "}\n";
1338 
1339 	return buf.str();
1340 }
1341 
createDrawCommand(void)1342 void ComputeShaderGeneratedCase::createDrawCommand (void)
1343 {
1344 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
1345 	const int				triangleCount	= m_gridSize * m_gridSize * 2;
1346 	const deUint32			numDrawCallTris	= triangleCount / m_numDrawCmds;
1347 
1348 	if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1349 	{
1350 		std::vector<DrawArraysCommand> cmds;
1351 
1352 		for (int ndx = 0; ndx < m_numDrawCmds; ++ndx)
1353 		{
1354 			const deUint32				firstTri = ndx * numDrawCallTris;
1355 			DrawArraysCommand			data;
1356 
1357 			data.count					= numDrawCallTris*3;
1358 			data.primCount				= 1;
1359 			data.first					= firstTri*3;
1360 			data.reservedMustBeZero		= 0;
1361 
1362 			cmds.push_back(data);
1363 		}
1364 
1365 		DE_ASSERT((int)(sizeof(DrawArraysCommand)*cmds.size()) == m_numDrawCmds * m_commandSize);
1366 
1367 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1368 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawArraysCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW);
1369 	}
1370 	else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1371 	{
1372 		std::vector<DrawElementsCommand> cmds;
1373 
1374 		for (int ndx = 0; ndx < m_numDrawCmds; ++ndx)
1375 		{
1376 			const deUint32			firstTri = ndx * numDrawCallTris;
1377 			DrawElementsCommand		data;
1378 
1379 			data.count				= numDrawCallTris*3;
1380 			data.primCount			= 1;
1381 			data.firstIndex			= firstTri*3;
1382 			data.baseVertex			= 0;
1383 			data.reservedMustBeZero	= 0;
1384 
1385 			cmds.push_back(data);
1386 		}
1387 
1388 		DE_ASSERT((int)(sizeof(DrawElementsCommand)*cmds.size()) == m_numDrawCmds * m_commandSize);
1389 
1390 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1391 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawElementsCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW);
1392 	}
1393 	else
1394 		DE_ASSERT(false);
1395 
1396 	glu::checkError(gl.getError(), "create draw command", __FILE__, __LINE__);
1397 }
1398 
createDrawData(void)1399 void ComputeShaderGeneratedCase::createDrawData (void)
1400 {
1401 	const tcu::Vec4			yellow	(1.0f, 1.0f, 0.0f, 1.0f);
1402 	const tcu::Vec4			green	(0.0f, 1.0f, 0.0f, 1.0f);
1403 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1404 
1405 	if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1406 	{
1407 		// Store elements in the order they are drawn. Interleave color.
1408 		std::vector<tcu::Vec4> buffer(m_gridSize*m_gridSize*6*2);
1409 
1410 		DE_ASSERT(buffer.size() == calcDrawBufferSize());
1411 
1412 		for (int y = 0; y < m_gridSize; ++y)
1413 		for (int x = 0; x < m_gridSize; ++x)
1414 		{
1415 			const float 		posX		= (x / (float)m_gridSize) * 2.0f - 1.0f;
1416 			const float 		posY		= (y / (float)m_gridSize) * 2.0f - 1.0f;
1417 			const float			cellSize	= 2.0f / (float)m_gridSize;
1418 			const tcu::Vec4&	color		= ((x + y)%2) ? (yellow) : (green);
1419 
1420 			buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 0] = tcu::Vec4(posX,			posY,				0.0f, 1.0f);
1421 			buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 0] = tcu::Vec4(posX + cellSize,	posY,				0.0f, 1.0f);
1422 			buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 0] = tcu::Vec4(posX + cellSize,	posY + cellSize,	0.0f, 1.0f);
1423 			buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 0] = tcu::Vec4(posX,			posY,				0.0f, 1.0f);
1424 			buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 0] = tcu::Vec4(posX + cellSize, posY + cellSize,	0.0f, 1.0f);
1425 			buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 0] = tcu::Vec4(posX,			posY + cellSize,	0.0f, 1.0f);
1426 
1427 			buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 1] = color;
1428 			buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 1] = color;
1429 			buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 1] = color;
1430 			buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 1] = color;
1431 			buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 1] = color;
1432 			buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 1] = color;
1433 		}
1434 
1435 		gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1436 		gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW);
1437 	}
1438 	else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1439 	{
1440 		// Elements are indexed by index buffer. Interleave color. Two vertices per position since 2 colors
1441 
1442 		std::vector<tcu::Vec4> buffer((m_gridSize+1)*(m_gridSize+1)*4);
1443 
1444 		DE_ASSERT(buffer.size() == calcDrawBufferSize());
1445 
1446 		for (int y = 0; y < m_gridSize+1; ++y)
1447 		for (int x = 0; x < m_gridSize+1; ++x)
1448 		{
1449 			const float 		posX		= (x / (float)m_gridSize) * 2.0f - 1.0f;
1450 			const float 		posY		= (y / (float)m_gridSize) * 2.0f - 1.0f;
1451 
1452 			buffer[(y * (m_gridSize+1) + x) * 4 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1453 			buffer[(y * (m_gridSize+1) + x) * 4 + 1] = green;
1454 			buffer[(y * (m_gridSize+1) + x) * 4 + 2] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1455 			buffer[(y * (m_gridSize+1) + x) * 4 + 3] = yellow;
1456 		}
1457 
1458 		gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1459 		gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW);
1460 	}
1461 	else
1462 		DE_ASSERT(false);
1463 
1464 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1465 }
1466 
createDrawIndices(void)1467 void ComputeShaderGeneratedCase::createDrawIndices (void)
1468 {
1469 	DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1470 
1471 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1472 	std::vector<deUint32>	buffer	(m_gridSize*m_gridSize*6);
1473 
1474 	DE_ASSERT(buffer.size() == calcIndexBufferSize());
1475 
1476 	for (int y = 0; y < m_gridSize; ++y)
1477 	for (int x = 0; x < m_gridSize; ++x)
1478 	{
1479 		const int color = ((x + y)%2);
1480 
1481 		buffer[(y * m_gridSize + x) * 6 + 0] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color;
1482 		buffer[(y * m_gridSize + x) * 6 + 1] = ((y+1) * (m_gridSize+1) + (x+0)) * 2 + color;
1483 		buffer[(y * m_gridSize + x) * 6 + 2] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color;
1484 		buffer[(y * m_gridSize + x) * 6 + 3] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color;
1485 		buffer[(y * m_gridSize + x) * 6 + 4] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color;
1486 		buffer[(y * m_gridSize + x) * 6 + 5] = ((y+0) * (m_gridSize+1) + (x+1)) * 2 + color;
1487 	}
1488 
1489 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
1490 	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(buffer.size() * sizeof(deUint32)), &buffer[0], GL_STATIC_DRAW);
1491 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1492 }
1493 
renderTo(tcu::Surface & dst)1494 void ComputeShaderGeneratedCase::renderTo (tcu::Surface& dst)
1495 {
1496 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1497 	const deInt32			positionLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_position");
1498 	const deInt32			colorLoc	= gl.getAttribLocation(m_shaderProgram->getProgram(), "a_color");
1499 	deUint32				vaoID		= 0;
1500 
1501 	gl.genVertexArrays(1, &vaoID);
1502 	gl.bindVertexArray(vaoID);
1503 
1504 	// Setup buffers
1505 
1506 	gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1507 	gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), DE_NULL);
1508 	gl.vertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), ((const deUint8*)DE_NULL) + 4*sizeof(float));
1509 	gl.enableVertexAttribArray(positionLoc);
1510 	gl.enableVertexAttribArray(colorLoc);
1511 
1512 	DE_ASSERT(positionLoc != -1);
1513 	DE_ASSERT(colorLoc != -1);
1514 
1515 	if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1516 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
1517 
1518 	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1519 
1520 	// draw
1521 
1522 	gl.clearColor(0, 0, 0, 1);
1523 	gl.clear(GL_COLOR_BUFFER_BIT);
1524 	gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1525 
1526 	gl.useProgram(m_shaderProgram->getProgram());
1527 	for (int drawCmdNdx = 0; drawCmdNdx < m_numDrawCmds; ++drawCmdNdx)
1528 	{
1529 		const void* offset = ((deUint8*)DE_NULL) + drawCmdNdx*m_commandSize;
1530 
1531 		if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1532 			gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset);
1533 		else if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1534 			gl.drawArraysIndirect(GL_TRIANGLES, offset);
1535 		else
1536 			DE_ASSERT(DE_FALSE);
1537 	}
1538 	gl.useProgram(0);
1539 
1540 	// free
1541 
1542 	gl.deleteVertexArrays(1, &vaoID);
1543 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1544 
1545 	gl.finish();
1546 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1547 
1548 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1549 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1550 }
1551 
calcDrawBufferSize(void) const1552 deUint32 ComputeShaderGeneratedCase::calcDrawBufferSize (void) const
1553 {
1554 	// returns size in "vec4"s
1555 	if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1556 		return m_gridSize*m_gridSize*6*2;
1557 	else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1558 		return (m_gridSize+1)*(m_gridSize+1)*4;
1559 	else
1560 		DE_ASSERT(DE_FALSE);
1561 
1562 	return 0;
1563 }
1564 
calcIndexBufferSize(void) const1565 deUint32 ComputeShaderGeneratedCase::calcIndexBufferSize (void) const
1566 {
1567 	if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1568 		return m_gridSize*m_gridSize*6;
1569 	else
1570 		return 0;
1571 }
1572 
1573 class ComputeShaderGeneratedCombinedCase : public ComputeShaderGeneratedCase
1574 {
1575 public:
1576 						ComputeShaderGeneratedCombinedCase	(Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls);
1577 						~ComputeShaderGeneratedCombinedCase	(void);
1578 
1579 	void				init								(void);
1580 	void				deinit								(void);
1581 
1582 private:
1583 	void				runComputeShader					(void);
1584 
1585 	glu::ShaderProgram*	m_computeProgram;
1586 };
1587 
ComputeShaderGeneratedCombinedCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int numDrawCalls)1588 ComputeShaderGeneratedCombinedCase::ComputeShaderGeneratedCombinedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls)
1589 	: ComputeShaderGeneratedCase(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls)
1590 	, m_computeProgram			(DE_NULL)
1591 {
1592 }
1593 
~ComputeShaderGeneratedCombinedCase(void)1594 ComputeShaderGeneratedCombinedCase::~ComputeShaderGeneratedCombinedCase (void)
1595 {
1596 	deinit();
1597 }
1598 
init(void)1599 void ComputeShaderGeneratedCombinedCase::init (void)
1600 {
1601 	// generate compute shader
1602 
1603 	m_computeProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genComputeSource(m_computeCmd, m_computeData, m_computeIndices)));
1604 	m_testCtx.getLog() << *m_computeProgram;
1605 
1606 	if (!m_computeProgram->isOk())
1607 		throw tcu::TestError("Failed to compile compute shader.");
1608 
1609 	// init parent
1610 	ComputeShaderGeneratedCase::init();
1611 }
1612 
deinit(void)1613 void ComputeShaderGeneratedCombinedCase::deinit (void)
1614 {
1615 	// deinit parent
1616 	ComputeShaderGeneratedCase::deinit();
1617 
1618 	if (m_computeProgram)
1619 	{
1620 		delete m_computeProgram;
1621 		m_computeProgram = DE_NULL;
1622 	}
1623 }
1624 
runComputeShader(void)1625 void ComputeShaderGeneratedCombinedCase::runComputeShader (void)
1626 {
1627 	const glw::Functions&	gl									= m_context.getRenderContext().getFunctions();
1628 	const bool				indexed								= (m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1629 	const tcu::IVec3		nullSize							(0, 0, 0);
1630 	const tcu::IVec3		commandDispatchSize					= (m_computeCmd)				? (tcu::IVec3(m_numDrawCmds, 1, 1))				: (nullSize);
1631 	const tcu::IVec3		drawElementsDataBufferDispatchSize	= (m_computeData)				? (tcu::IVec3(m_gridSize+1, m_gridSize+1, 1))	: (nullSize);
1632 	const tcu::IVec3		drawArraysDataBufferDispatchSize	= (m_computeData)				? (tcu::IVec3(m_gridSize,   m_gridSize,   1))	: (nullSize);
1633 	const tcu::IVec3		indexBufferDispatchSize				= (m_computeIndices && indexed)	? (tcu::IVec3(m_gridSize,   m_gridSize,   1))	: (nullSize);
1634 
1635 	const tcu::IVec3		dataBufferDispatchSize				= (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize);
1636 	const tcu::IVec3		dispatchSize						= tcu::max(tcu::max(commandDispatchSize, dataBufferDispatchSize), indexBufferDispatchSize);
1637 
1638 	gl.useProgram(m_computeProgram->getProgram());
1639 	glu::checkError(gl.getError(), "use compute shader", __FILE__, __LINE__);
1640 
1641 	// setup buffers
1642 
1643 	if (m_computeCmd)
1644 	{
1645 		const int			bindingPoint	= 0;
1646 		const int			bufferSize		= m_commandSize * m_numDrawCmds;
1647 
1648 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1649 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID);
1650 
1651 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1652 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1653 	}
1654 
1655 	if (m_computeData)
1656 	{
1657 		const int			bindingPoint	= (m_computeCmd) ? (1) : (0);
1658 		const int			bufferSize		= (int)(calcDrawBufferSize()*sizeof(tcu::Vec4));
1659 
1660 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1661 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID);
1662 
1663 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1664 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1665 	}
1666 
1667 	if (m_computeIndices)
1668 	{
1669 		const int			bindingPoint	= (m_computeCmd && m_computeData) ? (2) : (m_computeCmd || m_computeData) ? (1) : (0);
1670 		const int			bufferSize		= (int)(calcIndexBufferSize()*sizeof(deUint32));
1671 
1672 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1673 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID);
1674 
1675 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1676 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1677 	}
1678 
1679 	glu::checkError(gl.getError(), "setup buffers", __FILE__, __LINE__);
1680 
1681 	// calculate
1682 
1683 	m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching compute, size = " << dispatchSize << tcu::TestLog::EndMessage;
1684 	gl.dispatchCompute(dispatchSize.x(), dispatchSize.y(), dispatchSize.z());
1685 
1686 	glu::checkError(gl.getError(), "calculate", __FILE__, __LINE__);
1687 }
1688 
1689 class ComputeShaderGeneratedSeparateCase : public ComputeShaderGeneratedCase
1690 {
1691 public:
1692 						ComputeShaderGeneratedSeparateCase	(Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls);
1693 						~ComputeShaderGeneratedSeparateCase	(void);
1694 
1695 	void				init								(void);
1696 	void				deinit								(void);
1697 
1698 private:
1699 	std::string			genCmdComputeSource					(void);
1700 	std::string			genDataComputeSource				(void);
1701 	std::string			genIndexComputeSource				(void);
1702 	void				runComputeShader					(void);
1703 
1704 	glu::ShaderProgram*	m_computeCmdProgram;
1705 	glu::ShaderProgram*	m_computeDataProgram;
1706 	glu::ShaderProgram*	m_computeIndicesProgram;
1707 };
1708 
ComputeShaderGeneratedSeparateCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int numDrawCalls)1709 ComputeShaderGeneratedSeparateCase::ComputeShaderGeneratedSeparateCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls)
1710 	: ComputeShaderGeneratedCase	(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls)
1711 	, m_computeCmdProgram			(DE_NULL)
1712 	, m_computeDataProgram			(DE_NULL)
1713 	, m_computeIndicesProgram		(DE_NULL)
1714 {
1715 }
1716 
~ComputeShaderGeneratedSeparateCase(void)1717 ComputeShaderGeneratedSeparateCase::~ComputeShaderGeneratedSeparateCase (void)
1718 {
1719 	deinit();
1720 }
1721 
init(void)1722 void ComputeShaderGeneratedSeparateCase::init (void)
1723 {
1724 	// generate cmd compute shader
1725 
1726 	if (m_computeCmd)
1727 	{
1728 		m_computeCmdProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genCmdComputeSource()));
1729 		m_testCtx.getLog() << *m_computeCmdProgram;
1730 
1731 		if (!m_computeCmdProgram->isOk())
1732 			throw tcu::TestError("Failed to compile command compute shader.");
1733 	}
1734 
1735 	// generate data compute shader
1736 
1737 	if (m_computeData)
1738 	{
1739 		m_computeDataProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genDataComputeSource()));
1740 		m_testCtx.getLog() << *m_computeDataProgram;
1741 
1742 		if (!m_computeDataProgram->isOk())
1743 			throw tcu::TestError("Failed to compile data compute shader.");
1744 	}
1745 
1746 	// generate index compute shader
1747 
1748 	if (m_computeIndices)
1749 	{
1750 		m_computeIndicesProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genIndexComputeSource()));
1751 		m_testCtx.getLog() << *m_computeIndicesProgram;
1752 
1753 		if (!m_computeIndicesProgram->isOk())
1754 			throw tcu::TestError("Failed to compile data compute shader.");
1755 	}
1756 
1757 	// init parent
1758 	ComputeShaderGeneratedCase::init();
1759 }
1760 
deinit(void)1761 void ComputeShaderGeneratedSeparateCase::deinit (void)
1762 {
1763 	// deinit parent
1764 	ComputeShaderGeneratedCase::deinit();
1765 
1766 	if (m_computeCmdProgram)
1767 	{
1768 		delete m_computeCmdProgram;
1769 		m_computeCmdProgram = DE_NULL;
1770 	}
1771 	if (m_computeDataProgram)
1772 	{
1773 		delete m_computeDataProgram;
1774 		m_computeDataProgram = DE_NULL;
1775 	}
1776 	if (m_computeIndicesProgram)
1777 	{
1778 		delete m_computeIndicesProgram;
1779 		m_computeIndicesProgram = DE_NULL;
1780 	}
1781 }
1782 
genCmdComputeSource(void)1783 std::string ComputeShaderGeneratedSeparateCase::genCmdComputeSource (void)
1784 {
1785 	return ComputeShaderGeneratedCase::genComputeSource(true, false, false);
1786 }
1787 
genDataComputeSource(void)1788 std::string ComputeShaderGeneratedSeparateCase::genDataComputeSource (void)
1789 {
1790 	return ComputeShaderGeneratedCase::genComputeSource(false, true, false);
1791 }
1792 
genIndexComputeSource(void)1793 std::string ComputeShaderGeneratedSeparateCase::genIndexComputeSource (void)
1794 {
1795 	return ComputeShaderGeneratedCase::genComputeSource(false, false, true);
1796 }
1797 
runComputeShader(void)1798 void ComputeShaderGeneratedSeparateCase::runComputeShader (void)
1799 {
1800 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1801 
1802 	// Compute command
1803 
1804 	if (m_computeCmd)
1805 	{
1806 		const int				bindingPoint			= 0;
1807 		const tcu::IVec3		commandDispatchSize		(m_numDrawCmds, 1, 1);
1808 		const int				bufferSize				= m_commandSize * m_numDrawCmds;
1809 
1810 		gl.useProgram(m_computeCmdProgram->getProgram());
1811 
1812 		// setup buffers
1813 
1814 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1815 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID);
1816 
1817 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1818 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1819 
1820 		// calculate
1821 
1822 		m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching command compute, size = " << commandDispatchSize << tcu::TestLog::EndMessage;
1823 		gl.dispatchCompute(commandDispatchSize.x(), commandDispatchSize.y(), commandDispatchSize.z());
1824 
1825 		glu::checkError(gl.getError(), "calculate cmd", __FILE__, __LINE__);
1826 	}
1827 
1828 	// Compute data
1829 
1830 	if (m_computeData)
1831 	{
1832 		const int				bindingPoint						= 0;
1833 		const tcu::IVec3		drawElementsDataBufferDispatchSize	(m_gridSize+1, m_gridSize+1, 1);
1834 		const tcu::IVec3		drawArraysDataBufferDispatchSize	(m_gridSize,   m_gridSize,   1);
1835 		const tcu::IVec3		dataBufferDispatchSize				= (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize);
1836 		const int				bufferSize							= (int)(calcDrawBufferSize()*sizeof(tcu::Vec4));
1837 
1838 		gl.useProgram(m_computeDataProgram->getProgram());
1839 
1840 		// setup buffers
1841 
1842 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1843 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID);
1844 
1845 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1846 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1847 
1848 		// calculate
1849 
1850 		m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching data compute, size = " << dataBufferDispatchSize << tcu::TestLog::EndMessage;
1851 		gl.dispatchCompute(dataBufferDispatchSize.x(), dataBufferDispatchSize.y(), dataBufferDispatchSize.z());
1852 
1853 		glu::checkError(gl.getError(), "calculate data", __FILE__, __LINE__);
1854 	}
1855 
1856 	// Compute indices
1857 
1858 	if (m_computeIndices)
1859 	{
1860 		const int				bindingPoint				= 0;
1861 		const tcu::IVec3		indexBufferDispatchSize		(m_gridSize, m_gridSize, 1);
1862 		const int				bufferSize					= (int)(calcIndexBufferSize()*sizeof(deUint32));
1863 
1864 		DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1865 
1866 		gl.useProgram(m_computeIndicesProgram->getProgram());
1867 
1868 		// setup buffers
1869 
1870 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1871 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID);
1872 
1873 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1874 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1875 
1876 		// calculate
1877 
1878 		m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching index compute, size = " << indexBufferDispatchSize << tcu::TestLog::EndMessage;
1879 		gl.dispatchCompute(indexBufferDispatchSize.x(), indexBufferDispatchSize.y(), indexBufferDispatchSize.z());
1880 
1881 		glu::checkError(gl.getError(), "calculate indices", __FILE__, __LINE__);
1882 	}
1883 
1884 	glu::checkError(gl.getError(), "post dispatch", __FILE__, __LINE__);
1885 }
1886 
1887 class ComputeShaderGeneratedGroup : public TestCaseGroup
1888 {
1889 public:
1890 			ComputeShaderGeneratedGroup		(Context& context, const char* name, const char* descr);
1891 			~ComputeShaderGeneratedGroup	(void);
1892 
1893 	void	init							(void);
1894 };
1895 
ComputeShaderGeneratedGroup(Context & context,const char * name,const char * descr)1896 ComputeShaderGeneratedGroup::ComputeShaderGeneratedGroup (Context& context, const char* name, const char* descr)
1897 	: TestCaseGroup	(context, name, descr)
1898 {
1899 }
1900 
~ComputeShaderGeneratedGroup(void)1901 ComputeShaderGeneratedGroup::~ComputeShaderGeneratedGroup (void)
1902 {
1903 }
1904 
init(void)1905 void ComputeShaderGeneratedGroup::init (void)
1906 {
1907 	const int					gridSize		= 8;
1908 	tcu::TestCaseGroup* const	separateGroup	= new tcu::TestCaseGroup(m_testCtx, "separate", "Use separate compute shaders for each buffer");
1909 	tcu::TestCaseGroup* const	combinedGroup	= new tcu::TestCaseGroup(m_testCtx, "combined", "Use combined compute shader for all buffers");
1910 	tcu::TestCaseGroup* const	largeGroup		= new tcu::TestCaseGroup(m_testCtx, "large",   "Draw shapes with large buffers");
1911 
1912 	this->addChild(separateGroup);
1913 	this->addChild(combinedGroup);
1914 	this->addChild(largeGroup);
1915 
1916 	// .separate
1917 	{
1918 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd",							"Command from compute shader",						ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,		true,	false,	false,	gridSize,	1));
1919 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_data",						"Data from compute shader",							ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,		false,	true,	false,	gridSize,	1));
1920 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd_and_data",				"Command and data from compute shader",				ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,		true,	true,	false,	gridSize,	1));
1921 
1922 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd",						"Command from compute shader",						ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	false,	false,	gridSize,	1));
1923 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data",						"Data from compute shader",							ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false,	true,	false,	gridSize,	1));
1924 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_indices",					"Indices from compute shader",						ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false,	false,	true,	gridSize,	1));
1925 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_data",				"Command and data from compute shader",				ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	true,	false,	gridSize,	1));
1926 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_indices",			"Command and indices from compute shader",			ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	false,	true,	gridSize,	1));
1927 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data_and_indices",			"Data and indices from compute shader",				ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false,	true,	true,	gridSize,	1));
1928 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_data_and_indices",	"Command, data and indices from compute shader",	ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	true,	true,	gridSize,	1));
1929 	}
1930 
1931 	// .combined
1932 	{
1933 		combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawarrays_compute_cmd_and_data",				"Command and data from compute shader",				ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,		true,	true,	false,	gridSize,	1));
1934 		combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_data",				"Command and data from compute shader",				ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	true,	false,	gridSize,	1));
1935 		combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_indices",			"Command and indices from compute shader",			ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	false,	true,	gridSize,	1));
1936 		combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_data_and_indices",			"Data and indices from compute shader",				ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false,	true,	true,	gridSize,	1));
1937 		combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_data_and_indices",	"Command, data and indices from compute shader",	ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	true,	true,	gridSize,	1));
1938 	}
1939 
1940 	// .large
1941 	{
1942 		struct TestSpec
1943 		{
1944 			int gridSize;
1945 			int numDrawCommands;
1946 		};
1947 		struct TestMethod
1948 		{
1949 			ComputeShaderGeneratedCase::DrawMethod method;
1950 			bool                                   separateCompute;
1951 		};
1952 
1953 		static const TestSpec specs[] =
1954 		{
1955 			{ 100,	1 },		// !< drawArrays array size ~ 1.9 MB
1956 			{ 200,	1 },		// !< drawArrays array size ~ 7.7 MB
1957 			{ 500,	1 },		// !< drawArrays array size ~ 48 MB
1958 			{ 1000,	1 },		// !< drawArrays array size ~ 192 MB
1959 			{ 1200,	1 },		// !< drawArrays array size ~ 277 MB
1960 			{ 1500,	1 },		// !< drawArrays array size ~ 430 MB
1961 
1962 			{ 100,	8 },		// !< drawArrays array size ~ 1.9 MB
1963 			{ 200,	8 },		// !< drawArrays array size ~ 7.7 MB
1964 			{ 500,	8 },		// !< drawArrays array size ~ 48 MB
1965 			{ 1000,	8 },		// !< drawArrays array size ~ 192 MB
1966 			{ 1200,	8 },		// !< drawArrays array size ~ 277 MB
1967 			{ 1500,	8 },		// !< drawArrays array size ~ 430 MB
1968 
1969 			{ 100,	200  },		// !< 50 cells per draw call
1970 			{ 200,	800  },		// !< 50 cells per draw call
1971 			{ 500,	2500 },		// !< 100 cells per draw call
1972 			{ 1000,	5000 },		// !< 250 cells per draw call
1973 		};
1974 		static const TestMethod methods[] =
1975 		{
1976 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,	true	},
1977 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,	false	},
1978 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true	},
1979 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false	},
1980 		};
1981 
1982 		for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(methods); ++methodNdx)
1983 		for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); ++specNdx)
1984 		{
1985 			const std::string name = std::string("")
1986 									+ ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays") : ("drawelements"))
1987 									+ ((methods[methodNdx].separateCompute) ? ("_separate") : ("_combined"))
1988 									+ "_grid_" + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize)
1989 									+ "_drawcount_" + de::toString(specs[specNdx].numDrawCommands);
1990 
1991 			const std::string desc = std::string("Draw grid with ")
1992 									+ ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays indirect") : ("drawelements indirect"))
1993 									+ " calculating buffers in " + ((methods[methodNdx].separateCompute) ? ("separate") : ("combined")) + " compute shader."
1994 									+ " Grid size is " + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize)
1995 									+ ", draw count is "  + de::toString(specs[specNdx].numDrawCommands);
1996 
1997 			const bool computeIndices = (methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS);
1998 
1999 			if (methods[methodNdx].separateCompute)
2000 				largeGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands));
2001 			else
2002 				largeGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands));
2003 		}
2004 	}
2005 }
2006 
2007 class RandomGroup : public TestCaseGroup
2008 {
2009 public:
2010 			RandomGroup		(Context& context, const char* name, const char* descr);
2011 			~RandomGroup	(void);
2012 
2013 	void	init			(void);
2014 };
2015 
2016 template <int SIZE>
2017 struct UniformWeightArray
2018 {
2019 	float weights[SIZE];
2020 
UniformWeightArraydeqp::gles31::Functional::__anon18b4acdd0111::UniformWeightArray2021 	UniformWeightArray (void)
2022 	{
2023 		for (int i=0; i<SIZE; ++i)
2024 			weights[i] = 1.0f;
2025 	}
2026 };
2027 
RandomGroup(Context & context,const char * name,const char * descr)2028 RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
2029 	: TestCaseGroup	(context, name, descr)
2030 {
2031 }
2032 
~RandomGroup(void)2033 RandomGroup::~RandomGroup (void)
2034 {
2035 }
2036 
init(void)2037 void RandomGroup::init (void)
2038 {
2039 	const int	numAttempts				= 100;
2040 
2041 	const int	attribCounts[]			= { 1,   2,   5 };
2042 	const float	attribWeights[]			= { 30, 10,   1 };
2043 	const int	primitiveCounts[]		= { 1,   5,  64 };
2044 	const float	primitiveCountWeights[]	= { 20, 10,   1 };
2045 	const int	indexOffsets[]			= { 0,   7,  13 };
2046 	const float	indexOffsetWeights[]	= { 20, 20,   1 };
2047 	const int	firsts[]				= { 0,   7,  13 };
2048 	const float	firstWeights[]			= { 20, 20,   1 };
2049 
2050 	const int	instanceCounts[]		= { 1,   2,  16,  17 };
2051 	const float	instanceWeights[]		= { 20, 10,   5,   1 };
2052 	const int	indexMins[]				= { 0,   1,   3,   8 };
2053 	const int	indexMaxs[]				= { 4,   8, 128, 257 };
2054 	const float	indexWeights[]			= { 50, 50,  50,  50 };
2055 	const int	offsets[]				= { 0,   1,   5,  12 };
2056 	const float	offsetWeights[]			= { 50, 10,  10,  10 };
2057 	const int	strides[]				= { 0,   7,  16,  17 };
2058 	const float	strideWeights[]			= { 50, 10,  10,  10 };
2059 	const int	instanceDivisors[]		= { 0,   1,   3, 129 };
2060 	const float	instanceDivisorWeights[]= { 70, 30,  10,  10 };
2061 
2062 	const int	indirectOffsets[]		= { 0,   1,   2 };
2063 	const float indirectOffsetWeigths[]	= { 2,   1,   1 };
2064 	const int	baseVertices[]			= { 0,   1,  -2,   4,  3 };
2065 	const float baseVertexWeigths[]		= { 4,   1,   1,   1,  1 };
2066 
2067 	gls::DrawTestSpec::Primitive primitives[] =
2068 	{
2069 		gls::DrawTestSpec::PRIMITIVE_POINTS,
2070 		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
2071 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
2072 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
2073 		gls::DrawTestSpec::PRIMITIVE_LINES,
2074 		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
2075 		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
2076 	};
2077 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
2078 
2079 	gls::DrawTestSpec::DrawMethod drawMethods[] =
2080 	{
2081 		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
2082 		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
2083 	};
2084 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
2085 
2086 	gls::DrawTestSpec::IndexType indexTypes[] =
2087 	{
2088 		gls::DrawTestSpec::INDEXTYPE_BYTE,
2089 		gls::DrawTestSpec::INDEXTYPE_SHORT,
2090 		gls::DrawTestSpec::INDEXTYPE_INT,
2091 	};
2092 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
2093 
2094 	gls::DrawTestSpec::InputType inputTypes[] =
2095 	{
2096 		gls::DrawTestSpec::INPUTTYPE_FLOAT,
2097 		gls::DrawTestSpec::INPUTTYPE_FIXED,
2098 		gls::DrawTestSpec::INPUTTYPE_BYTE,
2099 		gls::DrawTestSpec::INPUTTYPE_SHORT,
2100 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
2101 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
2102 		gls::DrawTestSpec::INPUTTYPE_INT,
2103 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
2104 		gls::DrawTestSpec::INPUTTYPE_HALF,
2105 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2106 		gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
2107 	};
2108 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
2109 
2110 	gls::DrawTestSpec::OutputType outputTypes[] =
2111 	{
2112 		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
2113 		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
2114 		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
2115 		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
2116 		gls::DrawTestSpec::OUTPUTTYPE_INT,
2117 		gls::DrawTestSpec::OUTPUTTYPE_UINT,
2118 		gls::DrawTestSpec::OUTPUTTYPE_IVEC2,
2119 		gls::DrawTestSpec::OUTPUTTYPE_IVEC3,
2120 		gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
2121 		gls::DrawTestSpec::OUTPUTTYPE_UVEC2,
2122 		gls::DrawTestSpec::OUTPUTTYPE_UVEC3,
2123 		gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
2124 	};
2125 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
2126 
2127 	gls::DrawTestSpec::Usage usages[] =
2128 	{
2129 		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
2130 		gls::DrawTestSpec::USAGE_STATIC_DRAW,
2131 		gls::DrawTestSpec::USAGE_STREAM_DRAW,
2132 		gls::DrawTestSpec::USAGE_STREAM_READ,
2133 		gls::DrawTestSpec::USAGE_STREAM_COPY,
2134 		gls::DrawTestSpec::USAGE_STATIC_READ,
2135 		gls::DrawTestSpec::USAGE_STATIC_COPY,
2136 		gls::DrawTestSpec::USAGE_DYNAMIC_READ,
2137 		gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
2138 	};
2139 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
2140 
2141 	std::set<deUint32>	insertedHashes;
2142 	size_t				insertedCount = 0;
2143 
2144 	for (int ndx = 0; ndx < numAttempts; ++ndx)
2145 	{
2146 		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
2147 
2148 		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
2149 		int					drawCommandSize;
2150 		gls::DrawTestSpec	spec;
2151 
2152 		spec.apiType				= glu::ApiType::es(3,1);
2153 		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
2154 		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
2155 		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
2156 
2157 		if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
2158 			drawCommandSize = sizeof(deUint32[4]);
2159 		else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2160 			drawCommandSize = sizeof(deUint32[5]);
2161 		else
2162 		{
2163 			DE_ASSERT(DE_FALSE);
2164 			return;
2165 		}
2166 
2167 		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
2168 		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
2169 		spec.indexStorage			= gls::DrawTestSpec::STORAGE_BUFFER;
2170 		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
2171 		spec.indexMin				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMins),			DE_ARRAY_END(indexMins),		indexWeights);
2172 		spec.indexMax				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMaxs),			DE_ARRAY_END(indexMaxs),		indexWeights);
2173 		spec.instanceCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(instanceCounts),	DE_ARRAY_END(instanceCounts),	instanceWeights);
2174 		spec.indirectOffset			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indirectOffsets),	DE_ARRAY_END(indirectOffsets),	indirectOffsetWeigths) * drawCommandSize;
2175 		spec.baseVertex				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(baseVertices),		DE_ARRAY_END(baseVertices),		baseVertexWeigths);
2176 
2177 		// check spec is legal
2178 		if (!spec.valid())
2179 			continue;
2180 
2181 		for (int attrNdx = 0; attrNdx < attributeCount;)
2182 		{
2183 			bool valid;
2184 			gls::DrawTestSpec::AttributeSpec attribSpec;
2185 
2186 			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
2187 			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
2188 			attribSpec.storage				= gls::DrawTestSpec::STORAGE_BUFFER;
2189 			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
2190 			attribSpec.componentCount		= random.getInt(1, 4);
2191 			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
2192 			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
2193 			attribSpec.normalize			= random.getBool();
2194 			attribSpec.instanceDivisor		= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
2195 			attribSpec.useDefaultAttribute	= random.getBool();
2196 
2197 			// check spec is legal
2198 			valid = attribSpec.valid(spec.apiType);
2199 
2200 			// we do not want interleaved elements. (Might result in some weird floating point values)
2201 			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
2202 				valid = false;
2203 
2204 			// try again if not valid
2205 			if (valid)
2206 			{
2207 				spec.attribs.push_back(attribSpec);
2208 				++attrNdx;
2209 			}
2210 		}
2211 
2212 		// Do not collapse all vertex positions to a single positions
2213 		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2214 			spec.attribs[0].instanceDivisor = 0;
2215 
2216 		// Is render result meaningful?
2217 		{
2218 			// Only one vertex
2219 			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2220 				continue;
2221 			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2222 				continue;
2223 
2224 			// Triangle only on one axis
2225 			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
2226 			{
2227 				if (spec.attribs[0].componentCount == 1)
2228 					continue;
2229 				if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT)
2230 					continue;
2231 				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
2232 					continue;
2233 			}
2234 		}
2235 
2236 		// Add case
2237 		{
2238 			deUint32 hash = spec.hash();
2239 			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
2240 				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
2241 
2242 			if (insertedHashes.find(hash) == insertedHashes.end())
2243 			{
2244 				// Only aligned cases
2245 				if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET &&
2246 					spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
2247 					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
2248 				insertedHashes.insert(hash);
2249 
2250 				++insertedCount;
2251 			}
2252 		}
2253 	}
2254 }
2255 
2256 class BadCommandBufferCase : public TestCase
2257 {
2258 public:
2259 	enum
2260 	{
2261 		CommandSize = 20
2262 	};
2263 
2264 					BadCommandBufferCase	(Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 m_expectedError);
2265 					~BadCommandBufferCase	(void);
2266 
2267 	IterateResult	iterate					(void);
2268 
2269 private:
2270 	const deUint32	m_alignment;
2271 	const deUint32	m_bufferSize;
2272 	const bool		m_writeCommandToBuffer;
2273 	const deUint32	m_expectedError;
2274 };
2275 
BadCommandBufferCase(Context & context,const char * name,const char * desc,deUint32 alignment,deUint32 bufferSize,bool writeCommandToBuffer,deUint32 expectedError)2276 BadCommandBufferCase::BadCommandBufferCase (Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 expectedError)
2277 	: TestCase					(context, name, desc)
2278 	, m_alignment				(alignment)
2279 	, m_bufferSize				(bufferSize)
2280 	, m_writeCommandToBuffer	(writeCommandToBuffer)
2281 	, m_expectedError			(expectedError)
2282 {
2283 }
2284 
~BadCommandBufferCase(void)2285 BadCommandBufferCase::~BadCommandBufferCase (void)
2286 {
2287 }
2288 
iterate(void)2289 BadCommandBufferCase::IterateResult	BadCommandBufferCase::iterate (void)
2290 {
2291 	const tcu::Vec4 vertexPositions[] =
2292 	{
2293 		tcu::Vec4(0,	0,		0, 1),
2294 		tcu::Vec4(1,	0,		0, 1),
2295 		tcu::Vec4(0,	1,		0, 1),
2296 	};
2297 
2298 	const deUint16 indices[] =
2299 	{
2300 		0, 2, 1,
2301 	};
2302 
2303 	DE_STATIC_ASSERT(CommandSize == sizeof(DrawElementsCommand));
2304 
2305 	sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
2306 
2307 	deUint32 vaoID			= 0;
2308 	deUint32 positionBuf	= 0;
2309 	deUint32 indexBuf		= 0;
2310 	deUint32 drawIndirectBuf= 0;
2311 	deUint32 error;
2312 
2313 	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
2314 	deUint32			programID		= program.getProgram();
2315 	deInt32				posLocation		= gl.getAttribLocation(programID, "a_position");
2316 
2317 	DrawElementsCommand drawCommand;
2318 	drawCommand.count				= 3;
2319 	drawCommand.primCount			= 1;
2320 	drawCommand.firstIndex			= 0;
2321 	drawCommand.baseVertex			= 0;
2322 	drawCommand.reservedMustBeZero	= 0;
2323 
2324 	std::vector<deInt8> drawCommandBuffer;
2325 	drawCommandBuffer.resize(m_bufferSize);
2326 
2327 	deMemset(&drawCommandBuffer[0], 0, (int)drawCommandBuffer.size());
2328 
2329 	if (m_writeCommandToBuffer)
2330 	{
2331 		DE_ASSERT(drawCommandBuffer.size() >= sizeof(drawCommand) + m_alignment);
2332 		deMemcpy(&drawCommandBuffer[m_alignment], &drawCommand, sizeof(drawCommand));
2333 	}
2334 
2335 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2336 	gl.genVertexArrays(1, &vaoID);
2337 	gl.bindVertexArray(vaoID);
2338 
2339 	gl.genBuffers(1, &positionBuf);
2340 	gl.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
2341 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2342 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2343 	gl.vertexAttribDivisor(posLocation, 0);
2344 	gl.enableVertexAttribArray(posLocation);
2345 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2346 
2347 	gl.genBuffers(1, &indexBuf);
2348 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
2349 	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2350 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2351 
2352 	gl.genBuffers(1, &drawIndirectBuf);
2353 	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf);
2354 	gl.bufferData(GL_DRAW_INDIRECT_BUFFER, drawCommandBuffer.size(), &drawCommandBuffer[0], GL_STATIC_DRAW);
2355 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2356 
2357 	gl.viewport(0, 0, 1, 1);
2358 
2359 	gl.useProgram(programID);
2360 	gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(deUintptr)m_alignment);
2361 
2362 	error = gl.getError();
2363 
2364 	gl.useProgram(0);
2365 
2366 	gl.deleteBuffers(1, &drawIndirectBuf);
2367 	gl.deleteBuffers(1, &indexBuf);
2368 	gl.deleteBuffers(1, &positionBuf);
2369 	gl.deleteVertexArrays(1, &vaoID);
2370 
2371 	m_testCtx.getLog() << tcu::TestLog::Message << "drawElementsIndirect generated " << glu::getErrorStr(error) << ", expecting " << glu::getErrorStr(m_expectedError) << "." << tcu::TestLog::EndMessage;
2372 
2373 	if (error == m_expectedError)
2374 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2375 	else
2376 	{
2377 		m_testCtx.getLog() << tcu::TestLog::Message << "\tUnexpected error." << tcu::TestLog::EndMessage;
2378 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2379 	}
2380 
2381 	return STOP;
2382 }
2383 
2384 class BadAlignmentCase : public BadCommandBufferCase
2385 {
2386 public:
2387 					BadAlignmentCase	(Context& context, const char* name, const char* desc, deUint32 alignment);
2388 					~BadAlignmentCase	(void);
2389 };
2390 
BadAlignmentCase(Context & context,const char * name,const char * desc,deUint32 alignment)2391 BadAlignmentCase::BadAlignmentCase (Context& context, const char* name, const char* desc, deUint32 alignment)
2392 	: BadCommandBufferCase(context, name, desc, alignment, CommandSize+alignment, true, GL_INVALID_VALUE)
2393 {
2394 }
2395 
~BadAlignmentCase(void)2396 BadAlignmentCase::~BadAlignmentCase (void)
2397 {
2398 }
2399 
2400 class BadBufferRangeCase : public BadCommandBufferCase
2401 {
2402 public:
2403 					BadBufferRangeCase	(Context& context, const char* name, const char* desc, deUint32 offset);
2404 					~BadBufferRangeCase	(void);
2405 };
2406 
BadBufferRangeCase(Context & context,const char * name,const char * desc,deUint32 offset)2407 BadBufferRangeCase::BadBufferRangeCase (Context& context, const char* name, const char* desc, deUint32 offset)
2408 	: BadCommandBufferCase(context, name, desc, offset, CommandSize, false, GL_INVALID_OPERATION)
2409 {
2410 }
2411 
~BadBufferRangeCase(void)2412 BadBufferRangeCase::~BadBufferRangeCase (void)
2413 {
2414 }
2415 
2416 class BadStateCase : public TestCase
2417 {
2418 public:
2419 	enum CaseType
2420 	{
2421 		CASE_CLIENT_BUFFER_VERTEXATTR = 0,
2422 		CASE_CLIENT_BUFFER_COMMAND,
2423 		CASE_DEFAULT_VAO,
2424 
2425 		CASE_CLIENT_LAST
2426 	};
2427 
2428 						BadStateCase	(Context& context, const char* name, const char* desc, CaseType type);
2429 						~BadStateCase	(void);
2430 
2431 	void				init			(void);
2432 	void				deinit			(void);
2433 	IterateResult		iterate			(void);
2434 
2435 private:
2436 	const CaseType		m_caseType;
2437 };
2438 
BadStateCase(Context & context,const char * name,const char * desc,CaseType type)2439 BadStateCase::BadStateCase (Context& context, const char* name, const char* desc, CaseType type)
2440 	: TestCase			(context, name, desc)
2441 	, m_caseType		(type)
2442 {
2443 	DE_ASSERT(type < CASE_CLIENT_LAST);
2444 }
2445 
~BadStateCase(void)2446 BadStateCase::~BadStateCase (void)
2447 {
2448 	deinit();
2449 }
2450 
init(void)2451 void BadStateCase::init (void)
2452 {
2453 }
2454 
deinit(void)2455 void BadStateCase::deinit (void)
2456 {
2457 }
2458 
iterate(void)2459 BadStateCase::IterateResult BadStateCase::iterate (void)
2460 {
2461 	const tcu::Vec4 vertexPositions[] =
2462 	{
2463 		tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
2464 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2465 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2466 	};
2467 
2468 	const deUint16 indices[] =
2469 	{
2470 		0, 2, 1,
2471 	};
2472 
2473 	sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
2474 
2475 	deUint32			error;
2476 	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
2477 	deUint32			vaoID			= 0;
2478 	deUint32			dataBufferID	= 0;
2479 	deUint32			indexBufferID	= 0;
2480 	deUint32			cmdBufferID		= 0;
2481 
2482 	const deUint32		programID		= program.getProgram();
2483 	const deInt32		posLocation		= gl.getAttribLocation(programID, "a_position");
2484 
2485 	DrawElementsCommand drawCommand;
2486 	drawCommand.count				= 3;
2487 	drawCommand.primCount			= 1;
2488 	drawCommand.firstIndex			= 0;
2489 	drawCommand.baseVertex			= 0;
2490 	drawCommand.reservedMustBeZero	= 0;
2491 
2492 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2493 
2494 	if (m_caseType == CASE_CLIENT_BUFFER_VERTEXATTR)
2495 	{
2496 		// \note We use default VAO since we use client pointers. Trying indirect draw with default VAO is also an error. => This test does two illegal operations
2497 
2498 		gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, vertexPositions);
2499 		gl.enableVertexAttribArray(posLocation);
2500 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2501 	}
2502 	else if (m_caseType == CASE_CLIENT_BUFFER_COMMAND)
2503 	{
2504 		gl.genVertexArrays(1, &vaoID);
2505 		gl.bindVertexArray(vaoID);
2506 
2507 		gl.genBuffers(1, &dataBufferID);
2508 		gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2509 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2510 		gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2511 		gl.enableVertexAttribArray(posLocation);
2512 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2513 	}
2514 	else if (m_caseType == CASE_DEFAULT_VAO)
2515 	{
2516 		gl.genBuffers(1, &dataBufferID);
2517 		gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2518 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2519 		gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2520 		gl.enableVertexAttribArray(posLocation);
2521 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2522 	}
2523 	else
2524 		DE_ASSERT(DE_FALSE);
2525 
2526 	gl.genBuffers(1, &indexBufferID);
2527 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
2528 	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2529 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2530 
2531 	if (m_caseType != CASE_CLIENT_BUFFER_COMMAND)
2532 	{
2533 		gl.genBuffers(1, &cmdBufferID);
2534 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID);
2535 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2536 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2537 	}
2538 
2539 	gl.viewport(0, 0, 1, 1);
2540 
2541 	gl.useProgram(programID);
2542 	gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (m_caseType != CASE_CLIENT_BUFFER_COMMAND) ? (DE_NULL) : (&drawCommand));
2543 
2544 	error = gl.getError();
2545 
2546 	gl.bindVertexArray(0);
2547 	gl.useProgram(0);
2548 
2549 	if (error == GL_INVALID_OPERATION)
2550 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2551 	else
2552 	{
2553 		m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
2554 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2555 	}
2556 
2557 	return STOP;
2558 }
2559 
2560 class BadDrawModeCase : public TestCase
2561 {
2562 public:
2563 	enum DrawType
2564 	{
2565 		DRAW_ARRAYS = 0,
2566 		DRAW_ELEMENTS,
2567 		DRAW_ELEMENTS_BAD_INDEX,
2568 
2569 		DRAW_LAST
2570 	};
2571 
2572 						BadDrawModeCase	(Context& context, const char* name, const char* desc, DrawType type);
2573 						~BadDrawModeCase(void);
2574 
2575 	void				init			(void);
2576 	void				deinit			(void);
2577 	IterateResult		iterate			(void);
2578 
2579 private:
2580 	const DrawType		m_drawType;
2581 };
2582 
BadDrawModeCase(Context & context,const char * name,const char * desc,DrawType type)2583 BadDrawModeCase::BadDrawModeCase (Context& context, const char* name, const char* desc, DrawType type)
2584 	: TestCase			(context, name, desc)
2585 	, m_drawType		(type)
2586 {
2587 	DE_ASSERT(type < DRAW_LAST);
2588 }
2589 
~BadDrawModeCase(void)2590 BadDrawModeCase::~BadDrawModeCase (void)
2591 {
2592 	deinit();
2593 }
2594 
init(void)2595 void BadDrawModeCase::init (void)
2596 {
2597 }
2598 
deinit(void)2599 void BadDrawModeCase::deinit (void)
2600 {
2601 }
2602 
iterate(void)2603 BadDrawModeCase::IterateResult BadDrawModeCase::iterate (void)
2604 {
2605 	const tcu::Vec4 vertexPositions[] =
2606 	{
2607 		tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
2608 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2609 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2610 	};
2611 
2612 	const deUint16 indices[] =
2613 	{
2614 		0, 2, 1,
2615 	};
2616 
2617 	sglr::GLContext		gl				(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
2618 
2619 	deUint32			error;
2620 	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
2621 	deUint32			vaoID			= 0;
2622 	deUint32			dataBufferID	= 0;
2623 	deUint32			indexBufferID	= 0;
2624 	deUint32			cmdBufferID		= 0;
2625 
2626 	const deUint32		programID		= program.getProgram();
2627 	const deInt32		posLocation		= gl.getAttribLocation(programID, "a_position");
2628 	const glw::GLenum	mode			= (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (GL_TRIANGLES) : (0x123);
2629 	const glw::GLenum	indexType		= (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (0x123) : (GL_UNSIGNED_SHORT);
2630 
2631 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2632 
2633 	// vao
2634 
2635 	gl.genVertexArrays(1, &vaoID);
2636 	gl.bindVertexArray(vaoID);
2637 
2638 	// va
2639 
2640 	gl.genBuffers(1, &dataBufferID);
2641 	gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2642 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2643 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2644 	gl.enableVertexAttribArray(posLocation);
2645 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2646 
2647 	// index
2648 
2649 	if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2650 	{
2651 		gl.genBuffers(1, &indexBufferID);
2652 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
2653 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2654 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2655 	}
2656 
2657 	// cmd
2658 
2659 	gl.genBuffers(1, &cmdBufferID);
2660 	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID);
2661 	if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2662 	{
2663 		DrawElementsCommand drawCommand;
2664 		drawCommand.count				= 3;
2665 		drawCommand.primCount			= 1;
2666 		drawCommand.firstIndex			= 0;
2667 		drawCommand.baseVertex			= 0;
2668 		drawCommand.reservedMustBeZero	= 0;
2669 
2670 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2671 	}
2672 	else if (m_drawType == DRAW_ARRAYS)
2673 	{
2674 		DrawArraysCommand drawCommand;
2675 		drawCommand.count				= 3;
2676 		drawCommand.primCount			= 1;
2677 		drawCommand.first				= 0;
2678 		drawCommand.reservedMustBeZero	= 0;
2679 
2680 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2681 	}
2682 	else
2683 		DE_ASSERT(DE_FALSE);
2684 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2685 
2686 	gl.viewport(0, 0, 1, 1);
2687 	gl.useProgram(programID);
2688 	if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2689 		gl.drawElementsIndirect(mode, indexType, DE_NULL);
2690 	else if (m_drawType == DRAW_ARRAYS)
2691 		gl.drawArraysIndirect(mode, DE_NULL);
2692 	else
2693 		DE_ASSERT(DE_FALSE);
2694 
2695 	error = gl.getError();
2696 	gl.useProgram(0);
2697 
2698 	if (error == GL_INVALID_ENUM)
2699 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2700 	else
2701 	{
2702 		m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_ENUM, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
2703 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2704 	}
2705 
2706 	return STOP;
2707 }
2708 
2709 class NegativeGroup : public TestCaseGroup
2710 {
2711 public:
2712 			NegativeGroup	(Context& context, const char* name, const char* descr);
2713 			~NegativeGroup	(void);
2714 
2715 	void	init			(void);
2716 };
2717 
NegativeGroup(Context & context,const char * name,const char * descr)2718 NegativeGroup::NegativeGroup (Context& context, const char* name, const char* descr)
2719 	: TestCaseGroup	(context, name, descr)
2720 {
2721 }
2722 
~NegativeGroup(void)2723 NegativeGroup::~NegativeGroup (void)
2724 {
2725 }
2726 
init(void)2727 void NegativeGroup::init (void)
2728 {
2729 	// invalid alignment
2730 	addChild(new BadAlignmentCase	(m_context, "command_bad_alignment_1",								"Bad command alignment",					1));
2731 	addChild(new BadAlignmentCase	(m_context, "command_bad_alignment_2",								"Bad command alignment",					2));
2732 	addChild(new BadAlignmentCase	(m_context, "command_bad_alignment_3",								"Bad command alignment",					3));
2733 
2734 	// command only partially or not at all in the buffer
2735 	addChild(new BadBufferRangeCase	(m_context, "command_offset_partially_in_buffer",					"Command not fully in the buffer range",	BadBufferRangeCase::CommandSize - 16));
2736 	addChild(new BadBufferRangeCase	(m_context, "command_offset_not_in_buffer",							"Command not in the buffer range",			BadBufferRangeCase::CommandSize));
2737 	addChild(new BadBufferRangeCase	(m_context, "command_offset_not_in_buffer_unsigned32_wrap",			"Command not in the buffer range",			0xFFFFFFFC));
2738 	addChild(new BadBufferRangeCase	(m_context, "command_offset_not_in_buffer_signed32_wrap",			"Command not in the buffer range",			0x7FFFFFFC));
2739 
2740 	// use with client data and default vao
2741 	addChild(new BadStateCase		(m_context, "client_vertex_attrib_array",							"Vertex attrib array in the client memory",	BadStateCase::CASE_CLIENT_BUFFER_VERTEXATTR));
2742 	addChild(new BadStateCase		(m_context, "client_command_array",									"Command array in the client memory",		BadStateCase::CASE_CLIENT_BUFFER_COMMAND));
2743 	addChild(new BadStateCase		(m_context, "default_vao",											"Use with default vao",						BadStateCase::CASE_DEFAULT_VAO));
2744 
2745 	// invalid mode & type
2746 	addChild(new BadDrawModeCase	(m_context, "invalid_mode_draw_arrays",								"Call DrawArraysIndirect with bad mode",	BadDrawModeCase::DRAW_ARRAYS));
2747 	addChild(new BadDrawModeCase	(m_context, "invalid_mode_draw_elements",							"Call DrawelementsIndirect with bad mode",	BadDrawModeCase::DRAW_ELEMENTS));
2748 	addChild(new BadDrawModeCase	(m_context, "invalid_type_draw_elements",							"Call DrawelementsIndirect with bad type",	BadDrawModeCase::DRAW_ELEMENTS_BAD_INDEX));
2749 }
2750 
2751 } // anonymous
2752 
DrawTests(Context & context)2753 DrawTests::DrawTests (Context& context)
2754 	: TestCaseGroup(context, "draw_indirect", "Indirect drawing tests")
2755 {
2756 }
2757 
~DrawTests(void)2758 DrawTests::~DrawTests (void)
2759 {
2760 }
2761 
init(void)2762 void DrawTests::init (void)
2763 {
2764 	// Basic
2765 	{
2766 		const gls::DrawTestSpec::DrawMethod basicMethods[] =
2767 		{
2768 			gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
2769 			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
2770 		};
2771 
2772 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
2773 		{
2774 			const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
2775 			const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
2776 
2777 			this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
2778 		}
2779 	}
2780 
2781 	// extreme instancing
2782 
2783 	this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count."));
2784 
2785 	// compute shader generated commands
2786 
2787 	this->addChild(new ComputeShaderGeneratedGroup(m_context, "compute_interop", "draw tests with a draw command generated in compute shader."));
2788 
2789 	// Random
2790 
2791 	this->addChild(new RandomGroup(m_context, "random", "random draw commands."));
2792 
2793 	// negative
2794 
2795 	this->addChild(new NegativeGroup(m_context, "negative", "invalid draw commands with defined error codes."));
2796 }
2797 
2798 } // Functional
2799 } // gles31
2800 } // deqp
2801