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