• 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 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 
124 class BindingRenderCase : public TestCase
125 {
126 public:
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 
139 private:
140 	virtual void		renderTo			(tcu::Surface& dst) = 0;
141 	virtual void		createBuffers		(void) = 0;
142 	virtual void		createShader		(void) = 0;
143 
144 protected:
145 	const bool			m_unalignedData;
146 	glw::GLuint			m_vao;
147 	glu::ShaderProgram*	m_program;
148 };
149 
BindingRenderCase(Context & ctx,const char * name,const char * desc,bool unalignedData)150 BindingRenderCase::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 
~BindingRenderCase(void)158 BindingRenderCase::~BindingRenderCase (void)
159 {
160 	deinit();
161 }
162 
init(void)163 void 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 
deinit(void)178 void 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 
iterate(void)190 BindingRenderCase::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 
210 class SingleBindingCase : public BindingRenderCase
211 {
212 public:
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 
231 private:
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 
SingleBindingCase(Context & ctx,const char * name,int flags)260 SingleBindingCase::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 
~SingleBindingCase(void)271 SingleBindingCase::~SingleBindingCase (void)
272 {
273 	deinit();
274 }
275 
init(void)276 void 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 
deinit(void)303 void 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 
renderTo(tcu::Surface & dst)314 void 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 
genTestSpec(int flags)371 SingleBindingCase::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 
genTestDescription(int flags)405 std::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 
isDataUnaligned(int flags)430 bool 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 
createBuffers(void)440 void 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 
createShader(void)482 void 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 
genVertexSource(void)491 std::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 
514 class BindVertexBufferCase : public TestCase
515 {
516 public:
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 
524 private:
525 	const int			m_offset;
526 	const int			m_drawCount;
527 	deUint32			m_buffer;
528 	glu::ShaderProgram*	m_program;
529 };
530 
BindVertexBufferCase(Context & ctx,const char * name,const char * desc,int offset,int drawCount)531 BindVertexBufferCase::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 
~BindVertexBufferCase(void)540 BindVertexBufferCase::~BindVertexBufferCase (void)
541 {
542 	deinit();
543 }
544 
init(void)545 void 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 
deinit(void)563 void 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 
iterate(void)575 BindVertexBufferCase::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 
VertexAttributeBindingTests(Context & context)618 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
619 	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding stress tests")
620 {
621 }
622 
~VertexAttributeBindingTests(void)623 VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
624 {
625 }
626 
init(void)627 void 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