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