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 stress tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31sVertexAttributeBindingTests.hpp"
25#include "tcuVector.hpp"
26#include "tcuTestLog.hpp"
27#include "tcuRenderTarget.hpp"
28#include "tcuSurface.hpp"
29#include "gluCallLogWrapper.hpp"
30#include "gluObjectWrapper.hpp"
31#include "gluPixelTransfer.hpp"
32#include "gluRenderContext.hpp"
33#include "gluShaderProgram.hpp"
34#include "gluStrUtil.hpp"
35#include "glwFunctions.hpp"
36#include "glwEnums.hpp"
37#include "deStringUtil.hpp"
38
39namespace deqp
40{
41namespace gles31
42{
43namespace Stress
44{
45namespace
46{
47
48static const char* const s_vertexSource =				"#version 310 es\n"
49														"in highp vec4 a_position;\n"
50														"void main (void)\n"
51														"{\n"
52														"	gl_Position = a_position;\n"
53														"}\n";
54
55static const char* const s_fragmentSource =				"#version 310 es\n"
56														"layout(location = 0) out mediump vec4 fragColor;\n"
57														"void main (void)\n"
58														"{\n"
59														"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
60														"}\n";
61
62static const char* const s_colorFragmentShader =		"#version 310 es\n"
63														"in mediump vec4 v_color;\n"
64														"layout(location = 0) out mediump vec4 fragColor;\n"
65														"void main (void)\n"
66														"{\n"
67														"	fragColor = v_color;\n"
68														"}\n";
69
70// Verifies image contains only yellow or greeen, or a linear combination
71// of these colors.
72static bool verifyImageYellowGreen (const tcu::Surface& image, tcu::TestLog& log, bool logImageOnSuccess)
73{
74	using tcu::TestLog;
75
76	const tcu::RGBA green		(0, 255, 0, 255);
77	const tcu::RGBA yellow		(255, 255, 0, 255);
78	const int colorThreshold	= 20;
79
80	tcu::Surface error			(image.getWidth(), image.getHeight());
81	bool isOk					= true;
82
83	log << TestLog::Message << "Verifying image contents." << TestLog::EndMessage;
84
85	for (int y = 0; y < image.getHeight(); y++)
86	for (int x = 0; x < image.getWidth(); x++)
87	{
88		const tcu::RGBA pixel = image.getPixel(x, y);
89		bool pixelOk = true;
90
91		// Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
92		if (de::abs(pixel.getGreen() - 255) > colorThreshold)
93			pixelOk = false;
94
95		// Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
96		if (de::abs(pixel.getBlue() - 0) > colorThreshold)
97			pixelOk = false;
98
99		error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
100		isOk = isOk && pixelOk;
101	}
102
103	if (!isOk)
104	{
105		log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
106		log << TestLog::ImageSet("Verfication result", "Result of rendering")
107			<< TestLog::Image("Result",		"Result",		image)
108			<< TestLog::Image("ErrorMask",	"Error mask",	error)
109			<< TestLog::EndImageSet;
110	}
111	else
112	{
113		log << TestLog::Message << "Image verification passed." << TestLog::EndMessage;
114
115		if (logImageOnSuccess)
116			log << TestLog::ImageSet("Verfication result", "Result of rendering")
117				<< TestLog::Image("Result", "Result", image)
118				<< TestLog::EndImageSet;
119	}
120
121	return isOk;
122}
123
124class BindingRenderCase : public TestCase
125{
126public:
127	enum
128	{
129		TEST_RENDER_SIZE = 64
130	};
131
132						BindingRenderCase	(Context& ctx, const char* name, const char* desc, bool unalignedData);
133	virtual				~BindingRenderCase	(void);
134
135	virtual void		init				(void);
136	virtual void		deinit				(void);
137	IterateResult		iterate				(void);
138
139private:
140	virtual void		renderTo			(tcu::Surface& dst) = 0;
141	virtual void		createBuffers		(void) = 0;
142	virtual void		createShader		(void) = 0;
143
144protected:
145	const bool			m_unalignedData;
146	glw::GLuint			m_vao;
147	glu::ShaderProgram*	m_program;
148};
149
150BindingRenderCase::BindingRenderCase (Context& ctx, const char* name, const char* desc, bool unalignedData)
151	: TestCase			(ctx, name, desc)
152	, m_unalignedData	(unalignedData)
153	, m_vao				(0)
154	, m_program			(DE_NULL)
155{
156}
157
158BindingRenderCase::~BindingRenderCase (void)
159{
160	deinit();
161}
162
163void BindingRenderCase::init (void)
164{
165	// check requirements
166	if (m_context.getRenderTarget().getWidth() < TEST_RENDER_SIZE || m_context.getRenderTarget().getHeight() < TEST_RENDER_SIZE)
167		throw tcu::NotSupportedError("Test requires at least " + de::toString<int>(TEST_RENDER_SIZE) + "x" + de::toString<int>(TEST_RENDER_SIZE) + " render target");
168
169	// resources
170	m_context.getRenderContext().getFunctions().genVertexArrays(1, &m_vao);
171	if (m_context.getRenderContext().getFunctions().getError() != GL_NO_ERROR)
172		throw tcu::TestError("could not gen vao");
173
174	createBuffers();
175	createShader();
176}
177
178void BindingRenderCase::deinit (void)
179{
180	if (m_vao)
181	{
182		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
183		m_vao = 0;
184	}
185
186	delete m_program;
187	m_program = DE_NULL;
188}
189
190BindingRenderCase::IterateResult BindingRenderCase::iterate (void)
191{
192	tcu::Surface surface(TEST_RENDER_SIZE, TEST_RENDER_SIZE);
193
194	// draw pattern
195
196	renderTo(surface);
197
198	// verify results
199
200	if (verifyImageYellowGreen(surface, m_testCtx.getLog(), false))
201		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
202	else if (m_unalignedData)
203		m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned data");
204	else
205		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
206
207	return STOP;
208}
209
210class SingleBindingCase : public BindingRenderCase
211{
212public:
213
214	enum CaseFlag
215	{
216		FLAG_ATTRIB_UNALIGNED			= (1<<0),		// !< unalign attributes with relativeOffset
217		FLAG_ATTRIB_ALIGNED				= (1<<1),		// !< align attributes with relativeOffset to the buffer begin (and not buffer offset)
218		FLAG_ATTRIBS_MULTIPLE_ELEMS		= (1<<2),		// !< use multiple attribute elements
219		FLAG_ATTRIBS_SHARED_ELEMS		= (1<<3),		// !< use multiple shared attribute elements. xyzw & rgba stored as (x, y, zr, wg, b, a)
220
221		FLAG_BUF_ALIGNED_OFFSET			= (1<<4),		// !< use aligned offset to the buffer object
222		FLAG_BUF_UNALIGNED_OFFSET		= (1<<5),		// !< use unaligned offset to the buffer object
223		FLAG_BUF_UNALIGNED_STRIDE		= (1<<6),		// !< unalign buffer elements
224	};
225						SingleBindingCase	(Context& ctx, const char* name, int flags);
226						~SingleBindingCase	(void);
227
228	void				init				(void);
229	void				deinit				(void);
230
231private:
232	struct TestSpec
233	{
234		int		bufferOffset;
235		int		bufferStride;
236		int		positionAttrOffset;
237		int		colorAttrOffset;
238		bool	hasColorAttr;
239	};
240
241	enum
242	{
243		GRID_SIZE = 20
244	};
245
246	void				renderTo			(tcu::Surface& dst);
247
248	static TestSpec		genTestSpec			(int flags);
249	static std::string	genTestDescription	(int flags);
250	static bool			isDataUnaligned		(int flags);
251
252	void				createBuffers		(void);
253	void				createShader		(void);
254	std::string			genVertexSource		(void);
255
256	const TestSpec		m_spec;
257	glw::GLuint			m_buf;
258};
259
260SingleBindingCase::SingleBindingCase (Context& ctx, const char* name, int flags)
261	: BindingRenderCase	(ctx, name, genTestDescription(flags).c_str(), isDataUnaligned(flags))
262	, m_spec			(genTestSpec(flags))
263	, m_buf				(0)
264{
265	DE_ASSERT(!((flags & FLAG_ATTRIB_UNALIGNED) && (flags & FLAG_ATTRIB_ALIGNED)));
266	DE_ASSERT(!((flags & FLAG_ATTRIB_ALIGNED) && (flags & FLAG_BUF_UNALIGNED_STRIDE)));
267
268	DE_ASSERT(isDataUnaligned(flags));
269}
270
271SingleBindingCase::~SingleBindingCase (void)
272{
273	deinit();
274}
275
276void SingleBindingCase::init (void)
277{
278	// log what we are trying to do
279
280	m_testCtx.getLog()	<< tcu::TestLog::Message
281						<< "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n"
282						<< "Buffer format:\n"
283						<< "	bufferOffset: " << m_spec.bufferOffset << "\n"
284						<< "	bufferStride: " << m_spec.bufferStride << "\n"
285						<< "Vertex position format:\n"
286						<< "	type: float4\n"
287						<< "	offset: " << m_spec.positionAttrOffset << "\n"
288						<< "	total offset: " << m_spec.bufferOffset + m_spec.positionAttrOffset << "\n"
289						<< tcu::TestLog::EndMessage;
290
291	if (m_spec.hasColorAttr)
292		m_testCtx.getLog()	<< tcu::TestLog::Message
293							<< "Color:\n"
294							<< "	type: float4\n"
295							<< "	offset: " << m_spec.colorAttrOffset << "\n"
296							<< "	total offset: " << m_spec.bufferOffset + m_spec.colorAttrOffset << "\n"
297							<< tcu::TestLog::EndMessage;
298	// init
299
300	BindingRenderCase::init();
301}
302
303void SingleBindingCase::deinit (void)
304{
305	if (m_buf)
306	{
307		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buf);
308		m_buf = 0;
309	}
310
311	BindingRenderCase::deinit();
312}
313
314void SingleBindingCase::renderTo (tcu::Surface& dst)
315{
316	glu::CallLogWrapper gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
317	const int			positionLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
318	const int			colorLoc		= gl.glGetAttribLocation(m_program->getProgram(), "a_color");
319	const int			colorUniformLoc	= gl.glGetUniformLocation(m_program->getProgram(), "u_color");
320
321	gl.enableLogging(true);
322
323	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
324	gl.glClear(GL_COLOR_BUFFER_BIT);
325	gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
326	gl.glBindVertexArray(m_vao);
327	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
328
329	gl.glUseProgram(m_program->getProgram());
330	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
331
332	if (m_spec.hasColorAttr)
333	{
334		gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
335
336		gl.glVertexAttribBinding(positionLoc, 3);
337		gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
338		gl.glEnableVertexAttribArray(positionLoc);
339
340		gl.glVertexAttribBinding(colorLoc, 3);
341		gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, m_spec.colorAttrOffset);
342		gl.glEnableVertexAttribArray(colorLoc);
343
344		GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
345
346		gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6);
347		GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
348	}
349	else
350	{
351		gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
352		gl.glVertexAttribBinding(positionLoc, 3);
353		gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
354		gl.glEnableVertexAttribArray(positionLoc);
355
356		GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
357		gl.glUniform4f(colorUniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
358
359		gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6);
360		GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
361	}
362
363	gl.glFinish();
364	gl.glBindVertexArray(0);
365	gl.glUseProgram(0);
366	GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
367
368	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
369}
370
371SingleBindingCase::TestSpec SingleBindingCase::genTestSpec (int flags)
372{
373	const int	datumSize				= 4;
374	const int	bufferOffset			= (flags & FLAG_BUF_ALIGNED_OFFSET) ? (32) : (flags & FLAG_BUF_UNALIGNED_OFFSET) ? (19) : (0);
375	const int	attrBufAlignment		= ((bufferOffset % datumSize) == 0) ? (0) : (datumSize - (bufferOffset % datumSize));
376	const int	positionAttrOffset		= (flags & FLAG_ATTRIB_UNALIGNED) ? (3) : (flags & FLAG_ATTRIB_ALIGNED) ? (attrBufAlignment) : (0);
377	const bool	hasColorAttr			= (flags & FLAG_ATTRIBS_SHARED_ELEMS) || (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS);
378	const int	colorAttrOffset			= (flags & FLAG_ATTRIBS_SHARED_ELEMS) ? (2 * datumSize) : (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) ? (4 * datumSize) : (-1);
379
380	const int	bufferStrideBase		= de::max(positionAttrOffset + 4 * datumSize, colorAttrOffset + 4 * datumSize);
381	const int	bufferStrideAlignment	= ((bufferStrideBase % datumSize) == 0) ? (0) : (datumSize - (bufferStrideBase % datumSize));
382	const int	bufferStridePadding		= ((flags & FLAG_BUF_UNALIGNED_STRIDE) && deIsAligned32(bufferStrideBase, datumSize)) ? (13) : (!(flags & FLAG_BUF_UNALIGNED_STRIDE) && !deIsAligned32(bufferStrideBase, datumSize)) ? (bufferStrideAlignment) : (0);
383
384	TestSpec spec;
385
386	spec.bufferOffset			= bufferOffset;
387	spec.bufferStride			= bufferStrideBase + bufferStridePadding;
388	spec.positionAttrOffset		= positionAttrOffset;
389	spec.colorAttrOffset		= colorAttrOffset;
390	spec.hasColorAttr			= hasColorAttr;
391
392	if (flags & FLAG_ATTRIB_UNALIGNED)
393		DE_ASSERT(!deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
394	else if (flags & FLAG_ATTRIB_ALIGNED)
395		DE_ASSERT(deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
396
397	if (flags & FLAG_BUF_UNALIGNED_STRIDE)
398		DE_ASSERT(!deIsAligned32(spec.bufferStride, datumSize));
399	else
400		DE_ASSERT(deIsAligned32(spec.bufferStride, datumSize));
401
402	return spec;
403}
404
405std::string SingleBindingCase::genTestDescription (int flags)
406{
407	std::ostringstream buf;
408	buf << "draw test pattern";
409
410	if (flags & FLAG_ATTRIB_UNALIGNED)
411		buf << ", attribute offset (unaligned)";
412	if (flags & FLAG_ATTRIB_ALIGNED)
413		buf << ", attribute offset (aligned)";
414
415	if (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS)
416		buf << ", 2 attributes";
417	if (flags & FLAG_ATTRIBS_SHARED_ELEMS)
418		buf << ", 2 attributes (some components shared)";
419
420	if (flags & FLAG_BUF_ALIGNED_OFFSET)
421		buf << ", buffer offset aligned";
422	if (flags & FLAG_BUF_UNALIGNED_OFFSET)
423		buf << ", buffer offset unaligned";
424	if (flags & FLAG_BUF_UNALIGNED_STRIDE)
425		buf << ", buffer stride unaligned";
426
427	return buf.str();
428}
429
430bool SingleBindingCase::isDataUnaligned (int flags)
431{
432	if (flags & FLAG_ATTRIB_UNALIGNED)
433		return true;
434	if (flags & FLAG_ATTRIB_ALIGNED)
435		return false;
436
437	return (flags & FLAG_BUF_UNALIGNED_OFFSET) || (flags & FLAG_BUF_UNALIGNED_STRIDE);
438}
439
440void SingleBindingCase::createBuffers (void)
441{
442	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
443	std::vector<deUint8>	dataBuf	(m_spec.bufferOffset + m_spec.bufferStride * GRID_SIZE * GRID_SIZE * 6);
444
445	// In interleaved mode color rg and position zw are the same. Select "good" values for r and g
446	const tcu::Vec4			colorA	(0.0f, 1.0f, 0.0f, 1.0f);
447	const tcu::Vec4			colorB	(0.5f, 1.0f, 0.0f, 1.0f);
448
449	for (int y = 0; y < GRID_SIZE; ++y)
450	for (int x = 0; x < GRID_SIZE; ++x)
451	{
452		const tcu::Vec4&	color = ((x + y) % 2 == 0) ? (colorA) : (colorB);
453		const tcu::Vec4		positions[6] =
454		{
455			tcu::Vec4((x+0) / float(GRID_SIZE) * 2.0f - 1.0f, (y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
456			tcu::Vec4((x+0) / float(GRID_SIZE) * 2.0f - 1.0f, (y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
457			tcu::Vec4((x+1) / float(GRID_SIZE) * 2.0f - 1.0f, (y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
458			tcu::Vec4((x+0) / float(GRID_SIZE) * 2.0f - 1.0f, (y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
459			tcu::Vec4((x+1) / float(GRID_SIZE) * 2.0f - 1.0f, (y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
460			tcu::Vec4((x+1) / float(GRID_SIZE) * 2.0f - 1.0f, (y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f),
461		};
462
463		// copy cell vertices to the buffer.
464		for (int v = 0; v < 6; ++v)
465			memcpy(&dataBuf[m_spec.bufferOffset + m_spec.positionAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], positions[v].getPtr(), sizeof(positions[v]));
466
467		// copy color to buffer
468		if (m_spec.hasColorAttr)
469			for (int v = 0; v < 6; ++v)
470				memcpy(&dataBuf[m_spec.bufferOffset + m_spec.colorAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], color.getPtr(), sizeof(color));
471	}
472
473	gl.genBuffers(1, &m_buf);
474	gl.bindBuffer(GL_ARRAY_BUFFER, m_buf);
475	gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)dataBuf.size(), &dataBuf[0], GL_STATIC_DRAW);
476	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
477
478	if (gl.getError() != GL_NO_ERROR)
479		throw tcu::TestError("could not init buffer");
480}
481
482void SingleBindingCase::createShader (void)
483{
484	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(s_colorFragmentShader));
485	m_testCtx.getLog() << *m_program;
486
487	if (!m_program->isOk())
488		throw tcu::TestError("could not build shader");
489}
490
491std::string SingleBindingCase::genVertexSource (void)
492{
493	const bool			useUniformColor = !m_spec.hasColorAttr;
494	std::ostringstream	buf;
495
496	buf <<	"#version 310 es\n"
497			"in highp vec4 a_position;\n";
498
499	if (!useUniformColor)
500		buf << "in highp vec4 a_color;\n";
501	else
502		buf << "uniform highp vec4 u_color;\n";
503
504	buf <<	"out highp vec4 v_color;\n"
505			"void main (void)\n"
506			"{\n"
507			"	gl_Position = a_position;\n"
508			"	v_color = " << ((useUniformColor) ? ("u_color") : ("a_color")) << ";\n"
509			"}\n";
510
511	return buf.str();
512}
513
514class BindVertexBufferCase : public TestCase
515{
516public:
517						BindVertexBufferCase	(Context& ctx, const char* name, const char* desc, int offset, int drawCount);
518						~BindVertexBufferCase	(void);
519
520	void				init					(void);
521	void				deinit					(void);
522	IterateResult		iterate					(void);
523
524private:
525	const int			m_offset;
526	const int			m_drawCount;
527	deUint32			m_buffer;
528	glu::ShaderProgram*	m_program;
529};
530
531BindVertexBufferCase::BindVertexBufferCase (Context& ctx, const char* name, const char* desc, int offset, int drawCount)
532	: TestCase		(ctx, name, desc)
533	, m_offset		(offset)
534	, m_drawCount	(drawCount)
535	, m_buffer		(0)
536	, m_program		(DE_NULL)
537{
538}
539
540BindVertexBufferCase::~BindVertexBufferCase (void)
541{
542	deinit();
543}
544
545void BindVertexBufferCase::init (void)
546{
547	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
548	std::vector<tcu::Vec4>	data	(m_drawCount); // !< some junk data to make sure buffer is really allocated
549
550	gl.genBuffers(1, &m_buffer);
551	gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
552	gl.bufferData(GL_ARRAY_BUFFER, int(m_drawCount * sizeof(tcu::Vec4)), &data[0], GL_STATIC_DRAW);
553	GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen");
554
555	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_vertexSource) << glu::FragmentSource(s_fragmentSource));
556	if (!m_program->isOk())
557	{
558		m_testCtx.getLog() << *m_program;
559		throw tcu::TestError("could not build program");
560	}
561}
562
563void BindVertexBufferCase::deinit (void)
564{
565	if (m_buffer)
566	{
567		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
568		m_buffer = 0;
569	}
570
571	delete m_program;
572	m_program = DE_NULL;
573}
574
575BindVertexBufferCase::IterateResult BindVertexBufferCase::iterate (void)
576{
577	glu::CallLogWrapper		gl			(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
578	const deInt32			positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
579	tcu::Surface			dst			(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight());
580	glu::VertexArray		vao			(m_context.getRenderContext());
581
582	gl.enableLogging(true);
583
584	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
585	gl.glClear(GL_COLOR_BUFFER_BIT);
586	GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup");
587
588	gl.glUseProgram(m_program->getProgram());
589	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
590
591	gl.glBindVertexArray(*vao);
592	gl.glEnableVertexAttribArray(positionLoc);
593	gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
594	gl.glVertexAttribBinding(positionLoc, 0);
595	gl.glBindVertexBuffer(0, m_buffer, m_offset, int(sizeof(tcu::Vec4)));
596	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set buffer");
597
598	gl.glDrawArrays(GL_POINTS, 0, m_drawCount);
599
600	// allow errors after attempted out-of-bounds memory access
601	{
602		const deUint32 error = gl.glGetError();
603
604		if (error != GL_NO_ERROR)
605			m_testCtx.getLog() << tcu::TestLog::Message << "Got error: " << glu::getErrorStr(error) << ", ignoring..." << tcu::TestLog::EndMessage;
606	}
607
608	// read pixels to wait for rendering
609	gl.glFinish();
610	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
611
612	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
613	return STOP;
614}
615
616} // anonymous
617
618VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
619	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding stress tests")
620{
621}
622
623VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
624{
625}
626
627void VertexAttributeBindingTests::init (void)
628{
629	tcu::TestCaseGroup* const unalignedGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned",		"Unaligned access");
630	tcu::TestCaseGroup* const bufferRangeGroup	= new tcu::TestCaseGroup(m_testCtx, "buffer_bounds",	"Source data over buffer bounds");
631
632	addChild(unalignedGroup);
633	addChild(bufferRangeGroup);
634
635	// .unaligned
636	{
637		unalignedGroup->addChild(new SingleBindingCase(m_context, "elements_1_unaligned",																		  SingleBindingCase::FLAG_ATTRIB_UNALIGNED));
638		unalignedGroup->addChild(new SingleBindingCase(m_context, "offset_elements_1_unaligned",				SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET		| SingleBindingCase::FLAG_ATTRIB_UNALIGNED));
639
640		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1",				SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET	| 0));
641		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1_unaligned",		SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET	| SingleBindingCase::FLAG_ATTRIB_UNALIGNED));
642		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_2",				SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET	| SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
643		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_2_share_elements",	SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET	| SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
644
645		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_1",				SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE	| 0));
646		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_2",				SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE	| SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
647		unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_2_share_elements",	SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE	| SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
648	}
649
650	// .buffer_bounds
651	{
652		// bind buffer offset cases
653		bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_over_bounds_10",		"Offset over buffer bounds",				0x00210000, 10));
654		bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_over_bounds_1000",	"Offset over buffer bounds",				0x00210000, 1000));
655		bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_near_wrap_10",		"Offset over buffer bounds, near wrapping",	0x7FFFFFF0, 10));
656		bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_near_wrap_1000",		"Offset over buffer bounds, near wrapping",	0x7FFFFFF0, 1000));
657	}
658}
659
660} // Stress
661} // gles31
662} // deqp
663