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
46namespace deqp
47{
48namespace gls
49{
50namespace BufferTestUtil
51{
52
53enum
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
61using tcu::TestLog;
62using std::vector;
63using std::string;
64using std::set;
65
66// Helper functions.
67
68void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed)
69{
70	std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr);
71}
72
73bool 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
135const 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
154const 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
175BufferCase::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
182BufferCase::~BufferCase (void)
183{
184	enableLogging(false);
185	BufferCase::deinit();
186}
187
188void BufferCase::init (void)
189{
190	enableLogging(true);
191}
192
193void 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
199deUint32 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
218void BufferCase::deleteBuffer (deUint32 buffer)
219{
220	glDeleteBuffers(1, &buffer);
221	m_allocatedBuffers.erase(buffer);
222}
223
224void 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
233void ReferenceBuffer::setSize (int numBytes)
234{
235	m_data.resize(numBytes);
236}
237
238void ReferenceBuffer::setData (int numBytes, const deUint8* bytes)
239{
240	m_data.resize(numBytes);
241	std::copy(bytes, bytes+numBytes, m_data.begin());
242}
243
244void 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
252BufferWriterBase::BufferWriterBase (glu::RenderContext& renderCtx, tcu::TestLog& log)
253	: CallLogWrapper	(renderCtx.getFunctions(), log)
254	, m_renderCtx		(renderCtx)
255{
256	enableLogging(true);
257}
258
259void 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
267BufferWriter::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
279BufferWriter::~BufferWriter (void)
280{
281	delete m_writer;
282}
283
284void 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
292void 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
302void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
303{
304	write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
305}
306
307void 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
317void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
318{
319	write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
320}
321
322void 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
338BufferVerifierBase::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
346bool 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
354BufferVerifier::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
367BufferVerifier::~BufferVerifier (void)
368{
369	delete m_verifier;
370}
371
372bool 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
380bool 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
390bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
391{
392	return verify(buffer, reference, offset, numBytes, GL_ARRAY_BUFFER);
393}
394
395bool 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
417VertexArrayVerifier::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
465VertexArrayVerifier::~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
476static 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			= (x+0) / (float)gridSizeX;
484		float	sy0			= (y+0) / (float)gridSizeY;
485		float	sx1			= (x+1) / (float)gridSizeX;
486		float	sy1			= (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
500static 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
523static 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
531static 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
568bool 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
655IndexArrayVerifier::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
703IndexArrayVerifier::~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
714static 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
733static 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
750template<typename T>
751static 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
757bool 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
851const 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
863const 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