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