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.
verifyImageYellowGreen(const tcu::Surface & image,tcu::TestLog & log,bool logImageOnSuccess)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 
BindingRenderCase(Context & ctx,const char * name,const char * desc,bool unalignedData)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 
~BindingRenderCase(void)162 BindingRenderCase::~BindingRenderCase (void)
163 {
164 	deinit();
165 }
166 
init(void)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 
deinit(void)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 
iterate(void)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 
SingleBindingCase(Context & ctx,const char * name,int flags)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 
~SingleBindingCase(void)275 SingleBindingCase::~SingleBindingCase (void)
276 {
277 	deinit();
278 }
279 
init(void)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 
deinit(void)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 
renderTo(tcu::Surface & dst)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 
genTestSpec(int flags)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 
genTestDescription(int flags)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 
isDataUnaligned(int flags)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 
createBuffers(void)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 
createShader(void)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 
genVertexSource(void)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 
MultipleBindingCase(Context & ctx,const char * name,int flags)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 
~MultipleBindingCase(void)569 MultipleBindingCase::~MultipleBindingCase (void)
570 {
571 	deinit();
572 }
573 
init(void)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 
deinit(void)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 
renderTo(tcu::Surface & dst)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 
genTestSpec(int flags) const682 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 
genTestDescription(int flags) const693 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 
createBuffers(void)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 
createShader(void)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 
MixedBindingCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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 
~MixedBindingCase(void)861 MixedBindingCase::~MixedBindingCase (void)
862 {
863 	deinit();
864 }
865 
init(void)866 void MixedBindingCase::init (void)
867 {
868 	BindingRenderCase::init();
869 }
870 
deinit(void)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 
renderTo(tcu::Surface & dst)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)), (deUint8*)DE_NULL + 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)), (deUint8*)DE_NULL + 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 
createBuffers(void)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 
createShader(void)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 
MixedApiCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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 
~MixedApiCase(void)1103 MixedApiCase::~MixedApiCase (void)
1104 {
1105 	deinit();
1106 }
1107 
init(void)1108 void MixedApiCase::init (void)
1109 {
1110 	BindingRenderCase::init();
1111 }
1112 
deinit(void)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 
renderTo(tcu::Surface & dst)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)), (const deUint8*)DE_NULL + 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)), (const deUint8*)DE_NULL + 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 
createBuffers(void)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 
createShader(void)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 
DefaultVAOCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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 
~DefaultVAOCase(void)1310 DefaultVAOCase::~DefaultVAOCase (void)
1311 {
1312 }
1313 
iterate(void)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 
BindToCreateCase(Context & ctx,const char * name,const char * desc)1372 BindToCreateCase::BindToCreateCase (Context& ctx, const char* name, const char* desc)
1373 	: TestCase(ctx, name, desc)
1374 {
1375 }
1376 
~BindToCreateCase(void)1377 BindToCreateCase::~BindToCreateCase (void)
1378 {
1379 }
1380 
iterate(void)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 
NegativeApiCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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 
~NegativeApiCase(void)1439 NegativeApiCase::~NegativeApiCase (void)
1440 {
1441 }
1442 
iterate(void)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 
VertexAttributeBindingTests(Context & context)1560 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
1561 	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding")
1562 {
1563 }
1564 
~VertexAttributeBindingTests(void)1565 VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
1566 {
1567 }
1568 
init(void)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