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 Random shader test case.
22 *//*--------------------------------------------------------------------*/
23
24 #include "glsRandomShaderCase.hpp"
25
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluStrUtil.hpp"
30
31 #include "tcuImageCompare.hpp"
32 #include "tcuTestLog.hpp"
33
34 #include "deRandom.hpp"
35 #include "deStringUtil.hpp"
36
37 #include "rsgProgramGenerator.hpp"
38 #include "rsgProgramExecutor.hpp"
39 #include "rsgUtils.hpp"
40
41 #include "tcuTextureUtil.hpp"
42 #include "tcuRenderTarget.hpp"
43
44 #include "glw.h"
45 #include "glwFunctions.hpp"
46
47 using std::map;
48 using std::pair;
49 using std::string;
50 using std::vector;
51
52 namespace deqp
53 {
54 namespace gls
55 {
56
57 enum
58 {
59 VIEWPORT_WIDTH = 64,
60 VIEWPORT_HEIGHT = 64,
61
62 TEXTURE_2D_WIDTH = 64,
63 TEXTURE_2D_HEIGHT = 64,
64 TEXTURE_2D_FORMAT = GL_RGBA,
65 TEXTURE_2D_DATA_TYPE = GL_UNSIGNED_BYTE,
66
67 TEXTURE_CUBE_SIZE = 16,
68 TEXTURE_CUBE_FORMAT = GL_RGBA,
69 TEXTURE_CUBE_DATA_TYPE = GL_UNSIGNED_BYTE,
70
71 TEXTURE_WRAP_S = GL_CLAMP_TO_EDGE,
72 TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE,
73
74 TEXTURE_MIN_FILTER = GL_LINEAR,
75 TEXTURE_MAG_FILTER = GL_LINEAR
76 };
77
VertexArray(const rsg::ShaderInput * input,int numVertices)78 VertexArray::VertexArray(const rsg::ShaderInput *input, int numVertices)
79 : m_input(input)
80 , m_vertices(input->getVariable()->getType().getNumElements() * numVertices)
81 {
82 }
83
TextureManager(void)84 TextureManager::TextureManager(void)
85 {
86 }
87
~TextureManager(void)88 TextureManager::~TextureManager(void)
89 {
90 }
91
bindTexture(int unit,const glu::Texture2D * tex2D)92 void TextureManager::bindTexture(int unit, const glu::Texture2D *tex2D)
93 {
94 m_tex2D[unit] = tex2D;
95 }
96
bindTexture(int unit,const glu::TextureCube * texCube)97 void TextureManager::bindTexture(int unit, const glu::TextureCube *texCube)
98 {
99 m_texCube[unit] = texCube;
100 }
101
getBindings2D(void) const102 inline vector<pair<int, const glu::Texture2D *>> TextureManager::getBindings2D(void) const
103 {
104 vector<pair<int, const glu::Texture2D *>> bindings;
105 for (map<int, const glu::Texture2D *>::const_iterator i = m_tex2D.begin(); i != m_tex2D.end(); i++)
106 bindings.push_back(*i);
107 return bindings;
108 }
109
getBindingsCube(void) const110 inline vector<pair<int, const glu::TextureCube *>> TextureManager::getBindingsCube(void) const
111 {
112 vector<pair<int, const glu::TextureCube *>> bindings;
113 for (map<int, const glu::TextureCube *>::const_iterator i = m_texCube.begin(); i != m_texCube.end(); i++)
114 bindings.push_back(*i);
115 return bindings;
116 }
117
RandomShaderCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,const rsg::ProgramParameters & params)118 RandomShaderCase::RandomShaderCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name,
119 const char *description, const rsg::ProgramParameters ¶ms)
120 : tcu::TestCase(testCtx, name, description)
121 , m_renderCtx(renderCtx)
122 , m_parameters(params)
123 , m_gridWidth(1)
124 , m_gridHeight(1)
125 , m_vertexShader(rsg::Shader::TYPE_VERTEX)
126 , m_fragmentShader(rsg::Shader::TYPE_FRAGMENT)
127 , m_tex2D(DE_NULL)
128 , m_texCube(DE_NULL)
129 {
130 }
131
~RandomShaderCase(void)132 RandomShaderCase::~RandomShaderCase(void)
133 {
134 delete m_tex2D;
135 delete m_texCube;
136 }
137
init(void)138 void RandomShaderCase::init(void)
139 {
140 // Generate shaders
141 rsg::ProgramGenerator programGenerator;
142 programGenerator.generate(m_parameters, m_vertexShader, m_fragmentShader);
143
144 checkShaderLimits(m_vertexShader);
145 checkShaderLimits(m_fragmentShader);
146 checkProgramLimits(m_vertexShader, m_fragmentShader);
147
148 // Compute uniform values
149 std::vector<const rsg::ShaderInput *> unifiedUniforms;
150 de::Random rnd(m_parameters.seed);
151 rsg::computeUnifiedUniforms(m_vertexShader, m_fragmentShader, unifiedUniforms);
152 rsg::computeUniformValues(rnd, m_uniforms, unifiedUniforms);
153
154 // Generate vertices
155 const vector<rsg::ShaderInput *> &inputs = m_vertexShader.getInputs();
156 int numVertices = (m_gridWidth + 1) * (m_gridHeight + 1);
157
158 for (vector<rsg::ShaderInput *>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
159 {
160 const rsg::ShaderInput *input = *i;
161 rsg::ConstValueRangeAccess valueRange = input->getValueRange();
162 int numComponents = input->getVariable()->getType().getNumElements();
163 VertexArray vtxArray(input, numVertices);
164 bool isPosition = string(input->getVariable()->getName()) == "dEQP_Position";
165
166 TCU_CHECK(input->getVariable()->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT);
167
168 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++)
169 {
170 int y = vtxNdx / (m_gridWidth + 1);
171 int x = vtxNdx - y * (m_gridWidth + 1);
172 float xf = (float)x / (float)m_gridWidth;
173 float yf = (float)y / (float)m_gridHeight;
174 float *dst = &vtxArray.getVertices()[vtxNdx * numComponents];
175
176 if (isPosition)
177 {
178 // Position attribute gets special interpolation handling.
179 DE_ASSERT(numComponents == 4);
180 dst[0] = -1.0f + xf * 2.0f;
181 dst[1] = 1.0f + yf * -2.0f;
182 dst[2] = 0.0f;
183 dst[3] = 1.0f;
184 }
185 else
186 {
187 for (int compNdx = 0; compNdx < numComponents; compNdx++)
188 {
189 float minVal = valueRange.getMin().component(compNdx).asFloat();
190 float maxVal = valueRange.getMax().component(compNdx).asFloat();
191 float xd, yd;
192
193 rsg::getVertexInterpolationCoords(xd, yd, xf, yf, compNdx);
194
195 float f = (xd + yd) / 2.0f;
196
197 dst[compNdx] = minVal + f * (maxVal - minVal);
198 }
199 }
200 }
201
202 m_vertexArrays.push_back(vtxArray);
203 }
204
205 // Generate indices
206 int numQuads = m_gridWidth * m_gridHeight;
207 int numIndices = numQuads * 6;
208 m_indices.resize(numIndices);
209 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
210 {
211 int quadY = quadNdx / (m_gridWidth);
212 int quadX = quadNdx - quadY * m_gridWidth;
213
214 m_indices[quadNdx * 6 + 0] = (uint16_t)(quadX + quadY * (m_gridWidth + 1));
215 m_indices[quadNdx * 6 + 1] = (uint16_t)(quadX + (quadY + 1) * (m_gridWidth + 1));
216 m_indices[quadNdx * 6 + 2] = (uint16_t)(quadX + quadY * (m_gridWidth + 1) + 1);
217 m_indices[quadNdx * 6 + 3] = (uint16_t)(m_indices[quadNdx * 6 + 2]);
218 m_indices[quadNdx * 6 + 4] = (uint16_t)(m_indices[quadNdx * 6 + 1]);
219 m_indices[quadNdx * 6 + 5] = (uint16_t)(quadX + (quadY + 1) * (m_gridWidth + 1) + 1);
220 }
221
222 // Create textures.
223 for (vector<rsg::VariableValue>::const_iterator uniformIter = m_uniforms.begin(); uniformIter != m_uniforms.end();
224 uniformIter++)
225 {
226 const rsg::VariableType &type = uniformIter->getVariable()->getType();
227
228 if (!type.isSampler())
229 continue;
230
231 int unitNdx = uniformIter->getValue().asInt(0);
232
233 if (type == rsg::VariableType(rsg::VariableType::TYPE_SAMPLER_2D, 1))
234 m_texManager.bindTexture(unitNdx, getTex2D());
235 else if (type == rsg::VariableType(rsg::VariableType::TYPE_SAMPLER_CUBE, 1))
236 m_texManager.bindTexture(unitNdx, getTexCube());
237 else
238 DE_ASSERT(false);
239 }
240 }
241
getNumSamplerUniforms(const std::vector<rsg::ShaderInput * > & uniforms)242 static int getNumSamplerUniforms(const std::vector<rsg::ShaderInput *> &uniforms)
243 {
244 int numSamplers = 0;
245
246 for (std::vector<rsg::ShaderInput *>::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
247 {
248 if ((*it)->getVariable()->getType().isSampler())
249 ++numSamplers;
250 }
251
252 return numSamplers;
253 }
254
checkShaderLimits(const rsg::Shader & shader) const255 void RandomShaderCase::checkShaderLimits(const rsg::Shader &shader) const
256 {
257 const int numRequiredSamplers = getNumSamplerUniforms(shader.getUniforms());
258
259 if (numRequiredSamplers > 0)
260 {
261 const GLenum pname = (shader.getType() == rsg::Shader::TYPE_VERTEX) ? (GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS) :
262 (GL_MAX_TEXTURE_IMAGE_UNITS);
263 int numSupported = -1;
264 GLenum error;
265
266 m_renderCtx.getFunctions().getIntegerv(pname, &numSupported);
267 error = m_renderCtx.getFunctions().getError();
268
269 if (error != GL_NO_ERROR)
270 throw tcu::TestError("Limit query failed: " + de::toString(glu::getErrorStr(error)));
271
272 if (numSupported < numRequiredSamplers)
273 throw tcu::NotSupportedError("Shader requires " + de::toString(numRequiredSamplers) +
274 " sampler(s). Implementation supports " + de::toString(numSupported));
275 }
276 }
277
checkProgramLimits(const rsg::Shader & vtxShader,const rsg::Shader & frgShader) const278 void RandomShaderCase::checkProgramLimits(const rsg::Shader &vtxShader, const rsg::Shader &frgShader) const
279 {
280 const int numRequiredCombinedSamplers =
281 getNumSamplerUniforms(vtxShader.getUniforms()) + getNumSamplerUniforms(frgShader.getUniforms());
282
283 if (numRequiredCombinedSamplers > 0)
284 {
285 int numSupported = -1;
286 GLenum error;
287
288 m_renderCtx.getFunctions().getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numSupported);
289 error = m_renderCtx.getFunctions().getError();
290
291 if (error != GL_NO_ERROR)
292 throw tcu::TestError("Limit query failed: " + de::toString(glu::getErrorStr(error)));
293
294 if (numSupported < numRequiredCombinedSamplers)
295 throw tcu::NotSupportedError("Program requires " + de::toString(numRequiredCombinedSamplers) +
296 " sampler(s). Implementation supports " + de::toString(numSupported));
297 }
298 }
299
getTex2D(void)300 const glu::Texture2D *RandomShaderCase::getTex2D(void)
301 {
302 if (!m_tex2D)
303 {
304 m_tex2D = new glu::Texture2D(m_renderCtx, TEXTURE_2D_FORMAT, TEXTURE_2D_DATA_TYPE, TEXTURE_2D_WIDTH,
305 TEXTURE_2D_HEIGHT);
306
307 m_tex2D->getRefTexture().allocLevel(0);
308 tcu::fillWithComponentGradients(m_tex2D->getRefTexture().getLevel(0), tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f),
309 tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
310 m_tex2D->upload();
311
312 // Setup parameters.
313 glBindTexture(GL_TEXTURE_2D, m_tex2D->getGLTexture());
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, TEXTURE_WRAP_S);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, TEXTURE_WRAP_T);
316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXTURE_MIN_FILTER);
317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXTURE_MAG_FILTER);
318
319 GLU_CHECK();
320 }
321
322 return m_tex2D;
323 }
324
getTexCube(void)325 const glu::TextureCube *RandomShaderCase::getTexCube(void)
326 {
327 if (!m_texCube)
328 {
329 m_texCube = new glu::TextureCube(m_renderCtx, TEXTURE_CUBE_FORMAT, TEXTURE_CUBE_DATA_TYPE, TEXTURE_CUBE_SIZE);
330
331 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = {
332 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative x
333 {tcu::Vec4(0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive x
334 {tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative y
335 {tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive y
336 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)}, // negative z
337 {tcu::Vec4(0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)} // positive z
338 };
339
340 // Fill level 0.
341 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
342 {
343 m_texCube->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
344 tcu::fillWithComponentGradients(m_texCube->getRefTexture().getLevelFace(0, (tcu::CubeFace)face),
345 gradients[face][0], gradients[face][1]);
346 }
347
348 m_texCube->upload();
349
350 // Setup parameters.
351 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texCube->getGLTexture());
352 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, TEXTURE_WRAP_S);
353 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, TEXTURE_WRAP_T);
354 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, TEXTURE_MIN_FILTER);
355 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, TEXTURE_MAG_FILTER);
356
357 GLU_CHECK();
358 }
359
360 return m_texCube;
361 }
362
deinit(void)363 void RandomShaderCase::deinit(void)
364 {
365 delete m_tex2D;
366 delete m_texCube;
367
368 m_tex2D = DE_NULL;
369 m_texCube = DE_NULL;
370
371 // Free up memory
372 m_vertexArrays.clear();
373 m_indices.clear();
374 }
375
376 namespace
377 {
378
setUniformValue(int location,rsg::ConstValueAccess value)379 void setUniformValue(int location, rsg::ConstValueAccess value)
380 {
381 DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(float));
382 DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(int));
383
384 switch (value.getType().getBaseType())
385 {
386 case rsg::VariableType::TYPE_FLOAT:
387 switch (value.getType().getNumElements())
388 {
389 case 1:
390 glUniform1fv(location, 1, (float *)value.value().getValuePtr());
391 break;
392 case 2:
393 glUniform2fv(location, 1, (float *)value.value().getValuePtr());
394 break;
395 case 3:
396 glUniform3fv(location, 1, (float *)value.value().getValuePtr());
397 break;
398 case 4:
399 glUniform4fv(location, 1, (float *)value.value().getValuePtr());
400 break;
401 default:
402 TCU_FAIL("Unsupported type");
403 }
404 break;
405
406 case rsg::VariableType::TYPE_INT:
407 case rsg::VariableType::TYPE_BOOL:
408 case rsg::VariableType::TYPE_SAMPLER_2D:
409 case rsg::VariableType::TYPE_SAMPLER_CUBE:
410 switch (value.getType().getNumElements())
411 {
412 case 1:
413 glUniform1iv(location, 1, (int *)value.value().getValuePtr());
414 break;
415 case 2:
416 glUniform2iv(location, 1, (int *)value.value().getValuePtr());
417 break;
418 case 3:
419 glUniform3iv(location, 1, (int *)value.value().getValuePtr());
420 break;
421 case 4:
422 glUniform4iv(location, 1, (int *)value.value().getValuePtr());
423 break;
424 default:
425 TCU_FAIL("Unsupported type");
426 }
427 break;
428
429 default:
430 TCU_FAIL("Unsupported type");
431 }
432 }
433
operator <<(tcu::MessageBuilder & message,rsg::ConstValueAccess value)434 tcu::MessageBuilder &operator<<(tcu::MessageBuilder &message, rsg::ConstValueAccess value)
435 {
436 const char *scalarType = DE_NULL;
437 const char *vecType = DE_NULL;
438
439 switch (value.getType().getBaseType())
440 {
441 case rsg::VariableType::TYPE_FLOAT:
442 scalarType = "float";
443 vecType = "vec";
444 break;
445 case rsg::VariableType::TYPE_INT:
446 scalarType = "int";
447 vecType = "ivec";
448 break;
449 case rsg::VariableType::TYPE_BOOL:
450 scalarType = "bool";
451 vecType = "bvec";
452 break;
453 case rsg::VariableType::TYPE_SAMPLER_2D:
454 scalarType = "sampler2D";
455 break;
456 case rsg::VariableType::TYPE_SAMPLER_CUBE:
457 scalarType = "samplerCube";
458 break;
459 default:
460 TCU_FAIL("Unsupported type.");
461 }
462
463 int numElements = value.getType().getNumElements();
464 if (numElements == 1)
465 message << scalarType << "(";
466 else
467 message << vecType << numElements << "(";
468
469 for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
470 {
471 if (elementNdx > 0)
472 message << ", ";
473
474 switch (value.getType().getBaseType())
475 {
476 case rsg::VariableType::TYPE_FLOAT:
477 message << value.component(elementNdx).asFloat();
478 break;
479 case rsg::VariableType::TYPE_INT:
480 message << value.component(elementNdx).asInt();
481 break;
482 case rsg::VariableType::TYPE_BOOL:
483 message << (value.component(elementNdx).asBool() ? "true" : "false");
484 break;
485 case rsg::VariableType::TYPE_SAMPLER_2D:
486 message << value.component(elementNdx).asInt();
487 break;
488 case rsg::VariableType::TYPE_SAMPLER_CUBE:
489 message << value.component(elementNdx).asInt();
490 break;
491 default:
492 DE_ASSERT(false);
493 }
494 }
495
496 message << ")";
497
498 return message;
499 }
500
operator <<(tcu::MessageBuilder & message,rsg::ConstValueRangeAccess valueRange)501 tcu::MessageBuilder &operator<<(tcu::MessageBuilder &message, rsg::ConstValueRangeAccess valueRange)
502 {
503 return message << valueRange.getMin() << " -> " << valueRange.getMax();
504 }
505
506 } // namespace
507
iterate(void)508 RandomShaderCase::IterateResult RandomShaderCase::iterate(void)
509 {
510 tcu::TestLog &log = m_testCtx.getLog();
511
512 // Compile program
513 glu::ShaderProgram program(m_renderCtx,
514 glu::makeVtxFragSources(m_vertexShader.getSource(), m_fragmentShader.getSource()));
515 log << program;
516
517 if (!program.isOk())
518 {
519 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to compile shader");
520 return STOP;
521 }
522
523 // Compute random viewport
524 de::Random rnd(m_parameters.seed);
525 int viewportWidth = de::min<int>(VIEWPORT_WIDTH, m_renderCtx.getRenderTarget().getWidth());
526 int viewportHeight = de::min<int>(VIEWPORT_HEIGHT, m_renderCtx.getRenderTarget().getHeight());
527 int viewportX = rnd.getInt(0, m_renderCtx.getRenderTarget().getWidth() - viewportWidth);
528 int viewportY = rnd.getInt(0, m_renderCtx.getRenderTarget().getHeight() - viewportHeight);
529 bool hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
530 tcu::TextureLevel rendered(tcu::TextureFormat(hasAlpha ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB,
531 tcu::TextureFormat::UNORM_INT8),
532 viewportWidth, viewportHeight);
533 tcu::TextureLevel reference(tcu::TextureFormat(hasAlpha ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB,
534 tcu::TextureFormat::UNORM_INT8),
535 viewportWidth, viewportHeight);
536
537 // Reference program executor.
538 rsg::ProgramExecutor executor(reference.getAccess(), m_gridWidth, m_gridHeight);
539
540 GLU_CHECK_CALL(glUseProgram(program.getProgram()));
541
542 // Set up attributes
543 for (vector<VertexArray>::const_iterator attribIter = m_vertexArrays.begin(); attribIter != m_vertexArrays.end();
544 attribIter++)
545 {
546 GLint location = glGetAttribLocation(program.getProgram(), attribIter->getName());
547
548 // Print to log.
549 log << tcu::TestLog::Message << "attribute[" << location << "]: " << attribIter->getName() << " = "
550 << attribIter->getValueRange() << tcu::TestLog::EndMessage;
551
552 if (location >= 0)
553 {
554 glVertexAttribPointer(location, attribIter->getNumComponents(), GL_FLOAT, GL_FALSE, 0,
555 &attribIter->getVertices()[0]);
556 glEnableVertexAttribArray(location);
557 }
558 }
559 GLU_CHECK_MSG("After attribute setup");
560
561 // Uniforms
562 for (vector<rsg::VariableValue>::const_iterator uniformIter = m_uniforms.begin(); uniformIter != m_uniforms.end();
563 uniformIter++)
564 {
565 GLint location = glGetUniformLocation(program.getProgram(), uniformIter->getVariable()->getName());
566
567 log << tcu::TestLog::Message << "uniform[" << location << "]: " << uniformIter->getVariable()->getName()
568 << " = " << uniformIter->getValue() << tcu::TestLog::EndMessage;
569
570 if (location >= 0)
571 setUniformValue(location, uniformIter->getValue());
572 }
573 GLU_CHECK_MSG("After uniform setup");
574
575 // Textures
576 vector<pair<int, const glu::Texture2D *>> tex2DBindings = m_texManager.getBindings2D();
577 vector<pair<int, const glu::TextureCube *>> texCubeBindings = m_texManager.getBindingsCube();
578
579 for (vector<pair<int, const glu::Texture2D *>>::const_iterator i = tex2DBindings.begin(); i != tex2DBindings.end();
580 i++)
581 {
582 int unitNdx = i->first;
583 const glu::Texture2D *texture = i->second;
584
585 glActiveTexture(GL_TEXTURE0 + unitNdx);
586 glBindTexture(GL_TEXTURE_2D, texture->getGLTexture());
587
588 executor.setTexture(unitNdx, &texture->getRefTexture(),
589 glu::mapGLSampler(TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE_MIN_FILTER, TEXTURE_MAG_FILTER));
590 }
591 GLU_CHECK_MSG("After 2D texture setup");
592
593 for (vector<pair<int, const glu::TextureCube *>>::const_iterator i = texCubeBindings.begin();
594 i != texCubeBindings.end(); i++)
595 {
596 int unitNdx = i->first;
597 const glu::TextureCube *texture = i->second;
598
599 glActiveTexture(GL_TEXTURE0 + unitNdx);
600 glBindTexture(GL_TEXTURE_CUBE_MAP, texture->getGLTexture());
601
602 executor.setTexture(unitNdx, &texture->getRefTexture(),
603 glu::mapGLSampler(TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE_MIN_FILTER, TEXTURE_MAG_FILTER));
604 }
605 GLU_CHECK_MSG("After cubemap setup");
606
607 // Draw and read
608 glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
609 glDrawElements(GL_TRIANGLES, (GLsizei)m_indices.size(), GL_UNSIGNED_SHORT, &m_indices[0]);
610 glFlush();
611 GLU_CHECK_MSG("Draw");
612
613 // Render reference while GPU is doing work
614 executor.execute(m_vertexShader, m_fragmentShader, m_uniforms);
615
616 if (rendered.getFormat().order != tcu::TextureFormat::RGBA ||
617 rendered.getFormat().type != tcu::TextureFormat::UNORM_INT8)
618 {
619 // Read as GL_RGBA8
620 tcu::TextureLevel readBuf(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
621 rendered.getWidth(), rendered.getHeight());
622 glu::readPixels(m_renderCtx, viewportX, viewportY, readBuf.getAccess());
623 GLU_CHECK_MSG("Read pixels");
624 tcu::copy(rendered, readBuf);
625 }
626 else
627 glu::readPixels(m_renderCtx, viewportX, viewportY, rendered.getAccess());
628
629 // Compare
630 {
631 float threshold = 0.02f;
632 bool imagesOk = tcu::fuzzyCompare(log, "Result", "Result images", reference.getAccess(), rendered.getAccess(),
633 threshold, tcu::COMPARE_LOG_RESULT);
634
635 if (imagesOk)
636 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
637 else
638 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
639 }
640
641 return STOP;
642 }
643
644 } // namespace gls
645 } // namespace deqp
646