1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file
22 * \brief Shader execute test.
23 */ /*-------------------------------------------------------------------*/
24
25#include "glcShaderRenderCase.hpp"
26
27#include "tcuImageCompare.hpp"
28#include "tcuRenderTarget.hpp"
29#include "tcuSurface.hpp"
30#include "tcuTestLog.hpp"
31#include "tcuVector.hpp"
32
33#include "gluDrawUtil.hpp"
34#include "gluPixelTransfer.hpp"
35#include "gluTexture.hpp"
36#include "gluTextureUtil.hpp"
37
38#include "glwEnums.hpp"
39#include "glwFunctions.hpp"
40
41#include "deMath.h"
42#include "deMemory.h"
43#include "deRandom.hpp"
44#include "deString.h"
45#include "deStringUtil.hpp"
46
47#include <stdio.h>
48#include <string>
49#include <vector>
50
51namespace deqp
52{
53
54using namespace std;
55using namespace tcu;
56using namespace glu;
57
58static const int	   GRID_SIZE		   = 64;
59static const int	   MAX_RENDER_WIDTH	= 128;
60static const int	   MAX_RENDER_HEIGHT   = 112;
61static const tcu::Vec4 DEFAULT_CLEAR_COLOR = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
62
63inline RGBA toRGBA(const Vec4& a)
64{
65	return RGBA(
66		deClamp32(deRoundFloatToInt32(a.x() * 255.0f), 0, 255), deClamp32(deRoundFloatToInt32(a.y() * 255.0f), 0, 255),
67		deClamp32(deRoundFloatToInt32(a.z() * 255.0f), 0, 255), deClamp32(deRoundFloatToInt32(a.w() * 255.0f), 0, 255));
68}
69
70inline tcu::Vec4 toVec(const RGBA& c)
71{
72	return tcu::Vec4(static_cast<float>(c.getRed()) / 255.0f, static_cast<float>(c.getGreen()) / 255.0f,
73					 static_cast<float>(c.getBlue()) / 255.0f, static_cast<float>(c.getAlpha()) / 255.0f);
74}
75
76// TextureBinding
77
78TextureBinding::TextureBinding(const glu::Texture2D* tex2D, const tcu::Sampler& sampler)
79	: m_type(TYPE_2D), m_sampler(sampler)
80{
81	m_binding.tex2D = tex2D;
82}
83
84TextureBinding::TextureBinding(const glu::TextureCube* texCube, const tcu::Sampler& sampler)
85	: m_type(TYPE_CUBE_MAP), m_sampler(sampler)
86{
87	m_binding.texCube = texCube;
88}
89
90TextureBinding::TextureBinding(const glu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler)
91	: m_type(TYPE_2D_ARRAY), m_sampler(sampler)
92{
93	m_binding.tex2DArray = tex2DArray;
94}
95
96TextureBinding::TextureBinding(const glu::Texture3D* tex3D, const tcu::Sampler& sampler)
97	: m_type(TYPE_3D), m_sampler(sampler)
98{
99	m_binding.tex3D = tex3D;
100}
101
102TextureBinding::TextureBinding(void) : m_type(TYPE_NONE)
103{
104	m_binding.tex2D = DE_NULL;
105}
106
107void TextureBinding::setSampler(const tcu::Sampler& sampler)
108{
109	m_sampler = sampler;
110}
111
112void TextureBinding::setTexture(const glu::Texture2D* tex2D)
113{
114	m_type			= TYPE_2D;
115	m_binding.tex2D = tex2D;
116}
117
118void TextureBinding::setTexture(const glu::TextureCube* texCube)
119{
120	m_type			  = TYPE_CUBE_MAP;
121	m_binding.texCube = texCube;
122}
123
124void TextureBinding::setTexture(const glu::Texture2DArray* tex2DArray)
125{
126	m_type				 = TYPE_2D_ARRAY;
127	m_binding.tex2DArray = tex2DArray;
128}
129
130void TextureBinding::setTexture(const glu::Texture3D* tex3D)
131{
132	m_type			= TYPE_3D;
133	m_binding.tex3D = tex3D;
134}
135
136// QuadGrid.
137
138class QuadGrid
139{
140public:
141	QuadGrid(int gridSize, int screenWidth, int screenHeight, const Vec4& constCoords,
142			 const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures);
143	~QuadGrid(void);
144
145	int getGridSize(void) const
146	{
147		return m_gridSize;
148	}
149	int getNumVertices(void) const
150	{
151		return m_numVertices;
152	}
153	int getNumTriangles(void) const
154	{
155		return m_numTriangles;
156	}
157	const Vec4& getConstCoords(void) const
158	{
159		return m_constCoords;
160	}
161	const vector<Mat4> getUserAttribTransforms(void) const
162	{
163		return m_userAttribTransforms;
164	}
165	const vector<TextureBinding>& getTextures(void) const
166	{
167		return m_textures;
168	}
169
170	const Vec4* getPositions(void) const
171	{
172		return &m_positions[0];
173	}
174	const float* getAttribOne(void) const
175	{
176		return &m_attribOne[0];
177	}
178	const Vec4* getCoords(void) const
179	{
180		return &m_coords[0];
181	}
182	const Vec4* getUnitCoords(void) const
183	{
184		return &m_unitCoords[0];
185	}
186	const Vec4* getUserAttrib(int attribNdx) const
187	{
188		return &m_userAttribs[attribNdx][0];
189	}
190	const deUint16* getIndices(void) const
191	{
192		return &m_indices[0];
193	}
194
195	Vec4 getCoords(float sx, float sy) const;
196	Vec4 getUnitCoords(float sx, float sy) const;
197
198	int getNumUserAttribs(void) const
199	{
200		return (int)m_userAttribTransforms.size();
201	}
202	Vec4 getUserAttrib(int attribNdx, float sx, float sy) const;
203
204private:
205	int					   m_gridSize;
206	int					   m_numVertices;
207	int					   m_numTriangles;
208	Vec4				   m_constCoords;
209	vector<Mat4>		   m_userAttribTransforms;
210	vector<TextureBinding> m_textures;
211
212	vector<Vec4>	 m_screenPos;
213	vector<Vec4>	 m_positions;
214	vector<Vec4>	 m_coords;	 //!< Near-unit coordinates, roughly [-2.0 .. 2.0].
215	vector<Vec4>	 m_unitCoords; //!< Positive-only coordinates [0.0 .. 1.5].
216	vector<float>	m_attribOne;
217	vector<Vec4>	 m_userAttribs[ShaderEvalContext::MAX_TEXTURES];
218	vector<deUint16> m_indices;
219};
220
221QuadGrid::QuadGrid(int gridSize, int width, int height, const Vec4& constCoords,
222				   const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures)
223	: m_gridSize(gridSize)
224	, m_numVertices((gridSize + 1) * (gridSize + 1))
225	, m_numTriangles(gridSize * gridSize * 2)
226	, m_constCoords(constCoords)
227	, m_userAttribTransforms(userAttribTransforms)
228	, m_textures(textures)
229{
230	Vec4 viewportScale = Vec4((float)width, (float)height, 0.0f, 0.0f);
231
232	// Compute vertices.
233	m_positions.resize(m_numVertices);
234	m_coords.resize(m_numVertices);
235	m_unitCoords.resize(m_numVertices);
236	m_attribOne.resize(m_numVertices);
237	m_screenPos.resize(m_numVertices);
238
239	// User attributes.
240	for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_userAttribs); i++)
241		m_userAttribs[i].resize(m_numVertices);
242
243	for (int y = 0; y < gridSize + 1; y++)
244		for (int x = 0; x < gridSize + 1; x++)
245		{
246			float sx	 = static_cast<float>(x) / static_cast<float>(gridSize);
247			float sy	 = static_cast<float>(y) / static_cast<float>(gridSize);
248			float fx	 = 2.0f * sx - 1.0f;
249			float fy	 = 2.0f * sy - 1.0f;
250			int   vtxNdx = ((y * (gridSize + 1)) + x);
251
252			m_positions[vtxNdx]  = Vec4(fx, fy, 0.0f, 1.0f);
253			m_attribOne[vtxNdx]  = 1.0f;
254			m_screenPos[vtxNdx]  = Vec4(sx, sy, 0.0f, 1.0f) * viewportScale;
255			m_coords[vtxNdx]	 = getCoords(sx, sy);
256			m_unitCoords[vtxNdx] = getUnitCoords(sx, sy);
257
258			for (int attribNdx					 = 0; attribNdx < getNumUserAttribs(); attribNdx++)
259				m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy);
260		}
261
262	// Compute indices.
263	m_indices.resize(3 * m_numTriangles);
264	for (int y = 0; y < gridSize; y++)
265		for (int x = 0; x < gridSize; x++)
266		{
267			int stride = gridSize + 1;
268			int v00	= (y * stride) + x;
269			int v01	= (y * stride) + x + 1;
270			int v10	= ((y + 1) * stride) + x;
271			int v11	= ((y + 1) * stride) + x + 1;
272
273			int baseNdx			   = ((y * gridSize) + x) * 6;
274			m_indices[baseNdx + 0] = static_cast<deUint16>(v10);
275			m_indices[baseNdx + 1] = static_cast<deUint16>(v00);
276			m_indices[baseNdx + 2] = static_cast<deUint16>(v01);
277
278			m_indices[baseNdx + 3] = static_cast<deUint16>(v10);
279			m_indices[baseNdx + 4] = static_cast<deUint16>(v01);
280			m_indices[baseNdx + 5] = static_cast<deUint16>(v11);
281		}
282}
283
284QuadGrid::~QuadGrid(void)
285{
286}
287
288inline Vec4 QuadGrid::getCoords(float sx, float sy) const
289{
290	float fx = 2.0f * sx - 1.0f;
291	float fy = 2.0f * sy - 1.0f;
292	return Vec4(fx, fy, -fx + 0.33f * fy, -0.275f * fx - fy);
293}
294
295inline Vec4 QuadGrid::getUnitCoords(float sx, float sy) const
296{
297	return Vec4(sx, sy, 0.33f * sx + 0.5f * sy, 0.5f * sx + 0.25f * sy);
298}
299
300inline Vec4 QuadGrid::getUserAttrib(int attribNdx, float sx, float sy) const
301{
302	// homogeneous normalized screen-space coordinates
303	return m_userAttribTransforms[attribNdx] * Vec4(sx, sy, 0.0f, 1.0f);
304}
305
306// ShaderEvalContext.
307
308ShaderEvalContext::ShaderEvalContext(const QuadGrid& quadGrid_)
309	: constCoords(quadGrid_.getConstCoords()), isDiscarded(false), quadGrid(quadGrid_)
310{
311	const vector<TextureBinding>& bindings = quadGrid.getTextures();
312	DE_ASSERT((int)bindings.size() <= MAX_TEXTURES);
313
314	// Fill in texture array.
315	for (int ndx = 0; ndx < (int)bindings.size(); ndx++)
316	{
317		const TextureBinding& binding = bindings[ndx];
318
319		if (binding.getType() == TextureBinding::TYPE_NONE)
320			continue;
321
322		textures[ndx].sampler = binding.getSampler();
323
324		switch (binding.getType())
325		{
326		case TextureBinding::TYPE_2D:
327			textures[ndx].tex2D = &binding.get2D()->getRefTexture();
328			break;
329		case TextureBinding::TYPE_CUBE_MAP:
330			textures[ndx].texCube = &binding.getCube()->getRefTexture();
331			break;
332		case TextureBinding::TYPE_2D_ARRAY:
333			textures[ndx].tex2DArray = &binding.get2DArray()->getRefTexture();
334			break;
335		case TextureBinding::TYPE_3D:
336			textures[ndx].tex3D = &binding.get3D()->getRefTexture();
337			break;
338		default:
339			DE_ASSERT(DE_FALSE);
340		}
341	}
342}
343
344ShaderEvalContext::~ShaderEvalContext(void)
345{
346}
347
348void ShaderEvalContext::reset(float sx, float sy)
349{
350	// Clear old values
351	color		= Vec4(0.0f, 0.0f, 0.0f, 1.0f);
352	isDiscarded = false;
353
354	// Compute coords
355	coords	 = quadGrid.getCoords(sx, sy);
356	unitCoords = quadGrid.getUnitCoords(sx, sy);
357
358	// Compute user attributes.
359	int numAttribs = quadGrid.getNumUserAttribs();
360	DE_ASSERT(numAttribs <= MAX_USER_ATTRIBS);
361	for (int attribNdx = 0; attribNdx < numAttribs; attribNdx++)
362		in[attribNdx]  = quadGrid.getUserAttrib(attribNdx, sx, sy);
363}
364
365tcu::Vec4 ShaderEvalContext::texture2D(int unitNdx, const tcu::Vec2& texCoords)
366{
367	if (textures[unitNdx].tex2D)
368		return textures[unitNdx].tex2D->sample(textures[unitNdx].sampler, texCoords.x(), texCoords.y(), 0.0f);
369	else
370		return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
371}
372
373// ShaderEvaluator
374
375ShaderEvaluator::ShaderEvaluator(void) : m_evalFunc(DE_NULL)
376{
377}
378
379ShaderEvaluator::ShaderEvaluator(ShaderEvalFunc evalFunc) : m_evalFunc(evalFunc)
380{
381}
382
383ShaderEvaluator::~ShaderEvaluator(void)
384{
385}
386
387void ShaderEvaluator::evaluate(ShaderEvalContext& ctx)
388{
389	DE_ASSERT(m_evalFunc);
390	m_evalFunc(ctx);
391}
392
393// ShaderRenderCase.
394
395ShaderRenderCase::ShaderRenderCase(TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo,
396								   const char* name, const char* description, bool isVertexCase,
397								   ShaderEvalFunc evalFunc)
398	: TestCase(testCtx, name, description)
399	, m_renderCtx(renderCtx)
400	, m_ctxInfo(ctxInfo)
401	, m_isVertexCase(isVertexCase)
402	, m_defaultEvaluator(evalFunc)
403	, m_evaluator(m_defaultEvaluator)
404	, m_clearColor(DEFAULT_CLEAR_COLOR)
405	, m_program(DE_NULL)
406{
407}
408
409ShaderRenderCase::ShaderRenderCase(TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo,
410								   const char* name, const char* description, bool isVertexCase,
411								   ShaderEvaluator& evaluator)
412	: TestCase(testCtx, name, description)
413	, m_renderCtx(renderCtx)
414	, m_ctxInfo(ctxInfo)
415	, m_isVertexCase(isVertexCase)
416	, m_defaultEvaluator(DE_NULL)
417	, m_evaluator(evaluator)
418	, m_clearColor(DEFAULT_CLEAR_COLOR)
419	, m_program(DE_NULL)
420{
421}
422
423ShaderRenderCase::~ShaderRenderCase(void)
424{
425	ShaderRenderCase::deinit();
426}
427
428void ShaderRenderCase::init(void)
429{
430	TestLog&			  log = m_testCtx.getLog();
431	const glw::Functions& gl  = m_renderCtx.getFunctions();
432
433	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() begin");
434
435	DE_ASSERT(!m_program);
436	m_program =
437		new ShaderProgram(m_renderCtx, glu::makeVtxFragSources(m_vertShaderSource.c_str(), m_fragShaderSource.c_str()));
438
439	try
440	{
441		log << *m_program; // Always log shader program.
442
443		if (!m_program->isOk())
444			TCU_FAIL("Failed to compile shader program");
445
446		GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() end");
447	}
448	catch (const std::exception&)
449	{
450		// Clean up.
451		ShaderRenderCase::deinit();
452		throw;
453	}
454}
455
456void ShaderRenderCase::deinit(void)
457{
458	delete m_program;
459	m_program = DE_NULL;
460}
461
462tcu::IVec2 ShaderRenderCase::getViewportSize(void) const
463{
464	return tcu::IVec2(de::min(m_renderCtx.getRenderTarget().getWidth(), MAX_RENDER_WIDTH),
465					  de::min(m_renderCtx.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT));
466}
467
468TestNode::IterateResult ShaderRenderCase::iterate(void)
469{
470	const glw::Functions& gl = m_renderCtx.getFunctions();
471
472	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::iterate() begin");
473
474	DE_ASSERT(m_program);
475	deUint32 programID = m_program->getProgram();
476	gl.useProgram(programID);
477
478	// Create quad grid.
479	IVec2 viewportSize = getViewportSize();
480	int   width		   = viewportSize.x();
481	int   height	   = viewportSize.y();
482
483	// \todo [petri] Better handling of constCoords (render in multiple chunks, vary coords).
484	QuadGrid quadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, Vec4(0.0f, 0.0f, 0.0f, 1.0f),
485					  m_userAttribTransforms, m_textures);
486
487	// Render result.
488	Surface resImage(width, height);
489	render(resImage, programID, quadGrid);
490
491	// Compute reference.
492	Surface refImage(width, height);
493	if (m_isVertexCase)
494		computeVertexReference(refImage, quadGrid);
495	else
496		computeFragmentReference(refImage, quadGrid);
497
498	// Compare.
499	bool testOk = compareImages(resImage, refImage, 0.05f);
500
501	// De-initialize.
502	gl.useProgram(0);
503
504	m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, testOk ? "Pass" : "Fail");
505	return TestNode::STOP;
506}
507
508void ShaderRenderCase::setup(deUint32 programID)
509{
510	DE_UNREF(programID);
511}
512
513void ShaderRenderCase::setupUniforms(deUint32 programID, const Vec4& constCoords)
514{
515	DE_UNREF(programID);
516	DE_UNREF(constCoords);
517}
518
519void ShaderRenderCase::setupDefaultInputs(int programID)
520{
521	const glw::Functions& gl = m_renderCtx.getFunctions();
522
523	// SETUP UNIFORMS.
524
525	setupDefaultUniforms(m_renderCtx, programID);
526
527	GLU_EXPECT_NO_ERROR(gl.getError(), "post uniform setup");
528
529	// SETUP TEXTURES.
530
531	for (int ndx = 0; ndx < (int)m_textures.size(); ndx++)
532	{
533		const TextureBinding& tex		= m_textures[ndx];
534		const tcu::Sampler&   sampler   = tex.getSampler();
535		deUint32			  texTarget = GL_NONE;
536		deUint32			  texObj	= 0;
537
538		if (tex.getType() == TextureBinding::TYPE_NONE)
539			continue;
540
541		// Feature check.
542		if (m_renderCtx.getType().getAPI() == glu::ApiType(2, 0, glu::PROFILE_ES))
543		{
544			if (tex.getType() == TextureBinding::TYPE_2D_ARRAY)
545				throw tcu::NotSupportedError("2D array texture binding is not supported");
546
547			if (tex.getType() == TextureBinding::TYPE_3D)
548				throw tcu::NotSupportedError("3D texture binding is not supported");
549
550			if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE)
551				throw tcu::NotSupportedError("Shadow lookups are not supported");
552		}
553
554		switch (tex.getType())
555		{
556		case TextureBinding::TYPE_2D:
557			texTarget = GL_TEXTURE_2D;
558			texObj	= tex.get2D()->getGLTexture();
559			break;
560		case TextureBinding::TYPE_CUBE_MAP:
561			texTarget = GL_TEXTURE_CUBE_MAP;
562			texObj	= tex.getCube()->getGLTexture();
563			break;
564		case TextureBinding::TYPE_2D_ARRAY:
565			texTarget = GL_TEXTURE_2D_ARRAY;
566			texObj	= tex.get2DArray()->getGLTexture();
567			break;
568		case TextureBinding::TYPE_3D:
569			texTarget = GL_TEXTURE_3D;
570			texObj	= tex.get3D()->getGLTexture();
571			break;
572		default:
573			DE_ASSERT(DE_FALSE);
574		}
575
576		gl.activeTexture(GL_TEXTURE0 + ndx);
577		gl.bindTexture(texTarget, texObj);
578		gl.texParameteri(texTarget, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(sampler.wrapS));
579		gl.texParameteri(texTarget, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(sampler.wrapT));
580		gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(sampler.minFilter));
581		gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(sampler.magFilter));
582
583		if (texTarget == GL_TEXTURE_3D)
584			gl.texParameteri(texTarget, GL_TEXTURE_WRAP_R, glu::getGLWrapMode(sampler.wrapR));
585
586		if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE)
587		{
588			gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
589			gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(sampler.compare));
590		}
591	}
592
593	GLU_EXPECT_NO_ERROR(gl.getError(), "texture sampler setup");
594}
595
596static void getDefaultVertexArrays(const glw::Functions& gl, const QuadGrid& quadGrid, deUint32 program,
597								   vector<VertexArrayBinding>& vertexArrays)
598{
599	const int numElements = quadGrid.getNumVertices();
600
601	vertexArrays.push_back(va::Float("a_position", 4, numElements, 0, (const float*)quadGrid.getPositions()));
602	vertexArrays.push_back(va::Float("a_coords", 4, numElements, 0, (const float*)quadGrid.getCoords()));
603	vertexArrays.push_back(va::Float("a_unitCoords", 4, numElements, 0, (const float*)quadGrid.getUnitCoords()));
604	vertexArrays.push_back(va::Float("a_one", 1, numElements, 0, quadGrid.getAttribOne()));
605
606	// a_inN.
607	for (int userNdx = 0; userNdx < quadGrid.getNumUserAttribs(); userNdx++)
608	{
609		string name = string("a_in") + de::toString(userNdx);
610		vertexArrays.push_back(va::Float(name, 4, numElements, 0, (const float*)quadGrid.getUserAttrib(userNdx)));
611	}
612
613	// Matrix attributes - these are set by location
614	static const struct
615	{
616		const char* name;
617		int			numCols;
618		int			numRows;
619	} matrices[] = { { "a_mat2", 2, 2 },   { "a_mat2x3", 2, 3 }, { "a_mat2x4", 2, 4 },
620					 { "a_mat3x2", 3, 2 }, { "a_mat3", 3, 3 },   { "a_mat3x4", 3, 4 },
621					 { "a_mat4x2", 4, 2 }, { "a_mat4x3", 4, 3 }, { "a_mat4", 4, 4 } };
622
623	for (int matNdx = 0; matNdx < DE_LENGTH_OF_ARRAY(matrices); matNdx++)
624	{
625		int loc = gl.getAttribLocation(program, matrices[matNdx].name);
626
627		if (loc < 0)
628			continue; // Not used in shader.
629
630		int numRows = matrices[matNdx].numRows;
631		int numCols = matrices[matNdx].numCols;
632
633		for (int colNdx = 0; colNdx < numCols; colNdx++)
634			vertexArrays.push_back(va::Float(loc + colNdx, numRows, numElements, 4 * (int)sizeof(float),
635											 (const float*)quadGrid.getUserAttrib(colNdx)));
636	}
637}
638
639void ShaderRenderCase::render(Surface& result, int programID, const QuadGrid& quadGrid)
640{
641	const glw::Functions& gl = m_renderCtx.getFunctions();
642
643	GLU_EXPECT_NO_ERROR(gl.getError(), "pre render");
644
645	// Buffer info.
646	int width  = result.getWidth();
647	int height = result.getHeight();
648
649	int xOffsetMax = m_renderCtx.getRenderTarget().getWidth() - width;
650	int yOffsetMax = m_renderCtx.getRenderTarget().getHeight() - height;
651
652	deUint32   hash = deStringHash(m_vertShaderSource.c_str()) + deStringHash(m_fragShaderSource.c_str());
653	de::Random rnd(hash);
654
655	int xOffset = rnd.getInt(0, xOffsetMax);
656	int yOffset = rnd.getInt(0, yOffsetMax);
657
658	gl.viewport(xOffset, yOffset, width, height);
659
660	// Setup program.
661	setupUniforms(programID, quadGrid.getConstCoords());
662	setupDefaultInputs(programID);
663
664	// Disable dither.
665	gl.disable(GL_DITHER);
666
667	// Clear.
668	gl.clearColor(m_clearColor.x(), m_clearColor.y(), m_clearColor.z(), m_clearColor.w());
669	gl.clear(GL_COLOR_BUFFER_BIT);
670
671	// Draw.
672	{
673		std::vector<VertexArrayBinding> vertexArrays;
674		const int						numElements = quadGrid.getNumTriangles() * 3;
675
676		getDefaultVertexArrays(gl, quadGrid, programID, vertexArrays);
677		draw(m_renderCtx, programID, (int)vertexArrays.size(), &vertexArrays[0],
678			 pr::Triangles(numElements, quadGrid.getIndices()));
679	}
680	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
681
682	// Read back results.
683	glu::readPixels(m_renderCtx, xOffset, yOffset, result.getAccess());
684
685	GLU_EXPECT_NO_ERROR(gl.getError(), "post render");
686}
687
688void ShaderRenderCase::computeVertexReference(Surface& result, const QuadGrid& quadGrid)
689{
690	// Buffer info.
691	int				  width	= result.getWidth();
692	int				  height   = result.getHeight();
693	int				  gridSize = quadGrid.getGridSize();
694	int				  stride   = gridSize + 1;
695	bool			  hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
696	ShaderEvalContext evalCtx(quadGrid);
697
698	// Evaluate color for each vertex.
699	vector<Vec4> colors((gridSize + 1) * (gridSize + 1));
700	for (int y = 0; y < gridSize + 1; y++)
701		for (int x = 0; x < gridSize + 1; x++)
702		{
703			float sx	 = static_cast<float>(x) / static_cast<float>(gridSize);
704			float sy	 = static_cast<float>(y) / static_cast<float>(gridSize);
705			int   vtxNdx = ((y * (gridSize + 1)) + x);
706
707			evalCtx.reset(sx, sy);
708			m_evaluator.evaluate(evalCtx);
709			DE_ASSERT(!evalCtx.isDiscarded); // Discard is not available in vertex shader.
710			Vec4 color = evalCtx.color;
711
712			if (!hasAlpha)
713				color.w() = 1.0f;
714
715			colors[vtxNdx] = color;
716		}
717
718	// Render quads.
719	for (int y = 0; y < gridSize; y++)
720		for (int x = 0; x < gridSize; x++)
721		{
722			float x0 = static_cast<float>(x) / static_cast<float>(gridSize);
723			float x1 = static_cast<float>(x + 1) / static_cast<float>(gridSize);
724			float y0 = static_cast<float>(y) / static_cast<float>(gridSize);
725			float y1 = static_cast<float>(y + 1) / static_cast<float>(gridSize);
726
727			float sx0  = x0 * (float)width;
728			float sx1  = x1 * (float)width;
729			float sy0  = y0 * (float)height;
730			float sy1  = y1 * (float)height;
731			float oosx = 1.0f / (sx1 - sx0);
732			float oosy = 1.0f / (sy1 - sy0);
733
734			int ix0 = deCeilFloatToInt32(sx0 - 0.5f);
735			int ix1 = deCeilFloatToInt32(sx1 - 0.5f);
736			int iy0 = deCeilFloatToInt32(sy0 - 0.5f);
737			int iy1 = deCeilFloatToInt32(sy1 - 0.5f);
738
739			int  v00 = (y * stride) + x;
740			int  v01 = (y * stride) + x + 1;
741			int  v10 = ((y + 1) * stride) + x;
742			int  v11 = ((y + 1) * stride) + x + 1;
743			Vec4 c00 = colors[v00];
744			Vec4 c01 = colors[v01];
745			Vec4 c10 = colors[v10];
746			Vec4 c11 = colors[v11];
747
748			//printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1);
749
750			for (int iy = iy0; iy < iy1; iy++)
751				for (int ix = ix0; ix < ix1; ix++)
752				{
753					DE_ASSERT(deInBounds32(ix, 0, width));
754					DE_ASSERT(deInBounds32(iy, 0, height));
755
756					float sfx = (float)ix + 0.5f;
757					float sfy = (float)iy + 0.5f;
758					float fx1 = deFloatClamp((sfx - sx0) * oosx, 0.0f, 1.0f);
759					float fy1 = deFloatClamp((sfy - sy0) * oosy, 0.0f, 1.0f);
760
761					// Triangle quad interpolation.
762					bool		tri   = fx1 + fy1 <= 1.0f;
763					float		tx	= tri ? fx1 : (1.0f - fx1);
764					float		ty	= tri ? fy1 : (1.0f - fy1);
765					const Vec4& t0	= tri ? c00 : c11;
766					const Vec4& t1	= tri ? c01 : c10;
767					const Vec4& t2	= tri ? c10 : c01;
768					Vec4		color = t0 + (t1 - t0) * tx + (t2 - t0) * ty;
769
770					// Quantizing for 1-bit alpha
771					if ((m_renderCtx.getRenderTarget().getPixelFormat().alphaBits) == 1)
772						color.w() = deFloatRound(color.w());
773
774					result.setPixel(ix, iy, toRGBA(color));
775				}
776		}
777}
778
779void ShaderRenderCase::computeFragmentReference(Surface& result, const QuadGrid& quadGrid)
780{
781	// Buffer info.
782	int				  width	= result.getWidth();
783	int				  height   = result.getHeight();
784	bool			  hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
785	ShaderEvalContext evalCtx(quadGrid);
786
787	// Render.
788	for (int y = 0; y < height; y++)
789		for (int x = 0; x < width; x++)
790		{
791			float sx = ((float)x + 0.5f) / (float)width;
792			float sy = ((float)y + 0.5f) / (float)height;
793
794			evalCtx.reset(sx, sy);
795			m_evaluator.evaluate(evalCtx);
796			// Select either clear color or computed color based on discarded bit.
797			Vec4 color = evalCtx.isDiscarded ? m_clearColor : evalCtx.color;
798
799			if (!hasAlpha)
800				color.w() = 1.0f;
801
802			// Quantizing for 1-bit alpha
803			if ((m_renderCtx.getRenderTarget().getPixelFormat().alphaBits) == 1)
804				color.w() = deFloatRound(color.w());
805
806			result.setPixel(x, y, toRGBA(color));
807		}
808}
809
810bool ShaderRenderCase::compareImages(const Surface& resImage, const Surface& refImage, float errorThreshold)
811{
812	return tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", refImage, resImage,
813							 errorThreshold, tcu::COMPARE_LOG_RESULT);
814}
815
816// Uniform name helpers.
817
818const char* getIntUniformName(int number)
819{
820	switch (number)
821	{
822	case 0:
823		return "ui_zero";
824	case 1:
825		return "ui_one";
826	case 2:
827		return "ui_two";
828	case 3:
829		return "ui_three";
830	case 4:
831		return "ui_four";
832	case 5:
833		return "ui_five";
834	case 6:
835		return "ui_six";
836	case 7:
837		return "ui_seven";
838	case 8:
839		return "ui_eight";
840	case 101:
841		return "ui_oneHundredOne";
842	default:
843		DE_ASSERT(false);
844		return "";
845	}
846}
847
848const char* getFloatUniformName(int number)
849{
850	switch (number)
851	{
852	case 0:
853		return "uf_zero";
854	case 1:
855		return "uf_one";
856	case 2:
857		return "uf_two";
858	case 3:
859		return "uf_three";
860	case 4:
861		return "uf_four";
862	case 5:
863		return "uf_five";
864	case 6:
865		return "uf_six";
866	case 7:
867		return "uf_seven";
868	case 8:
869		return "uf_eight";
870	default:
871		DE_ASSERT(false);
872		return "";
873	}
874}
875
876const char* getFloatFractionUniformName(int number)
877{
878	switch (number)
879	{
880	case 1:
881		return "uf_one";
882	case 2:
883		return "uf_half";
884	case 3:
885		return "uf_third";
886	case 4:
887		return "uf_fourth";
888	case 5:
889		return "uf_fifth";
890	case 6:
891		return "uf_sixth";
892	case 7:
893		return "uf_seventh";
894	case 8:
895		return "uf_eighth";
896	default:
897		DE_ASSERT(false);
898		return "";
899	}
900}
901
902void setupDefaultUniforms(const glu::RenderContext& context, deUint32 programID)
903{
904	const glw::Functions& gl = context.getFunctions();
905
906	// Bool.
907	struct BoolUniform
908	{
909		const char* name;
910		bool		value;
911	};
912	static const BoolUniform s_boolUniforms[] = {
913		{ "ub_true", true }, { "ub_false", false },
914	};
915
916	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_boolUniforms); i++)
917	{
918		int uniLoc = gl.getUniformLocation(programID, s_boolUniforms[i].name);
919		if (uniLoc != -1)
920			gl.uniform1i(uniLoc, s_boolUniforms[i].value);
921	}
922
923	// BVec4.
924	struct BVec4Uniform
925	{
926		const char* name;
927		BVec4		value;
928	};
929	static const BVec4Uniform s_bvec4Uniforms[] = {
930		{ "ub4_true", BVec4(true) }, { "ub4_false", BVec4(false) },
931	};
932
933	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_bvec4Uniforms); i++)
934	{
935		const BVec4Uniform& uni = s_bvec4Uniforms[i];
936		int					arr[4];
937		arr[0]	 = (int)uni.value.x();
938		arr[1]	 = (int)uni.value.y();
939		arr[2]	 = (int)uni.value.z();
940		arr[3]	 = (int)uni.value.w();
941		int uniLoc = gl.getUniformLocation(programID, uni.name);
942		if (uniLoc != -1)
943			gl.uniform4iv(uniLoc, 1, &arr[0]);
944	}
945
946	// Int.
947	struct IntUniform
948	{
949		const char* name;
950		int			value;
951	};
952	static const IntUniform s_intUniforms[] = {
953		{ "ui_minusOne", -1 },		{ "ui_zero", 0 }, { "ui_one", 1 }, { "ui_two", 2 },   { "ui_three", 3 },
954		{ "ui_four", 4 },			{ "ui_five", 5 }, { "ui_six", 6 }, { "ui_seven", 7 }, { "ui_eight", 8 },
955		{ "ui_oneHundredOne", 101 }
956	};
957
958	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_intUniforms); i++)
959	{
960		int uniLoc = gl.getUniformLocation(programID, s_intUniforms[i].name);
961		if (uniLoc != -1)
962			gl.uniform1i(uniLoc, s_intUniforms[i].value);
963	}
964
965	// IVec2.
966	struct IVec2Uniform
967	{
968		const char* name;
969		IVec2		value;
970	};
971	static const IVec2Uniform s_ivec2Uniforms[] = { { "ui2_minusOne", IVec2(-1) }, { "ui2_zero", IVec2(0) },
972													{ "ui2_one", IVec2(1) },	   { "ui2_two", IVec2(2) },
973													{ "ui2_four", IVec2(4) },	  { "ui2_five", IVec2(5) } };
974
975	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec2Uniforms); i++)
976	{
977		int uniLoc = gl.getUniformLocation(programID, s_ivec2Uniforms[i].name);
978		if (uniLoc != -1)
979			gl.uniform2iv(uniLoc, 1, s_ivec2Uniforms[i].value.getPtr());
980	}
981
982	// IVec3.
983	struct IVec3Uniform
984	{
985		const char* name;
986		IVec3		value;
987	};
988	static const IVec3Uniform s_ivec3Uniforms[] = { { "ui3_minusOne", IVec3(-1) }, { "ui3_zero", IVec3(0) },
989													{ "ui3_one", IVec3(1) },	   { "ui3_two", IVec3(2) },
990													{ "ui3_four", IVec3(4) },	  { "ui3_five", IVec3(5) } };
991
992	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec3Uniforms); i++)
993	{
994		int uniLoc = gl.getUniformLocation(programID, s_ivec3Uniforms[i].name);
995		if (uniLoc != -1)
996			gl.uniform3iv(uniLoc, 1, s_ivec3Uniforms[i].value.getPtr());
997	}
998
999	// IVec4.
1000	struct IVec4Uniform
1001	{
1002		const char* name;
1003		IVec4		value;
1004	};
1005	static const IVec4Uniform s_ivec4Uniforms[] = { { "ui4_minusOne", IVec4(-1) }, { "ui4_zero", IVec4(0) },
1006													{ "ui4_one", IVec4(1) },	   { "ui4_two", IVec4(2) },
1007													{ "ui4_four", IVec4(4) },	  { "ui4_five", IVec4(5) } };
1008
1009	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec4Uniforms); i++)
1010	{
1011		int uniLoc = gl.getUniformLocation(programID, s_ivec4Uniforms[i].name);
1012		if (uniLoc != -1)
1013			gl.uniform4iv(uniLoc, 1, s_ivec4Uniforms[i].value.getPtr());
1014	}
1015
1016	// Float.
1017	struct FloatUniform
1018	{
1019		const char* name;
1020		float		value;
1021	};
1022	static const FloatUniform s_floatUniforms[] = {
1023		{ "uf_zero", 0.0f },		 { "uf_one", 1.0f },		  { "uf_two", 2.0f },
1024		{ "uf_three", 3.0f },		 { "uf_four", 4.0f },		  { "uf_five", 5.0f },
1025		{ "uf_six", 6.0f },			 { "uf_seven", 7.0f },		  { "uf_eight", 8.0f },
1026		{ "uf_half", 1.0f / 2.0f },  { "uf_third", 1.0f / 3.0f }, { "uf_fourth", 1.0f / 4.0f },
1027		{ "uf_fifth", 1.0f / 5.0f }, { "uf_sixth", 1.0f / 6.0f }, { "uf_seventh", 1.0f / 7.0f },
1028		{ "uf_eighth", 1.0f / 8.0f }
1029	};
1030
1031	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_floatUniforms); i++)
1032	{
1033		int uniLoc = gl.getUniformLocation(programID, s_floatUniforms[i].name);
1034		if (uniLoc != -1)
1035			gl.uniform1f(uniLoc, s_floatUniforms[i].value);
1036	}
1037
1038	// Vec2.
1039	struct Vec2Uniform
1040	{
1041		const char* name;
1042		Vec2		value;
1043	};
1044	static const Vec2Uniform s_vec2Uniforms[] = {
1045		{ "uv2_minusOne", Vec2(-1.0f) }, { "uv2_zero", Vec2(0.0f) }, { "uv2_half", Vec2(0.5f) },
1046		{ "uv2_one", Vec2(1.0f) },		 { "uv2_two", Vec2(2.0f) },
1047	};
1048
1049	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec2Uniforms); i++)
1050	{
1051		int uniLoc = gl.getUniformLocation(programID, s_vec2Uniforms[i].name);
1052		if (uniLoc != -1)
1053			gl.uniform2fv(uniLoc, 1, s_vec2Uniforms[i].value.getPtr());
1054	}
1055
1056	// Vec3.
1057	struct Vec3Uniform
1058	{
1059		const char* name;
1060		Vec3		value;
1061	};
1062	static const Vec3Uniform s_vec3Uniforms[] = {
1063		{ "uv3_minusOne", Vec3(-1.0f) }, { "uv3_zero", Vec3(0.0f) }, { "uv3_half", Vec3(0.5f) },
1064		{ "uv3_one", Vec3(1.0f) },		 { "uv3_two", Vec3(2.0f) },
1065	};
1066
1067	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec3Uniforms); i++)
1068	{
1069		int uniLoc = gl.getUniformLocation(programID, s_vec3Uniforms[i].name);
1070		if (uniLoc != -1)
1071			gl.uniform3fv(uniLoc, 1, s_vec3Uniforms[i].value.getPtr());
1072	}
1073
1074	// Vec4.
1075	struct Vec4Uniform
1076	{
1077		const char* name;
1078		Vec4		value;
1079	};
1080	static const Vec4Uniform s_vec4Uniforms[] = {
1081		{ "uv4_minusOne", Vec4(-1.0f) },
1082		{ "uv4_zero", Vec4(0.0f) },
1083		{ "uv4_half", Vec4(0.5f) },
1084		{ "uv4_one", Vec4(1.0f) },
1085		{ "uv4_two", Vec4(2.0f) },
1086		{ "uv4_black", Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
1087		{ "uv4_gray", Vec4(0.5f, 0.5f, 0.5f, 1.0f) },
1088		{ "uv4_white", Vec4(1.0f, 1.0f, 1.0f, 1.0f) },
1089	};
1090
1091	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec4Uniforms); i++)
1092	{
1093		int uniLoc = gl.getUniformLocation(programID, s_vec4Uniforms[i].name);
1094		if (uniLoc != -1)
1095			gl.uniform4fv(uniLoc, 1, s_vec4Uniforms[i].value.getPtr());
1096	}
1097}
1098
1099} // deqp
1100