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
38namespace deqp
39{
40namespace gles31
41{
42namespace Functional
43{
44namespace
45{
46
47static 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
55static 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
65static 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.
78static 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
130class BindingRenderCase : public TestCase
131{
132public:
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
145private:
146	virtual void		renderTo			(tcu::Surface& dst) = 0;
147	virtual void		createBuffers		(void) = 0;
148	virtual void		createShader		(void) = 0;
149
150protected:
151	const bool			m_unalignedData;
152	glw::GLuint			m_vao;
153	glu::ShaderProgram*	m_program;
154};
155
156BindingRenderCase::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
164BindingRenderCase::~BindingRenderCase (void)
165{
166	deinit();
167}
168
169void 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
184void 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
196BindingRenderCase::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
216class SingleBindingCase : public BindingRenderCase
217{
218public:
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
237private:
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
266SingleBindingCase::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
277SingleBindingCase::~SingleBindingCase (void)
278{
279	deinit();
280}
281
282void 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
309void 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
320void 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
377SingleBindingCase::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
411std::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
436bool 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
446void 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
488void 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
497std::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
520class MultipleBindingCase : public BindingRenderCase
521{
522public:
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
537private:
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
562MultipleBindingCase::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
571MultipleBindingCase::~MultipleBindingCase (void)
572{
573	deinit();
574}
575
576void 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
599void 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
616void 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
684MultipleBindingCase::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
695std::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
710void 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
811void 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
820class MixedBindingCase : public BindingRenderCase
821{
822public:
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
839private:
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
854MixedBindingCase::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
863MixedBindingCase::~MixedBindingCase (void)
864{
865	deinit();
866}
867
868void MixedBindingCase::init (void)
869{
870	BindingRenderCase::init();
871}
872
873void 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
890void 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
997void 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
1053void 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
1062class MixedApiCase : public BindingRenderCase
1063{
1064public:
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
1082private:
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
1097MixedApiCase::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
1105MixedApiCase::~MixedApiCase (void)
1106{
1107	deinit();
1108}
1109
1110void MixedApiCase::init (void)
1111{
1112	BindingRenderCase::init();
1113}
1114
1115void 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
1126void 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
1238void 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
1273void 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
1282class DefaultVAOCase : public TestCase
1283{
1284public:
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
1301private:
1302	const CaseType	m_caseType;
1303};
1304
1305DefaultVAOCase::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
1312DefaultVAOCase::~DefaultVAOCase (void)
1313{
1314}
1315
1316DefaultVAOCase::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
1365class BindToCreateCase : public TestCase
1366{
1367public:
1368					BindToCreateCase	(Context& ctx, const char* name, const char* desc);
1369					~BindToCreateCase	(void);
1370
1371	IterateResult	iterate				(void);
1372};
1373
1374BindToCreateCase::BindToCreateCase (Context& ctx, const char* name, const char* desc)
1375	: TestCase(ctx, name, desc)
1376{
1377}
1378
1379BindToCreateCase::~BindToCreateCase (void)
1380{
1381}
1382
1383BindToCreateCase::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
1412class NegativeApiCase : public TestCase
1413{
1414public:
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
1431private:
1432	const CaseType	m_caseType;
1433};
1434
1435NegativeApiCase::NegativeApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType)
1436	: TestCase		(ctx, name, desc)
1437	, m_caseType	(caseType)
1438{
1439}
1440
1441NegativeApiCase::~NegativeApiCase (void)
1442{
1443}
1444
1445NegativeApiCase::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
1562VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
1563	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding")
1564{
1565}
1566
1567VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
1568{
1569}
1570
1571void 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