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