Home | History | Annotate | Download | only in stress
      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.
     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 
    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 
    156 BindingRenderCase::~BindingRenderCase (void)
    157 {
    158 	deinit();
    159 }
    160 
    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 
    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 
    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 
    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 
    269 SingleBindingCase::~SingleBindingCase (void)
    270 {
    271 	deinit();
    272 }
    273 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    538 BindVertexBufferCase::~BindVertexBufferCase (void)
    539 {
    540 	deinit();
    541 }
    542 
    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 
    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 
    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 
    616 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
    617 	: TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding stress tests")
    618 {
    619 }
    620 
    621 VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
    622 {
    623 }
    624 
    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