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