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 47using std::vector; 48using std::string; 49using std::pair; 50using std::map; 51 52namespace deqp 53{ 54namespace gls 55{ 56 57enum 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 78VertexArray::VertexArray (const rsg::ShaderInput* input, int numVertices) 79 : m_input (input) 80 , m_vertices (input->getVariable()->getType().getNumElements() * numVertices) 81{ 82} 83 84TextureManager::TextureManager (void) 85{ 86} 87 88TextureManager::~TextureManager (void) 89{ 90} 91 92void TextureManager::bindTexture (int unit, const glu::Texture2D* tex2D) 93{ 94 m_tex2D[unit] = tex2D; 95} 96 97void TextureManager::bindTexture (int unit, const glu::TextureCube* texCube) 98{ 99 m_texCube[unit] = texCube; 100} 101 102inline 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 110inline 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 118RandomShaderCase::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 131RandomShaderCase::~RandomShaderCase (void) 132{ 133 delete m_tex2D; 134 delete m_texCube; 135} 136 137void 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] = quadX + quadY*(m_gridWidth+1); 214 m_indices[quadNdx*6+1] = quadX + (quadY+1)*(m_gridWidth+1); 215 m_indices[quadNdx*6+2] = quadX + quadY*(m_gridWidth+1) + 1; 216 m_indices[quadNdx*6+3] = m_indices[quadNdx*6+2]; 217 m_indices[quadNdx*6+4] = m_indices[quadNdx*6+1]; 218 m_indices[quadNdx*6+5] = 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 240static 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 253void 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 274void 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 294const 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 317const 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 355void 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 368namespace 369{ 370 371void 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 408tcu::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 452tcu::MessageBuilder& operator<< (tcu::MessageBuilder& message, rsg::ConstValueRangeAccess valueRange) 453{ 454 return message << valueRange.getMin() << " -> " << valueRange.getMax(); 455} 456 457} // anonymous 458 459RandomShaderCase::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