1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2016 Google Inc. 6 * Copyright (c) 2016 The Khronos Group Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ /*! 21 * \file 22 * \brief Shader execute test. 23 */ /*-------------------------------------------------------------------*/ 24 25#include "glcShaderRenderCase.hpp" 26 27#include "tcuImageCompare.hpp" 28#include "tcuRenderTarget.hpp" 29#include "tcuSurface.hpp" 30#include "tcuTestLog.hpp" 31#include "tcuVector.hpp" 32 33#include "gluDrawUtil.hpp" 34#include "gluPixelTransfer.hpp" 35#include "gluTexture.hpp" 36#include "gluTextureUtil.hpp" 37 38#include "glwEnums.hpp" 39#include "glwFunctions.hpp" 40 41#include "deMath.h" 42#include "deMemory.h" 43#include "deRandom.hpp" 44#include "deString.h" 45#include "deStringUtil.hpp" 46 47#include <stdio.h> 48#include <string> 49#include <vector> 50 51namespace deqp 52{ 53 54using namespace std; 55using namespace tcu; 56using namespace glu; 57 58static const int GRID_SIZE = 64; 59static const int MAX_RENDER_WIDTH = 128; 60static const int MAX_RENDER_HEIGHT = 112; 61static const tcu::Vec4 DEFAULT_CLEAR_COLOR = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 62 63inline RGBA toRGBA(const Vec4& a) 64{ 65 return RGBA( 66 deClamp32(deRoundFloatToInt32(a.x() * 255.0f), 0, 255), deClamp32(deRoundFloatToInt32(a.y() * 255.0f), 0, 255), 67 deClamp32(deRoundFloatToInt32(a.z() * 255.0f), 0, 255), deClamp32(deRoundFloatToInt32(a.w() * 255.0f), 0, 255)); 68} 69 70inline tcu::Vec4 toVec(const RGBA& c) 71{ 72 return tcu::Vec4(static_cast<float>(c.getRed()) / 255.0f, static_cast<float>(c.getGreen()) / 255.0f, 73 static_cast<float>(c.getBlue()) / 255.0f, static_cast<float>(c.getAlpha()) / 255.0f); 74} 75 76// TextureBinding 77 78TextureBinding::TextureBinding(const glu::Texture2D* tex2D, const tcu::Sampler& sampler) 79 : m_type(TYPE_2D), m_sampler(sampler) 80{ 81 m_binding.tex2D = tex2D; 82} 83 84TextureBinding::TextureBinding(const glu::TextureCube* texCube, const tcu::Sampler& sampler) 85 : m_type(TYPE_CUBE_MAP), m_sampler(sampler) 86{ 87 m_binding.texCube = texCube; 88} 89 90TextureBinding::TextureBinding(const glu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler) 91 : m_type(TYPE_2D_ARRAY), m_sampler(sampler) 92{ 93 m_binding.tex2DArray = tex2DArray; 94} 95 96TextureBinding::TextureBinding(const glu::Texture3D* tex3D, const tcu::Sampler& sampler) 97 : m_type(TYPE_3D), m_sampler(sampler) 98{ 99 m_binding.tex3D = tex3D; 100} 101 102TextureBinding::TextureBinding(void) : m_type(TYPE_NONE) 103{ 104 m_binding.tex2D = DE_NULL; 105} 106 107void TextureBinding::setSampler(const tcu::Sampler& sampler) 108{ 109 m_sampler = sampler; 110} 111 112void TextureBinding::setTexture(const glu::Texture2D* tex2D) 113{ 114 m_type = TYPE_2D; 115 m_binding.tex2D = tex2D; 116} 117 118void TextureBinding::setTexture(const glu::TextureCube* texCube) 119{ 120 m_type = TYPE_CUBE_MAP; 121 m_binding.texCube = texCube; 122} 123 124void TextureBinding::setTexture(const glu::Texture2DArray* tex2DArray) 125{ 126 m_type = TYPE_2D_ARRAY; 127 m_binding.tex2DArray = tex2DArray; 128} 129 130void TextureBinding::setTexture(const glu::Texture3D* tex3D) 131{ 132 m_type = TYPE_3D; 133 m_binding.tex3D = tex3D; 134} 135 136// QuadGrid. 137 138class QuadGrid 139{ 140public: 141 QuadGrid(int gridSize, int screenWidth, int screenHeight, const Vec4& constCoords, 142 const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures); 143 ~QuadGrid(void); 144 145 int getGridSize(void) const 146 { 147 return m_gridSize; 148 } 149 int getNumVertices(void) const 150 { 151 return m_numVertices; 152 } 153 int getNumTriangles(void) const 154 { 155 return m_numTriangles; 156 } 157 const Vec4& getConstCoords(void) const 158 { 159 return m_constCoords; 160 } 161 const vector<Mat4> getUserAttribTransforms(void) const 162 { 163 return m_userAttribTransforms; 164 } 165 const vector<TextureBinding>& getTextures(void) const 166 { 167 return m_textures; 168 } 169 170 const Vec4* getPositions(void) const 171 { 172 return &m_positions[0]; 173 } 174 const float* getAttribOne(void) const 175 { 176 return &m_attribOne[0]; 177 } 178 const Vec4* getCoords(void) const 179 { 180 return &m_coords[0]; 181 } 182 const Vec4* getUnitCoords(void) const 183 { 184 return &m_unitCoords[0]; 185 } 186 const Vec4* getUserAttrib(int attribNdx) const 187 { 188 return &m_userAttribs[attribNdx][0]; 189 } 190 const deUint16* getIndices(void) const 191 { 192 return &m_indices[0]; 193 } 194 195 Vec4 getCoords(float sx, float sy) const; 196 Vec4 getUnitCoords(float sx, float sy) const; 197 198 int getNumUserAttribs(void) const 199 { 200 return (int)m_userAttribTransforms.size(); 201 } 202 Vec4 getUserAttrib(int attribNdx, float sx, float sy) const; 203 204private: 205 int m_gridSize; 206 int m_numVertices; 207 int m_numTriangles; 208 Vec4 m_constCoords; 209 vector<Mat4> m_userAttribTransforms; 210 vector<TextureBinding> m_textures; 211 212 vector<Vec4> m_screenPos; 213 vector<Vec4> m_positions; 214 vector<Vec4> m_coords; //!< Near-unit coordinates, roughly [-2.0 .. 2.0]. 215 vector<Vec4> m_unitCoords; //!< Positive-only coordinates [0.0 .. 1.5]. 216 vector<float> m_attribOne; 217 vector<Vec4> m_userAttribs[ShaderEvalContext::MAX_TEXTURES]; 218 vector<deUint16> m_indices; 219}; 220 221QuadGrid::QuadGrid(int gridSize, int width, int height, const Vec4& constCoords, 222 const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures) 223 : m_gridSize(gridSize) 224 , m_numVertices((gridSize + 1) * (gridSize + 1)) 225 , m_numTriangles(gridSize * gridSize * 2) 226 , m_constCoords(constCoords) 227 , m_userAttribTransforms(userAttribTransforms) 228 , m_textures(textures) 229{ 230 Vec4 viewportScale = Vec4((float)width, (float)height, 0.0f, 0.0f); 231 232 // Compute vertices. 233 m_positions.resize(m_numVertices); 234 m_coords.resize(m_numVertices); 235 m_unitCoords.resize(m_numVertices); 236 m_attribOne.resize(m_numVertices); 237 m_screenPos.resize(m_numVertices); 238 239 // User attributes. 240 for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_userAttribs); i++) 241 m_userAttribs[i].resize(m_numVertices); 242 243 for (int y = 0; y < gridSize + 1; y++) 244 for (int x = 0; x < gridSize + 1; x++) 245 { 246 float sx = static_cast<float>(x) / static_cast<float>(gridSize); 247 float sy = static_cast<float>(y) / static_cast<float>(gridSize); 248 float fx = 2.0f * sx - 1.0f; 249 float fy = 2.0f * sy - 1.0f; 250 int vtxNdx = ((y * (gridSize + 1)) + x); 251 252 m_positions[vtxNdx] = Vec4(fx, fy, 0.0f, 1.0f); 253 m_attribOne[vtxNdx] = 1.0f; 254 m_screenPos[vtxNdx] = Vec4(sx, sy, 0.0f, 1.0f) * viewportScale; 255 m_coords[vtxNdx] = getCoords(sx, sy); 256 m_unitCoords[vtxNdx] = getUnitCoords(sx, sy); 257 258 for (int attribNdx = 0; attribNdx < getNumUserAttribs(); attribNdx++) 259 m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy); 260 } 261 262 // Compute indices. 263 m_indices.resize(3 * m_numTriangles); 264 for (int y = 0; y < gridSize; y++) 265 for (int x = 0; x < gridSize; x++) 266 { 267 int stride = gridSize + 1; 268 int v00 = (y * stride) + x; 269 int v01 = (y * stride) + x + 1; 270 int v10 = ((y + 1) * stride) + x; 271 int v11 = ((y + 1) * stride) + x + 1; 272 273 int baseNdx = ((y * gridSize) + x) * 6; 274 m_indices[baseNdx + 0] = static_cast<deUint16>(v10); 275 m_indices[baseNdx + 1] = static_cast<deUint16>(v00); 276 m_indices[baseNdx + 2] = static_cast<deUint16>(v01); 277 278 m_indices[baseNdx + 3] = static_cast<deUint16>(v10); 279 m_indices[baseNdx + 4] = static_cast<deUint16>(v01); 280 m_indices[baseNdx + 5] = static_cast<deUint16>(v11); 281 } 282} 283 284QuadGrid::~QuadGrid(void) 285{ 286} 287 288inline Vec4 QuadGrid::getCoords(float sx, float sy) const 289{ 290 float fx = 2.0f * sx - 1.0f; 291 float fy = 2.0f * sy - 1.0f; 292 return Vec4(fx, fy, -fx + 0.33f * fy, -0.275f * fx - fy); 293} 294 295inline Vec4 QuadGrid::getUnitCoords(float sx, float sy) const 296{ 297 return Vec4(sx, sy, 0.33f * sx + 0.5f * sy, 0.5f * sx + 0.25f * sy); 298} 299 300inline Vec4 QuadGrid::getUserAttrib(int attribNdx, float sx, float sy) const 301{ 302 // homogeneous normalized screen-space coordinates 303 return m_userAttribTransforms[attribNdx] * Vec4(sx, sy, 0.0f, 1.0f); 304} 305 306// ShaderEvalContext. 307 308ShaderEvalContext::ShaderEvalContext(const QuadGrid& quadGrid_) 309 : constCoords(quadGrid_.getConstCoords()), isDiscarded(false), quadGrid(quadGrid_) 310{ 311 const vector<TextureBinding>& bindings = quadGrid.getTextures(); 312 DE_ASSERT((int)bindings.size() <= MAX_TEXTURES); 313 314 // Fill in texture array. 315 for (int ndx = 0; ndx < (int)bindings.size(); ndx++) 316 { 317 const TextureBinding& binding = bindings[ndx]; 318 319 if (binding.getType() == TextureBinding::TYPE_NONE) 320 continue; 321 322 textures[ndx].sampler = binding.getSampler(); 323 324 switch (binding.getType()) 325 { 326 case TextureBinding::TYPE_2D: 327 textures[ndx].tex2D = &binding.get2D()->getRefTexture(); 328 break; 329 case TextureBinding::TYPE_CUBE_MAP: 330 textures[ndx].texCube = &binding.getCube()->getRefTexture(); 331 break; 332 case TextureBinding::TYPE_2D_ARRAY: 333 textures[ndx].tex2DArray = &binding.get2DArray()->getRefTexture(); 334 break; 335 case TextureBinding::TYPE_3D: 336 textures[ndx].tex3D = &binding.get3D()->getRefTexture(); 337 break; 338 default: 339 DE_ASSERT(DE_FALSE); 340 } 341 } 342} 343 344ShaderEvalContext::~ShaderEvalContext(void) 345{ 346} 347 348void ShaderEvalContext::reset(float sx, float sy) 349{ 350 // Clear old values 351 color = Vec4(0.0f, 0.0f, 0.0f, 1.0f); 352 isDiscarded = false; 353 354 // Compute coords 355 coords = quadGrid.getCoords(sx, sy); 356 unitCoords = quadGrid.getUnitCoords(sx, sy); 357 358 // Compute user attributes. 359 int numAttribs = quadGrid.getNumUserAttribs(); 360 DE_ASSERT(numAttribs <= MAX_USER_ATTRIBS); 361 for (int attribNdx = 0; attribNdx < numAttribs; attribNdx++) 362 in[attribNdx] = quadGrid.getUserAttrib(attribNdx, sx, sy); 363} 364 365tcu::Vec4 ShaderEvalContext::texture2D(int unitNdx, const tcu::Vec2& texCoords) 366{ 367 if (textures[unitNdx].tex2D) 368 return textures[unitNdx].tex2D->sample(textures[unitNdx].sampler, texCoords.x(), texCoords.y(), 0.0f); 369 else 370 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 371} 372 373// ShaderEvaluator 374 375ShaderEvaluator::ShaderEvaluator(void) : m_evalFunc(DE_NULL) 376{ 377} 378 379ShaderEvaluator::ShaderEvaluator(ShaderEvalFunc evalFunc) : m_evalFunc(evalFunc) 380{ 381} 382 383ShaderEvaluator::~ShaderEvaluator(void) 384{ 385} 386 387void ShaderEvaluator::evaluate(ShaderEvalContext& ctx) 388{ 389 DE_ASSERT(m_evalFunc); 390 m_evalFunc(ctx); 391} 392 393// ShaderRenderCase. 394 395ShaderRenderCase::ShaderRenderCase(TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo, 396 const char* name, const char* description, bool isVertexCase, 397 ShaderEvalFunc evalFunc) 398 : TestCase(testCtx, name, description) 399 , m_renderCtx(renderCtx) 400 , m_ctxInfo(ctxInfo) 401 , m_isVertexCase(isVertexCase) 402 , m_defaultEvaluator(evalFunc) 403 , m_evaluator(m_defaultEvaluator) 404 , m_clearColor(DEFAULT_CLEAR_COLOR) 405 , m_program(DE_NULL) 406{ 407} 408 409ShaderRenderCase::ShaderRenderCase(TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo, 410 const char* name, const char* description, bool isVertexCase, 411 ShaderEvaluator& evaluator) 412 : TestCase(testCtx, name, description) 413 , m_renderCtx(renderCtx) 414 , m_ctxInfo(ctxInfo) 415 , m_isVertexCase(isVertexCase) 416 , m_defaultEvaluator(DE_NULL) 417 , m_evaluator(evaluator) 418 , m_clearColor(DEFAULT_CLEAR_COLOR) 419 , m_program(DE_NULL) 420{ 421} 422 423ShaderRenderCase::~ShaderRenderCase(void) 424{ 425 ShaderRenderCase::deinit(); 426} 427 428void ShaderRenderCase::init(void) 429{ 430 TestLog& log = m_testCtx.getLog(); 431 const glw::Functions& gl = m_renderCtx.getFunctions(); 432 433 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() begin"); 434 435 DE_ASSERT(!m_program); 436 m_program = 437 new ShaderProgram(m_renderCtx, glu::makeVtxFragSources(m_vertShaderSource.c_str(), m_fragShaderSource.c_str())); 438 439 try 440 { 441 log << *m_program; // Always log shader program. 442 443 if (!m_program->isOk()) 444 TCU_FAIL("Failed to compile shader program"); 445 446 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() end"); 447 } 448 catch (const std::exception&) 449 { 450 // Clean up. 451 ShaderRenderCase::deinit(); 452 throw; 453 } 454} 455 456void ShaderRenderCase::deinit(void) 457{ 458 delete m_program; 459 m_program = DE_NULL; 460} 461 462tcu::IVec2 ShaderRenderCase::getViewportSize(void) const 463{ 464 return tcu::IVec2(de::min(m_renderCtx.getRenderTarget().getWidth(), MAX_RENDER_WIDTH), 465 de::min(m_renderCtx.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT)); 466} 467 468TestNode::IterateResult ShaderRenderCase::iterate(void) 469{ 470 const glw::Functions& gl = m_renderCtx.getFunctions(); 471 472 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::iterate() begin"); 473 474 DE_ASSERT(m_program); 475 deUint32 programID = m_program->getProgram(); 476 gl.useProgram(programID); 477 478 // Create quad grid. 479 IVec2 viewportSize = getViewportSize(); 480 int width = viewportSize.x(); 481 int height = viewportSize.y(); 482 483 // \todo [petri] Better handling of constCoords (render in multiple chunks, vary coords). 484 QuadGrid quadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, Vec4(0.0f, 0.0f, 0.0f, 1.0f), 485 m_userAttribTransforms, m_textures); 486 487 // Render result. 488 Surface resImage(width, height); 489 render(resImage, programID, quadGrid); 490 491 // Compute reference. 492 Surface refImage(width, height); 493 if (m_isVertexCase) 494 computeVertexReference(refImage, quadGrid); 495 else 496 computeFragmentReference(refImage, quadGrid); 497 498 // Compare. 499 bool testOk = compareImages(resImage, refImage, 0.05f); 500 501 // De-initialize. 502 gl.useProgram(0); 503 504 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, testOk ? "Pass" : "Fail"); 505 return TestNode::STOP; 506} 507 508void ShaderRenderCase::setup(deUint32 programID) 509{ 510 DE_UNREF(programID); 511} 512 513void ShaderRenderCase::setupUniforms(deUint32 programID, const Vec4& constCoords) 514{ 515 DE_UNREF(programID); 516 DE_UNREF(constCoords); 517} 518 519void ShaderRenderCase::setupDefaultInputs(int programID) 520{ 521 const glw::Functions& gl = m_renderCtx.getFunctions(); 522 523 // SETUP UNIFORMS. 524 525 setupDefaultUniforms(m_renderCtx, programID); 526 527 GLU_EXPECT_NO_ERROR(gl.getError(), "post uniform setup"); 528 529 // SETUP TEXTURES. 530 531 for (int ndx = 0; ndx < (int)m_textures.size(); ndx++) 532 { 533 const TextureBinding& tex = m_textures[ndx]; 534 const tcu::Sampler& sampler = tex.getSampler(); 535 deUint32 texTarget = GL_NONE; 536 deUint32 texObj = 0; 537 538 if (tex.getType() == TextureBinding::TYPE_NONE) 539 continue; 540 541 // Feature check. 542 if (m_renderCtx.getType().getAPI() == glu::ApiType(2, 0, glu::PROFILE_ES)) 543 { 544 if (tex.getType() == TextureBinding::TYPE_2D_ARRAY) 545 throw tcu::NotSupportedError("2D array texture binding is not supported"); 546 547 if (tex.getType() == TextureBinding::TYPE_3D) 548 throw tcu::NotSupportedError("3D texture binding is not supported"); 549 550 if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE) 551 throw tcu::NotSupportedError("Shadow lookups are not supported"); 552 } 553 554 switch (tex.getType()) 555 { 556 case TextureBinding::TYPE_2D: 557 texTarget = GL_TEXTURE_2D; 558 texObj = tex.get2D()->getGLTexture(); 559 break; 560 case TextureBinding::TYPE_CUBE_MAP: 561 texTarget = GL_TEXTURE_CUBE_MAP; 562 texObj = tex.getCube()->getGLTexture(); 563 break; 564 case TextureBinding::TYPE_2D_ARRAY: 565 texTarget = GL_TEXTURE_2D_ARRAY; 566 texObj = tex.get2DArray()->getGLTexture(); 567 break; 568 case TextureBinding::TYPE_3D: 569 texTarget = GL_TEXTURE_3D; 570 texObj = tex.get3D()->getGLTexture(); 571 break; 572 default: 573 DE_ASSERT(DE_FALSE); 574 } 575 576 gl.activeTexture(GL_TEXTURE0 + ndx); 577 gl.bindTexture(texTarget, texObj); 578 gl.texParameteri(texTarget, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(sampler.wrapS)); 579 gl.texParameteri(texTarget, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(sampler.wrapT)); 580 gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(sampler.minFilter)); 581 gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(sampler.magFilter)); 582 583 if (texTarget == GL_TEXTURE_3D) 584 gl.texParameteri(texTarget, GL_TEXTURE_WRAP_R, glu::getGLWrapMode(sampler.wrapR)); 585 586 if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE) 587 { 588 gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 589 gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(sampler.compare)); 590 } 591 } 592 593 GLU_EXPECT_NO_ERROR(gl.getError(), "texture sampler setup"); 594} 595 596static void getDefaultVertexArrays(const glw::Functions& gl, const QuadGrid& quadGrid, deUint32 program, 597 vector<VertexArrayBinding>& vertexArrays) 598{ 599 const int numElements = quadGrid.getNumVertices(); 600 601 vertexArrays.push_back(va::Float("a_position", 4, numElements, 0, (const float*)quadGrid.getPositions())); 602 vertexArrays.push_back(va::Float("a_coords", 4, numElements, 0, (const float*)quadGrid.getCoords())); 603 vertexArrays.push_back(va::Float("a_unitCoords", 4, numElements, 0, (const float*)quadGrid.getUnitCoords())); 604 vertexArrays.push_back(va::Float("a_one", 1, numElements, 0, quadGrid.getAttribOne())); 605 606 // a_inN. 607 for (int userNdx = 0; userNdx < quadGrid.getNumUserAttribs(); userNdx++) 608 { 609 string name = string("a_in") + de::toString(userNdx); 610 vertexArrays.push_back(va::Float(name, 4, numElements, 0, (const float*)quadGrid.getUserAttrib(userNdx))); 611 } 612 613 // Matrix attributes - these are set by location 614 static const struct 615 { 616 const char* name; 617 int numCols; 618 int numRows; 619 } matrices[] = { { "a_mat2", 2, 2 }, { "a_mat2x3", 2, 3 }, { "a_mat2x4", 2, 4 }, 620 { "a_mat3x2", 3, 2 }, { "a_mat3", 3, 3 }, { "a_mat3x4", 3, 4 }, 621 { "a_mat4x2", 4, 2 }, { "a_mat4x3", 4, 3 }, { "a_mat4", 4, 4 } }; 622 623 for (int matNdx = 0; matNdx < DE_LENGTH_OF_ARRAY(matrices); matNdx++) 624 { 625 int loc = gl.getAttribLocation(program, matrices[matNdx].name); 626 627 if (loc < 0) 628 continue; // Not used in shader. 629 630 int numRows = matrices[matNdx].numRows; 631 int numCols = matrices[matNdx].numCols; 632 633 for (int colNdx = 0; colNdx < numCols; colNdx++) 634 vertexArrays.push_back(va::Float(loc + colNdx, numRows, numElements, 4 * (int)sizeof(float), 635 (const float*)quadGrid.getUserAttrib(colNdx))); 636 } 637} 638 639void ShaderRenderCase::render(Surface& result, int programID, const QuadGrid& quadGrid) 640{ 641 const glw::Functions& gl = m_renderCtx.getFunctions(); 642 643 GLU_EXPECT_NO_ERROR(gl.getError(), "pre render"); 644 645 // Buffer info. 646 int width = result.getWidth(); 647 int height = result.getHeight(); 648 649 int xOffsetMax = m_renderCtx.getRenderTarget().getWidth() - width; 650 int yOffsetMax = m_renderCtx.getRenderTarget().getHeight() - height; 651 652 deUint32 hash = deStringHash(m_vertShaderSource.c_str()) + deStringHash(m_fragShaderSource.c_str()); 653 de::Random rnd(hash); 654 655 int xOffset = rnd.getInt(0, xOffsetMax); 656 int yOffset = rnd.getInt(0, yOffsetMax); 657 658 gl.viewport(xOffset, yOffset, width, height); 659 660 // Setup program. 661 setupUniforms(programID, quadGrid.getConstCoords()); 662 setupDefaultInputs(programID); 663 664 // Disable dither. 665 gl.disable(GL_DITHER); 666 667 // Clear. 668 gl.clearColor(m_clearColor.x(), m_clearColor.y(), m_clearColor.z(), m_clearColor.w()); 669 gl.clear(GL_COLOR_BUFFER_BIT); 670 671 // Draw. 672 { 673 std::vector<VertexArrayBinding> vertexArrays; 674 const int numElements = quadGrid.getNumTriangles() * 3; 675 676 getDefaultVertexArrays(gl, quadGrid, programID, vertexArrays); 677 draw(m_renderCtx, programID, (int)vertexArrays.size(), &vertexArrays[0], 678 pr::Triangles(numElements, quadGrid.getIndices())); 679 } 680 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 681 682 // Read back results. 683 glu::readPixels(m_renderCtx, xOffset, yOffset, result.getAccess()); 684 685 GLU_EXPECT_NO_ERROR(gl.getError(), "post render"); 686} 687 688void ShaderRenderCase::computeVertexReference(Surface& result, const QuadGrid& quadGrid) 689{ 690 // Buffer info. 691 int width = result.getWidth(); 692 int height = result.getHeight(); 693 int gridSize = quadGrid.getGridSize(); 694 int stride = gridSize + 1; 695 bool hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0; 696 ShaderEvalContext evalCtx(quadGrid); 697 698 // Evaluate color for each vertex. 699 vector<Vec4> colors((gridSize + 1) * (gridSize + 1)); 700 for (int y = 0; y < gridSize + 1; y++) 701 for (int x = 0; x < gridSize + 1; x++) 702 { 703 float sx = static_cast<float>(x) / static_cast<float>(gridSize); 704 float sy = static_cast<float>(y) / static_cast<float>(gridSize); 705 int vtxNdx = ((y * (gridSize + 1)) + x); 706 707 evalCtx.reset(sx, sy); 708 m_evaluator.evaluate(evalCtx); 709 DE_ASSERT(!evalCtx.isDiscarded); // Discard is not available in vertex shader. 710 Vec4 color = evalCtx.color; 711 712 if (!hasAlpha) 713 color.w() = 1.0f; 714 715 colors[vtxNdx] = color; 716 } 717 718 // Render quads. 719 for (int y = 0; y < gridSize; y++) 720 for (int x = 0; x < gridSize; x++) 721 { 722 float x0 = static_cast<float>(x) / static_cast<float>(gridSize); 723 float x1 = static_cast<float>(x + 1) / static_cast<float>(gridSize); 724 float y0 = static_cast<float>(y) / static_cast<float>(gridSize); 725 float y1 = static_cast<float>(y + 1) / static_cast<float>(gridSize); 726 727 float sx0 = x0 * (float)width; 728 float sx1 = x1 * (float)width; 729 float sy0 = y0 * (float)height; 730 float sy1 = y1 * (float)height; 731 float oosx = 1.0f / (sx1 - sx0); 732 float oosy = 1.0f / (sy1 - sy0); 733 734 int ix0 = deCeilFloatToInt32(sx0 - 0.5f); 735 int ix1 = deCeilFloatToInt32(sx1 - 0.5f); 736 int iy0 = deCeilFloatToInt32(sy0 - 0.5f); 737 int iy1 = deCeilFloatToInt32(sy1 - 0.5f); 738 739 int v00 = (y * stride) + x; 740 int v01 = (y * stride) + x + 1; 741 int v10 = ((y + 1) * stride) + x; 742 int v11 = ((y + 1) * stride) + x + 1; 743 Vec4 c00 = colors[v00]; 744 Vec4 c01 = colors[v01]; 745 Vec4 c10 = colors[v10]; 746 Vec4 c11 = colors[v11]; 747 748 //printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1); 749 750 for (int iy = iy0; iy < iy1; iy++) 751 for (int ix = ix0; ix < ix1; ix++) 752 { 753 DE_ASSERT(deInBounds32(ix, 0, width)); 754 DE_ASSERT(deInBounds32(iy, 0, height)); 755 756 float sfx = (float)ix + 0.5f; 757 float sfy = (float)iy + 0.5f; 758 float fx1 = deFloatClamp((sfx - sx0) * oosx, 0.0f, 1.0f); 759 float fy1 = deFloatClamp((sfy - sy0) * oosy, 0.0f, 1.0f); 760 761 // Triangle quad interpolation. 762 bool tri = fx1 + fy1 <= 1.0f; 763 float tx = tri ? fx1 : (1.0f - fx1); 764 float ty = tri ? fy1 : (1.0f - fy1); 765 const Vec4& t0 = tri ? c00 : c11; 766 const Vec4& t1 = tri ? c01 : c10; 767 const Vec4& t2 = tri ? c10 : c01; 768 Vec4 color = t0 + (t1 - t0) * tx + (t2 - t0) * ty; 769 770 // Quantizing for 1-bit alpha 771 if ((m_renderCtx.getRenderTarget().getPixelFormat().alphaBits) == 1) 772 color.w() = deFloatRound(color.w()); 773 774 result.setPixel(ix, iy, toRGBA(color)); 775 } 776 } 777} 778 779void ShaderRenderCase::computeFragmentReference(Surface& result, const QuadGrid& quadGrid) 780{ 781 // Buffer info. 782 int width = result.getWidth(); 783 int height = result.getHeight(); 784 bool hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0; 785 ShaderEvalContext evalCtx(quadGrid); 786 787 // Render. 788 for (int y = 0; y < height; y++) 789 for (int x = 0; x < width; x++) 790 { 791 float sx = ((float)x + 0.5f) / (float)width; 792 float sy = ((float)y + 0.5f) / (float)height; 793 794 evalCtx.reset(sx, sy); 795 m_evaluator.evaluate(evalCtx); 796 // Select either clear color or computed color based on discarded bit. 797 Vec4 color = evalCtx.isDiscarded ? m_clearColor : evalCtx.color; 798 799 if (!hasAlpha) 800 color.w() = 1.0f; 801 802 // Quantizing for 1-bit alpha 803 if ((m_renderCtx.getRenderTarget().getPixelFormat().alphaBits) == 1) 804 color.w() = deFloatRound(color.w()); 805 806 result.setPixel(x, y, toRGBA(color)); 807 } 808} 809 810bool ShaderRenderCase::compareImages(const Surface& resImage, const Surface& refImage, float errorThreshold) 811{ 812 return tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", refImage, resImage, 813 errorThreshold, tcu::COMPARE_LOG_RESULT); 814} 815 816// Uniform name helpers. 817 818const char* getIntUniformName(int number) 819{ 820 switch (number) 821 { 822 case 0: 823 return "ui_zero"; 824 case 1: 825 return "ui_one"; 826 case 2: 827 return "ui_two"; 828 case 3: 829 return "ui_three"; 830 case 4: 831 return "ui_four"; 832 case 5: 833 return "ui_five"; 834 case 6: 835 return "ui_six"; 836 case 7: 837 return "ui_seven"; 838 case 8: 839 return "ui_eight"; 840 case 101: 841 return "ui_oneHundredOne"; 842 default: 843 DE_ASSERT(false); 844 return ""; 845 } 846} 847 848const char* getFloatUniformName(int number) 849{ 850 switch (number) 851 { 852 case 0: 853 return "uf_zero"; 854 case 1: 855 return "uf_one"; 856 case 2: 857 return "uf_two"; 858 case 3: 859 return "uf_three"; 860 case 4: 861 return "uf_four"; 862 case 5: 863 return "uf_five"; 864 case 6: 865 return "uf_six"; 866 case 7: 867 return "uf_seven"; 868 case 8: 869 return "uf_eight"; 870 default: 871 DE_ASSERT(false); 872 return ""; 873 } 874} 875 876const char* getFloatFractionUniformName(int number) 877{ 878 switch (number) 879 { 880 case 1: 881 return "uf_one"; 882 case 2: 883 return "uf_half"; 884 case 3: 885 return "uf_third"; 886 case 4: 887 return "uf_fourth"; 888 case 5: 889 return "uf_fifth"; 890 case 6: 891 return "uf_sixth"; 892 case 7: 893 return "uf_seventh"; 894 case 8: 895 return "uf_eighth"; 896 default: 897 DE_ASSERT(false); 898 return ""; 899 } 900} 901 902void setupDefaultUniforms(const glu::RenderContext& context, deUint32 programID) 903{ 904 const glw::Functions& gl = context.getFunctions(); 905 906 // Bool. 907 struct BoolUniform 908 { 909 const char* name; 910 bool value; 911 }; 912 static const BoolUniform s_boolUniforms[] = { 913 { "ub_true", true }, { "ub_false", false }, 914 }; 915 916 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_boolUniforms); i++) 917 { 918 int uniLoc = gl.getUniformLocation(programID, s_boolUniforms[i].name); 919 if (uniLoc != -1) 920 gl.uniform1i(uniLoc, s_boolUniforms[i].value); 921 } 922 923 // BVec4. 924 struct BVec4Uniform 925 { 926 const char* name; 927 BVec4 value; 928 }; 929 static const BVec4Uniform s_bvec4Uniforms[] = { 930 { "ub4_true", BVec4(true) }, { "ub4_false", BVec4(false) }, 931 }; 932 933 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_bvec4Uniforms); i++) 934 { 935 const BVec4Uniform& uni = s_bvec4Uniforms[i]; 936 int arr[4]; 937 arr[0] = (int)uni.value.x(); 938 arr[1] = (int)uni.value.y(); 939 arr[2] = (int)uni.value.z(); 940 arr[3] = (int)uni.value.w(); 941 int uniLoc = gl.getUniformLocation(programID, uni.name); 942 if (uniLoc != -1) 943 gl.uniform4iv(uniLoc, 1, &arr[0]); 944 } 945 946 // Int. 947 struct IntUniform 948 { 949 const char* name; 950 int value; 951 }; 952 static const IntUniform s_intUniforms[] = { 953 { "ui_minusOne", -1 }, { "ui_zero", 0 }, { "ui_one", 1 }, { "ui_two", 2 }, { "ui_three", 3 }, 954 { "ui_four", 4 }, { "ui_five", 5 }, { "ui_six", 6 }, { "ui_seven", 7 }, { "ui_eight", 8 }, 955 { "ui_oneHundredOne", 101 } 956 }; 957 958 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_intUniforms); i++) 959 { 960 int uniLoc = gl.getUniformLocation(programID, s_intUniforms[i].name); 961 if (uniLoc != -1) 962 gl.uniform1i(uniLoc, s_intUniforms[i].value); 963 } 964 965 // IVec2. 966 struct IVec2Uniform 967 { 968 const char* name; 969 IVec2 value; 970 }; 971 static const IVec2Uniform s_ivec2Uniforms[] = { { "ui2_minusOne", IVec2(-1) }, { "ui2_zero", IVec2(0) }, 972 { "ui2_one", IVec2(1) }, { "ui2_two", IVec2(2) }, 973 { "ui2_four", IVec2(4) }, { "ui2_five", IVec2(5) } }; 974 975 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec2Uniforms); i++) 976 { 977 int uniLoc = gl.getUniformLocation(programID, s_ivec2Uniforms[i].name); 978 if (uniLoc != -1) 979 gl.uniform2iv(uniLoc, 1, s_ivec2Uniforms[i].value.getPtr()); 980 } 981 982 // IVec3. 983 struct IVec3Uniform 984 { 985 const char* name; 986 IVec3 value; 987 }; 988 static const IVec3Uniform s_ivec3Uniforms[] = { { "ui3_minusOne", IVec3(-1) }, { "ui3_zero", IVec3(0) }, 989 { "ui3_one", IVec3(1) }, { "ui3_two", IVec3(2) }, 990 { "ui3_four", IVec3(4) }, { "ui3_five", IVec3(5) } }; 991 992 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec3Uniforms); i++) 993 { 994 int uniLoc = gl.getUniformLocation(programID, s_ivec3Uniforms[i].name); 995 if (uniLoc != -1) 996 gl.uniform3iv(uniLoc, 1, s_ivec3Uniforms[i].value.getPtr()); 997 } 998 999 // IVec4. 1000 struct IVec4Uniform 1001 { 1002 const char* name; 1003 IVec4 value; 1004 }; 1005 static const IVec4Uniform s_ivec4Uniforms[] = { { "ui4_minusOne", IVec4(-1) }, { "ui4_zero", IVec4(0) }, 1006 { "ui4_one", IVec4(1) }, { "ui4_two", IVec4(2) }, 1007 { "ui4_four", IVec4(4) }, { "ui4_five", IVec4(5) } }; 1008 1009 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec4Uniforms); i++) 1010 { 1011 int uniLoc = gl.getUniformLocation(programID, s_ivec4Uniforms[i].name); 1012 if (uniLoc != -1) 1013 gl.uniform4iv(uniLoc, 1, s_ivec4Uniforms[i].value.getPtr()); 1014 } 1015 1016 // Float. 1017 struct FloatUniform 1018 { 1019 const char* name; 1020 float value; 1021 }; 1022 static const FloatUniform s_floatUniforms[] = { 1023 { "uf_zero", 0.0f }, { "uf_one", 1.0f }, { "uf_two", 2.0f }, 1024 { "uf_three", 3.0f }, { "uf_four", 4.0f }, { "uf_five", 5.0f }, 1025 { "uf_six", 6.0f }, { "uf_seven", 7.0f }, { "uf_eight", 8.0f }, 1026 { "uf_half", 1.0f / 2.0f }, { "uf_third", 1.0f / 3.0f }, { "uf_fourth", 1.0f / 4.0f }, 1027 { "uf_fifth", 1.0f / 5.0f }, { "uf_sixth", 1.0f / 6.0f }, { "uf_seventh", 1.0f / 7.0f }, 1028 { "uf_eighth", 1.0f / 8.0f } 1029 }; 1030 1031 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_floatUniforms); i++) 1032 { 1033 int uniLoc = gl.getUniformLocation(programID, s_floatUniforms[i].name); 1034 if (uniLoc != -1) 1035 gl.uniform1f(uniLoc, s_floatUniforms[i].value); 1036 } 1037 1038 // Vec2. 1039 struct Vec2Uniform 1040 { 1041 const char* name; 1042 Vec2 value; 1043 }; 1044 static const Vec2Uniform s_vec2Uniforms[] = { 1045 { "uv2_minusOne", Vec2(-1.0f) }, { "uv2_zero", Vec2(0.0f) }, { "uv2_half", Vec2(0.5f) }, 1046 { "uv2_one", Vec2(1.0f) }, { "uv2_two", Vec2(2.0f) }, 1047 }; 1048 1049 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec2Uniforms); i++) 1050 { 1051 int uniLoc = gl.getUniformLocation(programID, s_vec2Uniforms[i].name); 1052 if (uniLoc != -1) 1053 gl.uniform2fv(uniLoc, 1, s_vec2Uniforms[i].value.getPtr()); 1054 } 1055 1056 // Vec3. 1057 struct Vec3Uniform 1058 { 1059 const char* name; 1060 Vec3 value; 1061 }; 1062 static const Vec3Uniform s_vec3Uniforms[] = { 1063 { "uv3_minusOne", Vec3(-1.0f) }, { "uv3_zero", Vec3(0.0f) }, { "uv3_half", Vec3(0.5f) }, 1064 { "uv3_one", Vec3(1.0f) }, { "uv3_two", Vec3(2.0f) }, 1065 }; 1066 1067 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec3Uniforms); i++) 1068 { 1069 int uniLoc = gl.getUniformLocation(programID, s_vec3Uniforms[i].name); 1070 if (uniLoc != -1) 1071 gl.uniform3fv(uniLoc, 1, s_vec3Uniforms[i].value.getPtr()); 1072 } 1073 1074 // Vec4. 1075 struct Vec4Uniform 1076 { 1077 const char* name; 1078 Vec4 value; 1079 }; 1080 static const Vec4Uniform s_vec4Uniforms[] = { 1081 { "uv4_minusOne", Vec4(-1.0f) }, 1082 { "uv4_zero", Vec4(0.0f) }, 1083 { "uv4_half", Vec4(0.5f) }, 1084 { "uv4_one", Vec4(1.0f) }, 1085 { "uv4_two", Vec4(2.0f) }, 1086 { "uv4_black", Vec4(0.0f, 0.0f, 0.0f, 1.0f) }, 1087 { "uv4_gray", Vec4(0.5f, 0.5f, 0.5f, 1.0f) }, 1088 { "uv4_white", Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, 1089 }; 1090 1091 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec4Uniforms); i++) 1092 { 1093 int uniLoc = gl.getUniformLocation(programID, s_vec4Uniforms[i].name); 1094 if (uniLoc != -1) 1095 gl.uniform4fv(uniLoc, 1, s_vec4Uniforms[i].value.getPtr()); 1096 } 1097} 1098 1099} // deqp 1100