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