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 Texture buffer test case
22 *//*--------------------------------------------------------------------*/
23
24#include "glsTextureBufferCase.hpp"
25
26#include "tcuFormatUtil.hpp"
27#include "tcuImageCompare.hpp"
28#include "tcuRenderTarget.hpp"
29#include "tcuStringTemplate.hpp"
30#include "tcuSurface.hpp"
31#include "tcuTestLog.hpp"
32#include "tcuTextureUtil.hpp"
33
34#include "rrRenderer.hpp"
35#include "rrShaders.hpp"
36
37#include "gluObjectWrapper.hpp"
38#include "gluPixelTransfer.hpp"
39#include "gluShaderProgram.hpp"
40#include "gluShaderUtil.hpp"
41#include "gluStrUtil.hpp"
42#include "gluTexture.hpp"
43
44#include "glwEnums.hpp"
45#include "glwFunctions.hpp"
46
47#include "deRandom.hpp"
48#include "deStringUtil.hpp"
49#include "deUniquePtr.hpp"
50
51#include "deMemory.h"
52#include "deString.h"
53#include "deMath.h"
54
55#include <sstream>
56#include <string>
57#include <vector>
58
59using tcu::TestLog;
60
61using std::map;
62using std::string;
63using std::vector;
64
65using namespace deqp::gls::TextureBufferCaseUtil;
66
67namespace deqp
68{
69namespace gls
70{
71namespace
72{
73
74enum
75{
76	MAX_VIEWPORT_WIDTH	= 256,
77	MAX_VIEWPORT_HEIGHT	= 256,
78	MIN_VIEWPORT_WIDTH	= 64,
79	MIN_VIEWPORT_HEIGHT	= 64,
80};
81
82deUint8 extend2BitsToByte (deUint8 bits)
83{
84	deUint8 x = 0;
85
86	DE_ASSERT((bits & (~0x03u)) == 0);
87
88	x |= bits << 6;
89	x |= bits << 4;
90	x |= bits << 2;
91	x |= bits;
92
93	return x;
94}
95
96void genRandomCoords (de::Random rng, vector<deUint8>& coords, size_t offset, size_t size)
97{
98	const deUint8 bits		= 2;
99	const deUint8 bitMask	= deUint8((0x1u << bits) - 1);
100
101	coords.resize(size);
102
103	for (int i = 0; i < (int)size; i++)
104	{
105		const deUint8 xBits = deUint8(rng.getUint32() & bitMask);
106		coords[i] = extend2BitsToByte(xBits);
107	}
108
109	// Fill indices with nice quad
110	{
111		const deUint8 indices[] =
112		{
113			extend2BitsToByte(0x0u),
114			extend2BitsToByte(0x1u),
115			extend2BitsToByte(0x2u),
116			extend2BitsToByte(0x3u)
117		};
118
119		for (int i = 0; i < DE_LENGTH_OF_ARRAY(indices); i++)
120		{
121			const deUint8	index	= indices[i];
122			const size_t	posX	= (size_t(index) * 2) + 0;
123			const size_t	posY	= (size_t(index) * 2) + 1;
124
125			if (posX >= offset && posX < offset+size)
126				coords[posX - offset] = ((i % 2) == 0 ? extend2BitsToByte(0x0u) : extend2BitsToByte(0x3u));
127
128			if (posY >= offset && posY < offset+size)
129				coords[posY - offset] = ((i / 2) == 1 ? extend2BitsToByte(0x3u) : extend2BitsToByte(0x0u));
130		}
131	}
132
133	// Fill beginning of buffer
134	{
135		const deUint8 indices[] =
136		{
137			extend2BitsToByte(0x0u),
138			extend2BitsToByte(0x3u),
139			extend2BitsToByte(0x1u),
140
141			extend2BitsToByte(0x1u),
142			extend2BitsToByte(0x2u),
143			extend2BitsToByte(0x0u),
144
145			extend2BitsToByte(0x0u),
146			extend2BitsToByte(0x2u),
147			extend2BitsToByte(0x1u),
148
149			extend2BitsToByte(0x1u),
150			extend2BitsToByte(0x3u),
151			extend2BitsToByte(0x0u)
152		};
153
154		for (int i = (int)offset; i < DE_LENGTH_OF_ARRAY(indices) && i < (int)(offset + size); i++)
155			coords[i-offset] = indices[i];
156	}
157}
158
159class CoordVertexShader : public rr::VertexShader
160{
161public:
162	CoordVertexShader (void)
163		: rr::VertexShader(1, 1)
164	{
165		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
166		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
167	}
168
169	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
170	{
171		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
172		{
173			rr::VertexPacket* const		packet		= packets[packetNdx];
174			tcu::Vec4					position;
175
176			readVertexAttrib(position, inputs[0], packet->instanceNdx, packet->vertexNdx);
177
178			packet->outputs[0]	= tcu::Vec4(1.0f);
179			packet->position	= tcu::Vec4(2.0f * (position.x() - 0.5f), 2.0f * (position.y() - 0.5f), 0.0f, 1.0f);
180		}
181	}
182};
183
184class TextureVertexShader : public rr::VertexShader
185{
186public:
187	TextureVertexShader (const tcu::ConstPixelBufferAccess& texture)
188		: rr::VertexShader	(1, 1)
189		, m_texture			(texture)
190	{
191		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
192		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
193	}
194
195	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
196	{
197		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
198		{
199			rr::VertexPacket* const		packet		= packets[packetNdx];
200			tcu::Vec4					position;
201			tcu::Vec4					texelValue;
202
203			readVertexAttrib(position, inputs[0], packet->instanceNdx, packet->vertexNdx);
204
205			texelValue	= tcu::Vec4(m_texture.getPixel(de::clamp<int>((deRoundFloatToInt32(position.x() * 4) + 4) * (deRoundFloatToInt32(position.y() * 4) + 4), 0, m_texture.getWidth()-1), 0));
206
207			packet->outputs[0]	= texelValue;
208			packet->position	= tcu::Vec4(2.0f * (position.x() - 0.5f), 2.0f * (position.y() - 0.5f), 0.0f, 1.0f);
209		}
210	}
211
212private:
213	const tcu::ConstPixelBufferAccess& m_texture;
214};
215
216class CoordFragmentShader : public rr::FragmentShader
217{
218public:
219	CoordFragmentShader (void)
220		: rr::FragmentShader (1, 1)
221	{
222		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
223		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
224	}
225
226
227	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
228	{
229		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
230		{
231			rr::FragmentPacket&	packet		= packets[packetNdx];
232
233			const tcu::Vec4		vtxColor0	= rr::readVarying<float>(packet, context, 0, 0);
234			const tcu::Vec4		vtxColor1	= rr::readVarying<float>(packet, context, 0, 1);
235			const tcu::Vec4		vtxColor2	= rr::readVarying<float>(packet, context, 0, 2);
236			const tcu::Vec4		vtxColor3	= rr::readVarying<float>(packet, context, 0, 3);
237
238			const tcu::Vec4		color0		= vtxColor0;
239			const tcu::Vec4		color1		= vtxColor1;
240			const tcu::Vec4		color2		= vtxColor2;
241			const tcu::Vec4		color3		= vtxColor3;
242
243			rr::writeFragmentOutput(context, packetNdx, 0, 0, tcu::Vec4(color0.x() * color0.w(), color0.y() * color0.w(), color0.z() * color0.w(), 1.0f));
244			rr::writeFragmentOutput(context, packetNdx, 1, 0, tcu::Vec4(color1.x() * color1.w(), color1.y() * color1.w(), color1.z() * color1.w(), 1.0f));
245			rr::writeFragmentOutput(context, packetNdx, 2, 0, tcu::Vec4(color2.x() * color2.w(), color2.y() * color2.w(), color2.z() * color2.w(), 1.0f));
246			rr::writeFragmentOutput(context, packetNdx, 3, 0, tcu::Vec4(color3.x() * color3.w(), color3.y() * color3.w(), color3.z() * color3.w(), 1.0f));
247		}
248	}
249};
250
251class TextureFragmentShader : public rr::FragmentShader
252{
253public:
254	TextureFragmentShader (const tcu::ConstPixelBufferAccess& texture)
255		: rr::FragmentShader	(1, 1)
256		, m_texture				(texture)
257	{
258		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
259		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
260	}
261
262	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
263	{
264		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
265		{
266			rr::FragmentPacket&	packet		= packets[packetNdx];
267
268			const tcu::IVec2	position	= packet.position;
269
270			const tcu::IVec2	position0	= packet.position + tcu::IVec2(0, 0);
271			const tcu::IVec2	position1	= packet.position + tcu::IVec2(1, 0);
272			const tcu::IVec2	position2	= packet.position + tcu::IVec2(0, 1);
273			const tcu::IVec2	position3	= packet.position + tcu::IVec2(1, 1);
274
275			const tcu::Vec4		texColor0	= m_texture.getPixel(de::clamp((position0.x() * position0.y()), 0, m_texture.getWidth()-1), 0);
276			const tcu::Vec4		texColor1	= m_texture.getPixel(de::clamp((position1.x() * position1.y()), 0, m_texture.getWidth()-1), 0);
277			const tcu::Vec4		texColor2	= m_texture.getPixel(de::clamp((position2.x() * position2.y()), 0, m_texture.getWidth()-1), 0);
278			const tcu::Vec4		texColor3	= m_texture.getPixel(de::clamp((position3.x() * position3.y()), 0, m_texture.getWidth()-1), 0);
279
280			const tcu::Vec4		vtxColor0	= rr::readVarying<float>(packet, context, 0, 0);
281			const tcu::Vec4		vtxColor1	= rr::readVarying<float>(packet, context, 0, 1);
282			const tcu::Vec4		vtxColor2	= rr::readVarying<float>(packet, context, 0, 2);
283			const tcu::Vec4		vtxColor3	= rr::readVarying<float>(packet, context, 0, 3);
284
285			const tcu::Vec4		color0		= 0.5f * (vtxColor0 + texColor0);
286			const tcu::Vec4		color1		= 0.5f * (vtxColor1 + texColor1);
287			const tcu::Vec4		color2		= 0.5f * (vtxColor2 + texColor2);
288			const tcu::Vec4		color3		= 0.5f * (vtxColor3 + texColor3);
289
290			rr::writeFragmentOutput(context, packetNdx, 0, 0, tcu::Vec4(color0.x() * color0.w(), color0.y() * color0.w(), color0.z() * color0.w(), 1.0f));
291			rr::writeFragmentOutput(context, packetNdx, 1, 0, tcu::Vec4(color1.x() * color1.w(), color1.y() * color1.w(), color1.z() * color1.w(), 1.0f));
292			rr::writeFragmentOutput(context, packetNdx, 2, 0, tcu::Vec4(color2.x() * color2.w(), color2.y() * color2.w(), color2.z() * color2.w(), 1.0f));
293			rr::writeFragmentOutput(context, packetNdx, 3, 0, tcu::Vec4(color3.x() * color3.w(), color3.y() * color3.w(), color3.z() * color3.w(), 1.0f));
294		}
295	}
296
297private:
298	const tcu::ConstPixelBufferAccess& m_texture;
299};
300
301string generateVertexShaderTemplate (RenderBits renderBits)
302{
303	std::ostringstream stream;
304
305	stream <<
306		"${VERSION_HEADER}\n";
307
308	if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE)
309		stream << "${TEXTURE_BUFFER_EXT}";
310
311	stream <<
312		"${VTX_INPUT} layout(location = 0) ${HIGHP} vec2 i_coord;\n"
313		"${VTX_OUTPUT} ${HIGHP} vec4 v_color;\n";
314
315	if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE)
316	{
317		stream <<
318			"uniform ${HIGHP} samplerBuffer u_vtxSampler;\n";
319	}
320
321	stream <<
322		"\n"
323		"void main (void)\n"
324		"{\n";
325
326	if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE)
327		stream << "\tv_color = texelFetch(u_vtxSampler, clamp((int(round(i_coord.x * 4.0)) + 4) * (int(round(i_coord.y * 4.0)) + 4), 0, textureSize(u_vtxSampler)-1));\n";
328	else
329		stream << "\tv_color = vec4(1.0);\n";
330
331	stream <<
332		"\tgl_Position = vec4(2.0 * (i_coord - vec2(0.5)), 0.0, 1.0);\n"
333		"}\n";
334
335	return stream.str();
336}
337
338string generateFragmentShaderTemplate (RenderBits renderBits)
339{
340	std::ostringstream stream;
341
342	stream <<
343		"${VERSION_HEADER}\n";
344
345	if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE)
346		stream << "${TEXTURE_BUFFER_EXT}";
347
348	stream <<
349		"${FRAG_OUTPUT} layout(location = 0) ${HIGHP} vec4 dEQP_FragColor;\n"
350		"${FRAG_INPUT} ${HIGHP} vec4 v_color;\n";
351
352	if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE)
353		stream << "uniform ${HIGHP} samplerBuffer u_fragSampler;\n";
354
355	stream <<
356		"\n"
357		"void main (void)\n"
358		"{\n";
359
360	if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE)
361		stream << "\t${HIGHP} vec4 color = 0.5 * (v_color + texelFetch(u_fragSampler, clamp(int(gl_FragCoord.x) * int(gl_FragCoord.y), 0, textureSize(u_fragSampler)-1)));\n";
362	else
363		stream << "\t${HIGHP} vec4 color = v_color;\n";
364
365	stream <<
366		"\tdEQP_FragColor = vec4(color.xyz * color.w, 1.0);\n"
367		"}\n";
368
369	return stream.str();
370}
371
372string specializeShader (const string& shaderTemplateString, glu::GLSLVersion glslVersion)
373{
374	const tcu::StringTemplate	shaderTemplate(shaderTemplateString);
375	map<string, string>			parameters;
376
377	parameters["VERSION_HEADER"]		= glu::getGLSLVersionDeclaration(glslVersion);
378	parameters["VTX_OUTPUT"]			= "out";
379	parameters["VTX_INPUT"]				= "in";
380	parameters["FRAG_INPUT"]			= "in";
381	parameters["FRAG_OUTPUT"]			= "out";
382	parameters["HIGHP"]					= (glslVersion == glu::GLSL_VERSION_330 ? "" : "highp");
383	parameters["TEXTURE_BUFFER_EXT"]	= (glslVersion == glu::GLSL_VERSION_330 ? "" : "#extension GL_EXT_texture_buffer : enable\n");
384
385	return shaderTemplate.specialize(parameters);
386}
387
388glu::ShaderProgram* createRenderProgram (glu::RenderContext&	renderContext,
389										 RenderBits				renderBits)
390{
391	const string				vertexShaderTemplate	= generateVertexShaderTemplate(renderBits);
392	const string				fragmentShaderTemplate	= generateFragmentShaderTemplate(renderBits);
393
394	const glu::GLSLVersion		glslVersion				= glu::getContextTypeGLSLVersion(renderContext.getType());
395
396	const string				vertexShaderSource		= specializeShader(vertexShaderTemplate, glslVersion);
397	const string				fragmentShaderSource	= specializeShader(fragmentShaderTemplate, glslVersion);
398
399	glu::ShaderProgram* const	program					= new glu::ShaderProgram(renderContext, glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
400
401	return program;
402}
403
404void logModifications (TestLog& log, ModifyBits modifyBits)
405{
406	tcu::ScopedLogSection section(log, "Modify Operations", "Modify Operations");
407
408	const struct
409	{
410		ModifyBits	bit;
411		const char*	str;
412	} bitInfos[] =
413	{
414		{ MODIFYBITS_BUFFERDATA,			"Recreate buffer data with glBufferData()."			},
415		{ MODIFYBITS_BUFFERSUBDATA,			"Modify texture buffer with glBufferSubData()."		},
416		{ MODIFYBITS_MAPBUFFER_WRITE,		"Map buffer write-only and rewrite data."			},
417		{ MODIFYBITS_MAPBUFFER_READWRITE,	"Map buffer readw-write check and rewrite data."	}
418	};
419
420	DE_ASSERT(modifyBits != 0);
421
422	for (int infoNdx = 0; infoNdx < DE_LENGTH_OF_ARRAY(bitInfos); infoNdx++)
423	{
424		if (modifyBits & bitInfos[infoNdx].bit)
425			log << TestLog::Message << bitInfos[infoNdx].str << TestLog::EndMessage;
426	}
427}
428
429void modifyBufferData (TestLog&				log,
430					   de::Random&			rng,
431					   glu::TextureBuffer&	texture)
432{
433	vector<deUint8> data;
434
435	genRandomCoords(rng, data, 0, texture.getBufferSize());
436
437	log << TestLog::Message << "BufferData, Size: " << data.size() << TestLog::EndMessage;
438
439	texture.bufferData(&(data[0]), data.size());
440	texture.upload();
441}
442
443void modifyBufferSubData (TestLog&				log,
444						  de::Random&			rng,
445						  const glw::Functions&	gl,
446						  glu::TextureBuffer&	texture)
447{
448	const size_t				minSize		= 4*16;
449	const size_t				size		= de::max<size_t>(minSize, size_t((texture.getSize() != 0 ? texture.getSize() : texture.getBufferSize()) * (0.7 + 0.3 * rng.getFloat())));
450	const size_t				minOffset	= texture.getOffset();
451	const size_t				offset		= minOffset + (rng.getUint32() % (texture.getBufferSize() - (size + minOffset)));
452	vector<deUint8>				data;
453
454	genRandomCoords(rng, data, offset, size);
455
456	log << TestLog::Message << "BufferSubData, Offset: " << offset << ", Size: " << size << TestLog::EndMessage;
457
458	gl.bindBuffer(GL_TEXTURE_BUFFER, texture.getGLBuffer());
459	gl.bufferSubData(GL_TEXTURE_BUFFER, (glw::GLsizei)offset, (glw::GLsizei)data.size(), &(data[0]));
460	gl.bindBuffer(GL_TEXTURE_BUFFER, 0);
461	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update data with glBufferSubData()");
462
463	deMemcpy(texture.getRefBuffer() + offset, &(data[0]), int(data.size()));
464}
465
466void modifyMapWrite (TestLog&				log,
467					 de::Random&			rng,
468					 const glw::Functions&	gl,
469					 glu::TextureBuffer&	texture)
470{
471	const size_t				minSize		= 4*16;
472	const size_t				size		= de::max<size_t>(minSize, size_t((texture.getSize() != 0 ? texture.getSize() : texture.getBufferSize()) * (0.7 + 0.3 * rng.getFloat())));
473	const size_t				minOffset	= texture.getOffset();
474	const size_t				offset		= minOffset + (rng.getUint32() % (texture.getBufferSize() - (size + minOffset)));
475	vector<deUint8>				data;
476
477	genRandomCoords(rng, data, offset, size);
478
479	log << TestLog::Message << "glMapBufferRange, Write Only, Offset: " << offset << ", Size: " << size << TestLog::EndMessage;
480
481	gl.bindBuffer(GL_TEXTURE_BUFFER, texture.getGLBuffer());
482	{
483		deUint8* ptr = (deUint8*)gl.mapBufferRange(GL_TEXTURE_BUFFER, (glw::GLsizei)offset, (glw::GLsizei)size, GL_MAP_WRITE_BIT);
484
485		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
486		TCU_CHECK(ptr);
487
488		for (int i = 0; i < (int)data.size(); i++)
489			ptr[i] = data[i];
490
491		TCU_CHECK(gl.unmapBuffer(GL_TEXTURE_BUFFER));
492	}
493	gl.bindBuffer(GL_TEXTURE_BUFFER, 0);
494	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update data with glMapBufferRange()");
495
496	deMemcpy(texture.getRefBuffer()+offset, &(data[0]), int(data.size()));
497}
498
499void modifyMapReadWrite (TestLog&				log,
500						 tcu::ResultCollector&	resultCollector,
501						 de::Random&			rng,
502						 const glw::Functions&	gl,
503						 glu::TextureBuffer&	texture)
504{
505	const size_t				minSize		= 4*16;
506	const size_t				size		= de::max<size_t>(minSize, size_t((texture.getSize() != 0 ? texture.getSize() : texture.getBufferSize()) * (0.7 + 0.3 * rng.getFloat())));
507	const size_t				minOffset	= texture.getOffset();
508	const size_t				offset		= minOffset + (rng.getUint32() % (texture.getBufferSize() - (size + minOffset)));
509	vector<deUint8>				data;
510
511	genRandomCoords(rng, data, offset, size);
512
513	log << TestLog::Message << "glMapBufferRange, Read Write, Offset: " << offset << ", Size: " << size << TestLog::EndMessage;
514
515	gl.bindBuffer(GL_TEXTURE_BUFFER, texture.getGLBuffer());
516	{
517		size_t			invalidBytes	= 0;
518		deUint8* const	ptr				= (deUint8*)gl.mapBufferRange(GL_TEXTURE_BUFFER, (glw::GLsizei)offset, (glw::GLsizei)size, GL_MAP_WRITE_BIT|GL_MAP_READ_BIT);
519
520		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
521		TCU_CHECK(ptr);
522
523		for (int i = 0; i < (int)data.size(); i++)
524		{
525			if (ptr[i] != texture.getRefBuffer()[offset+i])
526			{
527				if (invalidBytes < 24)
528					log << TestLog::Message << "Invalid byte in mapped buffer. " << tcu::Format::Hex<2>(data[i]).toString() << " at " << i << ", expected " << tcu::Format::Hex<2>(texture.getRefBuffer()[i]).toString() << TestLog::EndMessage;
529
530				invalidBytes++;
531			}
532
533			ptr[i] = data[i];
534		}
535
536		TCU_CHECK(gl.unmapBuffer(GL_TEXTURE_BUFFER));
537
538		if (invalidBytes > 0)
539		{
540			log << TestLog::Message << "Total of " << invalidBytes << " invalid bytes." << TestLog::EndMessage;
541			resultCollector.fail("Invalid data in mapped buffer");
542		}
543	}
544
545	gl.bindBuffer(GL_TEXTURE_BUFFER, 0);
546	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update data with glMapBufferRange()");
547
548	for (int i = 0; i < (int)data.size(); i++)
549		texture.getRefBuffer()[offset+i] = data[i];
550}
551
552void modify (TestLog&						log,
553			 tcu::ResultCollector&			resultCollector,
554			 glu::RenderContext&			renderContext,
555			 ModifyBits						modifyBits,
556			 de::Random&					rng,
557			 glu::TextureBuffer&			texture)
558{
559	const tcu::ScopedLogSection modifySection(log, "Modifying Texture buffer", "Modifying Texture Buffer");
560
561	logModifications(log, modifyBits);
562
563	if (modifyBits & MODIFYBITS_BUFFERDATA)
564		modifyBufferData(log, rng, texture);
565
566	if (modifyBits & MODIFYBITS_BUFFERSUBDATA)
567		modifyBufferSubData(log, rng, renderContext.getFunctions(), texture);
568
569	if (modifyBits & MODIFYBITS_MAPBUFFER_WRITE)
570		modifyMapWrite(log, rng, renderContext.getFunctions(), texture);
571
572	if (modifyBits & MODIFYBITS_MAPBUFFER_READWRITE)
573		modifyMapReadWrite(log, resultCollector, rng, renderContext.getFunctions(), texture);
574}
575
576void renderGL (glu::RenderContext&		renderContext,
577			   RenderBits				renderBits,
578			   deUint32					coordSeed,
579			   int						triangleCount,
580			   glu::ShaderProgram&		program,
581			   glu::TextureBuffer&		texture)
582{
583	const glw::Functions&	gl			= renderContext.getFunctions();
584	const glu::VertexArray	vao			(renderContext);
585	const glu::Buffer		coordBuffer	(renderContext);
586
587	gl.useProgram(program.getProgram());
588	gl.bindVertexArray(*vao);
589
590	gl.enableVertexAttribArray(0);
591
592	if (renderBits & RENDERBITS_AS_VERTEX_ARRAY)
593	{
594		gl.bindBuffer(GL_ARRAY_BUFFER, texture.getGLBuffer());
595		gl.vertexAttribPointer(0, 2, GL_UNSIGNED_BYTE, true, 0, DE_NULL);
596	}
597	else
598	{
599		de::Random		rng(coordSeed);
600		vector<deUint8> coords;
601
602		genRandomCoords(rng, coords, 0, 256*2);
603
604		gl.bindBuffer(GL_ARRAY_BUFFER, *coordBuffer);
605		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizei)coords.size(), &(coords[0]), GL_STREAM_DRAW);
606		gl.vertexAttribPointer(0, 2, GL_UNSIGNED_BYTE, true, 0, DE_NULL);
607	}
608
609	if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE)
610	{
611		const deInt32 location = gl.getUniformLocation(program.getProgram(), "u_vtxSampler");
612
613		gl.activeTexture(GL_TEXTURE0);
614		gl.bindTexture(GL_TEXTURE_BUFFER, texture.getGLTexture());
615		gl.uniform1i(location, 0);
616	}
617
618	if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE)
619	{
620		const deInt32 location = gl.getUniformLocation(program.getProgram(), "u_fragSampler");
621
622		gl.activeTexture(GL_TEXTURE1);
623		gl.bindTexture(GL_TEXTURE_BUFFER, texture.getGLTexture());
624		gl.uniform1i(location, 1);
625		gl.activeTexture(GL_TEXTURE0);
626	}
627
628	if (renderBits & RENDERBITS_AS_INDEX_ARRAY)
629	{
630		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, texture.getGLBuffer());
631		gl.drawElements(GL_TRIANGLES, triangleCount * 3, GL_UNSIGNED_BYTE, DE_NULL);
632		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
633	}
634	else
635		gl.drawArrays(GL_TRIANGLES, 0, triangleCount * 3);
636
637	if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE)
638	{
639		gl.activeTexture(GL_TEXTURE1);
640		gl.bindTexture(GL_TEXTURE_BUFFER, 0);
641	}
642
643	if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE)
644	{
645		gl.activeTexture(GL_TEXTURE0);
646		gl.bindTexture(GL_TEXTURE_BUFFER, 0);
647	}
648
649	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
650	gl.disableVertexAttribArray(0);
651
652	gl.bindVertexArray(0);
653	gl.useProgram(0);
654	GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
655}
656
657void renderReference (RenderBits					renderBits,
658					  deUint32						coordSeed,
659					  int							triangleCount,
660					  glu::TextureBuffer&			texture,
661					  const tcu::PixelBufferAccess&	target)
662{
663	const CoordVertexShader			coordVertexShader;
664	const TextureVertexShader		textureVertexShader		(texture.getRefTexture());
665	const rr::VertexShader* const	vertexShader			= (renderBits & RENDERBITS_AS_VERTEX_TEXTURE ? static_cast<const rr::VertexShader*>(&textureVertexShader) : &coordVertexShader);
666
667	const CoordFragmentShader		coordFragmmentShader;
668	const TextureFragmentShader		textureFragmentShader	(texture.getRefTexture());
669	const rr::FragmentShader* const	fragmentShader			= (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE ? static_cast<const rr::FragmentShader*>(&textureFragmentShader) : &coordFragmmentShader);
670
671	const rr::Renderer				renderer;
672	const rr::RenderState			renderState(rr::ViewportState(rr::WindowRectangle(0, 0, target.getWidth(), target.getHeight())));
673	const rr::RenderTarget			renderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(target));
674
675	const rr::Program				program(vertexShader, fragmentShader);
676
677	rr::VertexAttrib				vertexAttribs[1];
678	vector<deUint8>					coords;
679
680	if (renderBits & RENDERBITS_AS_VERTEX_ARRAY)
681	{
682		vertexAttribs[0].type			= rr::VERTEXATTRIBTYPE_NONPURE_UNORM8;
683		vertexAttribs[0].size			= 2;
684		vertexAttribs[0].pointer		= texture.getRefBuffer();
685	}
686	else
687	{
688		de::Random rng(coordSeed);
689
690		genRandomCoords(rng, coords, 0, 256*2);
691
692		vertexAttribs[0].type			= rr::VERTEXATTRIBTYPE_NONPURE_UNORM8;
693		vertexAttribs[0].size			= 2;
694		vertexAttribs[0].pointer		= &(coords[0]);
695	}
696
697	if (renderBits & RENDERBITS_AS_INDEX_ARRAY)
698	{
699		const rr::PrimitiveList	primitives(rr::PRIMITIVETYPE_TRIANGLES, triangleCount * 3, rr::DrawIndices((const void*)texture.getRefBuffer(), rr::INDEXTYPE_UINT8));
700		const rr::DrawCommand	cmd(renderState, renderTarget, program, 1, vertexAttribs, primitives);
701
702		renderer.draw(cmd);
703	}
704	else
705	{
706		const rr::PrimitiveList	primitives(rr::PRIMITIVETYPE_TRIANGLES, triangleCount * 3, 0);
707		const rr::DrawCommand	cmd(renderState, renderTarget, program, 1, vertexAttribs, primitives);
708
709		renderer.draw(cmd);
710	}
711}
712
713void logRendering (TestLog& log, RenderBits renderBits)
714{
715	const struct
716	{
717		RenderBits	bit;
718		const char*	str;
719	} bitInfos[] =
720	{
721		{ RENDERBITS_AS_VERTEX_ARRAY,		"vertex array"		},
722		{ RENDERBITS_AS_INDEX_ARRAY,		"index array"		},
723		{ RENDERBITS_AS_VERTEX_TEXTURE,		"vertex texture"	},
724		{ RENDERBITS_AS_FRAGMENT_TEXTURE,	"fragment texture"	}
725	};
726
727	std::ostringstream	stream;
728	vector<const char*> usedAs;
729
730	DE_ASSERT(renderBits != 0);
731
732	for (int infoNdx = 0; infoNdx < DE_LENGTH_OF_ARRAY(bitInfos); infoNdx++)
733	{
734		if (renderBits & bitInfos[infoNdx].bit)
735			usedAs.push_back(bitInfos[infoNdx].str);
736	}
737
738	stream << "Render using texture buffer as ";
739
740	for (int asNdx = 0; asNdx < (int)usedAs.size(); asNdx++)
741	{
742		if (asNdx+1 == (int)usedAs.size() && (int)usedAs.size() > 1)
743			stream << " and ";
744		else if (asNdx > 0)
745			stream << ", ";
746
747		stream << usedAs[asNdx];
748	}
749
750	stream << ".";
751
752	log << TestLog::Message << stream.str() << TestLog::EndMessage;
753}
754
755void render (TestLog&						log,
756			 glu::RenderContext&			renderContext,
757			 RenderBits						renderBits,
758			 de::Random&					rng,
759			 glu::ShaderProgram&			program,
760			 glu::TextureBuffer&			texture,
761			 const tcu::PixelBufferAccess&	target)
762{
763	const tcu::ScopedLogSection	renderSection	(log, "Render Texture buffer", "Render Texture Buffer");
764	const int					triangleCount	= 8;
765	const deUint32				coordSeed		= rng.getUint32();
766
767	logRendering(log, renderBits);
768
769	renderGL(renderContext, renderBits, coordSeed, triangleCount, program, texture);
770	renderReference(renderBits, coordSeed, triangleCount, texture, target);
771}
772
773void verifyScreen (TestLog&								log,
774				   tcu::ResultCollector&				resultCollector,
775				   glu::RenderContext&					renderContext,
776				   const tcu::ConstPixelBufferAccess&	referenceTarget)
777{
778	const tcu::ScopedLogSection	verifySection	(log, "Verify screen contents", "Verify screen contents");
779	tcu::Surface				screen			(referenceTarget.getWidth(), referenceTarget.getHeight());
780
781	glu::readPixels(renderContext, 0, 0, screen.getAccess());
782
783	if (!tcu::fuzzyCompare(log, "Result of rendering", "Result of rendering", referenceTarget, screen.getAccess(), 0.05f, tcu::COMPARE_LOG_RESULT))
784		resultCollector.fail("Rendering failed");
785}
786
787void logImplementationInfo (TestLog& log, glu::RenderContext& renderContext)
788{
789	const tcu::ScopedLogSection		section	(log, "Implementation Values", "Implementation Values");
790	de::UniquePtr<glu::ContextInfo>	info	(glu::ContextInfo::create(renderContext));
791	const glw::Functions&			gl		= renderContext.getFunctions();
792
793	if (glu::contextSupports(renderContext.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE)))
794	{
795		deInt32 maxTextureSize;
796
797		gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize);
798		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE)");
799
800		log << TestLog::Message << "GL_MAX_TEXTURE_BUFFER_SIZE : " <<  maxTextureSize << TestLog::EndMessage;
801	}
802	else if (glu::contextSupports(renderContext.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) && info->isExtensionSupported("GL_EXT_texture_buffer"))
803	{
804		{
805			deInt32 maxTextureSize;
806
807			gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize);
808			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_EXT)");
809
810			log << TestLog::Message << "GL_MAX_TEXTURE_BUFFER_SIZE_EXT : " <<  maxTextureSize << TestLog::EndMessage;
811		}
812
813		{
814			deInt32 textureBufferAlignment;
815
816			gl.getIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &textureBufferAlignment);
817			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT)");
818
819			log << TestLog::Message << "GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT : " <<  textureBufferAlignment << TestLog::EndMessage;
820		}
821	}
822	else
823		DE_ASSERT(DE_FALSE);
824}
825
826void logTextureInfo (TestLog&	log,
827					 deUint32	format,
828					 size_t		bufferSize,
829					 size_t		offset,
830					 size_t		size)
831{
832	const tcu::ScopedLogSection	section(log, "Texture Info", "Texture Info");
833
834	log << TestLog::Message << "Texture format : " << glu::getPixelFormatStr(format) << TestLog::EndMessage;
835	log << TestLog::Message << "Buffer size : " << bufferSize << TestLog::EndMessage;
836
837	if (offset != 0 || size != 0)
838	{
839		log << TestLog::Message << "Buffer range offset: " << offset << TestLog::EndMessage;
840		log << TestLog::Message << "Buffer range size: " << size << TestLog::EndMessage;
841	}
842}
843
844void runTests (tcu::TestContext&	testCtx,
845			   glu::RenderContext&	renderContext,
846			   de::Random&			rng,
847			   deUint32				format,
848			   size_t				bufferSize,
849			   size_t				offset,
850			   size_t				size,
851			   RenderBits			preRender,
852			   glu::ShaderProgram*	preRenderProgram,
853			   ModifyBits			modifyType,
854			   RenderBits			postRender,
855			   glu::ShaderProgram*	postRenderProgram)
856{
857	const tcu::RenderTarget	renderTarget	(renderContext.getRenderTarget());
858	const glw::Functions&	gl				= renderContext.getFunctions();
859
860	const int				width			= de::min<int>(renderTarget.getWidth(), MAX_VIEWPORT_WIDTH);
861	const int				height			= de::min<int>(renderTarget.getHeight(), MAX_VIEWPORT_HEIGHT);
862	const tcu::Vec4			clearColor		(0.25f, 0.5f, 0.75f, 1.0f);
863
864	TestLog&				log				= testCtx.getLog();
865	tcu::ResultCollector	resultCollector	(log);
866
867	logImplementationInfo(log, renderContext);
868	logTextureInfo(log, format, bufferSize, offset, size);
869
870	{
871		tcu::Surface			referenceTarget	(width, height);
872		vector<deUint8>			bufferData;
873
874		genRandomCoords(rng, bufferData, 0, bufferSize);
875
876		for (deUint8 i = 0; i < 4; i++)
877		{
878			const deUint8 val = extend2BitsToByte(i);
879
880			if (val >= offset && val < offset + size)
881			{
882				bufferData[val*2 + 0] = (i / 2 == 0 ? extend2BitsToByte(0x2u) : extend2BitsToByte(0x01u));
883				bufferData[val*2 + 1] = (i % 2 == 0 ? extend2BitsToByte(0x2u) : extend2BitsToByte(0x01u));
884			}
885		}
886
887		{
888			glu::TextureBuffer texture (renderContext, format, bufferSize, offset, size, &(bufferData[0]));
889
890			TCU_CHECK_MSG(width >= MIN_VIEWPORT_WIDTH || height >= MIN_VIEWPORT_HEIGHT, "Too small viewport");
891
892			DE_ASSERT(preRender == 0 || preRenderProgram);
893			DE_ASSERT(postRender == 0 || postRenderProgram);
894
895			gl.viewport(0, 0, width, height);
896			gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
897			gl.clear(GL_COLOR_BUFFER_BIT);
898			GLU_EXPECT_NO_ERROR(gl.getError(), "Screen setup failed");
899
900			tcu::clear(referenceTarget.getAccess(), clearColor);
901
902			texture.upload();
903
904			if (preRender != 0)
905				render(log, renderContext, preRender, rng, *preRenderProgram, texture, referenceTarget.getAccess());
906
907			if (modifyType != 0)
908				modify(log, resultCollector, renderContext, modifyType, rng, texture);
909
910			if (postRender != 0)
911				render(log, renderContext, postRender, rng, *postRenderProgram, texture, referenceTarget.getAccess());
912		}
913
914		verifyScreen(log, resultCollector, renderContext, referenceTarget.getAccess());
915
916		resultCollector.setTestContextResult(testCtx);
917	}
918}
919
920} // anonymous
921
922TextureBufferCase::TextureBufferCase (tcu::TestContext&		testCtx,
923									  glu::RenderContext&	renderCtx,
924									  deUint32				format,
925									  size_t				bufferSize,
926									  size_t				offset,
927									  size_t				size,
928									  RenderBits			preRender,
929									  ModifyBits			modify,
930									  RenderBits			postRender,
931									  const char*			name,
932									  const char*			description)
933	: tcu::TestCase				(testCtx, name, description)
934	, m_renderCtx				(renderCtx)
935	, m_format					(format)
936	, m_bufferSize				(bufferSize)
937	, m_offset					(offset)
938	, m_size					(size)
939
940	, m_preRender				(preRender)
941	, m_modify					(modify)
942	, m_postRender				(postRender)
943
944	, m_preRenderProgram		(DE_NULL)
945	, m_postRenderProgram		(DE_NULL)
946{
947}
948
949TextureBufferCase::~TextureBufferCase (void)
950{
951	TextureBufferCase::deinit();
952}
953
954void TextureBufferCase::init (void)
955{
956	de::UniquePtr<glu::ContextInfo> info (glu::ContextInfo::create(m_renderCtx));
957
958	if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE))
959		&& !(glu::contextSupports(m_renderCtx.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) && info->isExtensionSupported("GL_EXT_texture_buffer")))
960		throw tcu::NotSupportedError("Texture buffers not supported", "", __FILE__, __LINE__);
961
962	if (m_preRender != 0)
963	{
964		TestLog&					log			= m_testCtx.getLog();
965		const char* const			sectionName	= (m_postRender != 0 ? "Primary render program" : "Render program");
966		const tcu::ScopedLogSection	section		(log, sectionName, sectionName);
967
968		m_preRenderProgram = createRenderProgram(m_renderCtx, m_preRender);
969		m_testCtx.getLog() << (*m_preRenderProgram);
970
971		TCU_CHECK(m_preRenderProgram->isOk());
972	}
973
974	if (m_postRender != 0)
975	{
976		// Reusing program
977		if (m_preRender == m_postRender)
978		{
979			m_postRenderProgram = m_preRenderProgram;
980		}
981		else
982		{
983			TestLog&					log			= m_testCtx.getLog();
984			const char* const			sectionName	= (m_preRender!= 0 ? "Secondary render program" : "Render program");
985			const tcu::ScopedLogSection	section		(log, sectionName, sectionName);
986
987			m_postRenderProgram = createRenderProgram(m_renderCtx, m_postRender);
988			m_testCtx.getLog() << (*m_postRenderProgram);
989
990			TCU_CHECK(m_postRenderProgram->isOk());
991		}
992	}
993}
994
995void TextureBufferCase::deinit (void)
996{
997	if (m_preRenderProgram == m_postRenderProgram)
998		m_postRenderProgram = DE_NULL;
999
1000	delete m_preRenderProgram;
1001	m_preRenderProgram = DE_NULL;
1002
1003	delete m_postRenderProgram;
1004	m_postRenderProgram = DE_NULL;
1005}
1006
1007tcu::TestCase::IterateResult TextureBufferCase::iterate (void)
1008{
1009	de::Random	rng		(deInt32Hash(deStringHash(getName())));
1010	size_t		offset;
1011
1012	if (m_offset != 0)
1013	{
1014		const glw::Functions&	gl			= m_renderCtx.getFunctions();
1015		deInt32					alignment	= 0;
1016
1017		gl.getIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &alignment);
1018		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT)");
1019
1020		offset = m_offset * alignment;
1021	}
1022	else
1023		offset = 0;
1024
1025	runTests(m_testCtx, m_renderCtx, rng, m_format, m_bufferSize, offset, m_size, m_preRender, m_preRenderProgram, m_modify, m_postRender, m_postRenderProgram);
1026
1027	return STOP;
1028}
1029
1030} // gls
1031} // deqp
1032