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