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