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
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, 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
~RandomShaderCase(void)131 RandomShaderCase::~RandomShaderCase (void)
132 {
133 delete m_tex2D;
134 delete m_texCube;
135 }
136
init(void)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
getNumSamplerUniforms(const std::vector<rsg::ShaderInput * > & uniforms)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
checkShaderLimits(const rsg::Shader & shader) const253 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
checkProgramLimits(const rsg::Shader & vtxShader,const rsg::Shader & frgShader) const274 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
getTex2D(void)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
getTexCube(void)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
deinit(void)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
setUniformValue(int location,rsg::ConstValueAccess value)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
operator <<(tcu::MessageBuilder & message,rsg::ConstValueAccess value)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
operator <<(tcu::MessageBuilder & message,rsg::ConstValueRangeAccess valueRange)452 tcu::MessageBuilder& operator<< (tcu::MessageBuilder& message, rsg::ConstValueRangeAccess valueRange)
453 {
454 return message << valueRange.getMin() << " -> " << valueRange.getMax();
455 }
456
457 } // anonymous
458
iterate(void)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
580