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