• 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       posXp1      = (float(x+1u) / float(gridSize)) * 2.0 - 1.0;\n"
1281 				<< "        float       posY        = (float(y)    / float(gridSize)) * 2.0 - 1.0;\n"
1282 				<< "        float       posYp1      = (float(y+1u) / float(gridSize)) * 2.0 - 1.0;\n"
1283 				<< "        vec4        color       = ((x + y)%2u != 0u) ? (yellow) : (green);\n"
1284 				<< "\n"
1285 				<< "        attribs[((y * gridSize + x) * 6u + 0u) * 2u + 0u] = vec4(posX,   posY,   0.0, 1.0);\n"
1286 				<< "        attribs[((y * gridSize + x) * 6u + 1u) * 2u + 0u] = vec4(posXp1, posY,   0.0, 1.0);\n"
1287 				<< "        attribs[((y * gridSize + x) * 6u + 2u) * 2u + 0u] = vec4(posXp1, posYp1, 0.0, 1.0);\n"
1288 				<< "        attribs[((y * gridSize + x) * 6u + 3u) * 2u + 0u] = vec4(posX,   posY,   0.0, 1.0);\n"
1289 				<< "        attribs[((y * gridSize + x) * 6u + 4u) * 2u + 0u] = vec4(posXp1, posYp1, 0.0, 1.0);\n"
1290 				<< "        attribs[((y * gridSize + x) * 6u + 5u) * 2u + 0u] = vec4(posX,   posYp1, 0.0, 1.0);\n"
1291 				<< "\n"
1292 				<< "        attribs[((y * gridSize + x) * 6u + 0u) * 2u + 1u] = color;\n"
1293 				<< "        attribs[((y * gridSize + x) * 6u + 1u) * 2u + 1u] = color;\n"
1294 				<< "        attribs[((y * gridSize + x) * 6u + 2u) * 2u + 1u] = color;\n"
1295 				<< "        attribs[((y * gridSize + x) * 6u + 3u) * 2u + 1u] = color;\n"
1296 				<< "        attribs[((y * gridSize + x) * 6u + 4u) * 2u + 1u] = color;\n"
1297 				<< "        attribs[((y * gridSize + x) * 6u + 5u) * 2u + 1u] = color;\n"
1298 				<< "    }\n";
1299 		}
1300 		else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1301 		{
1302 			buf	<< "    if (gl_GlobalInvocationID.x < gridSize+1u && gl_GlobalInvocationID.y < gridSize+1u && gl_GlobalInvocationID.z == 0u) {\n"
1303 				<< "        uint        y           = gl_GlobalInvocationID.x;\n"
1304 				<< "        uint        x           = gl_GlobalInvocationID.y;\n"
1305 				<< "        float       posX        = (float(x) / float(gridSize)) * 2.0 - 1.0;\n"
1306 				<< "        float       posY        = (float(y) / float(gridSize)) * 2.0 - 1.0;\n"
1307 				<< "\n"
1308 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 0u] = vec4(posX, posY, 0.0, 1.0);\n"
1309 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 1u] = green;\n"
1310 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 2u] = vec4(posX, posY, 0.0, 1.0);\n"
1311 				<< "        attribs[(y * (gridSize+1u) + x) * 4u + 3u] = yellow;\n"
1312 				<< "    }\n";
1313 		}
1314 
1315 		buf << "\n";
1316 	}
1317 
1318 	if (computeIndices)
1319 	{
1320 		buf	<< "    // indices\n"
1321 			<< "    if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && gl_GlobalInvocationID.z == 0u) {\n"
1322 			<< "        uint    y       = gl_GlobalInvocationID.x;\n"
1323 			<< "        uint    x       = gl_GlobalInvocationID.y;\n"
1324 			<< "        uint    color   = ((x + y)%2u);\n"
1325 			<< "\n"
1326 			<< "        indices[(y * gridSize + x) * 6u + 0u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1327 			<< "        indices[(y * gridSize + x) * 6u + 1u] = ((y+1u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1328 			<< "        indices[(y * gridSize + x) * 6u + 2u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1329 			<< "        indices[(y * gridSize + x) * 6u + 3u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1330 			<< "        indices[(y * gridSize + x) * 6u + 4u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1331 			<< "        indices[(y * gridSize + x) * 6u + 5u] = ((y+0u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1332 			<< "    }\n"
1333 			<< "\n";
1334 	}
1335 
1336 	buf	<< "}\n";
1337 
1338 	return buf.str();
1339 }
1340 
createDrawCommand(void)1341 void ComputeShaderGeneratedCase::createDrawCommand (void)
1342 {
1343 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
1344 	const int				triangleCount	= m_gridSize * m_gridSize * 2;
1345 	const deUint32			numDrawCallTris	= triangleCount / m_numDrawCmds;
1346 
1347 	if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1348 	{
1349 		std::vector<DrawArraysCommand> cmds;
1350 
1351 		for (int ndx = 0; ndx < m_numDrawCmds; ++ndx)
1352 		{
1353 			const deUint32				firstTri = ndx * numDrawCallTris;
1354 			DrawArraysCommand			data;
1355 
1356 			data.count					= numDrawCallTris*3;
1357 			data.primCount				= 1;
1358 			data.first					= firstTri*3;
1359 			data.reservedMustBeZero		= 0;
1360 
1361 			cmds.push_back(data);
1362 		}
1363 
1364 		DE_ASSERT((int)(sizeof(DrawArraysCommand)*cmds.size()) == m_numDrawCmds * m_commandSize);
1365 
1366 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1367 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawArraysCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW);
1368 	}
1369 	else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1370 	{
1371 		std::vector<DrawElementsCommand> cmds;
1372 
1373 		for (int ndx = 0; ndx < m_numDrawCmds; ++ndx)
1374 		{
1375 			const deUint32			firstTri = ndx * numDrawCallTris;
1376 			DrawElementsCommand		data;
1377 
1378 			data.count				= numDrawCallTris*3;
1379 			data.primCount			= 1;
1380 			data.firstIndex			= firstTri*3;
1381 			data.baseVertex			= 0;
1382 			data.reservedMustBeZero	= 0;
1383 
1384 			cmds.push_back(data);
1385 		}
1386 
1387 		DE_ASSERT((int)(sizeof(DrawElementsCommand)*cmds.size()) == m_numDrawCmds * m_commandSize);
1388 
1389 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1390 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawElementsCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW);
1391 	}
1392 	else
1393 		DE_ASSERT(false);
1394 
1395 	glu::checkError(gl.getError(), "create draw command", __FILE__, __LINE__);
1396 }
1397 
createDrawData(void)1398 void ComputeShaderGeneratedCase::createDrawData (void)
1399 {
1400 	const tcu::Vec4			yellow	(1.0f, 1.0f, 0.0f, 1.0f);
1401 	const tcu::Vec4			green	(0.0f, 1.0f, 0.0f, 1.0f);
1402 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1403 
1404 	if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1405 	{
1406 		// Store elements in the order they are drawn. Interleave color.
1407 		std::vector<tcu::Vec4> buffer(m_gridSize*m_gridSize*6*2);
1408 
1409 		DE_ASSERT(buffer.size() == calcDrawBufferSize());
1410 
1411 		for (int y = 0; y < m_gridSize; ++y)
1412 		for (int x = 0; x < m_gridSize; ++x)
1413 		{
1414 			const float			posX		= ((float)x / (float)m_gridSize) * 2.0f - 1.0f;
1415 			const float			posY		= ((float)y / (float)m_gridSize) * 2.0f - 1.0f;
1416 			const float			cellSize	= 2.0f / (float)m_gridSize;
1417 			const tcu::Vec4&	color		= ((x + y)%2) ? (yellow) : (green);
1418 
1419 			buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 0] = tcu::Vec4(posX,			posY,				0.0f, 1.0f);
1420 			buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 0] = tcu::Vec4(posX + cellSize,	posY,				0.0f, 1.0f);
1421 			buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 0] = tcu::Vec4(posX + cellSize,	posY + cellSize,	0.0f, 1.0f);
1422 			buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 0] = tcu::Vec4(posX,			posY,				0.0f, 1.0f);
1423 			buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 0] = tcu::Vec4(posX + cellSize, posY + cellSize,	0.0f, 1.0f);
1424 			buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 0] = tcu::Vec4(posX,			posY + cellSize,	0.0f, 1.0f);
1425 
1426 			buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 1] = color;
1427 			buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 1] = color;
1428 			buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 1] = color;
1429 			buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 1] = color;
1430 			buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 1] = color;
1431 			buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 1] = color;
1432 		}
1433 
1434 		gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1435 		gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW);
1436 	}
1437 	else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1438 	{
1439 		// Elements are indexed by index buffer. Interleave color. Two vertices per position since 2 colors
1440 
1441 		std::vector<tcu::Vec4> buffer((m_gridSize+1)*(m_gridSize+1)*4);
1442 
1443 		DE_ASSERT(buffer.size() == calcDrawBufferSize());
1444 
1445 		for (int y = 0; y < m_gridSize+1; ++y)
1446 		for (int x = 0; x < m_gridSize+1; ++x)
1447 		{
1448 			const float			posX		= ((float)x / (float)m_gridSize) * 2.0f - 1.0f;
1449 			const float			posY		= ((float)y / (float)m_gridSize) * 2.0f - 1.0f;
1450 
1451 			buffer[(y * (m_gridSize+1) + x) * 4 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1452 			buffer[(y * (m_gridSize+1) + x) * 4 + 1] = green;
1453 			buffer[(y * (m_gridSize+1) + x) * 4 + 2] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1454 			buffer[(y * (m_gridSize+1) + x) * 4 + 3] = yellow;
1455 		}
1456 
1457 		gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1458 		gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW);
1459 	}
1460 	else
1461 		DE_ASSERT(false);
1462 
1463 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1464 }
1465 
createDrawIndices(void)1466 void ComputeShaderGeneratedCase::createDrawIndices (void)
1467 {
1468 	DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1469 
1470 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1471 	std::vector<deUint32>	buffer	(m_gridSize*m_gridSize*6);
1472 
1473 	DE_ASSERT(buffer.size() == calcIndexBufferSize());
1474 
1475 	for (int y = 0; y < m_gridSize; ++y)
1476 	for (int x = 0; x < m_gridSize; ++x)
1477 	{
1478 		const int color = ((x + y)%2);
1479 
1480 		buffer[(y * m_gridSize + x) * 6 + 0] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color;
1481 		buffer[(y * m_gridSize + x) * 6 + 1] = ((y+1) * (m_gridSize+1) + (x+0)) * 2 + color;
1482 		buffer[(y * m_gridSize + x) * 6 + 2] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color;
1483 		buffer[(y * m_gridSize + x) * 6 + 3] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color;
1484 		buffer[(y * m_gridSize + x) * 6 + 4] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color;
1485 		buffer[(y * m_gridSize + x) * 6 + 5] = ((y+0) * (m_gridSize+1) + (x+1)) * 2 + color;
1486 	}
1487 
1488 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
1489 	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(buffer.size() * sizeof(deUint32)), &buffer[0], GL_STATIC_DRAW);
1490 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1491 }
1492 
renderTo(tcu::Surface & dst)1493 void ComputeShaderGeneratedCase::renderTo (tcu::Surface& dst)
1494 {
1495 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1496 	const deInt32			positionLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_position");
1497 	const deInt32			colorLoc	= gl.getAttribLocation(m_shaderProgram->getProgram(), "a_color");
1498 	deUint32				vaoID		= 0;
1499 
1500 	gl.genVertexArrays(1, &vaoID);
1501 	gl.bindVertexArray(vaoID);
1502 
1503 	// Setup buffers
1504 
1505 	gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1506 	gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8 * (int)sizeof(float), DE_NULL);
1507 	gl.vertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, 8 * (int)sizeof(float), ((const deUint8*)DE_NULL) + 4*sizeof(float));
1508 	gl.enableVertexAttribArray(positionLoc);
1509 	gl.enableVertexAttribArray(colorLoc);
1510 
1511 	DE_ASSERT(positionLoc != -1);
1512 	DE_ASSERT(colorLoc != -1);
1513 
1514 	if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1515 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
1516 
1517 	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1518 
1519 	// draw
1520 
1521 	gl.clearColor(0, 0, 0, 1);
1522 	gl.clear(GL_COLOR_BUFFER_BIT);
1523 	gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1524 
1525 	gl.useProgram(m_shaderProgram->getProgram());
1526 	for (int drawCmdNdx = 0; drawCmdNdx < m_numDrawCmds; ++drawCmdNdx)
1527 	{
1528 		const void* offset = ((deUint8*)DE_NULL) + drawCmdNdx*m_commandSize;
1529 
1530 		if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1531 			gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset);
1532 		else if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1533 			gl.drawArraysIndirect(GL_TRIANGLES, offset);
1534 		else
1535 			DE_ASSERT(DE_FALSE);
1536 	}
1537 	gl.useProgram(0);
1538 
1539 	// free
1540 
1541 	gl.deleteVertexArrays(1, &vaoID);
1542 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1543 
1544 	gl.finish();
1545 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1546 
1547 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1548 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1549 }
1550 
calcDrawBufferSize(void) const1551 deUint32 ComputeShaderGeneratedCase::calcDrawBufferSize (void) const
1552 {
1553 	// returns size in "vec4"s
1554 	if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1555 		return m_gridSize*m_gridSize*6*2;
1556 	else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1557 		return (m_gridSize+1)*(m_gridSize+1)*4;
1558 	else
1559 		DE_ASSERT(DE_FALSE);
1560 
1561 	return 0;
1562 }
1563 
calcIndexBufferSize(void) const1564 deUint32 ComputeShaderGeneratedCase::calcIndexBufferSize (void) const
1565 {
1566 	if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1567 		return m_gridSize*m_gridSize*6;
1568 	else
1569 		return 0;
1570 }
1571 
1572 class ComputeShaderGeneratedCombinedCase : public ComputeShaderGeneratedCase
1573 {
1574 public:
1575 						ComputeShaderGeneratedCombinedCase	(Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls);
1576 						~ComputeShaderGeneratedCombinedCase	(void);
1577 
1578 	void				init								(void);
1579 	void				deinit								(void);
1580 
1581 private:
1582 	void				runComputeShader					(void);
1583 
1584 	glu::ShaderProgram*	m_computeProgram;
1585 };
1586 
ComputeShaderGeneratedCombinedCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int numDrawCalls)1587 ComputeShaderGeneratedCombinedCase::ComputeShaderGeneratedCombinedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls)
1588 	: ComputeShaderGeneratedCase(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls)
1589 	, m_computeProgram			(DE_NULL)
1590 {
1591 }
1592 
~ComputeShaderGeneratedCombinedCase(void)1593 ComputeShaderGeneratedCombinedCase::~ComputeShaderGeneratedCombinedCase (void)
1594 {
1595 	deinit();
1596 }
1597 
init(void)1598 void ComputeShaderGeneratedCombinedCase::init (void)
1599 {
1600 	// generate compute shader
1601 
1602 	m_computeProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genComputeSource(m_computeCmd, m_computeData, m_computeIndices)));
1603 	m_testCtx.getLog() << *m_computeProgram;
1604 
1605 	if (!m_computeProgram->isOk())
1606 		throw tcu::TestError("Failed to compile compute shader.");
1607 
1608 	// init parent
1609 	ComputeShaderGeneratedCase::init();
1610 }
1611 
deinit(void)1612 void ComputeShaderGeneratedCombinedCase::deinit (void)
1613 {
1614 	// deinit parent
1615 	ComputeShaderGeneratedCase::deinit();
1616 
1617 	if (m_computeProgram)
1618 	{
1619 		delete m_computeProgram;
1620 		m_computeProgram = DE_NULL;
1621 	}
1622 }
1623 
runComputeShader(void)1624 void ComputeShaderGeneratedCombinedCase::runComputeShader (void)
1625 {
1626 	const glw::Functions&	gl									= m_context.getRenderContext().getFunctions();
1627 	const bool				indexed								= (m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1628 	const tcu::IVec3		nullSize							(0, 0, 0);
1629 	const tcu::IVec3		commandDispatchSize					= (m_computeCmd)				? (tcu::IVec3(m_numDrawCmds, 1, 1))				: (nullSize);
1630 	const tcu::IVec3		drawElementsDataBufferDispatchSize	= (m_computeData)				? (tcu::IVec3(m_gridSize+1, m_gridSize+1, 1))	: (nullSize);
1631 	const tcu::IVec3		drawArraysDataBufferDispatchSize	= (m_computeData)				? (tcu::IVec3(m_gridSize,   m_gridSize,   1))	: (nullSize);
1632 	const tcu::IVec3		indexBufferDispatchSize				= (m_computeIndices && indexed)	? (tcu::IVec3(m_gridSize,   m_gridSize,   1))	: (nullSize);
1633 
1634 	const tcu::IVec3		dataBufferDispatchSize				= (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize);
1635 	const tcu::IVec3		dispatchSize						= tcu::max(tcu::max(commandDispatchSize, dataBufferDispatchSize), indexBufferDispatchSize);
1636 
1637 	gl.useProgram(m_computeProgram->getProgram());
1638 	glu::checkError(gl.getError(), "use compute shader", __FILE__, __LINE__);
1639 
1640 	// setup buffers
1641 
1642 	if (m_computeCmd)
1643 	{
1644 		const int			bindingPoint	= 0;
1645 		const int			bufferSize		= m_commandSize * m_numDrawCmds;
1646 
1647 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1648 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID);
1649 
1650 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1651 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1652 	}
1653 
1654 	if (m_computeData)
1655 	{
1656 		const int			bindingPoint	= (m_computeCmd) ? (1) : (0);
1657 		const int			bufferSize		= (int)(calcDrawBufferSize()*sizeof(tcu::Vec4));
1658 
1659 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1660 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID);
1661 
1662 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1663 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1664 	}
1665 
1666 	if (m_computeIndices)
1667 	{
1668 		const int			bindingPoint	= (m_computeCmd && m_computeData) ? (2) : (m_computeCmd || m_computeData) ? (1) : (0);
1669 		const int			bufferSize		= (int)(calcIndexBufferSize()*sizeof(deUint32));
1670 
1671 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1672 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID);
1673 
1674 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1675 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1676 	}
1677 
1678 	glu::checkError(gl.getError(), "setup buffers", __FILE__, __LINE__);
1679 
1680 	// calculate
1681 
1682 	m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching compute, size = " << dispatchSize << tcu::TestLog::EndMessage;
1683 	gl.dispatchCompute(dispatchSize.x(), dispatchSize.y(), dispatchSize.z());
1684 
1685 	glu::checkError(gl.getError(), "calculate", __FILE__, __LINE__);
1686 }
1687 
1688 class ComputeShaderGeneratedSeparateCase : public ComputeShaderGeneratedCase
1689 {
1690 public:
1691 						ComputeShaderGeneratedSeparateCase	(Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls);
1692 						~ComputeShaderGeneratedSeparateCase	(void);
1693 
1694 	void				init								(void);
1695 	void				deinit								(void);
1696 
1697 private:
1698 	std::string			genCmdComputeSource					(void);
1699 	std::string			genDataComputeSource				(void);
1700 	std::string			genIndexComputeSource				(void);
1701 	void				runComputeShader					(void);
1702 
1703 	glu::ShaderProgram*	m_computeCmdProgram;
1704 	glu::ShaderProgram*	m_computeDataProgram;
1705 	glu::ShaderProgram*	m_computeIndicesProgram;
1706 };
1707 
ComputeShaderGeneratedSeparateCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int numDrawCalls)1708 ComputeShaderGeneratedSeparateCase::ComputeShaderGeneratedSeparateCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls)
1709 	: ComputeShaderGeneratedCase	(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls)
1710 	, m_computeCmdProgram			(DE_NULL)
1711 	, m_computeDataProgram			(DE_NULL)
1712 	, m_computeIndicesProgram		(DE_NULL)
1713 {
1714 }
1715 
~ComputeShaderGeneratedSeparateCase(void)1716 ComputeShaderGeneratedSeparateCase::~ComputeShaderGeneratedSeparateCase (void)
1717 {
1718 	deinit();
1719 }
1720 
init(void)1721 void ComputeShaderGeneratedSeparateCase::init (void)
1722 {
1723 	// generate cmd compute shader
1724 
1725 	if (m_computeCmd)
1726 	{
1727 		m_computeCmdProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genCmdComputeSource()));
1728 		m_testCtx.getLog() << *m_computeCmdProgram;
1729 
1730 		if (!m_computeCmdProgram->isOk())
1731 			throw tcu::TestError("Failed to compile command compute shader.");
1732 	}
1733 
1734 	// generate data compute shader
1735 
1736 	if (m_computeData)
1737 	{
1738 		m_computeDataProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genDataComputeSource()));
1739 		m_testCtx.getLog() << *m_computeDataProgram;
1740 
1741 		if (!m_computeDataProgram->isOk())
1742 			throw tcu::TestError("Failed to compile data compute shader.");
1743 	}
1744 
1745 	// generate index compute shader
1746 
1747 	if (m_computeIndices)
1748 	{
1749 		m_computeIndicesProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genIndexComputeSource()));
1750 		m_testCtx.getLog() << *m_computeIndicesProgram;
1751 
1752 		if (!m_computeIndicesProgram->isOk())
1753 			throw tcu::TestError("Failed to compile data compute shader.");
1754 	}
1755 
1756 	// init parent
1757 	ComputeShaderGeneratedCase::init();
1758 }
1759 
deinit(void)1760 void ComputeShaderGeneratedSeparateCase::deinit (void)
1761 {
1762 	// deinit parent
1763 	ComputeShaderGeneratedCase::deinit();
1764 
1765 	if (m_computeCmdProgram)
1766 	{
1767 		delete m_computeCmdProgram;
1768 		m_computeCmdProgram = DE_NULL;
1769 	}
1770 	if (m_computeDataProgram)
1771 	{
1772 		delete m_computeDataProgram;
1773 		m_computeDataProgram = DE_NULL;
1774 	}
1775 	if (m_computeIndicesProgram)
1776 	{
1777 		delete m_computeIndicesProgram;
1778 		m_computeIndicesProgram = DE_NULL;
1779 	}
1780 }
1781 
genCmdComputeSource(void)1782 std::string ComputeShaderGeneratedSeparateCase::genCmdComputeSource (void)
1783 {
1784 	return ComputeShaderGeneratedCase::genComputeSource(true, false, false);
1785 }
1786 
genDataComputeSource(void)1787 std::string ComputeShaderGeneratedSeparateCase::genDataComputeSource (void)
1788 {
1789 	return ComputeShaderGeneratedCase::genComputeSource(false, true, false);
1790 }
1791 
genIndexComputeSource(void)1792 std::string ComputeShaderGeneratedSeparateCase::genIndexComputeSource (void)
1793 {
1794 	return ComputeShaderGeneratedCase::genComputeSource(false, false, true);
1795 }
1796 
runComputeShader(void)1797 void ComputeShaderGeneratedSeparateCase::runComputeShader (void)
1798 {
1799 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1800 
1801 	// Compute command
1802 
1803 	if (m_computeCmd)
1804 	{
1805 		const int				bindingPoint			= 0;
1806 		const tcu::IVec3		commandDispatchSize		(m_numDrawCmds, 1, 1);
1807 		const int				bufferSize				= m_commandSize * m_numDrawCmds;
1808 
1809 		gl.useProgram(m_computeCmdProgram->getProgram());
1810 
1811 		// setup buffers
1812 
1813 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1814 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID);
1815 
1816 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1817 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1818 
1819 		// calculate
1820 
1821 		m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching command compute, size = " << commandDispatchSize << tcu::TestLog::EndMessage;
1822 		gl.dispatchCompute(commandDispatchSize.x(), commandDispatchSize.y(), commandDispatchSize.z());
1823 
1824 		glu::checkError(gl.getError(), "calculate cmd", __FILE__, __LINE__);
1825 	}
1826 
1827 	// Compute data
1828 
1829 	if (m_computeData)
1830 	{
1831 		const int				bindingPoint						= 0;
1832 		const tcu::IVec3		drawElementsDataBufferDispatchSize	(m_gridSize+1, m_gridSize+1, 1);
1833 		const tcu::IVec3		drawArraysDataBufferDispatchSize	(m_gridSize,   m_gridSize,   1);
1834 		const tcu::IVec3		dataBufferDispatchSize				= (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize);
1835 		const int				bufferSize							= (int)(calcDrawBufferSize()*sizeof(tcu::Vec4));
1836 
1837 		gl.useProgram(m_computeDataProgram->getProgram());
1838 
1839 		// setup buffers
1840 
1841 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1842 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID);
1843 
1844 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1845 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1846 
1847 		// calculate
1848 
1849 		m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching data compute, size = " << dataBufferDispatchSize << tcu::TestLog::EndMessage;
1850 		gl.dispatchCompute(dataBufferDispatchSize.x(), dataBufferDispatchSize.y(), dataBufferDispatchSize.z());
1851 
1852 		glu::checkError(gl.getError(), "calculate data", __FILE__, __LINE__);
1853 	}
1854 
1855 	// Compute indices
1856 
1857 	if (m_computeIndices)
1858 	{
1859 		const int				bindingPoint				= 0;
1860 		const tcu::IVec3		indexBufferDispatchSize		(m_gridSize, m_gridSize, 1);
1861 		const int				bufferSize					= (int)(calcIndexBufferSize()*sizeof(deUint32));
1862 
1863 		DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1864 
1865 		gl.useProgram(m_computeIndicesProgram->getProgram());
1866 
1867 		// setup buffers
1868 
1869 		m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage;
1870 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID);
1871 
1872 		m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1873 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1874 
1875 		// calculate
1876 
1877 		m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching index compute, size = " << indexBufferDispatchSize << tcu::TestLog::EndMessage;
1878 		gl.dispatchCompute(indexBufferDispatchSize.x(), indexBufferDispatchSize.y(), indexBufferDispatchSize.z());
1879 
1880 		glu::checkError(gl.getError(), "calculate indices", __FILE__, __LINE__);
1881 	}
1882 
1883 	glu::checkError(gl.getError(), "post dispatch", __FILE__, __LINE__);
1884 }
1885 
1886 class ComputeShaderGeneratedGroup : public TestCaseGroup
1887 {
1888 public:
1889 			ComputeShaderGeneratedGroup		(Context& context, const char* name, const char* descr);
1890 			~ComputeShaderGeneratedGroup	(void);
1891 
1892 	void	init							(void);
1893 };
1894 
ComputeShaderGeneratedGroup(Context & context,const char * name,const char * descr)1895 ComputeShaderGeneratedGroup::ComputeShaderGeneratedGroup (Context& context, const char* name, const char* descr)
1896 	: TestCaseGroup	(context, name, descr)
1897 {
1898 }
1899 
~ComputeShaderGeneratedGroup(void)1900 ComputeShaderGeneratedGroup::~ComputeShaderGeneratedGroup (void)
1901 {
1902 }
1903 
init(void)1904 void ComputeShaderGeneratedGroup::init (void)
1905 {
1906 	const int					gridSize		= 8;
1907 	tcu::TestCaseGroup* const	separateGroup	= new tcu::TestCaseGroup(m_testCtx, "separate", "Use separate compute shaders for each buffer");
1908 	tcu::TestCaseGroup* const	combinedGroup	= new tcu::TestCaseGroup(m_testCtx, "combined", "Use combined compute shader for all buffers");
1909 	tcu::TestCaseGroup* const	largeGroup		= new tcu::TestCaseGroup(m_testCtx, "large",   "Draw shapes with large buffers");
1910 
1911 	this->addChild(separateGroup);
1912 	this->addChild(combinedGroup);
1913 	this->addChild(largeGroup);
1914 
1915 	// .separate
1916 	{
1917 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd",							"Command from compute shader",						ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,		true,	false,	false,	gridSize,	1));
1918 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_data",						"Data from compute shader",							ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,		false,	true,	false,	gridSize,	1));
1919 		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));
1920 
1921 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd",						"Command from compute shader",						ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true,	false,	false,	gridSize,	1));
1922 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data",						"Data from compute shader",							ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false,	true,	false,	gridSize,	1));
1923 		separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_indices",					"Indices from compute shader",						ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false,	false,	true,	gridSize,	1));
1924 		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));
1925 		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));
1926 		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));
1927 		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));
1928 	}
1929 
1930 	// .combined
1931 	{
1932 		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));
1933 		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));
1934 		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));
1935 		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));
1936 		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));
1937 	}
1938 
1939 	// .large
1940 	{
1941 		struct TestSpec
1942 		{
1943 			int gridSize;
1944 			int numDrawCommands;
1945 		};
1946 		struct TestMethod
1947 		{
1948 			ComputeShaderGeneratedCase::DrawMethod method;
1949 			bool                                   separateCompute;
1950 		};
1951 
1952 		static const TestSpec specs[] =
1953 		{
1954 			{ 100,	1 },		// !< drawArrays array size ~ 1.9 MB
1955 			{ 200,	1 },		// !< drawArrays array size ~ 7.7 MB
1956 			{ 500,	1 },		// !< drawArrays array size ~ 48 MB
1957 			{ 1000,	1 },		// !< drawArrays array size ~ 192 MB
1958 			{ 1200,	1 },		// !< drawArrays array size ~ 277 MB
1959 			{ 1500,	1 },		// !< drawArrays array size ~ 430 MB
1960 
1961 			{ 100,	8 },		// !< drawArrays array size ~ 1.9 MB
1962 			{ 200,	8 },		// !< drawArrays array size ~ 7.7 MB
1963 			{ 500,	8 },		// !< drawArrays array size ~ 48 MB
1964 			{ 1000,	8 },		// !< drawArrays array size ~ 192 MB
1965 			{ 1200,	8 },		// !< drawArrays array size ~ 277 MB
1966 			{ 1500,	8 },		// !< drawArrays array size ~ 430 MB
1967 
1968 			{ 100,	200  },		// !< 50 cells per draw call
1969 			{ 200,	800  },		// !< 50 cells per draw call
1970 			{ 500,	2500 },		// !< 100 cells per draw call
1971 			{ 1000,	5000 },		// !< 250 cells per draw call
1972 		};
1973 		static const TestMethod methods[] =
1974 		{
1975 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,	true	},
1976 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS,	false	},
1977 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	true	},
1978 			{ ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS,	false	},
1979 		};
1980 
1981 		for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(methods); ++methodNdx)
1982 		for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); ++specNdx)
1983 		{
1984 			const std::string name = std::string("")
1985 									+ ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays") : ("drawelements"))
1986 									+ ((methods[methodNdx].separateCompute) ? ("_separate") : ("_combined"))
1987 									+ "_grid_" + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize)
1988 									+ "_drawcount_" + de::toString(specs[specNdx].numDrawCommands);
1989 
1990 			const std::string desc = std::string("Draw grid with ")
1991 									+ ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays indirect") : ("drawelements indirect"))
1992 									+ " calculating buffers in " + ((methods[methodNdx].separateCompute) ? ("separate") : ("combined")) + " compute shader."
1993 									+ " Grid size is " + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize)
1994 									+ ", draw count is "  + de::toString(specs[specNdx].numDrawCommands);
1995 
1996 			const bool computeIndices = (methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS);
1997 
1998 			if (methods[methodNdx].separateCompute)
1999 				largeGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands));
2000 			else
2001 				largeGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands));
2002 		}
2003 	}
2004 }
2005 
2006 class RandomGroup : public TestCaseGroup
2007 {
2008 public:
2009 			RandomGroup		(Context& context, const char* name, const char* descr);
2010 			~RandomGroup	(void);
2011 
2012 	void	init			(void);
2013 };
2014 
2015 template <int SIZE>
2016 struct UniformWeightArray
2017 {
2018 	float weights[SIZE];
2019 
UniformWeightArraydeqp::gles31::Functional::__anon1bb0bc430111::UniformWeightArray2020 	UniformWeightArray (void)
2021 	{
2022 		for (int i=0; i<SIZE; ++i)
2023 			weights[i] = 1.0f;
2024 	}
2025 };
2026 
RandomGroup(Context & context,const char * name,const char * descr)2027 RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
2028 	: TestCaseGroup	(context, name, descr)
2029 {
2030 }
2031 
~RandomGroup(void)2032 RandomGroup::~RandomGroup (void)
2033 {
2034 }
2035 
init(void)2036 void RandomGroup::init (void)
2037 {
2038 	const int	numAttempts				= 100;
2039 
2040 	const int	attribCounts[]			= { 1,   2,   5 };
2041 	const float	attribWeights[]			= { 30, 10,   1 };
2042 	const int	primitiveCounts[]		= { 1,   5,  64 };
2043 	const float	primitiveCountWeights[]	= { 20, 10,   1 };
2044 	const int	indexOffsets[]			= { 0,   7,  13 };
2045 	const float	indexOffsetWeights[]	= { 20, 20,   1 };
2046 	const int	firsts[]				= { 0,   7,  13 };
2047 	const float	firstWeights[]			= { 20, 20,   1 };
2048 
2049 	const int	instanceCounts[]		= { 1,   2,  16,  17 };
2050 	const float	instanceWeights[]		= { 20, 10,   5,   1 };
2051 	const int	indexMins[]				= { 0,   1,   3,   8 };
2052 	const int	indexMaxs[]				= { 4,   8, 128, 257 };
2053 	const float	indexWeights[]			= { 50, 50,  50,  50 };
2054 	const int	offsets[]				= { 0,   1,   5,  12 };
2055 	const float	offsetWeights[]			= { 50, 10,  10,  10 };
2056 	const int	strides[]				= { 0,   7,  16,  17 };
2057 	const float	strideWeights[]			= { 50, 10,  10,  10 };
2058 	const int	instanceDivisors[]		= { 0,   1,   3, 129 };
2059 	const float	instanceDivisorWeights[]= { 70, 30,  10,  10 };
2060 
2061 	const int	indirectOffsets[]		= { 0,   1,   2 };
2062 	const float indirectOffsetWeigths[]	= { 2,   1,   1 };
2063 	const int	baseVertices[]			= { 0,   1,  -2,   4,  3 };
2064 	const float baseVertexWeigths[]		= { 4,   1,   1,   1,  1 };
2065 
2066 	gls::DrawTestSpec::Primitive primitives[] =
2067 	{
2068 		gls::DrawTestSpec::PRIMITIVE_POINTS,
2069 		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
2070 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
2071 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
2072 		gls::DrawTestSpec::PRIMITIVE_LINES,
2073 		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
2074 		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
2075 	};
2076 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
2077 
2078 	gls::DrawTestSpec::DrawMethod drawMethods[] =
2079 	{
2080 		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
2081 		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
2082 	};
2083 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
2084 
2085 	gls::DrawTestSpec::IndexType indexTypes[] =
2086 	{
2087 		gls::DrawTestSpec::INDEXTYPE_BYTE,
2088 		gls::DrawTestSpec::INDEXTYPE_SHORT,
2089 		gls::DrawTestSpec::INDEXTYPE_INT,
2090 	};
2091 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
2092 
2093 	gls::DrawTestSpec::InputType inputTypes[] =
2094 	{
2095 		gls::DrawTestSpec::INPUTTYPE_FLOAT,
2096 		gls::DrawTestSpec::INPUTTYPE_FIXED,
2097 		gls::DrawTestSpec::INPUTTYPE_BYTE,
2098 		gls::DrawTestSpec::INPUTTYPE_SHORT,
2099 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
2100 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
2101 		gls::DrawTestSpec::INPUTTYPE_INT,
2102 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
2103 		gls::DrawTestSpec::INPUTTYPE_HALF,
2104 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2105 		gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
2106 	};
2107 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
2108 
2109 	gls::DrawTestSpec::OutputType outputTypes[] =
2110 	{
2111 		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
2112 		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
2113 		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
2114 		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
2115 		gls::DrawTestSpec::OUTPUTTYPE_INT,
2116 		gls::DrawTestSpec::OUTPUTTYPE_UINT,
2117 		gls::DrawTestSpec::OUTPUTTYPE_IVEC2,
2118 		gls::DrawTestSpec::OUTPUTTYPE_IVEC3,
2119 		gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
2120 		gls::DrawTestSpec::OUTPUTTYPE_UVEC2,
2121 		gls::DrawTestSpec::OUTPUTTYPE_UVEC3,
2122 		gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
2123 	};
2124 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
2125 
2126 	gls::DrawTestSpec::Usage usages[] =
2127 	{
2128 		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
2129 		gls::DrawTestSpec::USAGE_STATIC_DRAW,
2130 		gls::DrawTestSpec::USAGE_STREAM_DRAW,
2131 		gls::DrawTestSpec::USAGE_STREAM_READ,
2132 		gls::DrawTestSpec::USAGE_STREAM_COPY,
2133 		gls::DrawTestSpec::USAGE_STATIC_READ,
2134 		gls::DrawTestSpec::USAGE_STATIC_COPY,
2135 		gls::DrawTestSpec::USAGE_DYNAMIC_READ,
2136 		gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
2137 	};
2138 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
2139 
2140 	std::set<deUint32>	insertedHashes;
2141 	size_t				insertedCount = 0;
2142 
2143 	for (int ndx = 0; ndx < numAttempts; ++ndx)
2144 	{
2145 		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
2146 
2147 		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
2148 		int					drawCommandSize;
2149 		gls::DrawTestSpec	spec;
2150 
2151 		spec.apiType				= glu::ApiType::es(3,1);
2152 		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
2153 		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
2154 		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
2155 
2156 		if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
2157 			drawCommandSize = sizeof(deUint32[4]);
2158 		else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2159 			drawCommandSize = sizeof(deUint32[5]);
2160 		else
2161 		{
2162 			DE_ASSERT(DE_FALSE);
2163 			return;
2164 		}
2165 
2166 		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
2167 		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
2168 		spec.indexStorage			= gls::DrawTestSpec::STORAGE_BUFFER;
2169 		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
2170 		spec.indexMin				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMins),			DE_ARRAY_END(indexMins),		indexWeights);
2171 		spec.indexMax				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMaxs),			DE_ARRAY_END(indexMaxs),		indexWeights);
2172 		spec.instanceCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(instanceCounts),	DE_ARRAY_END(instanceCounts),	instanceWeights);
2173 		spec.indirectOffset			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indirectOffsets),	DE_ARRAY_END(indirectOffsets),	indirectOffsetWeigths) * drawCommandSize;
2174 		spec.baseVertex				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(baseVertices),		DE_ARRAY_END(baseVertices),		baseVertexWeigths);
2175 
2176 		// check spec is legal
2177 		if (!spec.valid())
2178 			continue;
2179 
2180 		for (int attrNdx = 0; attrNdx < attributeCount;)
2181 		{
2182 			bool valid;
2183 			gls::DrawTestSpec::AttributeSpec attribSpec;
2184 
2185 			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
2186 			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
2187 			attribSpec.storage				= gls::DrawTestSpec::STORAGE_BUFFER;
2188 			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
2189 			attribSpec.componentCount		= random.getInt(1, 4);
2190 			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
2191 			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
2192 			attribSpec.normalize			= random.getBool();
2193 			attribSpec.instanceDivisor		= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
2194 			attribSpec.useDefaultAttribute	= random.getBool();
2195 
2196 			// check spec is legal
2197 			valid = attribSpec.valid(spec.apiType);
2198 
2199 			// we do not want interleaved elements. (Might result in some weird floating point values)
2200 			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
2201 				valid = false;
2202 
2203 			// try again if not valid
2204 			if (valid)
2205 			{
2206 				spec.attribs.push_back(attribSpec);
2207 				++attrNdx;
2208 			}
2209 		}
2210 
2211 		// Do not collapse all vertex positions to a single positions
2212 		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2213 			spec.attribs[0].instanceDivisor = 0;
2214 
2215 		// Is render result meaningful?
2216 		{
2217 			// Only one vertex
2218 			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2219 				continue;
2220 			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2221 				continue;
2222 
2223 			// Triangle only on one axis
2224 			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
2225 			{
2226 				if (spec.attribs[0].componentCount == 1)
2227 					continue;
2228 				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)
2229 					continue;
2230 				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
2231 					continue;
2232 			}
2233 		}
2234 
2235 		// Add case
2236 		{
2237 			deUint32 hash = spec.hash();
2238 			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
2239 				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
2240 
2241 			if (insertedHashes.find(hash) == insertedHashes.end())
2242 			{
2243 				// Only aligned cases
2244 				if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET &&
2245 					spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
2246 					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
2247 				insertedHashes.insert(hash);
2248 
2249 				++insertedCount;
2250 			}
2251 		}
2252 	}
2253 }
2254 
2255 class BadCommandBufferCase : public TestCase
2256 {
2257 public:
2258 	enum
2259 	{
2260 		CommandSize = 20
2261 	};
2262 
2263 					BadCommandBufferCase	(Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 m_expectedError);
2264 					~BadCommandBufferCase	(void);
2265 
2266 	IterateResult	iterate					(void);
2267 
2268 private:
2269 	const deUint32	m_alignment;
2270 	const deUint32	m_bufferSize;
2271 	const bool		m_writeCommandToBuffer;
2272 	const deUint32	m_expectedError;
2273 };
2274 
BadCommandBufferCase(Context & context,const char * name,const char * desc,deUint32 alignment,deUint32 bufferSize,bool writeCommandToBuffer,deUint32 expectedError)2275 BadCommandBufferCase::BadCommandBufferCase (Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 expectedError)
2276 	: TestCase					(context, name, desc)
2277 	, m_alignment				(alignment)
2278 	, m_bufferSize				(bufferSize)
2279 	, m_writeCommandToBuffer	(writeCommandToBuffer)
2280 	, m_expectedError			(expectedError)
2281 {
2282 }
2283 
~BadCommandBufferCase(void)2284 BadCommandBufferCase::~BadCommandBufferCase (void)
2285 {
2286 }
2287 
iterate(void)2288 BadCommandBufferCase::IterateResult	BadCommandBufferCase::iterate (void)
2289 {
2290 	const tcu::Vec4 vertexPositions[] =
2291 	{
2292 		tcu::Vec4(0,	0,		0, 1),
2293 		tcu::Vec4(1,	0,		0, 1),
2294 		tcu::Vec4(0,	1,		0, 1),
2295 	};
2296 
2297 	const deUint16 indices[] =
2298 	{
2299 		0, 2, 1,
2300 	};
2301 
2302 	DE_STATIC_ASSERT(CommandSize == sizeof(DrawElementsCommand));
2303 
2304 	sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
2305 
2306 	deUint32 vaoID			= 0;
2307 	deUint32 positionBuf	= 0;
2308 	deUint32 indexBuf		= 0;
2309 	deUint32 drawIndirectBuf= 0;
2310 	deUint32 error;
2311 
2312 	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
2313 	deUint32			programID		= program.getProgram();
2314 	deInt32				posLocation		= gl.getAttribLocation(programID, "a_position");
2315 
2316 	DrawElementsCommand drawCommand;
2317 	drawCommand.count				= 3;
2318 	drawCommand.primCount			= 1;
2319 	drawCommand.firstIndex			= 0;
2320 	drawCommand.baseVertex			= 0;
2321 	drawCommand.reservedMustBeZero	= 0;
2322 
2323 	std::vector<deInt8> drawCommandBuffer;
2324 	drawCommandBuffer.resize(m_bufferSize);
2325 
2326 	deMemset(&drawCommandBuffer[0], 0, (int)drawCommandBuffer.size());
2327 
2328 	if (m_writeCommandToBuffer)
2329 	{
2330 		DE_ASSERT(drawCommandBuffer.size() >= sizeof(drawCommand) + m_alignment);
2331 		deMemcpy(&drawCommandBuffer[m_alignment], &drawCommand, sizeof(drawCommand));
2332 	}
2333 
2334 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2335 	gl.genVertexArrays(1, &vaoID);
2336 	gl.bindVertexArray(vaoID);
2337 
2338 	gl.genBuffers(1, &positionBuf);
2339 	gl.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
2340 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2341 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2342 	gl.vertexAttribDivisor(posLocation, 0);
2343 	gl.enableVertexAttribArray(posLocation);
2344 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2345 
2346 	gl.genBuffers(1, &indexBuf);
2347 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
2348 	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2349 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2350 
2351 	gl.genBuffers(1, &drawIndirectBuf);
2352 	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf);
2353 	gl.bufferData(GL_DRAW_INDIRECT_BUFFER, drawCommandBuffer.size(), &drawCommandBuffer[0], GL_STATIC_DRAW);
2354 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2355 
2356 	gl.viewport(0, 0, 1, 1);
2357 
2358 	gl.useProgram(programID);
2359 	gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(deUintptr)m_alignment);
2360 
2361 	error = gl.getError();
2362 
2363 	gl.useProgram(0);
2364 
2365 	gl.deleteBuffers(1, &drawIndirectBuf);
2366 	gl.deleteBuffers(1, &indexBuf);
2367 	gl.deleteBuffers(1, &positionBuf);
2368 	gl.deleteVertexArrays(1, &vaoID);
2369 
2370 	m_testCtx.getLog() << tcu::TestLog::Message << "drawElementsIndirect generated " << glu::getErrorStr(error) << ", expecting " << glu::getErrorStr(m_expectedError) << "." << tcu::TestLog::EndMessage;
2371 
2372 	if (error == m_expectedError)
2373 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2374 	else
2375 	{
2376 		m_testCtx.getLog() << tcu::TestLog::Message << "\tUnexpected error." << tcu::TestLog::EndMessage;
2377 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2378 	}
2379 
2380 	return STOP;
2381 }
2382 
2383 class BadAlignmentCase : public BadCommandBufferCase
2384 {
2385 public:
2386 					BadAlignmentCase	(Context& context, const char* name, const char* desc, deUint32 alignment);
2387 					~BadAlignmentCase	(void);
2388 };
2389 
BadAlignmentCase(Context & context,const char * name,const char * desc,deUint32 alignment)2390 BadAlignmentCase::BadAlignmentCase (Context& context, const char* name, const char* desc, deUint32 alignment)
2391 	: BadCommandBufferCase(context, name, desc, alignment, CommandSize+alignment, true, GL_INVALID_VALUE)
2392 {
2393 }
2394 
~BadAlignmentCase(void)2395 BadAlignmentCase::~BadAlignmentCase (void)
2396 {
2397 }
2398 
2399 class BadBufferRangeCase : public BadCommandBufferCase
2400 {
2401 public:
2402 					BadBufferRangeCase	(Context& context, const char* name, const char* desc, deUint32 offset);
2403 					~BadBufferRangeCase	(void);
2404 };
2405 
BadBufferRangeCase(Context & context,const char * name,const char * desc,deUint32 offset)2406 BadBufferRangeCase::BadBufferRangeCase (Context& context, const char* name, const char* desc, deUint32 offset)
2407 	: BadCommandBufferCase(context, name, desc, offset, CommandSize, false, GL_INVALID_OPERATION)
2408 {
2409 }
2410 
~BadBufferRangeCase(void)2411 BadBufferRangeCase::~BadBufferRangeCase (void)
2412 {
2413 }
2414 
2415 class BadStateCase : public TestCase
2416 {
2417 public:
2418 	enum CaseType
2419 	{
2420 		CASE_CLIENT_BUFFER_VERTEXATTR = 0,
2421 		CASE_CLIENT_BUFFER_COMMAND,
2422 		CASE_DEFAULT_VAO,
2423 
2424 		CASE_CLIENT_LAST
2425 	};
2426 
2427 						BadStateCase	(Context& context, const char* name, const char* desc, CaseType type);
2428 						~BadStateCase	(void);
2429 
2430 	void				init			(void);
2431 	void				deinit			(void);
2432 	IterateResult		iterate			(void);
2433 
2434 private:
2435 	const CaseType		m_caseType;
2436 };
2437 
BadStateCase(Context & context,const char * name,const char * desc,CaseType type)2438 BadStateCase::BadStateCase (Context& context, const char* name, const char* desc, CaseType type)
2439 	: TestCase			(context, name, desc)
2440 	, m_caseType		(type)
2441 {
2442 	DE_ASSERT(type < CASE_CLIENT_LAST);
2443 }
2444 
~BadStateCase(void)2445 BadStateCase::~BadStateCase (void)
2446 {
2447 	deinit();
2448 }
2449 
init(void)2450 void BadStateCase::init (void)
2451 {
2452 }
2453 
deinit(void)2454 void BadStateCase::deinit (void)
2455 {
2456 }
2457 
iterate(void)2458 BadStateCase::IterateResult BadStateCase::iterate (void)
2459 {
2460 	const tcu::Vec4 vertexPositions[] =
2461 	{
2462 		tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
2463 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2464 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2465 	};
2466 
2467 	const deUint16 indices[] =
2468 	{
2469 		0, 2, 1,
2470 	};
2471 
2472 	sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
2473 
2474 	deUint32			error;
2475 	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
2476 	deUint32			vaoID			= 0;
2477 	deUint32			dataBufferID	= 0;
2478 	deUint32			indexBufferID	= 0;
2479 	deUint32			cmdBufferID		= 0;
2480 
2481 	const deUint32		programID		= program.getProgram();
2482 	const deInt32		posLocation		= gl.getAttribLocation(programID, "a_position");
2483 
2484 	DrawElementsCommand drawCommand;
2485 	drawCommand.count				= 3;
2486 	drawCommand.primCount			= 1;
2487 	drawCommand.firstIndex			= 0;
2488 	drawCommand.baseVertex			= 0;
2489 	drawCommand.reservedMustBeZero	= 0;
2490 
2491 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2492 
2493 	if (m_caseType == CASE_CLIENT_BUFFER_VERTEXATTR)
2494 	{
2495 		// \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
2496 
2497 		gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, vertexPositions);
2498 		gl.enableVertexAttribArray(posLocation);
2499 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2500 	}
2501 	else if (m_caseType == CASE_CLIENT_BUFFER_COMMAND)
2502 	{
2503 		gl.genVertexArrays(1, &vaoID);
2504 		gl.bindVertexArray(vaoID);
2505 
2506 		gl.genBuffers(1, &dataBufferID);
2507 		gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2508 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2509 		gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2510 		gl.enableVertexAttribArray(posLocation);
2511 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2512 	}
2513 	else if (m_caseType == CASE_DEFAULT_VAO)
2514 	{
2515 		gl.genBuffers(1, &dataBufferID);
2516 		gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2517 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2518 		gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2519 		gl.enableVertexAttribArray(posLocation);
2520 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2521 	}
2522 	else
2523 		DE_ASSERT(DE_FALSE);
2524 
2525 	gl.genBuffers(1, &indexBufferID);
2526 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
2527 	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2528 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2529 
2530 	if (m_caseType != CASE_CLIENT_BUFFER_COMMAND)
2531 	{
2532 		gl.genBuffers(1, &cmdBufferID);
2533 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID);
2534 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2535 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2536 	}
2537 
2538 	gl.viewport(0, 0, 1, 1);
2539 
2540 	gl.useProgram(programID);
2541 	gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (m_caseType != CASE_CLIENT_BUFFER_COMMAND) ? (DE_NULL) : (&drawCommand));
2542 
2543 	error = gl.getError();
2544 
2545 	gl.bindVertexArray(0);
2546 	gl.useProgram(0);
2547 
2548 	if (error == GL_INVALID_OPERATION)
2549 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2550 	else
2551 	{
2552 		m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
2553 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2554 	}
2555 
2556 	return STOP;
2557 }
2558 
2559 class BadDrawModeCase : public TestCase
2560 {
2561 public:
2562 	enum DrawType
2563 	{
2564 		DRAW_ARRAYS = 0,
2565 		DRAW_ELEMENTS,
2566 		DRAW_ELEMENTS_BAD_INDEX,
2567 
2568 		DRAW_LAST
2569 	};
2570 
2571 						BadDrawModeCase	(Context& context, const char* name, const char* desc, DrawType type);
2572 						~BadDrawModeCase(void);
2573 
2574 	void				init			(void);
2575 	void				deinit			(void);
2576 	IterateResult		iterate			(void);
2577 
2578 private:
2579 	const DrawType		m_drawType;
2580 };
2581 
BadDrawModeCase(Context & context,const char * name,const char * desc,DrawType type)2582 BadDrawModeCase::BadDrawModeCase (Context& context, const char* name, const char* desc, DrawType type)
2583 	: TestCase			(context, name, desc)
2584 	, m_drawType		(type)
2585 {
2586 	DE_ASSERT(type < DRAW_LAST);
2587 }
2588 
~BadDrawModeCase(void)2589 BadDrawModeCase::~BadDrawModeCase (void)
2590 {
2591 	deinit();
2592 }
2593 
init(void)2594 void BadDrawModeCase::init (void)
2595 {
2596 }
2597 
deinit(void)2598 void BadDrawModeCase::deinit (void)
2599 {
2600 }
2601 
iterate(void)2602 BadDrawModeCase::IterateResult BadDrawModeCase::iterate (void)
2603 {
2604 	const tcu::Vec4 vertexPositions[] =
2605 	{
2606 		tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
2607 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2608 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2609 	};
2610 
2611 	const deUint16 indices[] =
2612 	{
2613 		0, 2, 1,
2614 	};
2615 
2616 	sglr::GLContext		gl				(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
2617 
2618 	deUint32			error;
2619 	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
2620 	deUint32			vaoID			= 0;
2621 	deUint32			dataBufferID	= 0;
2622 	deUint32			indexBufferID	= 0;
2623 	deUint32			cmdBufferID		= 0;
2624 
2625 	const deUint32		programID		= program.getProgram();
2626 	const deInt32		posLocation		= gl.getAttribLocation(programID, "a_position");
2627 	const glw::GLenum	mode			= (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (GL_TRIANGLES) : (0x123);
2628 	const glw::GLenum	indexType		= (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (0x123) : (GL_UNSIGNED_SHORT);
2629 
2630 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2631 
2632 	// vao
2633 
2634 	gl.genVertexArrays(1, &vaoID);
2635 	gl.bindVertexArray(vaoID);
2636 
2637 	// va
2638 
2639 	gl.genBuffers(1, &dataBufferID);
2640 	gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2641 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2642 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2643 	gl.enableVertexAttribArray(posLocation);
2644 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2645 
2646 	// index
2647 
2648 	if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2649 	{
2650 		gl.genBuffers(1, &indexBufferID);
2651 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
2652 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2653 		glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2654 	}
2655 
2656 	// cmd
2657 
2658 	gl.genBuffers(1, &cmdBufferID);
2659 	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID);
2660 	if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2661 	{
2662 		DrawElementsCommand drawCommand;
2663 		drawCommand.count				= 3;
2664 		drawCommand.primCount			= 1;
2665 		drawCommand.firstIndex			= 0;
2666 		drawCommand.baseVertex			= 0;
2667 		drawCommand.reservedMustBeZero	= 0;
2668 
2669 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2670 	}
2671 	else if (m_drawType == DRAW_ARRAYS)
2672 	{
2673 		DrawArraysCommand drawCommand;
2674 		drawCommand.count				= 3;
2675 		drawCommand.primCount			= 1;
2676 		drawCommand.first				= 0;
2677 		drawCommand.reservedMustBeZero	= 0;
2678 
2679 		gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2680 	}
2681 	else
2682 		DE_ASSERT(DE_FALSE);
2683 	glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2684 
2685 	gl.viewport(0, 0, 1, 1);
2686 	gl.useProgram(programID);
2687 	if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2688 		gl.drawElementsIndirect(mode, indexType, DE_NULL);
2689 	else if (m_drawType == DRAW_ARRAYS)
2690 		gl.drawArraysIndirect(mode, DE_NULL);
2691 	else
2692 		DE_ASSERT(DE_FALSE);
2693 
2694 	error = gl.getError();
2695 	gl.useProgram(0);
2696 
2697 	if (error == GL_INVALID_ENUM)
2698 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2699 	else
2700 	{
2701 		m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_ENUM, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
2702 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2703 	}
2704 
2705 	return STOP;
2706 }
2707 
2708 class NegativeGroup : public TestCaseGroup
2709 {
2710 public:
2711 			NegativeGroup	(Context& context, const char* name, const char* descr);
2712 			~NegativeGroup	(void);
2713 
2714 	void	init			(void);
2715 };
2716 
NegativeGroup(Context & context,const char * name,const char * descr)2717 NegativeGroup::NegativeGroup (Context& context, const char* name, const char* descr)
2718 	: TestCaseGroup	(context, name, descr)
2719 {
2720 }
2721 
~NegativeGroup(void)2722 NegativeGroup::~NegativeGroup (void)
2723 {
2724 }
2725 
init(void)2726 void NegativeGroup::init (void)
2727 {
2728 	// invalid alignment
2729 	addChild(new BadAlignmentCase	(m_context, "command_bad_alignment_1",								"Bad command alignment",					1));
2730 	addChild(new BadAlignmentCase	(m_context, "command_bad_alignment_2",								"Bad command alignment",					2));
2731 	addChild(new BadAlignmentCase	(m_context, "command_bad_alignment_3",								"Bad command alignment",					3));
2732 
2733 	// command only partially or not at all in the buffer
2734 	addChild(new BadBufferRangeCase	(m_context, "command_offset_partially_in_buffer",					"Command not fully in the buffer range",	BadBufferRangeCase::CommandSize - 16));
2735 	addChild(new BadBufferRangeCase	(m_context, "command_offset_not_in_buffer",							"Command not in the buffer range",			BadBufferRangeCase::CommandSize));
2736 	addChild(new BadBufferRangeCase	(m_context, "command_offset_not_in_buffer_unsigned32_wrap",			"Command not in the buffer range",			0xFFFFFFFC));
2737 	addChild(new BadBufferRangeCase	(m_context, "command_offset_not_in_buffer_signed32_wrap",			"Command not in the buffer range",			0x7FFFFFFC));
2738 
2739 	// use with client data and default vao
2740 	addChild(new BadStateCase		(m_context, "client_vertex_attrib_array",							"Vertex attrib array in the client memory",	BadStateCase::CASE_CLIENT_BUFFER_VERTEXATTR));
2741 	addChild(new BadStateCase		(m_context, "client_command_array",									"Command array in the client memory",		BadStateCase::CASE_CLIENT_BUFFER_COMMAND));
2742 	addChild(new BadStateCase		(m_context, "default_vao",											"Use with default vao",						BadStateCase::CASE_DEFAULT_VAO));
2743 
2744 	// invalid mode & type
2745 	addChild(new BadDrawModeCase	(m_context, "invalid_mode_draw_arrays",								"Call DrawArraysIndirect with bad mode",	BadDrawModeCase::DRAW_ARRAYS));
2746 	addChild(new BadDrawModeCase	(m_context, "invalid_mode_draw_elements",							"Call DrawelementsIndirect with bad mode",	BadDrawModeCase::DRAW_ELEMENTS));
2747 	addChild(new BadDrawModeCase	(m_context, "invalid_type_draw_elements",							"Call DrawelementsIndirect with bad type",	BadDrawModeCase::DRAW_ELEMENTS_BAD_INDEX));
2748 }
2749 
2750 } // anonymous
2751 
DrawTests(Context & context)2752 DrawTests::DrawTests (Context& context)
2753 	: TestCaseGroup(context, "draw_indirect", "Indirect drawing tests")
2754 {
2755 }
2756 
~DrawTests(void)2757 DrawTests::~DrawTests (void)
2758 {
2759 }
2760 
init(void)2761 void DrawTests::init (void)
2762 {
2763 	// Basic
2764 	{
2765 		const gls::DrawTestSpec::DrawMethod basicMethods[] =
2766 		{
2767 			gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
2768 			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
2769 		};
2770 
2771 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
2772 		{
2773 			const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
2774 			const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
2775 
2776 			this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
2777 		}
2778 	}
2779 
2780 	// extreme instancing
2781 
2782 	this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count."));
2783 
2784 	// compute shader generated commands
2785 
2786 	this->addChild(new ComputeShaderGeneratedGroup(m_context, "compute_interop", "draw tests with a draw command generated in compute shader."));
2787 
2788 	// Random
2789 
2790 	this->addChild(new RandomGroup(m_context, "random", "random draw commands."));
2791 
2792 	// negative
2793 
2794 	this->addChild(new NegativeGroup(m_context, "negative", "invalid draw commands with defined error codes."));
2795 }
2796 
2797 } // Functional
2798 } // gles31
2799 } // deqp
2800