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