Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 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 Buffer test utilities.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fBufferTestUtil.hpp"
     25 #include "tcuRandomValueIterator.hpp"
     26 #include "tcuSurface.hpp"
     27 #include "tcuImageCompare.hpp"
     28 #include "tcuVector.hpp"
     29 #include "tcuFormatUtil.hpp"
     30 #include "tcuTextureUtil.hpp"
     31 #include "tcuRenderTarget.hpp"
     32 #include "gluPixelTransfer.hpp"
     33 #include "gluRenderContext.hpp"
     34 #include "gluStrUtil.hpp"
     35 #include "gluShaderProgram.hpp"
     36 #include "deMemory.h"
     37 #include "deStringUtil.hpp"
     38 
     39 #include <algorithm>
     40 
     41 #include "glwEnums.hpp"
     42 #include "glwFunctions.hpp"
     43 
     44 namespace deqp
     45 {
     46 namespace gles2
     47 {
     48 namespace Functional
     49 {
     50 namespace BufferTestUtil
     51 {
     52 
     53 enum
     54 {
     55 	VERIFY_QUAD_SIZE					= 8,		//!< Quad size in VertexArrayVerifier
     56 	MAX_LINES_PER_INDEX_ARRAY_DRAW		= 128,		//!< Maximum number of lines per one draw in IndexArrayVerifier
     57 	INDEX_ARRAY_DRAW_VIEWPORT_WIDTH		= 128,
     58 	INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT	= 128
     59 };
     60 
     61 static const bool LOG_VERIFIER_CALLS = false; //! \note Especially array verifier generates a lot of calls.
     62 
     63 using tcu::TestLog;
     64 using std::vector;
     65 using std::string;
     66 using std::set;
     67 
     68 // Helper functions.
     69 
     70 void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed)
     71 {
     72 	std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr);
     73 }
     74 
     75 bool compareByteArrays (tcu::TestLog& log, const deUint8* resPtr, const deUint8* refPtr, int numBytes)
     76 {
     77 	bool			isOk			= true;
     78 	const int		maxSpanLen		= 8;
     79 	const int		maxDiffSpans	= 4;
     80 	int				numDiffSpans	= 0;
     81 	int				diffSpanStart	= -1;
     82 	int				ndx				= 0;
     83 
     84 	log << TestLog::Section("Verify", "Verification result");
     85 
     86 	for (;ndx < numBytes; ndx++)
     87 	{
     88 		if (resPtr[ndx] != refPtr[ndx])
     89 		{
     90 			if (diffSpanStart < 0)
     91 				diffSpanStart = ndx;
     92 
     93 			isOk = false;
     94 		}
     95 		else if (diffSpanStart >= 0)
     96 		{
     97 			if (numDiffSpans < maxDiffSpans)
     98 			{
     99 				int len			= ndx-diffSpanStart;
    100 				int	printLen	= de::min(len, maxSpanLen);
    101 
    102 				log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n"
    103 										<< "  expected "	<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n"
    104 										<< "  got "			<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen))
    105 					<< TestLog::EndMessage;
    106 			}
    107 			else
    108 				log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
    109 
    110 			numDiffSpans	+= 1;
    111 			diffSpanStart	 = -1;
    112 		}
    113 	}
    114 
    115 	if (diffSpanStart >= 0)
    116 	{
    117 		if (numDiffSpans < maxDiffSpans)
    118 		{
    119 				int len			= ndx-diffSpanStart;
    120 				int	printLen	= de::min(len, maxSpanLen);
    121 
    122 				log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n"
    123 										<< "  expected "	<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n"
    124 										<< "  got "			<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen))
    125 					<< TestLog::EndMessage;
    126 		}
    127 		else
    128 			log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
    129 	}
    130 
    131 	log << TestLog::Message << (isOk ? "Verification passed." : "Verification FAILED!") << TestLog::EndMessage;
    132 	log << TestLog::EndSection;
    133 
    134 	return isOk;
    135 }
    136 
    137 const char* getBufferTargetName (deUint32 target)
    138 {
    139 	switch (target)
    140 	{
    141 		case GL_ARRAY_BUFFER:				return "array";
    142 		case GL_ELEMENT_ARRAY_BUFFER:		return "element_array";
    143 		default:
    144 			DE_ASSERT(false);
    145 			return DE_NULL;
    146 	}
    147 }
    148 
    149 const char* getUsageHintName (deUint32 hint)
    150 {
    151 	switch (hint)
    152 	{
    153 		case GL_STREAM_DRAW:	return "stream_draw";
    154 		case GL_STATIC_DRAW:	return "static_draw";
    155 		case GL_DYNAMIC_DRAW:	return "dynamic_draw";
    156 		default:
    157 			DE_ASSERT(false);
    158 			return DE_NULL;
    159 	}
    160 }
    161 
    162 // BufferCase
    163 
    164 BufferCase::BufferCase (Context& context, const char* name, const char* description)
    165 	: TestCase			(context, name, description)
    166 	, CallLogWrapper	(context.getRenderContext().getFunctions(), m_context.getTestContext().getLog())
    167 {
    168 }
    169 
    170 BufferCase::~BufferCase (void)
    171 {
    172 	enableLogging(false);
    173 	BufferCase::deinit();
    174 }
    175 
    176 void BufferCase::init (void)
    177 {
    178 	enableLogging(true);
    179 }
    180 
    181 void BufferCase::deinit (void)
    182 {
    183 	for (set<deUint32>::const_iterator bufIter = m_allocatedBuffers.begin(); bufIter != m_allocatedBuffers.end(); bufIter++)
    184 		glDeleteBuffers(1, &(*bufIter));
    185 }
    186 
    187 deUint32 BufferCase::genBuffer (void)
    188 {
    189 	deUint32 buf = 0;
    190 	glGenBuffers(1, &buf);
    191 	if (buf != 0)
    192 	{
    193 		try
    194 		{
    195 			m_allocatedBuffers.insert(buf);
    196 		}
    197 		catch (const std::exception&)
    198 		{
    199 			glDeleteBuffers(1, &buf);
    200 			throw;
    201 		}
    202 	}
    203 	return buf;
    204 }
    205 
    206 void BufferCase::deleteBuffer (deUint32 buffer)
    207 {
    208 	glDeleteBuffers(1, &buffer);
    209 	m_allocatedBuffers.erase(buffer);
    210 }
    211 
    212 void BufferCase::checkError (void)
    213 {
    214 	glw::GLenum err = glGetError();
    215 	if (err != GL_NO_ERROR)
    216 		throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
    217 }
    218 
    219 // ReferenceBuffer
    220 
    221 void ReferenceBuffer::setSize (int numBytes)
    222 {
    223 	m_data.resize(numBytes);
    224 }
    225 
    226 void ReferenceBuffer::setData (int numBytes, const deUint8* bytes)
    227 {
    228 	m_data.resize(numBytes);
    229 	std::copy(bytes, bytes+numBytes, m_data.begin());
    230 }
    231 
    232 void ReferenceBuffer::setSubData (int offset, int numBytes, const deUint8* bytes)
    233 {
    234 	DE_ASSERT(de::inBounds(offset, 0, (int)m_data.size()) && de::inRange(offset+numBytes, offset, (int)m_data.size()));
    235 	std::copy(bytes, bytes+numBytes, m_data.begin()+offset);
    236 }
    237 
    238 // BufferVerifierBase
    239 
    240 BufferVerifierBase::BufferVerifierBase (Context& context)
    241 	: CallLogWrapper	(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
    242 	, m_context			(context)
    243 {
    244 	enableLogging(LOG_VERIFIER_CALLS);
    245 }
    246 
    247 // BufferVerifier
    248 
    249 BufferVerifier::BufferVerifier (Context& context, VerifyType verifyType)
    250 	: m_verifier(DE_NULL)
    251 {
    252 	switch (verifyType)
    253 	{
    254 		case VERIFY_AS_VERTEX_ARRAY:	m_verifier = new VertexArrayVerifier(context);	break;
    255 		case VERIFY_AS_INDEX_ARRAY:		m_verifier = new IndexArrayVerifier	(context);	break;
    256 		default:
    257 			TCU_FAIL("Unsupported verifier");
    258 	}
    259 }
    260 
    261 BufferVerifier::~BufferVerifier (void)
    262 {
    263 	delete m_verifier;
    264 }
    265 
    266 bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
    267 {
    268 	DE_ASSERT(numBytes >= getMinSize());
    269 	DE_ASSERT(offset%getAlignment() == 0);
    270 	DE_ASSERT((offset+numBytes)%getAlignment() == 0);
    271 	return m_verifier->verify(buffer, reference, offset, numBytes);
    272 }
    273 
    274 // VertexArrayVerifier
    275 
    276 VertexArrayVerifier::VertexArrayVerifier (Context& context)
    277 	: BufferVerifierBase	(context)
    278 	, m_program				(DE_NULL)
    279 	, m_posLoc				(0)
    280 	, m_byteVecLoc			(0)
    281 {
    282 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
    283 		"attribute highp vec2 a_position;\n"
    284 		"attribute mediump vec3 a_byteVec;\n"
    285 		"varying mediump vec3 v_byteVec;\n"
    286 		"void main (void)\n"
    287 		"{\n"
    288 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
    289 		"	v_byteVec = a_byteVec;\n"
    290 		"}\n",
    291 
    292 		"varying mediump vec3 v_byteVec;\n"
    293 		"void main (void)\n"
    294 		"{\n"
    295 		"	gl_FragColor = vec4(v_byteVec, 1.0);\n"
    296 		"}\n"));
    297 
    298 	if (!m_program->isOk())
    299 	{
    300 		m_context.getTestContext().getLog() << *m_program;
    301 		delete m_program;
    302 		TCU_FAIL("Compile failed");
    303 	}
    304 
    305 	const glw::Functions& funcs = context.getRenderContext().getFunctions();
    306 	m_posLoc		= funcs.getAttribLocation(m_program->getProgram(), "a_position");
    307 	m_byteVecLoc	= funcs.getAttribLocation(m_program->getProgram(), "a_byteVec");
    308 }
    309 
    310 VertexArrayVerifier::~VertexArrayVerifier (void)
    311 {
    312 	delete m_program;
    313 }
    314 
    315 static void computePositions (vector<tcu::Vec2>& positions, int gridSizeX, int gridSizeY)
    316 {
    317 	positions.resize(gridSizeX*gridSizeY*4);
    318 
    319 	for (int y = 0; y < gridSizeY; y++)
    320 	for (int x = 0; x < gridSizeX; x++)
    321 	{
    322 		float	sx0			= (float)(x+0) / (float)gridSizeX;
    323 		float	sy0			= (float)(y+0) / (float)gridSizeY;
    324 		float	sx1			= (float)(x+1) / (float)gridSizeX;
    325 		float	sy1			= (float)(y+1) / (float)gridSizeY;
    326 		float	fx0			= 2.0f * sx0 - 1.0f;
    327 		float	fy0			= 2.0f * sy0 - 1.0f;
    328 		float	fx1			= 2.0f * sx1 - 1.0f;
    329 		float	fy1			= 2.0f * sy1 - 1.0f;
    330 		int		baseNdx		= (y * gridSizeX + x)*4;
    331 
    332 		positions[baseNdx+0] = tcu::Vec2(fx0, fy0);
    333 		positions[baseNdx+1] = tcu::Vec2(fx0, fy1);
    334 		positions[baseNdx+2] = tcu::Vec2(fx1, fy0);
    335 		positions[baseNdx+3] = tcu::Vec2(fx1, fy1);
    336 	}
    337 }
    338 
    339 static void computeIndices (vector<deUint16>& indices, int gridSizeX, int gridSizeY)
    340 {
    341 	indices.resize(3 * 2 * gridSizeX * gridSizeY);
    342 
    343 	for (int quadNdx = 0; quadNdx < gridSizeX*gridSizeY; quadNdx++)
    344 	{
    345 		int v00 = quadNdx*4 + 0;
    346 		int v01 = quadNdx*4 + 1;
    347 		int v10 = quadNdx*4 + 2;
    348 		int v11 = quadNdx*4 + 3;
    349 
    350 		DE_ASSERT(v11 < (1<<16));
    351 
    352 		indices[quadNdx*6 + 0] = (deUint16)v10;
    353 		indices[quadNdx*6 + 1] = (deUint16)v00;
    354 		indices[quadNdx*6 + 2] = (deUint16)v01;
    355 
    356 		indices[quadNdx*6 + 3] = (deUint16)v10;
    357 		indices[quadNdx*6 + 4] = (deUint16)v01;
    358 		indices[quadNdx*6 + 5] = (deUint16)v11;
    359 	}
    360 }
    361 
    362 static inline tcu::Vec4 fetchVtxColor (const deUint8* ptr, int vtxNdx)
    363 {
    364 	return tcu::RGBA(*(ptr + vtxNdx*3 + 0),
    365 					 *(ptr + vtxNdx*3 + 1),
    366 					 *(ptr + vtxNdx*3 + 2),
    367 					 255).toVec();
    368 }
    369 
    370 static void renderQuadGridReference (tcu::Surface& dst, int numQuads, int rowLength, const deUint8* inPtr)
    371 {
    372 	using tcu::Vec4;
    373 
    374 	dst.setSize(rowLength*VERIFY_QUAD_SIZE, (numQuads/rowLength + (numQuads%rowLength != 0 ? 1 : 0))*VERIFY_QUAD_SIZE);
    375 
    376 	tcu::PixelBufferAccess dstAccess = dst.getAccess();
    377 	tcu::clear(dstAccess, tcu::IVec4(0, 0, 0, 0xff));
    378 
    379 	for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
    380 	{
    381 		int		x0		= (quadNdx%rowLength)*VERIFY_QUAD_SIZE;
    382 		int		y0		= (quadNdx/rowLength)*VERIFY_QUAD_SIZE;
    383 		Vec4	v00		= fetchVtxColor(inPtr, quadNdx*4 + 0);
    384 		Vec4	v10		= fetchVtxColor(inPtr, quadNdx*4 + 1);
    385 		Vec4	v01		= fetchVtxColor(inPtr, quadNdx*4 + 2);
    386 		Vec4	v11		= fetchVtxColor(inPtr, quadNdx*4 + 3);
    387 
    388 		for (int y = 0; y < VERIFY_QUAD_SIZE; y++)
    389 		for (int x = 0; x < VERIFY_QUAD_SIZE; x++)
    390 		{
    391 			float		fx		= ((float)x+0.5f) / (float)VERIFY_QUAD_SIZE;
    392 			float		fy		= ((float)y+0.5f) / (float)VERIFY_QUAD_SIZE;
    393 
    394 			bool		tri		= fx + fy <= 1.0f;
    395 			float		tx		= tri ? fx : (1.0f-fx);
    396 			float		ty		= tri ? fy : (1.0f-fy);
    397 			const Vec4&	t0		= tri ? v00 : v11;
    398 			const Vec4&	t1		= tri ? v01 : v10;
    399 			const Vec4&	t2		= tri ? v10 : v01;
    400 			Vec4		color	= t0 + (t1-t0)*tx + (t2-t0)*ty;
    401 
    402 			dstAccess.setPixel(color, x0+x, y0+y);
    403 		}
    404 	}
    405 }
    406 
    407 bool VertexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes)
    408 {
    409 	const tcu::RenderTarget&	renderTarget		= m_context.getRenderContext().getRenderTarget();
    410 	const int					numBytesInVtx		= 3;
    411 	const int					numBytesInQuad		= numBytesInVtx*4;
    412 	int							maxQuadsX			= de::min(128, renderTarget.getWidth()	/ VERIFY_QUAD_SIZE);
    413 	int							maxQuadsY			= de::min(128, renderTarget.getHeight()	/ VERIFY_QUAD_SIZE);
    414 	int							maxQuadsPerBatch	= maxQuadsX*maxQuadsY;
    415 	int							numVerified			= 0;
    416 	deUint32					program				= m_program->getProgram();
    417 	tcu::RGBA					threshold			= renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(4,4,4,4);
    418 	bool						isOk				= true;
    419 
    420 	vector<tcu::Vec2>			positions;
    421 	vector<deUint16>			indices;
    422 
    423 	tcu::Surface				rendered;
    424 	tcu::Surface				reference;
    425 
    426 	DE_ASSERT(numBytes >= numBytesInQuad); // Can't render full quad with smaller buffers.
    427 
    428 	computePositions(positions, maxQuadsX, maxQuadsY);
    429 	computeIndices(indices, maxQuadsX, maxQuadsY);
    430 
    431 	// Reset buffer bindings.
    432 	glBindBuffer				(GL_ELEMENT_ARRAY_BUFFER,	0);
    433 	glBindBuffer				(GL_ARRAY_BUFFER,			0);
    434 
    435 	// Setup rendering state.
    436 	glViewport					(0, 0, maxQuadsX*VERIFY_QUAD_SIZE, maxQuadsY*VERIFY_QUAD_SIZE);
    437 	glClearColor				(0.0f, 0.0f, 0.0f, 1.0f);
    438 	glUseProgram				(program);
    439 	glEnableVertexAttribArray	(m_posLoc);
    440 	glVertexAttribPointer		(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &positions[0]);
    441 	glEnableVertexAttribArray	(m_byteVecLoc);
    442 	glBindBuffer				(GL_ARRAY_BUFFER, buffer);
    443 
    444 	while (numVerified < numBytes)
    445 	{
    446 		int		numRemaining		= numBytes-numVerified;
    447 		bool	isLeftoverBatch		= numRemaining < numBytesInQuad;
    448 		int		numBytesToVerify	= isLeftoverBatch ? numBytesInQuad				: de::min(maxQuadsPerBatch*numBytesInQuad, numRemaining - numRemaining%numBytesInQuad);
    449 		int		curOffset			= isLeftoverBatch ? (numBytes-numBytesInQuad)	: numVerified;
    450 		int		numQuads			= numBytesToVerify/numBytesInQuad;
    451 		int		numCols				= de::min(maxQuadsX, numQuads);
    452 		int		numRows				= numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0);
    453 		string	imageSetDesc		= string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1);
    454 
    455 		DE_ASSERT(numBytesToVerify > 0 && numBytesToVerify%numBytesInQuad == 0);
    456 		DE_ASSERT(de::inBounds(curOffset, 0, numBytes));
    457 		DE_ASSERT(de::inRange(curOffset+numBytesToVerify, curOffset, numBytes));
    458 
    459 		// Render batch.
    460 		glClear					(GL_COLOR_BUFFER_BIT);
    461 		glVertexAttribPointer	(m_byteVecLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const glw::GLvoid*)(deUintptr)(offset + curOffset));
    462 		glDrawElements			(GL_TRIANGLES, numQuads*6, GL_UNSIGNED_SHORT, &indices[0]);
    463 
    464 		renderQuadGridReference(reference,  numQuads, numCols, refPtr + offset + curOffset);
    465 
    466 		rendered.setSize(numCols*VERIFY_QUAD_SIZE, numRows*VERIFY_QUAD_SIZE);
    467 		glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess());
    468 
    469 		if (!tcu::pixelThresholdCompare(m_context.getTestContext().getLog(), "RenderResult", imageSetDesc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT))
    470 		{
    471 			isOk = false;
    472 			break;
    473 		}
    474 
    475 		numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
    476 	}
    477 
    478 	glDisableVertexAttribArray	(m_posLoc);
    479 	glDisableVertexAttribArray	(m_byteVecLoc);
    480 
    481 	return isOk;
    482 }
    483 
    484 // IndexArrayVerifier
    485 
    486 IndexArrayVerifier::IndexArrayVerifier (Context& context)
    487 	: BufferVerifierBase	(context)
    488 	, m_program				(DE_NULL)
    489 	, m_posLoc				(0)
    490 	, m_colorLoc			(0)
    491 {
    492 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
    493 		"attribute highp vec2 a_position;\n"
    494 		"attribute mediump vec3 a_color;\n"
    495 		"varying mediump vec3 v_color;\n"
    496 		"void main (void)\n"
    497 		"{\n"
    498 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
    499 		"	v_color = a_color;\n"
    500 		"}\n",
    501 
    502 		"varying mediump vec3 v_color;\n"
    503 		"void main (void)\n"
    504 		"{\n"
    505 		"	gl_FragColor = vec4(v_color, 1.0);\n"
    506 		"}\n"));
    507 
    508 	if (!m_program->isOk())
    509 	{
    510 		m_context.getTestContext().getLog() << *m_program;
    511 		delete m_program;
    512 		TCU_FAIL("Compile failed");
    513 	}
    514 
    515 	const glw::Functions& funcs = context.getRenderContext().getFunctions();
    516 	m_posLoc	= funcs.getAttribLocation(m_program->getProgram(), "a_position");
    517 	m_colorLoc	= funcs.getAttribLocation(m_program->getProgram(), "a_color");
    518 }
    519 
    520 IndexArrayVerifier::~IndexArrayVerifier (void)
    521 {
    522 	delete m_program;
    523 }
    524 
    525 static void computeIndexVerifierPositions (std::vector<tcu::Vec2>& dst)
    526 {
    527 	const int	numPosX		= 16;
    528 	const int	numPosY		= 16;
    529 
    530 	dst.resize(numPosX*numPosY);
    531 
    532 	for (int y = 0; y < numPosY; y++)
    533 	{
    534 		for (int x = 0; x < numPosX; x++)
    535 		{
    536 			float	xf	= float(x) / float(numPosX-1);
    537 			float	yf	= float(y) / float(numPosY-1);
    538 
    539 			dst[y*numPosX + x] = tcu::Vec2(2.0f*xf - 1.0f, 2.0f*yf - 1.0f);
    540 		}
    541 	}
    542 }
    543 
    544 static void computeIndexVerifierColors (std::vector<tcu::Vec3>& dst)
    545 {
    546 	const int	numColors	= 256;
    547 	const float	minVal		= 0.1f;
    548 	const float maxVal		= 0.5f;
    549 	de::Random	rnd			(0xabc231);
    550 
    551 	dst.resize(numColors);
    552 
    553 	for (std::vector<tcu::Vec3>::iterator i = dst.begin(); i != dst.end(); ++i)
    554 	{
    555 		i->x()	= rnd.getFloat(minVal, maxVal);
    556 		i->y()	= rnd.getFloat(minVal, maxVal);
    557 		i->z()	= rnd.getFloat(minVal, maxVal);
    558 	}
    559 }
    560 
    561 template<typename T>
    562 static void execVertexFetch (T* dst, const T* src, const deUint8* indices, int numIndices)
    563 {
    564 	for (int i = 0; i < numIndices; ++i)
    565 		dst[i] = src[indices[i]];
    566 }
    567 
    568 bool IndexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes)
    569 {
    570 	const tcu::RenderTarget&	renderTarget		= m_context.getRenderContext().getRenderTarget();
    571 	const int					viewportW			= de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, renderTarget.getWidth());
    572 	const int					viewportH			= de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, renderTarget.getHeight());
    573 	const int					minBytesPerBatch	= 2;
    574 	const tcu::RGBA				threshold			(0,0,0,0);
    575 
    576 	std::vector<tcu::Vec2>		positions;
    577 	std::vector<tcu::Vec3>		colors;
    578 
    579 	std::vector<tcu::Vec2>		fetchedPos			(MAX_LINES_PER_INDEX_ARRAY_DRAW+1);
    580 	std::vector<tcu::Vec3>		fetchedColor		(MAX_LINES_PER_INDEX_ARRAY_DRAW+1);
    581 
    582 	tcu::Surface				indexBufferImg		(viewportW, viewportH);
    583 	tcu::Surface				referenceImg		(viewportW, viewportH);
    584 
    585 	int							numVerified			= 0;
    586 	bool						isOk				= true;
    587 
    588 	DE_STATIC_ASSERT(sizeof(tcu::Vec2) == sizeof(float)*2);
    589 	DE_STATIC_ASSERT(sizeof(tcu::Vec3) == sizeof(float)*3);
    590 
    591 	computeIndexVerifierPositions(positions);
    592 	computeIndexVerifierColors(colors);
    593 
    594 	// Reset buffer bindings.
    595 	glBindBuffer				(GL_ARRAY_BUFFER,			0);
    596 	glBindBuffer				(GL_ELEMENT_ARRAY_BUFFER,	buffer);
    597 
    598 	// Setup rendering state.
    599 	glViewport					(0, 0, viewportW, viewportH);
    600 	glClearColor				(0.0f, 0.0f, 0.0f, 1.0f);
    601 	glUseProgram				(m_program->getProgram());
    602 	glEnableVertexAttribArray	(m_posLoc);
    603 	glEnableVertexAttribArray	(m_colorLoc);
    604 	glEnable					(GL_BLEND);
    605 	glBlendFunc					(GL_ONE, GL_ONE);
    606 	glBlendEquation				(GL_FUNC_ADD);
    607 
    608 	while (numVerified < numBytes)
    609 	{
    610 		int		numRemaining		= numBytes-numVerified;
    611 		bool	isLeftoverBatch		= numRemaining < minBytesPerBatch;
    612 		int		numBytesToVerify	= isLeftoverBatch ? minBytesPerBatch			: de::min(MAX_LINES_PER_INDEX_ARRAY_DRAW+1, numRemaining);
    613 		int		curOffset			= isLeftoverBatch ? (numBytes-minBytesPerBatch)	: numVerified;
    614 		string	imageSetDesc		= string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1);
    615 
    616 		// Step 1: Render using index buffer.
    617 		glClear					(GL_COLOR_BUFFER_BIT);
    618 		glVertexAttribPointer	(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &positions[0]);
    619 		glVertexAttribPointer	(m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, &colors[0]);
    620 		glDrawElements			(GL_LINE_STRIP, numBytesToVerify, GL_UNSIGNED_BYTE, (void*)(deUintptr)(offset+curOffset));
    621 		glu::readPixels			(m_context.getRenderContext(), 0, 0, indexBufferImg.getAccess());
    622 
    623 		// Step 2: Do manual fetch and render without index buffer.
    624 		execVertexFetch(&fetchedPos[0], &positions[0], refPtr+offset+curOffset, numBytesToVerify);
    625 		execVertexFetch(&fetchedColor[0], &colors[0], refPtr+offset+curOffset, numBytesToVerify);
    626 
    627 		glClear					(GL_COLOR_BUFFER_BIT);
    628 		glVertexAttribPointer	(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &fetchedPos[0]);
    629 		glVertexAttribPointer	(m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, &fetchedColor[0]);
    630 		glDrawArrays			(GL_LINE_STRIP, 0, numBytesToVerify);
    631 		glu::readPixels			(m_context.getRenderContext(), 0, 0, referenceImg.getAccess());
    632 
    633 		if (!tcu::pixelThresholdCompare(m_context.getTestContext().getLog(), "RenderResult", imageSetDesc.c_str(), referenceImg, indexBufferImg, threshold, tcu::COMPARE_LOG_RESULT))
    634 		{
    635 			isOk = false;
    636 			break;
    637 		}
    638 
    639 		numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
    640 	}
    641 
    642 	return isOk;
    643 }
    644 
    645 } // BufferTestUtil
    646 } // Functional
    647 } // gles2
    648 } // deqp
    649