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 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
128class BindingRenderCase : public TestCase
129{
130public:
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
143private:
144	virtual void		renderTo			(tcu::Surface& dst) = 0;
145	virtual void		createBuffers		(void) = 0;
146	virtual void		createShader		(void) = 0;
147
148protected:
149	const bool			m_unalignedData;
150	glw::GLuint			m_vao;
151	glu::ShaderProgram*	m_program;
152};
153
154BindingRenderCase::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
162BindingRenderCase::~BindingRenderCase (void)
163{
164	deinit();
165}
166
167void 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
182void 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
194BindingRenderCase::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
214class SingleBindingCase : public BindingRenderCase
215{
216public:
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
235private:
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
264SingleBindingCase::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
275SingleBindingCase::~SingleBindingCase (void)
276{
277	deinit();
278}
279
280void 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
307void 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
318void 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
375SingleBindingCase::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
409std::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
434bool 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
444void 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
486void 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
495std::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
518class MultipleBindingCase : public BindingRenderCase
519{
520public:
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
535private:
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
560MultipleBindingCase::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
569MultipleBindingCase::~MultipleBindingCase (void)
570{
571	deinit();
572}
573
574void 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
597void 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
614void 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
682MultipleBindingCase::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
693std::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
708void 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 / float(GRID_SIZE),	0.0f, 1.0f);
740		primitiveData[2] = tcu::Vec4(2.0f / float(GRID_SIZE),	2.0f / float(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 / float(GRID_SIZE),	2.0f / float(GRID_SIZE),	0.0f, 1.0f);
743		primitiveData[5] = tcu::Vec4(2.0f / float(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
809void 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
818class MixedBindingCase : public BindingRenderCase
819{
820public:
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
837private:
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
852MixedBindingCase::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
861MixedBindingCase::~MixedBindingCase (void)
862{
863	deinit();
864}
865
866void MixedBindingCase::init (void)
867{
868	BindingRenderCase::init();
869}
870
871void 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
888void MixedBindingCase::renderTo (tcu::Surface& dst)
889{
890	glu::CallLogWrapper gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
891	const int			positionLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
892	const int			colorLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_color");
893	const int			offsetLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_offset");
894
895	gl.enableLogging(true);
896
897	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
898	gl.glClear(GL_COLOR_BUFFER_BIT);
899	gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
900	gl.glBindVertexArray(m_vao);
901	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
902
903	gl.glUseProgram(m_program->getProgram());
904	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
905
906	switch (m_case)
907	{
908		case CASE_BASIC:
909		{
910			// bind position using vertex_attrib_binding api
911
912			gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4));
913			gl.glVertexAttribBinding(positionLoc, positionLoc);
914			gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
915			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
916
917			// bind color using old api
918
919			gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
920			gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL);
921			gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
922			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
923
924			// draw
925			gl.glEnableVertexAttribArray(positionLoc);
926			gl.glEnableVertexAttribArray(colorLoc);
927			gl.glEnableVertexAttribArray(offsetLoc);
928			gl.glDrawArrays(GL_TRIANGLES, 0, 6*GRID_SIZE*GRID_SIZE);
929			break;
930		}
931
932		case CASE_INSTANCED_BINDING:
933		{
934			// bind position using old api
935			gl.glBindBuffer(GL_ARRAY_BUFFER, m_posBuffer);
936			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
937			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
938
939			// bind color using vertex_attrib_binding api
940			gl.glBindVertexBuffer(colorLoc, m_colorOffsetBuffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
941			gl.glVertexBindingDivisor(colorLoc, 1);
942
943			gl.glVertexAttribBinding(colorLoc, colorLoc);
944			gl.glVertexAttribBinding(offsetLoc, colorLoc);
945
946			gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
947			gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4));
948
949			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
950
951			// draw
952			gl.glEnableVertexAttribArray(positionLoc);
953			gl.glEnableVertexAttribArray(colorLoc);
954			gl.glEnableVertexAttribArray(offsetLoc);
955			gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE);
956			break;
957		}
958
959		case CASE_INSTANCED_ATTRIB:
960		{
961			// bind position using vertex_attrib_binding api
962			gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4));
963			gl.glVertexAttribBinding(positionLoc, positionLoc);
964			gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
965			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
966
967			// bind color using old api
968			gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
969			gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL);
970			gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
971			gl.glVertexAttribDivisor(colorLoc, 1);
972			gl.glVertexAttribDivisor(offsetLoc, 1);
973			GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
974
975			// draw
976			gl.glEnableVertexAttribArray(positionLoc);
977			gl.glEnableVertexAttribArray(colorLoc);
978			gl.glEnableVertexAttribArray(offsetLoc);
979			gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE);
980			break;
981		}
982
983		default:
984			DE_ASSERT(DE_FALSE);
985	}
986
987	gl.glFinish();
988	gl.glBindVertexArray(0);
989	gl.glUseProgram(0);
990	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
991
992	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
993}
994
995void 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 / float(GRID_SIZE),	0.0f, 1.0f);
1018		positionData[primNdx*6 + 2] =  tcu::Vec4(2.0f / float(GRID_SIZE),	2.0f / float(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 / float(GRID_SIZE),	2.0f / float(GRID_SIZE),	0.0f, 1.0f);
1021		positionData[primNdx*6 + 5] =  tcu::Vec4(2.0f / float(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
1051void 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
1060class MixedApiCase : public BindingRenderCase
1061{
1062public:
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
1080private:
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
1095MixedApiCase::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
1103MixedApiCase::~MixedApiCase (void)
1104{
1105	deinit();
1106}
1107
1108void MixedApiCase::init (void)
1109{
1110	BindingRenderCase::init();
1111}
1112
1113void 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
1124void 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				unusedBuffer	(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, *unusedBuffer);
1149			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
1150			gl.glVertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
1151
1152			// change buffer with vertex_attrib_binding
1153
1154			gl.glBindVertexBuffer(positionLoc, m_buffer, 0,                 (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1155			gl.glBindVertexBuffer(colorLoc,    m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1156
1157			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1158			break;
1159		}
1160
1161		case CASE_CHANGE_BUFFER_OFFSET:
1162		{
1163			// bind data using old api
1164
1165			gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
1166			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
1167			gl.glVertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
1168
1169			// change buffer offset with vertex_attrib_binding
1170
1171			gl.glBindVertexBuffer(positionLoc, m_buffer, 0,                 (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1172			gl.glBindVertexBuffer(colorLoc,    m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1173
1174			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1175			break;
1176		}
1177
1178		case CASE_CHANGE_BUFFER_STRIDE:
1179		{
1180			// bind data using old api
1181
1182			gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
1183			gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8, (const deUint8*)DE_NULL);
1184			gl.glVertexAttribPointer(colorLoc,    4, GL_FLOAT, GL_FALSE, 4, (const deUint8*)DE_NULL);
1185
1186			// change buffer stride with vertex_attrib_binding
1187
1188			gl.glBindVertexBuffer(positionLoc, m_buffer, 0,                 (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1189			gl.glBindVertexBuffer(colorLoc,    m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1190
1191			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1192			break;
1193		}
1194
1195		case CASE_CHANGE_BINDING_POINT:
1196		{
1197			const int maxUsedLocation	= de::max(positionLoc, colorLoc);
1198			const int bindingPoint1		= maxUsedLocation + 1;
1199			const int bindingPoint2		= maxUsedLocation + 2;
1200
1201			// bind data using old api
1202
1203			gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
1204			gl.glVertexAttribPointer(bindingPoint1, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL);
1205			gl.glVertexAttribPointer(bindingPoint2, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
1206
1207			// change buffer binding point with vertex_attrib_binding
1208
1209			gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
1210			gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
1211
1212			gl.glVertexAttribBinding(positionLoc, bindingPoint1);
1213			gl.glVertexAttribBinding(colorLoc, bindingPoint2);
1214
1215			GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1216			break;
1217		}
1218
1219		default:
1220			DE_ASSERT(DE_FALSE);
1221	}
1222
1223	// draw
1224	gl.glEnableVertexAttribArray(positionLoc);
1225	gl.glEnableVertexAttribArray(colorLoc);
1226	gl.glDrawArrays(GL_TRIANGLES, 0, 6*GRID_SIZE*GRID_SIZE);
1227
1228	gl.glFinish();
1229	gl.glBindVertexArray(0);
1230	gl.glUseProgram(0);
1231	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
1232
1233	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1234}
1235
1236void 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
1271void 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
1280class DefaultVAOCase : public TestCase
1281{
1282public:
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
1299private:
1300	const CaseType	m_caseType;
1301};
1302
1303DefaultVAOCase::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
1310DefaultVAOCase::~DefaultVAOCase (void)
1311{
1312}
1313
1314DefaultVAOCase::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
1363class BindToCreateCase : public TestCase
1364{
1365public:
1366					BindToCreateCase	(Context& ctx, const char* name, const char* desc);
1367					~BindToCreateCase	(void);
1368
1369	IterateResult	iterate				(void);
1370};
1371
1372BindToCreateCase::BindToCreateCase (Context& ctx, const char* name, const char* desc)
1373	: TestCase(ctx, name, desc)
1374{
1375}
1376
1377BindToCreateCase::~BindToCreateCase (void)
1378{
1379}
1380
1381BindToCreateCase::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
1410class NegativeApiCase : public TestCase
1411{
1412public:
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
1429private:
1430	const CaseType	m_caseType;
1431};
1432
1433NegativeApiCase::NegativeApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType)
1434	: TestCase		(ctx, name, desc)
1435	, m_caseType	(caseType)
1436{
1437}
1438
1439NegativeApiCase::~NegativeApiCase (void)
1440{
1441}
1442
1443NegativeApiCase::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
1560VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
1561	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding")
1562{
1563}
1564
1565VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
1566{
1567}
1568
1569void 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