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