1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 "glsBufferTestUtil.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 "tcuTestLog.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluRenderContext.hpp"
35 #include "gluStrUtil.hpp"
36 #include "gluShaderProgram.hpp"
37 #include "deMemory.h"
38 #include "deStringUtil.hpp"
39 #include "deArrayUtil.hpp"
40 
41 #include <algorithm>
42 
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
45 
46 namespace deqp
47 {
48 namespace gls
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 using tcu::TestLog;
62 using std::vector;
63 using std::string;
64 using std::set;
65 
66 // Helper functions.
67 
fillWithRandomBytes(deUint8 * ptr,int numBytes,deUint32 seed)68 void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed)
69 {
70 	std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr);
71 }
72 
compareByteArrays(tcu::TestLog & log,const deUint8 * resPtr,const deUint8 * refPtr,int numBytes)73 bool compareByteArrays (tcu::TestLog& log, const deUint8* resPtr, const deUint8* refPtr, int numBytes)
74 {
75 	bool			isOk			= true;
76 	const int		maxSpanLen		= 8;
77 	const int		maxDiffSpans	= 4;
78 	int				numDiffSpans	= 0;
79 	int				diffSpanStart	= -1;
80 	int				ndx				= 0;
81 
82 	log << TestLog::Section("Verify", "Verification result");
83 
84 	for (;ndx < numBytes; ndx++)
85 	{
86 		if (resPtr[ndx] != refPtr[ndx])
87 		{
88 			if (diffSpanStart < 0)
89 				diffSpanStart = ndx;
90 
91 			isOk = false;
92 		}
93 		else if (diffSpanStart >= 0)
94 		{
95 			if (numDiffSpans < maxDiffSpans)
96 			{
97 				int len			= ndx-diffSpanStart;
98 				int	printLen	= de::min(len, maxSpanLen);
99 
100 				log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n"
101 										<< "  expected "	<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n"
102 										<< "  got "			<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen))
103 					<< TestLog::EndMessage;
104 			}
105 			else
106 				log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
107 
108 			numDiffSpans	+= 1;
109 			diffSpanStart	 = -1;
110 		}
111 	}
112 
113 	if (diffSpanStart >= 0)
114 	{
115 		if (numDiffSpans < maxDiffSpans)
116 		{
117 				int len			= ndx-diffSpanStart;
118 				int	printLen	= de::min(len, maxSpanLen);
119 
120 				log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n"
121 										<< "  expected "	<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n"
122 										<< "  got "			<< tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen))
123 					<< TestLog::EndMessage;
124 		}
125 		else
126 			log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
127 	}
128 
129 	log << TestLog::Message << (isOk ? "Verification passed." : "Verification FAILED!") << TestLog::EndMessage;
130 	log << TestLog::EndSection;
131 
132 	return isOk;
133 }
134 
getBufferTargetName(deUint32 target)135 const char* getBufferTargetName (deUint32 target)
136 {
137 	switch (target)
138 	{
139 		case GL_ARRAY_BUFFER:				return "array";
140 		case GL_COPY_READ_BUFFER:			return "copy_read";
141 		case GL_COPY_WRITE_BUFFER:			return "copy_write";
142 		case GL_ELEMENT_ARRAY_BUFFER:		return "element_array";
143 		case GL_PIXEL_PACK_BUFFER:			return "pixel_pack";
144 		case GL_PIXEL_UNPACK_BUFFER:		return "pixel_unpack";
145 		case GL_TEXTURE_BUFFER:				return "texture";
146 		case GL_TRANSFORM_FEEDBACK_BUFFER:	return "transform_feedback";
147 		case GL_UNIFORM_BUFFER:				return "uniform";
148 		default:
149 			DE_ASSERT(false);
150 			return DE_NULL;
151 	}
152 }
153 
getUsageHintName(deUint32 hint)154 const char* getUsageHintName (deUint32 hint)
155 {
156 	switch (hint)
157 	{
158 		case GL_STREAM_DRAW:	return "stream_draw";
159 		case GL_STREAM_READ:	return "stream_read";
160 		case GL_STREAM_COPY:	return "stream_copy";
161 		case GL_STATIC_DRAW:	return "static_draw";
162 		case GL_STATIC_READ:	return "static_read";
163 		case GL_STATIC_COPY:	return "static_copy";
164 		case GL_DYNAMIC_DRAW:	return "dynamic_draw";
165 		case GL_DYNAMIC_READ:	return "dynamic_read";
166 		case GL_DYNAMIC_COPY:	return "dynamic_copy";
167 		default:
168 			DE_ASSERT(false);
169 			return DE_NULL;
170 	}
171 }
172 
173 // BufferCase
174 
BufferCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description)175 BufferCase::BufferCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description)
176 	: TestCase			(testCtx, name, description)
177 	, CallLogWrapper	(renderCtx.getFunctions(), testCtx.getLog())
178 	, m_renderCtx		(renderCtx)
179 {
180 }
181 
~BufferCase(void)182 BufferCase::~BufferCase (void)
183 {
184 	enableLogging(false);
185 	BufferCase::deinit();
186 }
187 
init(void)188 void BufferCase::init (void)
189 {
190 	enableLogging(true);
191 }
192 
deinit(void)193 void BufferCase::deinit (void)
194 {
195 	for (set<deUint32>::const_iterator bufIter = m_allocatedBuffers.begin(); bufIter != m_allocatedBuffers.end(); bufIter++)
196 		glDeleteBuffers(1, &(*bufIter));
197 }
198 
genBuffer(void)199 deUint32 BufferCase::genBuffer (void)
200 {
201 	deUint32 buf = 0;
202 	glGenBuffers(1, &buf);
203 	if (buf != 0)
204 	{
205 		try
206 		{
207 			m_allocatedBuffers.insert(buf);
208 		}
209 		catch (const std::exception&)
210 		{
211 			glDeleteBuffers(1, &buf);
212 			throw;
213 		}
214 	}
215 	return buf;
216 }
217 
deleteBuffer(deUint32 buffer)218 void BufferCase::deleteBuffer (deUint32 buffer)
219 {
220 	glDeleteBuffers(1, &buffer);
221 	m_allocatedBuffers.erase(buffer);
222 }
223 
checkError(void)224 void BufferCase::checkError (void)
225 {
226 	glw::GLenum err = glGetError();
227 	if (err != GL_NO_ERROR)
228 		throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
229 }
230 
231 // ReferenceBuffer
232 
setSize(int numBytes)233 void ReferenceBuffer::setSize (int numBytes)
234 {
235 	m_data.resize(numBytes);
236 }
237 
setData(int numBytes,const deUint8 * bytes)238 void ReferenceBuffer::setData (int numBytes, const deUint8* bytes)
239 {
240 	m_data.resize(numBytes);
241 	std::copy(bytes, bytes+numBytes, m_data.begin());
242 }
243 
setSubData(int offset,int numBytes,const deUint8 * bytes)244 void ReferenceBuffer::setSubData (int offset, int numBytes, const deUint8* bytes)
245 {
246 	DE_ASSERT(de::inBounds(offset, 0, (int)m_data.size()) && de::inRange(offset+numBytes, offset, (int)m_data.size()));
247 	std::copy(bytes, bytes+numBytes, m_data.begin()+offset);
248 }
249 
250 // BufferWriterBase
251 
BufferWriterBase(glu::RenderContext & renderCtx,tcu::TestLog & log)252 BufferWriterBase::BufferWriterBase (glu::RenderContext& renderCtx, tcu::TestLog& log)
253 	: CallLogWrapper	(renderCtx.getFunctions(), log)
254 	, m_renderCtx		(renderCtx)
255 {
256 	enableLogging(true);
257 }
258 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes,deUint32 targetHint)259 void BufferWriterBase::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 targetHint)
260 {
261 	DE_UNREF(targetHint);
262 	write(buffer, offset, numBytes, bytes);
263 }
264 
265 // BufferWriter
266 
BufferWriter(glu::RenderContext & renderCtx,tcu::TestLog & log,WriteType writeType)267 BufferWriter::BufferWriter (glu::RenderContext& renderCtx, tcu::TestLog& log, WriteType writeType)
268 	: m_writer(DE_NULL)
269 {
270 	switch (writeType)
271 	{
272 		case WRITE_BUFFER_SUB_DATA:		m_writer = new BufferSubDataWriter	(renderCtx, log);	break;
273 		case WRITE_BUFFER_WRITE_MAP:	m_writer = new BufferWriteMapWriter	(renderCtx, log);	break;
274 		default:
275 			TCU_FAIL("Unsupported writer");
276 	}
277 }
278 
~BufferWriter(void)279 BufferWriter::~BufferWriter (void)
280 {
281 	delete m_writer;
282 }
283 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes)284 void BufferWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
285 {
286 	DE_ASSERT(numBytes >= getMinSize());
287 	DE_ASSERT(offset%getAlignment() == 0);
288 	DE_ASSERT((offset+numBytes)%getAlignment() == 0);
289 	return m_writer->write(buffer, offset, numBytes, bytes);
290 }
291 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes,deUint32 targetHint)292 void BufferWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 targetHint)
293 {
294 	DE_ASSERT(numBytes >= getMinSize());
295 	DE_ASSERT(offset%getAlignment() == 0);
296 	DE_ASSERT((offset+numBytes)%getAlignment() == 0);
297 	return m_writer->write(buffer, offset, numBytes, bytes, targetHint);
298 }
299 
300 // BufferSubDataWriter
301 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes)302 void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
303 {
304 	write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
305 }
306 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes,deUint32 target)307 void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 target)
308 {
309 	glBindBuffer(target, buffer);
310 	glBufferSubData(target, offset, numBytes, bytes);
311 	glBindBuffer(target, 0);
312 	GLU_CHECK();
313 }
314 
315 // BufferWriteMapWriter
316 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes)317 void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
318 {
319 	write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
320 }
321 
write(deUint32 buffer,int offset,int numBytes,const deUint8 * bytes,deUint32 target)322 void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 target)
323 {
324 	glBindBuffer(target, buffer);
325 
326 	void* ptr = glMapBufferRange(target, offset, numBytes, GL_MAP_WRITE_BIT);
327 	GLU_CHECK_MSG("glMapBufferRange");
328 
329 	deMemcpy(ptr, bytes, numBytes);
330 
331 	glUnmapBuffer(target);
332 	glBindBuffer(target, 0);
333 	GLU_CHECK();
334 }
335 
336 // BufferVerifierBase
337 
BufferVerifierBase(glu::RenderContext & renderCtx,tcu::TestLog & log)338 BufferVerifierBase::BufferVerifierBase (glu::RenderContext& renderCtx, tcu::TestLog& log)
339 	: CallLogWrapper	(renderCtx.getFunctions(), log)
340 	, m_renderCtx		(renderCtx)
341 	, m_log				(log)
342 {
343 	enableLogging(true);
344 }
345 
verify(deUint32 buffer,const deUint8 * reference,int offset,int numBytes,deUint32 targetHint)346 bool BufferVerifierBase::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 targetHint)
347 {
348 	DE_UNREF(targetHint);
349 	return verify(buffer, reference, offset, numBytes);
350 }
351 
352 // BufferVerifier
353 
BufferVerifier(glu::RenderContext & renderCtx,tcu::TestLog & log,VerifyType verifyType)354 BufferVerifier::BufferVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log, VerifyType verifyType)
355 	: m_verifier(DE_NULL)
356 {
357 	switch (verifyType)
358 	{
359 		case VERIFY_AS_VERTEX_ARRAY:	m_verifier = new VertexArrayVerifier(renderCtx, log);	break;
360 		case VERIFY_AS_INDEX_ARRAY:		m_verifier = new IndexArrayVerifier	(renderCtx, log);	break;
361 		case VERIFY_BUFFER_READ_MAP:	m_verifier = new BufferMapVerifier	(renderCtx, log);	break;
362 		default:
363 			TCU_FAIL("Unsupported verifier");
364 	}
365 }
366 
~BufferVerifier(void)367 BufferVerifier::~BufferVerifier (void)
368 {
369 	delete m_verifier;
370 }
371 
verify(deUint32 buffer,const deUint8 * reference,int offset,int numBytes)372 bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
373 {
374 	DE_ASSERT(numBytes >= getMinSize());
375 	DE_ASSERT(offset%getAlignment() == 0);
376 	DE_ASSERT((offset+numBytes)%getAlignment() == 0);
377 	return m_verifier->verify(buffer, reference, offset, numBytes);
378 }
379 
verify(deUint32 buffer,const deUint8 * reference,int offset,int numBytes,deUint32 targetHint)380 bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 targetHint)
381 {
382 	DE_ASSERT(numBytes >= getMinSize());
383 	DE_ASSERT(offset%getAlignment() == 0);
384 	DE_ASSERT((offset+numBytes)%getAlignment() == 0);
385 	return m_verifier->verify(buffer, reference, offset, numBytes, targetHint);
386 }
387 
388 // BufferMapVerifier
389 
verify(deUint32 buffer,const deUint8 * reference,int offset,int numBytes)390 bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
391 {
392 	return verify(buffer, reference, offset, numBytes, GL_ARRAY_BUFFER);
393 }
394 
verify(deUint32 buffer,const deUint8 * reference,int offset,int numBytes,deUint32 target)395 bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 target)
396 {
397 	const deUint8*	mapPtr		= DE_NULL;
398 	bool			isOk		= false;
399 
400 	glBindBuffer(target, buffer);
401 	mapPtr = (const deUint8*)glMapBufferRange(target, offset, numBytes, GL_MAP_READ_BIT);
402 	GLU_CHECK_MSG("glMapBufferRange");
403 	TCU_CHECK(mapPtr);
404 
405 	isOk = compareByteArrays(m_log, mapPtr, reference+offset, numBytes);
406 
407 	glUnmapBuffer(target);
408 	GLU_CHECK_MSG("glUnmapBuffer");
409 
410 	glBindBuffer(target, 0);
411 
412 	return isOk;
413 }
414 
415 // VertexArrayVerifier
416 
VertexArrayVerifier(glu::RenderContext & renderCtx,tcu::TestLog & log)417 VertexArrayVerifier::VertexArrayVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log)
418 	: BufferVerifierBase	(renderCtx, log)
419 	, m_program				(DE_NULL)
420 	, m_posLoc				(0)
421 	, m_byteVecLoc			(0)
422 	, m_vao					(0)
423 {
424 	const glu::ContextType	ctxType		= renderCtx.getType();
425 	const glu::GLSLVersion	glslVersion	= glu::isContextTypeES(ctxType) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
426 
427 	DE_ASSERT(glu::isGLSLVersionSupported(ctxType, glslVersion));
428 
429 	m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(
430 		string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n"
431 		"in highp vec2 a_position;\n"
432 		"in mediump vec3 a_byteVec;\n"
433 		"out mediump vec3 v_byteVec;\n"
434 		"void main (void)\n"
435 		"{\n"
436 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
437 		"	v_byteVec = a_byteVec;\n"
438 		"}\n",
439 
440 		string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n"
441 		"in mediump vec3 v_byteVec;\n"
442 		"layout(location = 0) out mediump vec4 o_color;\n"
443 		"void main (void)\n"
444 		"{\n"
445 		"	o_color = vec4(v_byteVec, 1.0);\n"
446 		"}\n"));
447 
448 	if (!m_program->isOk())
449 	{
450 		m_log << *m_program;
451 		delete m_program;
452 		TCU_FAIL("Compile failed");
453 	}
454 
455 	const glw::Functions& gl = m_renderCtx.getFunctions();
456 	m_posLoc		= gl.getAttribLocation(m_program->getProgram(), "a_position");
457 	m_byteVecLoc	= gl.getAttribLocation(m_program->getProgram(), "a_byteVec");
458 
459 	gl.genVertexArrays(1, &m_vao);
460 	gl.genBuffers(1, &m_positionBuf);
461 	gl.genBuffers(1, &m_indexBuf);
462 	GLU_EXPECT_NO_ERROR(gl.getError(), "Initialization failed");
463 }
464 
~VertexArrayVerifier(void)465 VertexArrayVerifier::~VertexArrayVerifier (void)
466 {
467 	const glw::Functions& gl = m_renderCtx.getFunctions();
468 
469 	if (m_vao)			gl.deleteVertexArrays(1, &m_vao);
470 	if (m_positionBuf)	gl.deleteBuffers(1, &m_positionBuf);
471 	if (m_indexBuf)		gl.deleteBuffers(1, &m_indexBuf);
472 
473 	delete m_program;
474 }
475 
computePositions(vector<tcu::Vec2> & positions,int gridSizeX,int gridSizeY)476 static void computePositions (vector<tcu::Vec2>& positions, int gridSizeX, int gridSizeY)
477 {
478 	positions.resize(gridSizeX*gridSizeY*4);
479 
480 	for (int y = 0; y < gridSizeY; y++)
481 	for (int x = 0; x < gridSizeX; x++)
482 	{
483 		float	sx0			= (float)(x+0) / (float)gridSizeX;
484 		float	sy0			= (float)(y+0) / (float)gridSizeY;
485 		float	sx1			= (float)(x+1) / (float)gridSizeX;
486 		float	sy1			= (float)(y+1) / (float)gridSizeY;
487 		float	fx0			= 2.0f * sx0 - 1.0f;
488 		float	fy0			= 2.0f * sy0 - 1.0f;
489 		float	fx1			= 2.0f * sx1 - 1.0f;
490 		float	fy1			= 2.0f * sy1 - 1.0f;
491 		int		baseNdx		= (y * gridSizeX + x)*4;
492 
493 		positions[baseNdx+0] = tcu::Vec2(fx0, fy0);
494 		positions[baseNdx+1] = tcu::Vec2(fx0, fy1);
495 		positions[baseNdx+2] = tcu::Vec2(fx1, fy0);
496 		positions[baseNdx+3] = tcu::Vec2(fx1, fy1);
497 	}
498 }
499 
computeIndices(vector<deUint16> & indices,int gridSizeX,int gridSizeY)500 static void computeIndices (vector<deUint16>& indices, int gridSizeX, int gridSizeY)
501 {
502 	indices.resize(3 * 2 * gridSizeX * gridSizeY);
503 
504 	for (int quadNdx = 0; quadNdx < gridSizeX*gridSizeY; quadNdx++)
505 	{
506 		int v00 = quadNdx*4 + 0;
507 		int v01 = quadNdx*4 + 1;
508 		int v10 = quadNdx*4 + 2;
509 		int v11 = quadNdx*4 + 3;
510 
511 		DE_ASSERT(v11 < (1<<16));
512 
513 		indices[quadNdx*6 + 0] = (deUint16)v10;
514 		indices[quadNdx*6 + 1] = (deUint16)v00;
515 		indices[quadNdx*6 + 2] = (deUint16)v01;
516 
517 		indices[quadNdx*6 + 3] = (deUint16)v10;
518 		indices[quadNdx*6 + 4] = (deUint16)v01;
519 		indices[quadNdx*6 + 5] = (deUint16)v11;
520 	}
521 }
522 
fetchVtxColor(const deUint8 * ptr,int vtxNdx)523 static inline tcu::Vec4 fetchVtxColor (const deUint8* ptr, int vtxNdx)
524 {
525 	return tcu::RGBA(*(ptr + vtxNdx*3 + 0),
526 					 *(ptr + vtxNdx*3 + 1),
527 					 *(ptr + vtxNdx*3 + 2),
528 					 255).toVec();
529 }
530 
renderQuadGridReference(tcu::Surface & dst,int numQuads,int rowLength,const deUint8 * inPtr)531 static void renderQuadGridReference (tcu::Surface& dst, int numQuads, int rowLength, const deUint8* inPtr)
532 {
533 	using tcu::Vec4;
534 
535 	dst.setSize(rowLength*VERIFY_QUAD_SIZE, (numQuads/rowLength + (numQuads%rowLength != 0 ? 1 : 0))*VERIFY_QUAD_SIZE);
536 
537 	tcu::PixelBufferAccess dstAccess = dst.getAccess();
538 	tcu::clear(dstAccess, tcu::IVec4(0, 0, 0, 0xff));
539 
540 	for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
541 	{
542 		int		x0		= (quadNdx%rowLength)*VERIFY_QUAD_SIZE;
543 		int		y0		= (quadNdx/rowLength)*VERIFY_QUAD_SIZE;
544 		Vec4	v00		= fetchVtxColor(inPtr, quadNdx*4 + 0);
545 		Vec4	v10		= fetchVtxColor(inPtr, quadNdx*4 + 1);
546 		Vec4	v01		= fetchVtxColor(inPtr, quadNdx*4 + 2);
547 		Vec4	v11		= fetchVtxColor(inPtr, quadNdx*4 + 3);
548 
549 		for (int y = 0; y < VERIFY_QUAD_SIZE; y++)
550 		for (int x = 0; x < VERIFY_QUAD_SIZE; x++)
551 		{
552 			float		fx		= ((float)x+0.5f) / (float)VERIFY_QUAD_SIZE;
553 			float		fy		= ((float)y+0.5f) / (float)VERIFY_QUAD_SIZE;
554 
555 			bool		tri		= fx + fy <= 1.0f;
556 			float		tx		= tri ? fx : (1.0f-fx);
557 			float		ty		= tri ? fy : (1.0f-fy);
558 			const Vec4&	t0		= tri ? v00 : v11;
559 			const Vec4&	t1		= tri ? v01 : v10;
560 			const Vec4&	t2		= tri ? v10 : v01;
561 			Vec4		color	= t0 + (t1-t0)*tx + (t2-t0)*ty;
562 
563 			dstAccess.setPixel(color, x0+x, y0+y);
564 		}
565 	}
566 }
567 
verify(deUint32 buffer,const deUint8 * refPtr,int offset,int numBytes)568 bool VertexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes)
569 {
570 	const tcu::RenderTarget&	renderTarget		= m_renderCtx.getRenderTarget();
571 	const int					numBytesInVtx		= 3;
572 	const int					numBytesInQuad		= numBytesInVtx*4;
573 	int							maxQuadsX			= de::min(128, renderTarget.getWidth()	/ VERIFY_QUAD_SIZE);
574 	int							maxQuadsY			= de::min(128, renderTarget.getHeight()	/ VERIFY_QUAD_SIZE);
575 	int							maxQuadsPerBatch	= maxQuadsX*maxQuadsY;
576 	int							numVerified			= 0;
577 	deUint32					program				= m_program->getProgram();
578 	tcu::RGBA					threshold			= renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3);
579 	bool						isOk				= true;
580 
581 	vector<tcu::Vec2>			positions;
582 	vector<deUint16>			indices;
583 
584 	tcu::Surface				rendered;
585 	tcu::Surface				reference;
586 
587 	DE_ASSERT(numBytes >= numBytesInQuad); // Can't render full quad with smaller buffers.
588 
589 	computePositions(positions, maxQuadsX, maxQuadsY);
590 	computeIndices(indices, maxQuadsX, maxQuadsY);
591 
592 	// Reset buffer bindings.
593 	glBindBuffer				(GL_PIXEL_PACK_BUFFER, 0);
594 
595 	// Setup rendering state.
596 	glViewport					(0, 0, maxQuadsX*VERIFY_QUAD_SIZE, maxQuadsY*VERIFY_QUAD_SIZE);
597 	glClearColor				(0.0f, 0.0f, 0.0f, 1.0f);
598 	glUseProgram				(program);
599 	glBindVertexArray			(m_vao);
600 
601 	// Upload positions
602 	glBindBuffer				(GL_ARRAY_BUFFER, m_positionBuf);
603 	glBufferData				(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STATIC_DRAW);
604 	glEnableVertexAttribArray	(m_posLoc);
605 	glVertexAttribPointer		(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
606 
607 	// Upload indices
608 	glBindBuffer				(GL_ELEMENT_ARRAY_BUFFER, m_indexBuf);
609 	glBufferData				(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size()*sizeof(indices[0])), &indices[0], GL_STATIC_DRAW);
610 
611 	glEnableVertexAttribArray	(m_byteVecLoc);
612 	glBindBuffer				(GL_ARRAY_BUFFER, buffer);
613 
614 	while (numVerified < numBytes)
615 	{
616 		int		numRemaining		= numBytes-numVerified;
617 		bool	isLeftoverBatch		= numRemaining < numBytesInQuad;
618 		int		numBytesToVerify	= isLeftoverBatch ? numBytesInQuad				: de::min(maxQuadsPerBatch*numBytesInQuad, numRemaining - numRemaining%numBytesInQuad);
619 		int		curOffset			= isLeftoverBatch ? (numBytes-numBytesInQuad)	: numVerified;
620 		int		numQuads			= numBytesToVerify/numBytesInQuad;
621 		int		numCols				= de::min(maxQuadsX, numQuads);
622 		int		numRows				= numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0);
623 		string	imageSetDesc		= string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1);
624 
625 		DE_ASSERT(numBytesToVerify > 0 && numBytesToVerify%numBytesInQuad == 0);
626 		DE_ASSERT(de::inBounds(curOffset, 0, numBytes));
627 		DE_ASSERT(de::inRange(curOffset+numBytesToVerify, curOffset, numBytes));
628 
629 		// Render batch.
630 		glClear					(GL_COLOR_BUFFER_BIT);
631 		glVertexAttribPointer	(m_byteVecLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const glw::GLvoid*)(deUintptr)(offset + curOffset));
632 		glDrawElements			(GL_TRIANGLES, numQuads*6, GL_UNSIGNED_SHORT, DE_NULL);
633 
634 		renderQuadGridReference(reference,  numQuads, numCols, refPtr + offset + curOffset);
635 
636 		rendered.setSize(numCols*VERIFY_QUAD_SIZE, numRows*VERIFY_QUAD_SIZE);
637 		glu::readPixels(m_renderCtx, 0, 0, rendered.getAccess());
638 
639 		if (!tcu::pixelThresholdCompare(m_log, "RenderResult", imageSetDesc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT))
640 		{
641 			isOk = false;
642 			break;
643 		}
644 
645 		numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
646 	}
647 
648 	glBindVertexArray(0);
649 
650 	return isOk;
651 }
652 
653 // IndexArrayVerifier
654 
IndexArrayVerifier(glu::RenderContext & renderCtx,tcu::TestLog & log)655 IndexArrayVerifier::IndexArrayVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log)
656 	: BufferVerifierBase	(renderCtx, log)
657 	, m_program				(DE_NULL)
658 	, m_posLoc				(0)
659 	, m_colorLoc			(0)
660 {
661 
662 	const glu::ContextType	ctxType		= renderCtx.getType();
663 	const glu::GLSLVersion	glslVersion	= glu::isContextTypeES(ctxType) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
664 
665 	DE_ASSERT(glu::isGLSLVersionSupported(ctxType, glslVersion));
666 
667 	m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(
668 		string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n"
669 		"in highp vec2 a_position;\n"
670 		"in mediump vec3 a_color;\n"
671 		"out mediump vec3 v_color;\n"
672 		"void main (void)\n"
673 		"{\n"
674 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
675 		"	v_color = a_color;\n"
676 		"}\n",
677 
678 		string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n"
679 		"in mediump vec3 v_color;\n"
680 		"layout(location = 0) out mediump vec4 o_color;\n"
681 		"void main (void)\n"
682 		"{\n"
683 		"	o_color = vec4(v_color, 1.0);\n"
684 		"}\n"));
685 
686 	if (!m_program->isOk())
687 	{
688 		m_log << *m_program;
689 		delete m_program;
690 		TCU_FAIL("Compile failed");
691 	}
692 
693 	const glw::Functions& gl = m_renderCtx.getFunctions();
694 	m_posLoc	= gl.getAttribLocation(m_program->getProgram(), "a_position");
695 	m_colorLoc	= gl.getAttribLocation(m_program->getProgram(), "a_color");
696 
697 	gl.genVertexArrays(1, &m_vao);
698 	gl.genBuffers(1, &m_positionBuf);
699 	gl.genBuffers(1, &m_colorBuf);
700 	GLU_EXPECT_NO_ERROR(gl.getError(), "Initialization failed");
701 }
702 
~IndexArrayVerifier(void)703 IndexArrayVerifier::~IndexArrayVerifier (void)
704 {
705 	const glw::Functions& gl = m_renderCtx.getFunctions();
706 
707 	if (m_vao)			gl.deleteVertexArrays(1, &m_vao);
708 	if (m_positionBuf)	gl.deleteBuffers(1, &m_positionBuf);
709 	if (m_colorBuf)		gl.deleteBuffers(1, &m_colorBuf);
710 
711 	delete m_program;
712 }
713 
computeIndexVerifierPositions(std::vector<tcu::Vec2> & dst)714 static void computeIndexVerifierPositions (std::vector<tcu::Vec2>& dst)
715 {
716 	const int	numPosX		= 16;
717 	const int	numPosY		= 16;
718 
719 	dst.resize(numPosX*numPosY);
720 
721 	for (int y = 0; y < numPosY; y++)
722 	{
723 		for (int x = 0; x < numPosX; x++)
724 		{
725 			float	xf	= float(x) / float(numPosX-1);
726 			float	yf	= float(y) / float(numPosY-1);
727 
728 			dst[y*numPosX + x] = tcu::Vec2(2.0f*xf - 1.0f, 2.0f*yf - 1.0f);
729 		}
730 	}
731 }
732 
computeIndexVerifierColors(std::vector<tcu::Vec3> & dst)733 static void computeIndexVerifierColors (std::vector<tcu::Vec3>& dst)
734 {
735 	const int	numColors	= 256;
736 	const float	minVal		= 0.1f;
737 	const float maxVal		= 0.5f;
738 	de::Random	rnd			(0xabc231);
739 
740 	dst.resize(numColors);
741 
742 	for (std::vector<tcu::Vec3>::iterator i = dst.begin(); i != dst.end(); ++i)
743 	{
744 		i->x()	= rnd.getFloat(minVal, maxVal);
745 		i->y()	= rnd.getFloat(minVal, maxVal);
746 		i->z()	= rnd.getFloat(minVal, maxVal);
747 	}
748 }
749 
750 template<typename T>
execVertexFetch(T * dst,const T * src,const deUint8 * indices,int numIndices)751 static void execVertexFetch (T* dst, const T* src, const deUint8* indices, int numIndices)
752 {
753 	for (int i = 0; i < numIndices; ++i)
754 		dst[i] = src[indices[i]];
755 }
756 
verify(deUint32 buffer,const deUint8 * refPtr,int offset,int numBytes)757 bool IndexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes)
758 {
759 	const tcu::RenderTarget&	renderTarget		= m_renderCtx.getRenderTarget();
760 	const int					viewportW			= de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, renderTarget.getWidth());
761 	const int					viewportH			= de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, renderTarget.getHeight());
762 	const int					minBytesPerBatch	= 2;
763 	const tcu::RGBA				threshold			(0,0,0,0);
764 
765 	std::vector<tcu::Vec2>		positions;
766 	std::vector<tcu::Vec3>		colors;
767 
768 	std::vector<tcu::Vec2>		fetchedPos			(MAX_LINES_PER_INDEX_ARRAY_DRAW+1);
769 	std::vector<tcu::Vec3>		fetchedColor		(MAX_LINES_PER_INDEX_ARRAY_DRAW+1);
770 
771 	tcu::Surface				indexBufferImg		(viewportW, viewportH);
772 	tcu::Surface				referenceImg		(viewportW, viewportH);
773 
774 	int							numVerified			= 0;
775 	bool						isOk				= true;
776 
777 	DE_STATIC_ASSERT(sizeof(tcu::Vec2) == sizeof(float)*2);
778 	DE_STATIC_ASSERT(sizeof(tcu::Vec3) == sizeof(float)*3);
779 
780 	computeIndexVerifierPositions(positions);
781 	computeIndexVerifierColors(colors);
782 
783 	// Reset buffer bindings.
784 	glBindVertexArray			(m_vao);
785 	glBindBuffer				(GL_PIXEL_PACK_BUFFER,		0);
786 	glBindBuffer				(GL_ELEMENT_ARRAY_BUFFER,	buffer);
787 
788 	// Setup rendering state.
789 	glViewport					(0, 0, viewportW, viewportH);
790 	glClearColor				(0.0f, 0.0f, 0.0f, 1.0f);
791 	glUseProgram				(m_program->getProgram());
792 	glEnableVertexAttribArray	(m_posLoc);
793 	glEnableVertexAttribArray	(m_colorLoc);
794 	glEnable					(GL_BLEND);
795 	glBlendFunc					(GL_ONE, GL_ONE);
796 	glBlendEquation				(GL_FUNC_ADD);
797 
798 	while (numVerified < numBytes)
799 	{
800 		int		numRemaining		= numBytes-numVerified;
801 		bool	isLeftoverBatch		= numRemaining < minBytesPerBatch;
802 		int		numBytesToVerify	= isLeftoverBatch ? minBytesPerBatch			: de::min(MAX_LINES_PER_INDEX_ARRAY_DRAW+1, numRemaining);
803 		int		curOffset			= isLeftoverBatch ? (numBytes-minBytesPerBatch)	: numVerified;
804 		string	imageSetDesc		= string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1);
805 
806 		// Step 1: Render using index buffer.
807 		glClear					(GL_COLOR_BUFFER_BIT);
808 
809 		glBindBuffer			(GL_ARRAY_BUFFER, m_positionBuf);
810 		glBufferData			(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STREAM_DRAW);
811 		glVertexAttribPointer	(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
812 
813 		glBindBuffer			(GL_ARRAY_BUFFER, m_colorBuf);
814 		glBufferData			(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size()*sizeof(colors[0])), &colors[0], GL_STREAM_DRAW);
815 		glVertexAttribPointer	(m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL);
816 
817 		glDrawElements			(GL_LINE_STRIP, numBytesToVerify, GL_UNSIGNED_BYTE, (void*)(deUintptr)(offset+curOffset));
818 		glu::readPixels			(m_renderCtx, 0, 0, indexBufferImg.getAccess());
819 
820 		// Step 2: Do manual fetch and render without index buffer.
821 		execVertexFetch(&fetchedPos[0], &positions[0], refPtr+offset+curOffset, numBytesToVerify);
822 		execVertexFetch(&fetchedColor[0], &colors[0], refPtr+offset+curOffset, numBytesToVerify);
823 
824 		glClear					(GL_COLOR_BUFFER_BIT);
825 
826 		glBindBuffer			(GL_ARRAY_BUFFER, m_positionBuf);
827 		glBufferData			(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(fetchedPos.size()*sizeof(fetchedPos[0])), &fetchedPos[0], GL_STREAM_DRAW);
828 		glVertexAttribPointer	(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
829 
830 		glBindBuffer			(GL_ARRAY_BUFFER, m_colorBuf);
831 		glBufferData			(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(fetchedColor.size()*sizeof(fetchedColor[0])), &fetchedColor[0], GL_STREAM_DRAW);
832 		glVertexAttribPointer	(m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL);
833 
834 		glDrawArrays			(GL_LINE_STRIP, 0, numBytesToVerify);
835 		glu::readPixels			(m_renderCtx, 0, 0, referenceImg.getAccess());
836 
837 		if (!tcu::pixelThresholdCompare(m_log, "RenderResult", imageSetDesc.c_str(), referenceImg, indexBufferImg, threshold, tcu::COMPARE_LOG_RESULT))
838 		{
839 			isOk = false;
840 			break;
841 		}
842 
843 		numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
844 	}
845 
846 	glBindVertexArray(0);
847 
848 	return isOk;
849 }
850 
getWriteTypeDescription(WriteType write)851 const char* getWriteTypeDescription (WriteType write)
852 {
853 	static const char* s_desc[] =
854 	{
855 		"glBufferSubData()",
856 		"glMapBufferRange()",
857 		"transform feedback",
858 		"glReadPixels() into PBO binding"
859 	};
860 	return de::getSizedArrayElement<WRITE_LAST>(s_desc, write);
861 }
862 
getVerifyTypeDescription(VerifyType verify)863 const char* getVerifyTypeDescription (VerifyType verify)
864 {
865 	static const char* s_desc[] =
866 	{
867 		"rendering as vertex data",
868 		"rendering as index data",
869 		"reading in shader as uniform buffer data",
870 		"using as PBO and uploading to texture",
871 		"reading back using glMapBufferRange()"
872 	};
873 	return de::getSizedArrayElement<VERIFY_LAST>(s_desc, verify);
874 }
875 
876 } // BufferTestUtil
877 } // gls
878 } // deqp
879