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 Vertex attribute binding tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fVertexAttributeBindingTests.hpp"
     25 #include "tcuRenderTarget.hpp"
     26 #include "tcuSurface.hpp"
     27 #include "gluCallLogWrapper.hpp"
     28 #include "gluRenderContext.hpp"
     29 #include "gluPixelTransfer.hpp"
     30 #include "gluShaderProgram.hpp"
     31 #include "gluObjectWrapper.hpp"
     32 #include "gluStrUtil.hpp"
     33 #include "glwFunctions.hpp"
     34 #include "glwEnums.hpp"
     35 #include "deStringUtil.hpp"
     36 #include "deInt32.h"
     37 
     38 namespace deqp
     39 {
     40 namespace gles31
     41 {
     42 namespace Functional
     43 {
     44 namespace
     45 {
     46 
     47 static const char* const s_colorFragmentShader =		"#version 310 es\n"
     48 														"in mediump vec4 v_color;\n"
     49 														"layout(location = 0) out mediump vec4 fragColor;\n"
     50 														"void main (void)\n"
     51 														"{\n"
     52 														"	fragColor = v_color;\n"
     53 														"}\n";
     54 
     55 static const char* const s_positionColorShader =		"#version 310 es\n"
     56 														"in highp vec4 a_position;\n"
     57 														"in highp vec4 a_color;\n"
     58 														"out highp vec4 v_color;\n"
     59 														"void main (void)\n"
     60 														"{\n"
     61 														"	gl_Position = a_position;\n"
     62 														"	v_color = a_color;\n"
     63 														"}\n";
     64 
     65 static const char* const s_positionColorOffsetShader =	"#version 310 es\n"
     66 														"in highp vec4 a_position;\n"
     67 														"in highp vec4 a_offset;\n"
     68 														"in highp vec4 a_color;\n"
     69 														"out highp vec4 v_color;\n"
     70 														"void main (void)\n"
     71 														"{\n"
     72 														"	gl_Position = a_position + a_offset;\n"
     73 														"	v_color = a_color;\n"
     74 														"}\n";
     75 
     76 // Verifies image contains only yellow or greeen, or a linear combination
     77 // of these colors.
     78 static bool verifyImageYellowGreen (const tcu::Surface& image, tcu::TestLog& log, bool logImageOnSuccess)
     79 {
     80 	using tcu::TestLog;
     81 
     82 	const int colorThreshold	= 20;
     83 
     84 	tcu::Surface error			(image.getWidth(), image.getHeight());
     85 	bool isOk					= true;
     86 
     87 	log << TestLog::Message << "Verifying image contents." << TestLog::EndMessage;
     88 
     89 	for (int y = 0; y < image.getHeight(); y++)
     90 	for (int x = 0; x < image.getWidth(); x++)
     91 	{
     92 		const tcu::RGBA pixel = image.getPixel(x, y);
     93 		bool pixelOk = true;
     94 
     95 		// Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
     96 		if (de::abs(pixel.getGreen() - 255) > colorThreshold)
     97 			pixelOk = false;
     98 
     99 		// Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
    100 		if (de::abs(pixel.getBlue() - 0) > colorThreshold)
    101 			pixelOk = false;
    102 
    103 		error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
    104 		isOk = isOk && pixelOk;
    105 	}
    106 
    107 	if (!isOk)
    108 	{
    109 		log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
    110 		log << TestLog::ImageSet("Verfication result", "Result of rendering")
    111 			<< TestLog::Image("Result",		"Result",		image)
    112 			<< TestLog::Image("ErrorMask",	"Error mask",	error)
    113 			<< TestLog::EndImageSet;
    114 	}
    115 	else
    116 	{
    117 		log << TestLog::Message << "Image verification passed." << TestLog::EndMessage;
    118 
    119 		if (logImageOnSuccess)
    120 			log << TestLog::ImageSet("Verfication result", "Result of rendering")
    121 				<< TestLog::Image("Result", "Result", image)
    122 				<< TestLog::EndImageSet;
    123 	}
    124 
    125 	return isOk;
    126 }
    127 
    128 class BindingRenderCase : public TestCase
    129 {
    130 public:
    131 	enum
    132 	{
    133 		TEST_RENDER_SIZE = 64
    134 	};
    135 
    136 						BindingRenderCase	(Context& ctx, const char* name, const char* desc, bool unalignedData);
    137 	virtual				~BindingRenderCase	(void);
    138 
    139 	virtual void		init				(void);
    140 	virtual void		deinit				(void);
    141 	IterateResult		iterate				(void);
    142 
    143 private:
    144 	virtual void		renderTo			(tcu::Surface& dst) = 0;
    145 	virtual void		createBuffers		(void) = 0;
    146 	virtual void		createShader		(void) = 0;
    147 
    148 protected:
    149 	const bool			m_unalignedData;
    150 	glw::GLuint			m_vao;
    151 	glu::ShaderProgram*	m_program;
    152 };
    153 
    154 BindingRenderCase::BindingRenderCase (Context& ctx, const char* name, const char* desc, bool unalignedData)
    155 	: TestCase			(ctx, name, desc)
    156 	, m_unalignedData	(unalignedData)
    157 	, m_vao				(0)
    158 	, m_program			(DE_NULL)
    159 {
    160 }
    161 
    162 BindingRenderCase::~BindingRenderCase (void)
    163 {
    164 	deinit();
    165 }
    166 
    167 void BindingRenderCase::init (void)
    168 {
    169 	// check requirements
    170 	if (m_context.getRenderTarget().getWidth() < TEST_RENDER_SIZE || m_context.getRenderTarget().getHeight() < TEST_RENDER_SIZE)
    171 		throw tcu::NotSupportedError("Test requires at least " + de::toString<int>(TEST_RENDER_SIZE) + "x" + de::toString<int>(TEST_RENDER_SIZE) + " render target");
    172 
    173 	// resources
    174 	m_context.getRenderContext().getFunctions().genVertexArrays(1, &m_vao);
    175 	if (m_context.getRenderContext().getFunctions().getError() != GL_NO_ERROR)
    176 		throw tcu::TestError("could not gen vao");
    177 
    178 	createBuffers();
    179 	createShader();
    180 }
    181 
    182 void BindingRenderCase::deinit (void)
    183 {
    184 	if (m_vao)
    185 	{
    186 		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
    187 		m_vao = 0;
    188 	}
    189 
    190 	delete m_program;
    191 	m_program = DE_NULL;
    192 }
    193 
    194 BindingRenderCase::IterateResult BindingRenderCase::iterate (void)
    195 {
    196 	tcu::Surface surface(TEST_RENDER_SIZE, TEST_RENDER_SIZE);
    197 
    198 	// draw pattern
    199 
    200 	renderTo(surface);
    201 
    202 	// verify results
    203 
    204 	if (verifyImageYellowGreen(surface, m_testCtx.getLog(), false))
    205 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    206 	else if (m_unalignedData)
    207 		m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned data");
    208 	else
    209 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
    210 
    211 	return STOP;
    212 }
    213 
    214 class SingleBindingCase : public BindingRenderCase
    215 {
    216 public:
    217 
    218 	enum CaseFlag
    219 	{
    220 		FLAG_ATTRIB_UNALIGNED			= (1<<0),		// !< unalign attributes with relativeOffset
    221 		FLAG_ATTRIB_ALIGNED				= (1<<1),		// !< align attributes with relativeOffset to the buffer begin (and not buffer offset)
    222 		FLAG_ATTRIBS_MULTIPLE_ELEMS		= (1<<2),		// !< use multiple attribute elements
    223 		FLAG_ATTRIBS_SHARED_ELEMS		= (1<<3),		// !< use multiple shared attribute elements. xyzw & rgba stored as (x, y, zr, wg, b, a)
    224 
    225 		FLAG_BUF_ALIGNED_OFFSET			= (1<<4),		// !< use aligned offset to the buffer object
    226 		FLAG_BUF_UNALIGNED_OFFSET		= (1<<5),		// !< use unaligned offset to the buffer object
    227 		FLAG_BUF_UNALIGNED_STRIDE		= (1<<6),		// !< unalign buffer elements
    228 	};
    229 						SingleBindingCase	(Context& ctx, const char* name, int flags);
    230 						~SingleBindingCase	(void);
    231 
    232 	void				init				(void);
    233 	void				deinit				(void);
    234 
    235 private:
    236 	struct TestSpec
    237 	{
    238 		int		bufferOffset;
    239 		int		bufferStride;
    240 		int		positionAttrOffset;
    241 		int		colorAttrOffset;
    242 		bool	hasColorAttr;
    243 	};
    244 
    245 	enum
    246 	{
    247 		GRID_SIZE = 20
    248 	};
    249 
    250 	void				renderTo			(tcu::Surface& dst);
    251 
    252 	static TestSpec		genTestSpec			(int flags);
    253 	static std::string	genTestDescription	(int flags);
    254 	static bool			isDataUnaligned		(int flags);
    255 
    256 	void				createBuffers		(void);
    257 	void				createShader		(void);
    258 	std::string			genVertexSource		(void);
    259 
    260 	const TestSpec		m_spec;
    261 	glw::GLuint			m_buf;
    262 };
    263 
    264 SingleBindingCase::SingleBindingCase (Context& ctx, const char* name, int flags)
    265 	: BindingRenderCase	(ctx, name, genTestDescription(flags).c_str(), isDataUnaligned(flags))
    266 	, m_spec			(genTestSpec(flags))
    267 	, m_buf				(0)
    268 {
    269 	DE_ASSERT(!((flags & FLAG_ATTRIB_UNALIGNED) && (flags & FLAG_ATTRIB_ALIGNED)));
    270 	DE_ASSERT(!((flags & FLAG_ATTRIB_ALIGNED) && (flags & FLAG_BUF_UNALIGNED_STRIDE)));
    271 
    272 	DE_ASSERT(!isDataUnaligned(flags));
    273 }
    274 
    275 SingleBindingCase::~SingleBindingCase (void)
    276 {
    277 	deinit();
    278 }
    279 
    280 void SingleBindingCase::init (void)
    281 {
    282 	// log what we are trying to do
    283 
    284 	m_testCtx.getLog()	<< tcu::TestLog::Message
    285 						<< "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n"
    286 						<< "Buffer format:\n"
    287 						<< "	bufferOffset: " << m_spec.bufferOffset << "\n"
    288 						<< "	bufferStride: " << m_spec.bufferStride << "\n"
    289 						<< "Vertex position format:\n"
    290 						<< "	type: float4\n"
    291 						<< "	offset: " << m_spec.positionAttrOffset << "\n"
    292 						<< "	total offset: " << m_spec.bufferOffset + m_spec.positionAttrOffset << "\n"
    293 						<< tcu::TestLog::EndMessage;
    294 
    295 	if (m_spec.hasColorAttr)
    296 		m_testCtx.getLog()	<< tcu::TestLog::Message
    297 							<< "Color:\n"
    298 							<< "	type: float4\n"
    299 							<< "	offset: " << m_spec.colorAttrOffset << "\n"
    300 							<< "	total offset: " << m_spec.bufferOffset + m_spec.colorAttrOffset << "\n"
    301 							<< tcu::TestLog::EndMessage;
    302 	// init
    303 
    304 	BindingRenderCase::init();
    305 }
    306 
    307 void SingleBindingCase::deinit (void)
    308 {
    309 	if (m_buf)
    310 	{
    311 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buf);
    312 		m_buf = 0;
    313 	}
    314 
    315 	BindingRenderCase::deinit();
    316 }
    317 
    318 void SingleBindingCase::renderTo (tcu::Surface& dst)
    319 {
    320 	glu::CallLogWrapper gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    321 	const int			positionLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
    322 	const int			colorLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_color");
    323 	const int			colorUniformLoc	= gl.glGetUniformLocation(m_program->getProgram(), "u_color");
    324 
    325 	gl.enableLogging(true);
    326 
    327 	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    328 	gl.glClear(GL_COLOR_BUFFER_BIT);
    329 	gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
    330 	gl.glBindVertexArray(m_vao);
    331 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
    332 
    333 	gl.glUseProgram(m_program->getProgram());
    334 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
    335 
    336 	if (m_spec.hasColorAttr)
    337 	{
    338 		gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
    339 
    340 		gl.glVertexAttribBinding(positionLoc, 3);
    341 		gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
    342 		gl.glEnableVertexAttribArray(positionLoc);
    343 
    344 		gl.glVertexAttribBinding(colorLoc, 3);
    345 		gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, m_spec.colorAttrOffset);
    346 		gl.glEnableVertexAttribArray(colorLoc);
    347 
    348 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
    349 
    350 		gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6);
    351 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
    352 	}
    353 	else
    354 	{
    355 		gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
    356 		gl.glVertexAttribBinding(positionLoc, 3);
    357 		gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
    358 		gl.glEnableVertexAttribArray(positionLoc);
    359 
    360 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
    361 		gl.glUniform4f(colorUniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
    362 
    363 		gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6);
    364 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
    365 	}
    366 
    367 	gl.glFinish();
    368 	gl.glBindVertexArray(0);
    369 	gl.glUseProgram(0);
    370 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
    371 
    372 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
    373 }
    374 
    375 SingleBindingCase::TestSpec SingleBindingCase::genTestSpec (int flags)
    376 {
    377 	const int	datumSize				= 4;
    378 	const int	bufferOffset			= (flags & FLAG_BUF_ALIGNED_OFFSET) ? (32) : (flags & FLAG_BUF_UNALIGNED_OFFSET) ? (19) : (0);
    379 	const int	attrBufAlignment		= ((bufferOffset % datumSize) == 0) ? (0) : (datumSize - (bufferOffset % datumSize));
    380 	const int	positionAttrOffset		= (flags & FLAG_ATTRIB_UNALIGNED) ? (3) : (flags & FLAG_ATTRIB_ALIGNED) ? (attrBufAlignment) : (0);
    381 	const bool	hasColorAttr			= (flags & FLAG_ATTRIBS_SHARED_ELEMS) || (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS);
    382 	const int	colorAttrOffset			= (flags & FLAG_ATTRIBS_SHARED_ELEMS) ? (2 * datumSize) : (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) ? (4 * datumSize) : (-1);
    383 
    384 	const int	bufferStrideBase		= de::max(positionAttrOffset + 4 * datumSize, colorAttrOffset + 4 * datumSize);
    385 	const int	bufferStrideAlignment	= ((bufferStrideBase % datumSize) == 0) ? (0) : (datumSize - (bufferStrideBase % datumSize));
    386 	const int	bufferStridePadding		= ((flags & FLAG_BUF_UNALIGNED_STRIDE) && deIsAligned32(bufferStrideBase, datumSize)) ? (13) : (!(flags & FLAG_BUF_UNALIGNED_STRIDE) && !deIsAligned32(bufferStrideBase, datumSize)) ? (bufferStrideAlignment) : (0);
    387 
    388 	TestSpec spec;
    389 
    390 	spec.bufferOffset			= bufferOffset;
    391 	spec.bufferStride			= bufferStrideBase + bufferStridePadding;
    392 	spec.positionAttrOffset		= positionAttrOffset;
    393 	spec.colorAttrOffset		= colorAttrOffset;
    394 	spec.hasColorAttr			= hasColorAttr;
    395 
    396 	if (flags & FLAG_ATTRIB_UNALIGNED)
    397 		DE_ASSERT(!deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
    398 	else if (flags & FLAG_ATTRIB_ALIGNED)
    399 		DE_ASSERT(deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
    400 
    401 	if (flags & FLAG_BUF_UNALIGNED_STRIDE)
    402 		DE_ASSERT(!deIsAligned32(spec.bufferStride, datumSize));
    403 	else
    404 		DE_ASSERT(deIsAligned32(spec.bufferStride, datumSize));
    405 
    406 	return spec;
    407 }
    408 
    409 std::string SingleBindingCase::genTestDescription (int flags)
    410 {
    411 	std::ostringstream buf;
    412 	buf << "draw test pattern";
    413 
    414 	if (flags & FLAG_ATTRIB_UNALIGNED)
    415 		buf << ", attribute offset (unaligned)";
    416 	if (flags & FLAG_ATTRIB_ALIGNED)
    417 		buf << ", attribute offset (aligned)";
    418 
    419 	if (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS)
    420 		buf << ", 2 attributes";
    421 	if (flags & FLAG_ATTRIBS_SHARED_ELEMS)
    422 		buf << ", 2 attributes (some components shared)";
    423 
    424 	if (flags & FLAG_BUF_ALIGNED_OFFSET)
    425 		buf << ", buffer offset aligned";
    426 	if (flags & FLAG_BUF_UNALIGNED_OFFSET)
    427 		buf << ", buffer offset unaligned";
    428 	if (flags & FLAG_BUF_UNALIGNED_STRIDE)
    429 		buf << ", buffer stride unaligned";
    430 
    431 	return buf.str();
    432 }
    433 
    434 bool SingleBindingCase::isDataUnaligned (int flags)
    435 {
    436 	if (flags & FLAG_ATTRIB_UNALIGNED)
    437 		return true;
    438 	if (flags & FLAG_ATTRIB_ALIGNED)
    439 		return false;
    440 
    441 	return (flags & FLAG_BUF_UNALIGNED_OFFSET) || (flags & FLAG_BUF_UNALIGNED_STRIDE);
    442 }
    443 
    444 void SingleBindingCase::createBuffers (void)
    445 {
    446 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
    447 	std::vector<deUint8>	dataBuf	(m_spec.bufferOffset + m_spec.bufferStride * GRID_SIZE * GRID_SIZE * 6);
    448 
    449 	// In interleaved mode color rg and position zw are the same. Select "good" values for r and g
    450 	const tcu::Vec4			colorA	(0.0f, 1.0f, 0.0f, 1.0f);
    451 	const tcu::Vec4			colorB	(0.5f, 1.0f, 0.0f, 1.0f);
    452 
    453 	for (int y = 0; y < GRID_SIZE; ++y)
    454 	for (int x = 0; x < GRID_SIZE; ++x)
    455 	{
    456 		const tcu::Vec4&	color = ((x + y) % 2 == 0) ? (colorA) : (colorB);
    457 		const tcu::Vec4		positions[6] =
    458 		{
    459 			tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
    460 			tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
    461 			tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
    462 			tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
    463 			tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
    464 			tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
    465 		};
    466 
    467 		// copy cell vertices to the buffer.
    468 		for (int v = 0; v < 6; ++v)
    469 			memcpy(&dataBuf[m_spec.bufferOffset + m_spec.positionAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], positions[v].getPtr(), sizeof(positions[v]));
    470 
    471 		// copy color to buffer
    472 		if (m_spec.hasColorAttr)
    473 			for (int v = 0; v < 6; ++v)
    474 				memcpy(&dataBuf[m_spec.bufferOffset + m_spec.colorAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], color.getPtr(), sizeof(color));
    475 	}
    476 
    477 	gl.genBuffers(1, &m_buf);
    478 	gl.bindBuffer(GL_ARRAY_BUFFER, m_buf);
    479 	gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)dataBuf.size(), &dataBuf[0], GL_STATIC_DRAW);
    480 	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    481 
    482 	if (gl.getError() != GL_NO_ERROR)
    483 		throw tcu::TestError("could not init buffer");
    484 }
    485 
    486 void SingleBindingCase::createShader (void)
    487 {
    488 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(s_colorFragmentShader));
    489 	m_testCtx.getLog() << *m_program;
    490 
    491 	if (!m_program->isOk())
    492 		throw tcu::TestError("could not build shader");
    493 }
    494 
    495 std::string SingleBindingCase::genVertexSource (void)
    496 {
    497 	const bool			useUniformColor = !m_spec.hasColorAttr;
    498 	std::ostringstream	buf;
    499 
    500 	buf <<	"#version 310 es\n"
    501 			"in highp vec4 a_position;\n";
    502 
    503 	if (!useUniformColor)
    504 		buf << "in highp vec4 a_color;\n";
    505 	else
    506 		buf << "uniform highp vec4 u_color;\n";
    507 
    508 	buf <<	"out highp vec4 v_color;\n"
    509 			"void main (void)\n"
    510 			"{\n"
    511 			"	gl_Position = a_position;\n"
    512 			"	v_color = " << ((useUniformColor) ? ("u_color") : ("a_color")) << ";\n"
    513 			"}\n";
    514 
    515 	return buf.str();
    516 }
    517 
    518 class MultipleBindingCase : public BindingRenderCase
    519 {
    520 public:
    521 
    522 	enum CaseFlag
    523 	{
    524 		FLAG_ZERO_STRIDE		= (1<<0),	// !< set a buffer stride to zero
    525 		FLAG_INSTANCED			= (1<<1),	// !< set a buffer instance divisor to non-zero
    526 		FLAG_ALIASING_BUFFERS	= (1<<2),	// !< bind buffer to multiple binding points
    527 	};
    528 
    529 						MultipleBindingCase		(Context& ctx, const char* name, int flags);
    530 						~MultipleBindingCase	(void);
    531 
    532 	void				init					(void);
    533 	void				deinit					(void);
    534 
    535 private:
    536 	struct TestSpec
    537 	{
    538 		bool zeroStride;
    539 		bool instanced;
    540 		bool aliasingBuffers;
    541 	};
    542 
    543 	enum
    544 	{
    545 		GRID_SIZE = 20
    546 	};
    547 
    548 	void				renderTo				(tcu::Surface& dst);
    549 
    550 	TestSpec			genTestSpec				(int flags) const;
    551 	std::string			genTestDescription		(int flags) const;
    552 	void				createBuffers			(void);
    553 	void				createShader			(void);
    554 
    555 	const TestSpec		m_spec;
    556 	glw::GLuint			m_primitiveBuf;
    557 	glw::GLuint			m_colorOffsetBuf;
    558 };
    559 
    560 MultipleBindingCase::MultipleBindingCase (Context& ctx, const char* name, int flags)
    561 	: BindingRenderCase	(ctx, name, genTestDescription(flags).c_str(), false)
    562 	, m_spec			(genTestSpec(flags))
    563 	, m_primitiveBuf	(0)
    564 	, m_colorOffsetBuf	(0)
    565 {
    566 	DE_ASSERT(!(m_spec.instanced && m_spec.zeroStride));
    567 }
    568 
    569 MultipleBindingCase::~MultipleBindingCase (void)
    570 {
    571 	deinit();
    572 }
    573 
    574 void MultipleBindingCase::init (void)
    575 {
    576 	BindingRenderCase::init();
    577 
    578 	// log what we are trying to do
    579 
    580 	m_testCtx.getLog()	<< tcu::TestLog::Message
    581 						<< "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n"
    582 						<< "Vertex positions:\n"
    583 						<< "	binding point: 1\n"
    584 						<< "Vertex offsets:\n"
    585 						<< "	binding point: 2\n"
    586 						<< "Vertex colors:\n"
    587 						<< "	binding point: 2\n"
    588 						<< "Binding point 1:\n"
    589 						<< "	buffer object: " << m_primitiveBuf << "\n"
    590 						<< "Binding point 2:\n"
    591 						<< "	buffer object: " << ((m_spec.aliasingBuffers) ? (m_primitiveBuf) : (m_colorOffsetBuf)) << "\n"
    592 						<< "	instance divisor: " << ((m_spec.instanced) ? (1) : (0)) << "\n"
    593 						<< "	stride: " << ((m_spec.zeroStride) ? (0) : (4*4*2)) << "\n"
    594 						<< tcu::TestLog::EndMessage;
    595 }
    596 
    597 void MultipleBindingCase::deinit (void)
    598 {
    599 	if (m_primitiveBuf)
    600 	{
    601 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_primitiveBuf);
    602 		m_primitiveBuf = DE_NULL;
    603 	}
    604 
    605 	if (m_colorOffsetBuf)
    606 	{
    607 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorOffsetBuf);
    608 		m_colorOffsetBuf = DE_NULL;
    609 	}
    610 
    611 	BindingRenderCase::deinit();
    612 }
    613 
    614 void MultipleBindingCase::renderTo (tcu::Surface& dst)
    615 {
    616 	glu::CallLogWrapper gl					(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    617 	const int			positionLoc			= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
    618 	const int			colorLoc			= gl.glGetAttribLocation(m_program->getProgram(), "a_color");
    619 	const int			offsetLoc			= gl.glGetAttribLocation(m_program->getProgram(), "a_offset");
    620 
    621 	const int			positionBinding		= 1;
    622 	const int			colorOffsetBinding	= 2;
    623 
    624 	gl.enableLogging(true);
    625 
    626 	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    627 	gl.glClear(GL_COLOR_BUFFER_BIT);
    628 	gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
    629 	gl.glBindVertexArray(m_vao);
    630 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
    631 
    632 	gl.glUseProgram(m_program->getProgram());
    633 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
    634 
    635 	// Setup format & binding
    636 
    637 	gl.glEnableVertexAttribArray(positionLoc);
    638 	gl.glEnableVertexAttribArray(colorLoc);
    639 	gl.glEnableVertexAttribArray(offsetLoc);
    640 
    641 	gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
    642 	gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
    643 	gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4));
    644 
    645 	gl.glVertexAttribBinding(positionLoc, positionBinding);
    646 	gl.glVertexAttribBinding(colorLoc, colorOffsetBinding);
    647 	gl.glVertexAttribBinding(offsetLoc, colorOffsetBinding);
    648 
    649 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup attribs");
    650 
    651 	// setup binding points
    652 
    653 	gl.glVertexBindingDivisor(positionBinding, 0);
    654 	gl.glBindVertexBuffer(positionBinding, m_primitiveBuf, 0, sizeof(tcu::Vec4));
    655 
    656 	{
    657 		const int			stride	= (m_spec.zeroStride) ? (0) : (2 * (int)sizeof(tcu::Vec4));
    658 		const int			offset	= (!m_spec.aliasingBuffers) ? (0) : (m_spec.instanced) ? (6 * (int)sizeof(tcu::Vec4)) : (6 * GRID_SIZE * GRID_SIZE * (int)sizeof(tcu::Vec4));
    659 		const glw::GLuint	buffer	= (m_spec.aliasingBuffers) ? (m_primitiveBuf) : (m_colorOffsetBuf);
    660 		const int			divisor	= (m_spec.instanced) ? (1) : (0);
    661 
    662 		gl.glVertexBindingDivisor(colorOffsetBinding, divisor);
    663 		gl.glBindVertexBuffer(colorOffsetBinding, buffer, offset, (glw::GLsizei)stride);
    664 	}
    665 
    666 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding points");
    667 
    668 	if (m_spec.instanced)
    669 		gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE);
    670 	else
    671 		gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6);
    672 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
    673 
    674 	gl.glFinish();
    675 	gl.glBindVertexArray(0);
    676 	gl.glUseProgram(0);
    677 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
    678 
    679 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
    680 }
    681 
    682 MultipleBindingCase::TestSpec MultipleBindingCase::genTestSpec (int flags) const
    683 {
    684 	MultipleBindingCase::TestSpec spec;
    685 
    686 	spec.zeroStride			= !!(flags & FLAG_ZERO_STRIDE);
    687 	spec.instanced			= !!(flags & FLAG_INSTANCED);
    688 	spec.aliasingBuffers	= !!(flags & FLAG_ALIASING_BUFFERS);
    689 
    690 	return spec;
    691 }
    692 
    693 std::string MultipleBindingCase::genTestDescription (int flags) const
    694 {
    695 	std::ostringstream buf;
    696 	buf << "draw test pattern";
    697 
    698 	if (flags & FLAG_ZERO_STRIDE)
    699 		buf << ", zero stride";
    700 	if (flags & FLAG_INSTANCED)
    701 		buf << ", instanced binding point";
    702 	if (flags & FLAG_ALIASING_BUFFERS)
    703 		buf << ", binding points share buffer object";
    704 
    705 	return buf.str();
    706 }
    707 
    708 void MultipleBindingCase::createBuffers (void)
    709 {
    710 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
    711 	const tcu::Vec4			green				= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
    712 	const tcu::Vec4			yellow				= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
    713 
    714 	const int				vertexDataSize		= (m_spec.instanced) ? (6) : (6 * GRID_SIZE * GRID_SIZE);
    715 	const int				offsetColorSize		= (m_spec.zeroStride) ? (2) : (m_spec.instanced) ? (2 * GRID_SIZE * GRID_SIZE) : (2 * 6 * GRID_SIZE * GRID_SIZE);
    716 	const int				primitiveBufSize	= (m_spec.aliasingBuffers) ? (vertexDataSize + offsetColorSize) : (vertexDataSize);
    717 	const int				colorOffsetBufSize	= (m_spec.aliasingBuffers) ? (0) : (offsetColorSize);
    718 
    719 	std::vector<tcu::Vec4>	primitiveData		(primitiveBufSize);
    720 	std::vector<tcu::Vec4>	colorOffsetData		(colorOffsetBufSize);
    721 	tcu::Vec4*				colorOffsetWritePtr = DE_NULL;
    722 
    723 	if (m_spec.aliasingBuffers)
    724 	{
    725 		if (m_spec.instanced)
    726 			colorOffsetWritePtr = &primitiveData[6];
    727 		else
    728 			colorOffsetWritePtr = &primitiveData[GRID_SIZE*GRID_SIZE*6];
    729 	}
    730 	else
    731 		colorOffsetWritePtr = &colorOffsetData[0];
    732 
    733 	// write vertex position
    734 
    735 	if (m_spec.instanced)
    736 	{
    737 		// store single basic primitive
    738 		primitiveData[0] = tcu::Vec4(0.0f,				0.0f,				0.0f, 1.0f);
    739 		primitiveData[1] = tcu::Vec4(0.0f,				2.0f / GRID_SIZE,	0.0f, 1.0f);
    740 		primitiveData[2] = tcu::Vec4(2.0f / GRID_SIZE,	2.0f / GRID_SIZE,	0.0f, 1.0f);
    741 		primitiveData[3] = tcu::Vec4(0.0f,				0.0f,				0.0f, 1.0f);
    742 		primitiveData[4] = tcu::Vec4(2.0f / GRID_SIZE,	2.0f / GRID_SIZE,	0.0f, 1.0f);
    743 		primitiveData[5] = tcu::Vec4(2.0f / GRID_SIZE,	0.0f,				0.0f, 1.0f);
    744 	}
    745 	else
    746 	{
    747 		// store whole grid
    748 		for (int y = 0; y < GRID_SIZE; ++y)
    749 		for (int x = 0; x < GRID_SIZE; ++x)
    750 		{
    751 			primitiveData[(y * GRID_SIZE + x) * 6 + 0] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
    752 			primitiveData[(y * GRID_SIZE + x) * 6 + 1] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
    753 			primitiveData[(y * GRID_SIZE + x) * 6 + 2] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
    754 			primitiveData[(y * GRID_SIZE + x) * 6 + 3] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
    755 			primitiveData[(y * GRID_SIZE + x) * 6 + 4] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
    756 			primitiveData[(y * GRID_SIZE + x) * 6 + 5] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
    757 		}
    758 	}
    759 
    760 	// store color&offset
    761 
    762 	if (m_spec.zeroStride)
    763 	{
    764 		colorOffsetWritePtr[0] = green;
    765 		colorOffsetWritePtr[1] = tcu::Vec4(0.0f);
    766 	}
    767 	else if (m_spec.instanced)
    768 	{
    769 		for (int y = 0; y < GRID_SIZE; ++y)
    770 		for (int x = 0; x < GRID_SIZE; ++x)
    771 		{
    772 			const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow);
    773 
    774 			colorOffsetWritePtr[(y * GRID_SIZE + x) * 2 + 0] = color;
    775 			colorOffsetWritePtr[(y * GRID_SIZE + x) * 2 + 1] = tcu::Vec4(float(x) / float(GRID_SIZE) * 2.0f - 1.0f, float(y) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 0.0f);
    776 		}
    777 	}
    778 	else
    779 	{
    780 		for (int y = 0; y < GRID_SIZE; ++y)
    781 		for (int x = 0; x < GRID_SIZE; ++x)
    782 		for (int v = 0; v < 6; ++v)
    783 		{
    784 			const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow);
    785 
    786 			colorOffsetWritePtr[((y * GRID_SIZE + x) * 6 + v) * 2 + 0] = color;
    787 			colorOffsetWritePtr[((y * GRID_SIZE + x) * 6 + v) * 2 + 1] = tcu::Vec4(0.0f);
    788 		}
    789 	}
    790 
    791 	// upload vertex data
    792 
    793 	gl.genBuffers(1, &m_primitiveBuf);
    794 	gl.bindBuffer(GL_ARRAY_BUFFER, m_primitiveBuf);
    795 	gl.bufferData(GL_ARRAY_BUFFER, (int)(primitiveData.size() * sizeof(tcu::Vec4)), primitiveData[0].getPtr(), GL_STATIC_DRAW);
    796 	GLU_EXPECT_NO_ERROR(gl.getError(), "upload data");
    797 
    798 	if (!m_spec.aliasingBuffers)
    799 	{
    800 		// upload color & offset data
    801 
    802 		gl.genBuffers(1, &m_colorOffsetBuf);
    803 		gl.bindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuf);
    804 		gl.bufferData(GL_ARRAY_BUFFER, (int)(colorOffsetData.size() * sizeof(tcu::Vec4)), colorOffsetData[0].getPtr(), GL_STATIC_DRAW);
    805 		GLU_EXPECT_NO_ERROR(gl.getError(), "upload colordata");
    806 	}
    807 }
    808 
    809 void MultipleBindingCase::createShader (void)
    810 {
    811 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionColorOffsetShader) << glu::FragmentSource(s_colorFragmentShader));
    812 	m_testCtx.getLog() << *m_program;
    813 
    814 	if (!m_program->isOk())
    815 		throw tcu::TestError("could not build shader");
    816 }
    817 
    818 class MixedBindingCase : public BindingRenderCase
    819 {
    820 public:
    821 
    822 	enum CaseType
    823 	{
    824 		CASE_BASIC = 0,
    825 		CASE_INSTANCED_BINDING,
    826 		CASE_INSTANCED_ATTRIB,
    827 
    828 		CASE_LAST
    829 	};
    830 
    831 						MixedBindingCase		(Context& ctx, const char* name, const char* desc, CaseType caseType);
    832 						~MixedBindingCase		(void);
    833 
    834 	void				init					(void);
    835 	void				deinit					(void);
    836 
    837 private:
    838 	enum
    839 	{
    840 		GRID_SIZE = 20
    841 	};
    842 
    843 	void				renderTo				(tcu::Surface& dst);
    844 	void				createBuffers			(void);
    845 	void				createShader			(void);
    846 
    847 	const CaseType		m_case;
    848 	glw::GLuint			m_posBuffer;
    849 	glw::GLuint			m_colorOffsetBuffer;
    850 };
    851 
    852 MixedBindingCase::MixedBindingCase (Context& ctx, const char* name, const char* desc, CaseType caseType)
    853 	: BindingRenderCase		(ctx, name, desc, false)
    854 	, m_case				(caseType)
    855 	, m_posBuffer			(0)
    856 	, m_colorOffsetBuffer	(0)
    857 {
    858 	DE_ASSERT(caseType < CASE_LAST);
    859 }
    860 
    861 MixedBindingCase::~MixedBindingCase (void)
    862 {
    863 	deinit();
    864 }
    865 
    866 void MixedBindingCase::init (void)
    867 {
    868 	BindingRenderCase::init();
    869 }
    870 
    871 void MixedBindingCase::deinit (void)
    872 {
    873 	if (m_posBuffer)
    874 	{
    875 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_posBuffer);
    876 		m_posBuffer = DE_NULL;
    877 	}
    878 
    879 	if (m_colorOffsetBuffer)
    880 	{
    881 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorOffsetBuffer);
    882 		m_colorOffsetBuffer = DE_NULL;
    883 	}
    884 
    885 	BindingRenderCase::deinit();
    886 }
    887 
    888 void MixedBindingCase::renderTo (tcu::Surface& dst)
    889 {
    890 	glu::CallLogWrapper gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    891 	const int			positionLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
    892 	const int			colorLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_color");
    893 	const int			offsetLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_offset");
    894 
    895 	gl.enableLogging(true);
    896 
    897 	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    898 	gl.glClear(GL_COLOR_BUFFER_BIT);
    899 	gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
    900 	gl.glBindVertexArray(m_vao);
    901 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
    902 
    903 	gl.glUseProgram(m_program->getProgram());
    904 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
    905 
    906 	switch (m_case)
    907 	{
    908 		case CASE_BASIC:
    909 		{
    910 			// bind position using vertex_attrib_binding api
    911 
    912 			gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4));
    913 			gl.glVertexAttribBinding(positionLoc, positionLoc);
    914 			gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
    915 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
    916 
    917 			// bind color using old api
    918 
    919 			gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
    920 			gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL);
    921 			gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
    922 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
    923 
    924 			// draw
    925 			gl.glEnableVertexAttribArray(positionLoc);
    926 			gl.glEnableVertexAttribArray(colorLoc);
    927 			gl.glEnableVertexAttribArray(offsetLoc);
    928 			gl.glDrawArrays(GL_TRIANGLES, 0, 6*GRID_SIZE*GRID_SIZE);
    929 			break;
    930 		}
    931 
    932 		case CASE_INSTANCED_BINDING:
    933 		{
    934 			// bind position using old api
    935 			gl.glBindBuffer(GL_ARRAY_BUFFER, m_posBuffer);
    936 			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    937 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
    938 
    939 			// bind color using vertex_attrib_binding api
    940 			gl.glBindVertexBuffer(colorLoc, m_colorOffsetBuffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
    941 			gl.glVertexBindingDivisor(colorLoc, 1);
    942 
    943 			gl.glVertexAttribBinding(colorLoc, colorLoc);
    944 			gl.glVertexAttribBinding(offsetLoc, colorLoc);
    945 
    946 			gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
    947 			gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4));
    948 
    949 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
    950 
    951 			// draw
    952 			gl.glEnableVertexAttribArray(positionLoc);
    953 			gl.glEnableVertexAttribArray(colorLoc);
    954 			gl.glEnableVertexAttribArray(offsetLoc);
    955 			gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE);
    956 			break;
    957 		}
    958 
    959 		case CASE_INSTANCED_ATTRIB:
    960 		{
    961 			// bind position using vertex_attrib_binding api
    962 			gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4));
    963 			gl.glVertexAttribBinding(positionLoc, positionLoc);
    964 			gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
    965 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
    966 
    967 			// bind color using old api
    968 			gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
    969 			gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL);
    970 			gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
    971 			gl.glVertexAttribDivisor(colorLoc, 1);
    972 			gl.glVertexAttribDivisor(offsetLoc, 1);
    973 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
    974 
    975 			// draw
    976 			gl.glEnableVertexAttribArray(positionLoc);
    977 			gl.glEnableVertexAttribArray(colorLoc);
    978 			gl.glEnableVertexAttribArray(offsetLoc);
    979 			gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE);
    980 			break;
    981 		}
    982 
    983 		default:
    984 			DE_ASSERT(DE_FALSE);
    985 	}
    986 
    987 	gl.glFinish();
    988 	gl.glBindVertexArray(0);
    989 	gl.glUseProgram(0);
    990 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
    991 
    992 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
    993 }
    994 
    995 void MixedBindingCase::createBuffers (void)
    996 {
    997 	const glw::Functions&	gl								= m_context.getRenderContext().getFunctions();
    998 	const tcu::Vec4			green							= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
    999 	const tcu::Vec4			yellow							= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
   1000 
   1001 	// draw grid. In instanced mode, each cell is an instance
   1002 	const bool				instanced						= (m_case == CASE_INSTANCED_BINDING) || (m_case == CASE_INSTANCED_ATTRIB);
   1003 	const int				numCells						= GRID_SIZE*GRID_SIZE;
   1004 	const int				numPositionCells				= (instanced) ? (1) : (numCells);
   1005 	const int				numPositionElements				= 6 * numPositionCells;
   1006 	const int				numInstanceElementsPerCell		= (instanced) ? (1) : (6);
   1007 	const int				numColorOffsetElements			= numInstanceElementsPerCell * numCells;
   1008 
   1009 	std::vector<tcu::Vec4>	positionData					(numPositionElements);
   1010 	std::vector<tcu::Vec4>	colorOffsetData					(2 * numColorOffsetElements);
   1011 
   1012 	// positions
   1013 
   1014 	for (int primNdx = 0; primNdx < numPositionCells; ++primNdx)
   1015 	{
   1016 		positionData[primNdx*6 + 0] =  tcu::Vec4(0.0f,				0.0f,				0.0f, 1.0f);
   1017 		positionData[primNdx*6 + 1] =  tcu::Vec4(0.0f,				2.0f / GRID_SIZE,	0.0f, 1.0f);
   1018 		positionData[primNdx*6 + 2] =  tcu::Vec4(2.0f / GRID_SIZE,	2.0f / GRID_SIZE,	0.0f, 1.0f);
   1019 		positionData[primNdx*6 + 3] =  tcu::Vec4(0.0f,				0.0f,				0.0f, 1.0f);
   1020 		positionData[primNdx*6 + 4] =  tcu::Vec4(2.0f / GRID_SIZE,	2.0f / GRID_SIZE,	0.0f, 1.0f);
   1021 		positionData[primNdx*6 + 5] =  tcu::Vec4(2.0f / GRID_SIZE,	0.0f,				0.0f, 1.0f);
   1022 	}
   1023 
   1024 	// color & offset
   1025 
   1026 	for (int y = 0; y < GRID_SIZE; ++y)
   1027 	for (int x = 0; x < GRID_SIZE; ++x)
   1028 	{
   1029 		for (int v = 0; v < numInstanceElementsPerCell; ++v)
   1030 		{
   1031 			const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow);
   1032 
   1033 			colorOffsetData[((y * GRID_SIZE + x) * numInstanceElementsPerCell + v) * 2 + 0] = color;
   1034 			colorOffsetData[((y * GRID_SIZE + x) * numInstanceElementsPerCell + v) * 2 + 1] = tcu::Vec4(float(x) / float(GRID_SIZE) * 2.0f - 1.0f, float(y) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 0.0f);
   1035 		}
   1036 	}
   1037 
   1038 	// upload vertex data
   1039 
   1040 	gl.genBuffers(1, &m_posBuffer);
   1041 	gl.bindBuffer(GL_ARRAY_BUFFER, m_posBuffer);
   1042 	gl.bufferData(GL_ARRAY_BUFFER, (int)(positionData.size() * sizeof(tcu::Vec4)), positionData[0].getPtr(), GL_STATIC_DRAW);
   1043 	GLU_EXPECT_NO_ERROR(gl.getError(), "upload position data");
   1044 
   1045 	gl.genBuffers(1, &m_colorOffsetBuffer);
   1046 	gl.bindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
   1047 	gl.bufferData(GL_ARRAY_BUFFER, (int)(colorOffsetData.size() * sizeof(tcu::Vec4)), colorOffsetData[0].getPtr(), GL_STATIC_DRAW);
   1048 	GLU_EXPECT_NO_ERROR(gl.getError(), "upload position data");
   1049 }
   1050 
   1051 void MixedBindingCase::createShader (void)
   1052 {
   1053 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionColorOffsetShader) << glu::FragmentSource(s_colorFragmentShader));
   1054 	m_testCtx.getLog() << *m_program;
   1055 
   1056 	if (!m_program->isOk())
   1057 		throw tcu::TestError("could not build shader");
   1058 }
   1059 
   1060 class MixedApiCase : public BindingRenderCase
   1061 {
   1062 public:
   1063 
   1064 	enum CaseType
   1065 	{
   1066 		CASE_CHANGE_BUFFER = 0,
   1067 		CASE_CHANGE_BUFFER_OFFSET,
   1068 		CASE_CHANGE_BUFFER_STRIDE,
   1069 		CASE_CHANGE_BINDING_POINT,
   1070 
   1071 		CASE_LAST
   1072 	};
   1073 
   1074 						MixedApiCase			(Context& ctx, const char* name, const char* desc, CaseType caseType);
   1075 						~MixedApiCase			(void);
   1076 
   1077 	void				init					(void);
   1078 	void				deinit					(void);
   1079 
   1080 private:
   1081 	enum
   1082 	{
   1083 		GRID_SIZE = 20
   1084 	};
   1085 
   1086 	void				renderTo				(tcu::Surface& dst);
   1087 	void				createBuffers			(void);
   1088 	void				createShader			(void);
   1089 
   1090 	const CaseType		m_case;
   1091 	glw::GLuint			m_buffer;
   1092 };
   1093 
   1094 
   1095 MixedApiCase::MixedApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType)
   1096 	: BindingRenderCase		(ctx, name, desc, false)
   1097 	, m_case				(caseType)
   1098 	, m_buffer				(0)
   1099 {
   1100 	DE_ASSERT(caseType < CASE_LAST);
   1101 }
   1102 
   1103 MixedApiCase::~MixedApiCase (void)
   1104 {
   1105 	deinit();
   1106 }
   1107 
   1108 void MixedApiCase::init (void)
   1109 {
   1110 	BindingRenderCase::init();
   1111 }
   1112 
   1113 void MixedApiCase::deinit (void)
   1114 {
   1115 	if (m_buffer)
   1116 	{
   1117 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
   1118 		m_buffer = DE_NULL;
   1119 	}
   1120 
   1121 	BindingRenderCase::deinit();
   1122 }
   1123 
   1124 void MixedApiCase::renderTo (tcu::Surface& dst)
   1125 {
   1126 	glu::CallLogWrapper		gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
   1127 	const int				positionLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
   1128 	const int				colorLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_color");
   1129 	glu::Buffer				dummyBuffer		(m_context.getRenderContext());
   1130 
   1131 	gl.enableLogging(true);
   1132 
   1133 	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   1134 	gl.glClear(GL_COLOR_BUFFER_BIT);
   1135 	gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
   1136 	gl.glBindVertexArray(m_vao);
   1137 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
   1138 
   1139 	gl.glUseProgram(m_program->getProgram());
   1140 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
   1141 
   1142 	switch (m_case)
   1143 	{
   1144 		case CASE_CHANGE_BUFFER:
   1145 		{
   1146 			// bind data using old api
   1147 
   1148 			gl.glBindBuffer(GL_ARRAY_BUFFER, *dummyBuffer);
   1149 			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
   1150 			gl.glVertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
   1151 
   1152 			// change buffer with vertex_attrib_binding
   1153 
   1154 			gl.glBindVertexBuffer(positionLoc, m_buffer, 0,                 (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
   1155 			gl.glBindVertexBuffer(colorLoc,    m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
   1156 
   1157 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1158 			break;
   1159 		}
   1160 
   1161 		case CASE_CHANGE_BUFFER_OFFSET:
   1162 		{
   1163 			// bind data using old api
   1164 
   1165 			gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
   1166 			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
   1167 			gl.glVertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
   1168 
   1169 			// change buffer offset with vertex_attrib_binding
   1170 
   1171 			gl.glBindVertexBuffer(positionLoc, m_buffer, 0,                 (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
   1172 			gl.glBindVertexBuffer(colorLoc,    m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
   1173 
   1174 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1175 			break;
   1176 		}
   1177 
   1178 		case CASE_CHANGE_BUFFER_STRIDE:
   1179 		{
   1180 			// bind data using old api
   1181 
   1182 			gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
   1183 			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8, (const deUint8*)DE_NULL);
   1184 			gl.glVertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, 4, (const deUint8*)DE_NULL);
   1185 
   1186 			// change buffer stride with vertex_attrib_binding
   1187 
   1188 			gl.glBindVertexBuffer(positionLoc, m_buffer, 0,                 (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
   1189 			gl.glBindVertexBuffer(colorLoc,    m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
   1190 
   1191 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1192 			break;
   1193 		}
   1194 
   1195 		case CASE_CHANGE_BINDING_POINT:
   1196 		{
   1197 			const int maxUsedLocation	= de::max(positionLoc, colorLoc);
   1198 			const int bindingPoint1		= maxUsedLocation + 1;
   1199 			const int bindingPoint2		= maxUsedLocation + 2;
   1200 
   1201 			// bind data using old api
   1202 
   1203 			gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
   1204 			gl.glVertexAttribPointer(bindingPoint1, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
   1205 			gl.glVertexAttribPointer(bindingPoint2, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
   1206 
   1207 			// change buffer binding point with vertex_attrib_binding
   1208 
   1209 			gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
   1210 			gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
   1211 
   1212 			gl.glVertexAttribBinding(positionLoc, bindingPoint1);
   1213 			gl.glVertexAttribBinding(colorLoc, bindingPoint2);
   1214 
   1215 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1216 			break;
   1217 		}
   1218 
   1219 		default:
   1220 			DE_ASSERT(DE_FALSE);
   1221 	}
   1222 
   1223 	// draw
   1224 	gl.glEnableVertexAttribArray(positionLoc);
   1225 	gl.glEnableVertexAttribArray(colorLoc);
   1226 	gl.glDrawArrays(GL_TRIANGLES, 0, 6*GRID_SIZE*GRID_SIZE);
   1227 
   1228 	gl.glFinish();
   1229 	gl.glBindVertexArray(0);
   1230 	gl.glUseProgram(0);
   1231 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
   1232 
   1233 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
   1234 }
   1235 
   1236 void MixedApiCase::createBuffers (void)
   1237 {
   1238 	const tcu::Vec4			green							= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
   1239 	const tcu::Vec4			yellow							= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
   1240 
   1241 	const glw::Functions&	gl								= m_context.getRenderContext().getFunctions();
   1242 	std::vector<tcu::Vec4>	vertexData						(12 * GRID_SIZE * GRID_SIZE);
   1243 
   1244 	for (int y = 0; y < GRID_SIZE; ++y)
   1245 	for (int x = 0; x < GRID_SIZE; ++x)
   1246 	{
   1247 		const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow);
   1248 
   1249 		vertexData[(y * GRID_SIZE + x) * 12 +  0] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
   1250 		vertexData[(y * GRID_SIZE + x) * 12 +  1] = color;
   1251 		vertexData[(y * GRID_SIZE + x) * 12 +  2] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
   1252 		vertexData[(y * GRID_SIZE + x) * 12 +  3] = color;
   1253 		vertexData[(y * GRID_SIZE + x) * 12 +  4] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
   1254 		vertexData[(y * GRID_SIZE + x) * 12 +  5] = color;
   1255 		vertexData[(y * GRID_SIZE + x) * 12 +  6] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
   1256 		vertexData[(y * GRID_SIZE + x) * 12 +  7] = color;
   1257 		vertexData[(y * GRID_SIZE + x) * 12 +  8] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
   1258 		vertexData[(y * GRID_SIZE + x) * 12 +  9] = color;
   1259 		vertexData[(y * GRID_SIZE + x) * 12 + 10] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
   1260 		vertexData[(y * GRID_SIZE + x) * 12 + 11] = color;
   1261 	}
   1262 
   1263 	// upload vertex data
   1264 
   1265 	gl.genBuffers(1, &m_buffer);
   1266 	gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
   1267 	gl.bufferData(GL_ARRAY_BUFFER, (int)(vertexData.size() * sizeof(tcu::Vec4)), vertexData[0].getPtr(), GL_STATIC_DRAW);
   1268 	GLU_EXPECT_NO_ERROR(gl.getError(), "upload data");
   1269 }
   1270 
   1271 void MixedApiCase::createShader (void)
   1272 {
   1273 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionColorShader) << glu::FragmentSource(s_colorFragmentShader));
   1274 	m_testCtx.getLog() << *m_program;
   1275 
   1276 	if (!m_program->isOk())
   1277 		throw tcu::TestError("could not build shader");
   1278 }
   1279 
   1280 class DefaultVAOCase : public TestCase
   1281 {
   1282 public:
   1283 	enum CaseType
   1284 	{
   1285 		CASE_BIND_VERTEX_BUFFER,
   1286 		CASE_VERTEX_ATTRIB_FORMAT,
   1287 		CASE_VERTEX_ATTRIB_I_FORMAT,
   1288 		CASE_VERTEX_ATTRIB_BINDING,
   1289 		CASE_VERTEX_BINDING_DIVISOR,
   1290 
   1291 		CASE_LAST
   1292 	};
   1293 
   1294 					DefaultVAOCase		(Context& ctx, const char* name, const char* desc, CaseType caseType);
   1295 					~DefaultVAOCase		(void);
   1296 
   1297 	IterateResult	iterate				(void);
   1298 
   1299 private:
   1300 	const CaseType	m_caseType;
   1301 };
   1302 
   1303 DefaultVAOCase::DefaultVAOCase (Context& ctx, const char* name, const char* desc, CaseType caseType)
   1304 	: TestCase		(ctx, name, desc)
   1305 	, m_caseType	(caseType)
   1306 {
   1307 	DE_ASSERT(caseType < CASE_LAST);
   1308 }
   1309 
   1310 DefaultVAOCase::~DefaultVAOCase (void)
   1311 {
   1312 }
   1313 
   1314 DefaultVAOCase::IterateResult DefaultVAOCase::iterate (void)
   1315 {
   1316 	glw::GLenum			error	= 0;
   1317 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
   1318 
   1319 	gl.enableLogging(true);
   1320 
   1321 	switch (m_caseType)
   1322 	{
   1323 		case CASE_BIND_VERTEX_BUFFER:
   1324 		{
   1325 			glu::Buffer buffer(m_context.getRenderContext());
   1326 			gl.glBindVertexBuffer(0, *buffer, 0, 0);
   1327 			break;
   1328 		}
   1329 
   1330 		case CASE_VERTEX_ATTRIB_FORMAT:
   1331 			gl.glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, 0);
   1332 			break;
   1333 
   1334 		case CASE_VERTEX_ATTRIB_I_FORMAT:
   1335 			gl.glVertexAttribIFormat(0, 4, GL_INT, 0);
   1336 			break;
   1337 
   1338 		case CASE_VERTEX_ATTRIB_BINDING:
   1339 			gl.glVertexAttribBinding(0, 0);
   1340 			break;
   1341 
   1342 		case CASE_VERTEX_BINDING_DIVISOR:
   1343 			gl.glVertexBindingDivisor(0, 1);
   1344 			break;
   1345 
   1346 		default:
   1347 			DE_ASSERT(false);
   1348 	}
   1349 
   1350 	error = gl.glGetError();
   1351 
   1352 	if (error != GL_INVALID_OPERATION)
   1353 	{
   1354 		m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
   1355 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error");
   1356 	}
   1357 	else
   1358 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1359 
   1360 	return STOP;
   1361 }
   1362 
   1363 class BindToCreateCase : public TestCase
   1364 {
   1365 public:
   1366 					BindToCreateCase	(Context& ctx, const char* name, const char* desc);
   1367 					~BindToCreateCase	(void);
   1368 
   1369 	IterateResult	iterate				(void);
   1370 };
   1371 
   1372 BindToCreateCase::BindToCreateCase (Context& ctx, const char* name, const char* desc)
   1373 	: TestCase(ctx, name, desc)
   1374 {
   1375 }
   1376 
   1377 BindToCreateCase::~BindToCreateCase (void)
   1378 {
   1379 }
   1380 
   1381 BindToCreateCase::IterateResult BindToCreateCase::iterate (void)
   1382 {
   1383 	glw::GLuint			buffer	= 0;
   1384 	glw::GLenum			error;
   1385 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
   1386 	glu::VertexArray	vao		(m_context.getRenderContext());
   1387 
   1388 	gl.enableLogging(true);
   1389 
   1390 	gl.glGenBuffers(1, &buffer);
   1391 	gl.glDeleteBuffers(1, &buffer);
   1392 	GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1393 
   1394 	gl.glBindVertexArray(*vao);
   1395 	gl.glBindVertexBuffer(0, buffer, 0, 0);
   1396 
   1397 	error = gl.glGetError();
   1398 
   1399 	if (error != GL_INVALID_OPERATION)
   1400 	{
   1401 		m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
   1402 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error");
   1403 	}
   1404 	else
   1405 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1406 
   1407 	return STOP;
   1408 }
   1409 
   1410 class NegativeApiCase : public TestCase
   1411 {
   1412 public:
   1413 	enum CaseType
   1414 	{
   1415 		CASE_LARGE_OFFSET,
   1416 		CASE_LARGE_STRIDE,
   1417 		CASE_NEGATIVE_STRIDE,
   1418 		CASE_NEGATIVE_OFFSET,
   1419 		CASE_INVALID_ATTR,
   1420 		CASE_INVALID_BINDING,
   1421 
   1422 		CASE_LAST
   1423 	};
   1424 					NegativeApiCase		(Context& ctx, const char* name, const char* desc, CaseType caseType);
   1425 					~NegativeApiCase	(void);
   1426 
   1427 	IterateResult	iterate				(void);
   1428 
   1429 private:
   1430 	const CaseType	m_caseType;
   1431 };
   1432 
   1433 NegativeApiCase::NegativeApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType)
   1434 	: TestCase		(ctx, name, desc)
   1435 	, m_caseType	(caseType)
   1436 {
   1437 }
   1438 
   1439 NegativeApiCase::~NegativeApiCase (void)
   1440 {
   1441 }
   1442 
   1443 NegativeApiCase::IterateResult NegativeApiCase::iterate (void)
   1444 {
   1445 	glw::GLenum			error;
   1446 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
   1447 	glu::VertexArray	vao		(m_context.getRenderContext());
   1448 
   1449 	gl.enableLogging(true);
   1450 	gl.glBindVertexArray(*vao);
   1451 
   1452 	switch (m_caseType)
   1453 	{
   1454 		case CASE_LARGE_OFFSET:
   1455 		{
   1456 			glw::GLint	maxOffset	= -1;
   1457 			glw::GLint	largeOffset;
   1458 
   1459 			gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxOffset);
   1460 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1461 
   1462 			largeOffset = maxOffset + 1;
   1463 
   1464 			// skip if maximum unsigned or signed values
   1465 			if (maxOffset == -1 || maxOffset == 0x7FFFFFFF)
   1466 				throw tcu::NotSupportedError("Implementation supports all offsets");
   1467 
   1468 			gl.glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, largeOffset);
   1469 			break;
   1470 		}
   1471 
   1472 		case CASE_LARGE_STRIDE:
   1473 		{
   1474 			glu::Buffer buffer		(m_context.getRenderContext());
   1475 			glw::GLint	maxStride	= -1;
   1476 			glw::GLint	largeStride;
   1477 
   1478 			gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
   1479 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1480 
   1481 			largeStride = maxStride + 1;
   1482 
   1483 			// skip if maximum unsigned or signed values
   1484 			if (maxStride == -1 || maxStride == 0x7FFFFFFF)
   1485 				throw tcu::NotSupportedError("Implementation supports all strides");
   1486 
   1487 			gl.glBindVertexBuffer(0, *buffer, 0, largeStride);
   1488 			break;
   1489 		}
   1490 
   1491 		case CASE_NEGATIVE_STRIDE:
   1492 		{
   1493 			glu::Buffer buffer(m_context.getRenderContext());
   1494 			gl.glBindVertexBuffer(0, *buffer, 0, -20);
   1495 			break;
   1496 		}
   1497 
   1498 		case CASE_NEGATIVE_OFFSET:
   1499 		{
   1500 			glu::Buffer buffer(m_context.getRenderContext());
   1501 			gl.glBindVertexBuffer(0, *buffer, -20, 0);
   1502 			break;
   1503 		}
   1504 
   1505 		case CASE_INVALID_ATTR:
   1506 		{
   1507 			glw::GLint maxIndex = -1;
   1508 			glw::GLint largeIndex;
   1509 
   1510 			gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxIndex);
   1511 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1512 
   1513 			largeIndex = maxIndex + 1;
   1514 
   1515 			// skip if maximum unsigned or signed values
   1516 			if (maxIndex == -1 || maxIndex == 0x7FFFFFFF)
   1517 				throw tcu::NotSupportedError("Implementation supports any attribute index");
   1518 
   1519 			gl.glVertexAttribBinding(largeIndex, 0);
   1520 			break;
   1521 		}
   1522 
   1523 		case CASE_INVALID_BINDING:
   1524 		{
   1525 			glw::GLint maxBindings = -1;
   1526 			glw::GLint largeBinding;
   1527 
   1528 			gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &maxBindings);
   1529 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
   1530 
   1531 			largeBinding = maxBindings + 1;
   1532 
   1533 			// skip if maximum unsigned or signed values
   1534 			if (maxBindings == -1 || maxBindings == 0x7FFFFFFF)
   1535 				throw tcu::NotSupportedError("Implementation supports any binding");
   1536 
   1537 			gl.glVertexAttribBinding(0, largeBinding);
   1538 			break;
   1539 		}
   1540 
   1541 		default:
   1542 			DE_ASSERT(false);
   1543 	}
   1544 
   1545 	error = gl.glGetError();
   1546 
   1547 	if (error != GL_INVALID_VALUE)
   1548 	{
   1549 		m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
   1550 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error");
   1551 	}
   1552 	else
   1553 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1554 
   1555 	return STOP;
   1556 }
   1557 
   1558 } // anonymous
   1559 
   1560 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
   1561 	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding")
   1562 {
   1563 }
   1564 
   1565 VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
   1566 {
   1567 }
   1568 
   1569 void VertexAttributeBindingTests::init (void)
   1570 {
   1571 	tcu::TestCaseGroup* const usageGroup	= new tcu::TestCaseGroup(m_testCtx, "usage", "Test using binding points");
   1572 	tcu::TestCaseGroup* const negativeGroup	= new tcu::TestCaseGroup(m_testCtx, "negative", "Negative test");
   1573 
   1574 	addChild(usageGroup);
   1575 	addChild(negativeGroup);
   1576 
   1577 	// .usage
   1578 	{
   1579 		tcu::TestCaseGroup* const singleGroup	= new tcu::TestCaseGroup(m_testCtx, "single_binding", "Test using single binding point");
   1580 		tcu::TestCaseGroup* const multipleGroup	= new tcu::TestCaseGroup(m_testCtx, "multiple_bindings", "Test using multiple binding points");
   1581 		tcu::TestCaseGroup* const mixedGroup	= new tcu::TestCaseGroup(m_testCtx, "mixed_usage", "Test using binding point and non binding point api variants");
   1582 
   1583 		usageGroup->addChild(singleGroup);
   1584 		usageGroup->addChild(multipleGroup);
   1585 		usageGroup->addChild(mixedGroup);
   1586 
   1587 		// single binding
   1588 
   1589 		singleGroup->addChild(new SingleBindingCase(m_context, "elements_1",																					  0));
   1590 		singleGroup->addChild(new SingleBindingCase(m_context, "elements_2",																					  SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
   1591 		singleGroup->addChild(new SingleBindingCase(m_context, "elements_2_share_elements",																		  SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
   1592 		singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_1",								SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET		| 0));
   1593 		singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_2",								SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET		| SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
   1594 		singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_2_share_elements",				SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET		| SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
   1595 		singleGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1_aligned_elements",	SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET	| SingleBindingCase::FLAG_ATTRIB_ALIGNED));			// !< total offset is aligned
   1596 
   1597 		// multiple bindings
   1598 
   1599 		multipleGroup->addChild(new MultipleBindingCase(m_context, "basic",									0));
   1600 		multipleGroup->addChild(new MultipleBindingCase(m_context, "zero_stride",							MultipleBindingCase::FLAG_ZERO_STRIDE));
   1601 		multipleGroup->addChild(new MultipleBindingCase(m_context, "instanced",								MultipleBindingCase::FLAG_INSTANCED));
   1602 		multipleGroup->addChild(new MultipleBindingCase(m_context, "aliasing_buffer_zero_stride",			MultipleBindingCase::FLAG_ALIASING_BUFFERS	| MultipleBindingCase::FLAG_ZERO_STRIDE));
   1603 		multipleGroup->addChild(new MultipleBindingCase(m_context, "aliasing_buffer_instanced",				MultipleBindingCase::FLAG_ALIASING_BUFFERS	| MultipleBindingCase::FLAG_INSTANCED));
   1604 
   1605 		// mixed cases
   1606 		mixedGroup->addChild(new MixedBindingCase(m_context,		"mixed_attribs_basic",					"Use different api for different attributes",			MixedBindingCase::CASE_BASIC));
   1607 		mixedGroup->addChild(new MixedBindingCase(m_context,		"mixed_attribs_instanced_binding",		"Use different api for different attributes",			MixedBindingCase::CASE_INSTANCED_BINDING));
   1608 		mixedGroup->addChild(new MixedBindingCase(m_context,		"mixed_attribs_instanced_attrib",		"Use different api for different attributes",			MixedBindingCase::CASE_INSTANCED_ATTRIB));
   1609 
   1610 		mixedGroup->addChild(new MixedApiCase(m_context,			"mixed_api_change_buffer",				"change buffer with vertex_attrib_binding api",			MixedApiCase::CASE_CHANGE_BUFFER));
   1611 		mixedGroup->addChild(new MixedApiCase(m_context,			"mixed_api_change_buffer_offset",		"change buffer offset with vertex_attrib_binding api",	MixedApiCase::CASE_CHANGE_BUFFER_OFFSET));
   1612 		mixedGroup->addChild(new MixedApiCase(m_context,			"mixed_api_change_buffer_stride",		"change buffer stride with vertex_attrib_binding api",	MixedApiCase::CASE_CHANGE_BUFFER_STRIDE));
   1613 		mixedGroup->addChild(new MixedApiCase(m_context,			"mixed_api_change_binding_point",		"change binding point with vertex_attrib_binding api",	MixedApiCase::CASE_CHANGE_BINDING_POINT));
   1614 	}
   1615 
   1616 	// negative
   1617 	{
   1618 		negativeGroup->addChild(new DefaultVAOCase(m_context,	"default_vao_bind_vertex_buffer",			"use with default vao",	DefaultVAOCase::CASE_BIND_VERTEX_BUFFER));
   1619 		negativeGroup->addChild(new DefaultVAOCase(m_context,	"default_vao_vertex_attrib_format",			"use with default vao",	DefaultVAOCase::CASE_VERTEX_ATTRIB_FORMAT));
   1620 		negativeGroup->addChild(new DefaultVAOCase(m_context,	"default_vao_vertex_attrib_i_format",		"use with default vao",	DefaultVAOCase::CASE_VERTEX_ATTRIB_I_FORMAT));
   1621 		negativeGroup->addChild(new DefaultVAOCase(m_context,	"default_vao_vertex_attrib_binding",		"use with default vao",	DefaultVAOCase::CASE_VERTEX_ATTRIB_BINDING));
   1622 		negativeGroup->addChild(new DefaultVAOCase(m_context,	"default_vao_vertex_binding_divisor",		"use with default vao",	DefaultVAOCase::CASE_VERTEX_BINDING_DIVISOR));
   1623 
   1624 		negativeGroup->addChild(new BindToCreateCase(m_context,	"bind_create_new_buffer",					"bind not existing buffer"));
   1625 
   1626 		negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_format_large_offset",			"large relative offset",	NegativeApiCase::CASE_LARGE_OFFSET));
   1627 		negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_large_stride",			"large stride",				NegativeApiCase::CASE_LARGE_STRIDE));
   1628 		negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_negative_stride",		"negative stride",			NegativeApiCase::CASE_NEGATIVE_STRIDE));
   1629 		negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_negative_offset",		"negative offset",			NegativeApiCase::CASE_NEGATIVE_OFFSET));
   1630 		negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_binding_invalid_attr",		"bind invalid attr",		NegativeApiCase::CASE_INVALID_ATTR));
   1631 		negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_binding_invalid_binding",		"bind invalid binding",		NegativeApiCase::CASE_INVALID_BINDING));
   1632 	}
   1633 }
   1634 
   1635 } // Functional
   1636 } // gles31
   1637 } // deqp
   1638