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