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