1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 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 Texture unit usage tests. 22 * 23 * \todo [2012-07-12 nuutti] Come up with a good way to make these tests faster. 24 *//*--------------------------------------------------------------------*/ 25 26#include "es3fTextureUnitTests.hpp" 27#include "glsTextureTestUtil.hpp" 28#include "gluTextureUtil.hpp" 29#include "gluContextInfo.hpp" 30#include "gluTextureUtil.hpp" 31#include "tcuTextureUtil.hpp" 32#include "tcuImageCompare.hpp" 33#include "tcuMatrix.hpp" 34#include "tcuRenderTarget.hpp" 35#include "sglrContextUtil.hpp" 36#include "sglrReferenceContext.hpp" 37#include "sglrGLContext.hpp" 38#include "deRandom.hpp" 39#include "deStringUtil.hpp" 40 41#include "glwEnums.hpp" 42#include "glwFunctions.hpp" 43 44using tcu::Vec2; 45using tcu::Vec3; 46using tcu::Vec4; 47using tcu::IVec2; 48using tcu::IVec3; 49using tcu::Mat3; 50using tcu::Mat4; 51using std::vector; 52using std::string; 53using namespace glw; // GL types 54 55namespace deqp 56{ 57 58using namespace gls::TextureTestUtil; 59 60namespace gles3 61{ 62namespace Functional 63{ 64 65static const int VIEWPORT_WIDTH = 128; 66static const int VIEWPORT_HEIGHT = 128; 67 68static const int TEXTURE_WIDTH_2D = 128; 69static const int TEXTURE_HEIGHT_2D = 128; 70 71// \note Cube map texture size is larger in order to make minifications possible - otherwise would need to display different faces at same time. 72static const int TEXTURE_WIDTH_CUBE = 256; 73static const int TEXTURE_HEIGHT_CUBE = 256; 74 75static const int TEXTURE_WIDTH_2D_ARRAY = 64; 76static const int TEXTURE_HEIGHT_2D_ARRAY = 64; 77static const int TEXTURE_LAYERS_2D_ARRAY = 4; 78 79static const int TEXTURE_WIDTH_3D = 32; 80static const int TEXTURE_HEIGHT_3D = 32; 81static const int TEXTURE_DEPTH_3D = 32; 82 83static const int GRID_CELL_SIZE = 8; 84 85static const GLenum s_testSizedInternalFormats[] = 86{ 87 GL_RGBA32F, 88 GL_RGBA32I, 89 GL_RGBA32UI, 90 GL_RGBA16F, 91 GL_RGBA16I, 92 GL_RGBA16UI, 93 GL_RGBA8, 94 GL_RGBA8I, 95 GL_RGBA8UI, 96 GL_SRGB8_ALPHA8, 97 GL_RGB10_A2, 98 GL_RGB10_A2UI, 99 GL_RGBA4, 100 GL_RGB5_A1, 101 GL_RGBA8_SNORM, 102 GL_RGB8, 103 GL_RGB565, 104 GL_R11F_G11F_B10F, 105 GL_RGB32F, 106 GL_RGB32I, 107 GL_RGB32UI, 108 GL_RGB16F, 109 GL_RGB16I, 110 GL_RGB16UI, 111 GL_RGB8_SNORM, 112 GL_RGB8I, 113 GL_RGB8UI, 114 GL_SRGB8, 115 GL_RGB9_E5, 116 GL_RG32F, 117 GL_RG32I, 118 GL_RG32UI, 119 GL_RG16F, 120 GL_RG16I, 121 GL_RG16UI, 122 GL_RG8, 123 GL_RG8I, 124 GL_RG8UI, 125 GL_RG8_SNORM, 126 GL_R32F, 127 GL_R32I, 128 GL_R32UI, 129 GL_R16F, 130 GL_R16I, 131 GL_R16UI, 132 GL_R8, 133 GL_R8I, 134 GL_R8UI, 135 GL_R8_SNORM 136}; 137 138static const GLenum s_testWrapModes[] = 139{ 140 GL_CLAMP_TO_EDGE, 141 GL_REPEAT, 142 GL_MIRRORED_REPEAT, 143}; 144 145static const GLenum s_testMinFilters[] = 146{ 147 GL_NEAREST, 148 GL_LINEAR, 149 GL_NEAREST_MIPMAP_NEAREST, 150 GL_LINEAR_MIPMAP_NEAREST, 151 GL_NEAREST_MIPMAP_LINEAR, 152 GL_LINEAR_MIPMAP_LINEAR 153}; 154 155static const GLenum s_testNonMipmapMinFilters[] = 156{ 157 GL_NEAREST, 158 GL_LINEAR 159}; 160 161static const GLenum s_testNearestMinFilters[] = 162{ 163 GL_NEAREST, 164 GL_NEAREST_MIPMAP_NEAREST 165}; 166 167static const GLenum s_testMagFilters[] = 168{ 169 GL_NEAREST, 170 GL_LINEAR 171}; 172 173static const GLenum s_cubeFaceTargets[] = 174{ 175 GL_TEXTURE_CUBE_MAP_POSITIVE_X, 176 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 177 GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 178 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 179 GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 180 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 181}; 182 183// Extend a 3x3 transformation matrix to an equivalent 4x4 transformation matrix (i.e. 1.0 in right-down cell, 0.0's in other new cells). 184static Mat4 matExtend3To4 (const Mat3& mat) 185{ 186 Mat4 res; 187 for (int rowNdx = 0; rowNdx < 3; rowNdx++) 188 { 189 Vec3 row = mat.getRow(rowNdx); 190 res.setRow(rowNdx, Vec4(row.x(), row.y(), row.z(), 0.0f)); 191 } 192 res.setRow(3, Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 193 194 return res; 195} 196 197static string generateMultiTexFragmentShader (int numUnits, const vector<GLenum>& unitTypes, const vector<glu::DataType>& samplerTypes) 198{ 199 // The fragment shader calculates the average of a set of textures. 200 201 string samplersStr; 202 string matricesStr; 203 string scalesStr; 204 string biasesStr; 205 string lookupsStr; 206 207 string colorMultiplier = "(1.0/" + de::toString(numUnits) + ".0)"; 208 209 for (int ndx = 0; ndx < numUnits; ndx++) 210 { 211 string ndxStr = de::toString(ndx); 212 string samplerName = "u_sampler" + ndxStr; 213 string transformationName = "u_trans" + ndxStr; 214 string scaleName = "u_texScale" + ndxStr; 215 string biasName = "u_texBias" + ndxStr; 216 217 samplersStr += string("") + "uniform highp " + glu::getDataTypeName(samplerTypes[ndx]) + " " + samplerName + ";\n"; 218 matricesStr += "uniform highp mat4 " + transformationName + ";\n"; 219 scalesStr += "uniform highp vec4 " + scaleName + ";\n"; 220 biasesStr += "uniform highp vec4 " + biasName + ";\n"; 221 222 string lookupCoord = transformationName + "*vec4(v_coord, 1.0, 1.0)"; 223 224 if (unitTypes[ndx] == GL_TEXTURE_2D) 225 lookupCoord = "vec2(" + lookupCoord + ")"; 226 else 227 lookupCoord = "vec3(" + lookupCoord + ")"; 228 229 lookupsStr += "\tcolor += " + colorMultiplier + "*(vec4(texture(" + samplerName + ", " + lookupCoord + "))*" + scaleName + " + " + biasName + ");\n"; 230 } 231 232 return "#version 300 es\n" 233 "layout(location = 0) out mediump vec4 o_color;\n" + 234 samplersStr + 235 matricesStr + 236 scalesStr + 237 biasesStr + 238 "in highp vec2 v_coord;\n" 239 "\n" 240 "void main (void)\n" 241 "{\n" 242 " mediump vec4 color = vec4(0.0);\n" + 243 lookupsStr + 244 " o_color = color;\n" 245 "}\n"; 246} 247 248static sglr::pdec::ShaderProgramDeclaration generateShaderProgramDeclaration (int numUnits, const vector<GLenum>& unitTypes, const vector<glu::DataType>& samplerTypes) 249{ 250 sglr::pdec::ShaderProgramDeclaration decl; 251 252 decl << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT); 253 decl << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT); 254 decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT); 255 decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT); 256 257 for (int ndx = 0; ndx < numUnits; ++ndx) 258 { 259 string samplerName = "u_sampler" + de::toString(ndx); 260 string transformationName = "u_trans" + de::toString(ndx); 261 string scaleName = "u_texScale" + de::toString(ndx); 262 string biasName = "u_texBias" + de::toString(ndx); 263 264 decl << sglr::pdec::Uniform(samplerName, samplerTypes[ndx]); 265 decl << sglr::pdec::Uniform(transformationName, glu::TYPE_FLOAT_MAT4); 266 decl << sglr::pdec::Uniform(scaleName, glu::TYPE_FLOAT_VEC4); 267 decl << sglr::pdec::Uniform(biasName, glu::TYPE_FLOAT_VEC4); 268 } 269 270 decl << sglr::pdec::VertexSource("#version 300 es\n" 271 "in highp vec4 a_position;\n" 272 "in highp vec2 a_coord;\n" 273 "out highp vec2 v_coord;\n" 274 "\n" 275 "void main (void)\n" 276 "{\n" 277 " gl_Position = a_position;\n" 278 " v_coord = a_coord;\n" 279 "}\n"); 280 decl << sglr::pdec::FragmentSource(generateMultiTexFragmentShader(numUnits, unitTypes, samplerTypes)); 281 282 return decl; 283} 284 285// Calculates values that will be used in calculateLod(). 286static tcu::Vector<tcu::Vec2, 3> calculateLodDerivateParts (const Mat4& transformation) 287{ 288 // Calculate transformed coordinates of three screen corners. 289 Vec3 trans00 = (transformation * Vec4(0.0f, 0.0f, 1.0f, 1.0f)).xyz(); 290 Vec3 trans01 = (transformation * Vec4(0.0f, 1.0f, 1.0f, 1.0f)).xyz(); 291 Vec3 trans10 = (transformation * Vec4(1.0f, 0.0f, 1.0f, 1.0f)).xyz(); 292 293 return tcu::Vector<tcu::Vec2, 3>(Vec2(trans10.x() - trans00.x(), trans01.x() - trans00.x()), 294 Vec2(trans10.y() - trans00.y(), trans01.y() - trans00.y()), 295 Vec2(trans10.z() - trans00.z(), trans01.z() - trans00.z())); 296} 297 298// Calculates the maximum allowed lod from derivates 299static float calculateLodMax(const tcu::Vector<tcu::Vec2, 3>& derivateParts, const tcu::IVec3& textureSize, const Vec2& screenDerivate) 300{ 301 float dudx = derivateParts[0].x() * (float)textureSize.x() * screenDerivate.x(); 302 float dudy = derivateParts[0].y() * (float)textureSize.x() * screenDerivate.y(); 303 float dvdx = derivateParts[1].x() * (float)textureSize.y() * screenDerivate.x(); 304 float dvdy = derivateParts[1].y() * (float)textureSize.y() * screenDerivate.y(); 305 float dwdx = derivateParts[2].x() * (float)textureSize.z() * screenDerivate.x(); 306 float dwdy = derivateParts[2].y() * (float)textureSize.z() * screenDerivate.y(); 307 308 const float mu = de::max(de::abs(dudx), de::abs(dudy)); 309 const float mv = de::max(de::abs(dvdx), de::abs(dvdy)); 310 const float mw = de::max(de::abs(dwdx), de::abs(dwdy)); 311 return deFloatLog2(mu + mv + mw); 312} 313 314// Calculates the minimum allowed lod from derivates 315static float calculateLodMin(const tcu::Vector<tcu::Vec2, 3>& derivateParts, const tcu::IVec3& textureSize, const Vec2& screenDerivate) 316{ 317 float dudx = derivateParts[0].x() * (float)textureSize.x() * screenDerivate.x(); 318 float dudy = derivateParts[0].y() * (float)textureSize.x() * screenDerivate.y(); 319 float dvdx = derivateParts[1].x() * (float)textureSize.y() * screenDerivate.x(); 320 float dvdy = derivateParts[1].y() * (float)textureSize.y() * screenDerivate.y(); 321 float dwdx = derivateParts[2].x() * (float)textureSize.z() * screenDerivate.x(); 322 float dwdy = derivateParts[2].y() * (float)textureSize.z() * screenDerivate.y(); 323 324 const float mu = de::max(de::abs(dudx), de::abs(dudy)); 325 const float mv = de::max(de::abs(dvdx), de::abs(dvdy)); 326 const float mw = de::max(de::abs(dwdx), de::abs(dwdy)); 327 return deFloatLog2(de::max(mu, de::max(mv, mw))); 328} 329 330class MultiTexShader : public sglr::ShaderProgram 331{ 332public: 333 MultiTexShader (deUint32 randSeed, 334 int numUnits, 335 const vector<GLenum>& unitTypes, 336 const vector<glu::DataType>& samplerTypes, 337 const vector<Vec4>& texScales, 338 const vector<Vec4>& texBiases, 339 const vector<int>& num2dArrayLayers); // \note 2d array layer "coordinate" isn't normalized, so this is needed here. 340 341 void setUniforms (sglr::Context& context, deUint32 program) const; 342 void makeSafeLods (const vector<IVec3>& textureSizes, const IVec2& viewportSize); // Modifies texture coordinates so that LODs aren't too close to x.5 or 0.0 . 343 344private: 345 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const; 346 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const; 347 348 int m_numUnits; 349 vector<GLenum> m_unitTypes; // 2d, cube map, 2d array or 3d. 350 vector<Vec4> m_texScales; 351 vector<Vec4> m_texBiases; 352 vector<Mat4> m_transformations; 353 vector<tcu::Vector<tcu::Vec2, 3> > m_lodDerivateParts; // Parts of lod derivates; computed in init(), used in eval(). 354}; 355 356MultiTexShader::MultiTexShader (deUint32 randSeed, 357 int numUnits, 358 const vector<GLenum>& unitTypes, 359 const vector<glu::DataType>& samplerTypes, 360 const vector<Vec4>& texScales, 361 const vector<Vec4>& texBiases, 362 const vector<int>& num2dArrayLayers) 363 : sglr::ShaderProgram (generateShaderProgramDeclaration(numUnits, unitTypes, samplerTypes)) 364 , m_numUnits (numUnits) 365 , m_unitTypes (unitTypes) 366 , m_texScales (texScales) 367 , m_texBiases (texBiases) 368{ 369 // 2d-to-cube-face transformations. 370 // \note 2d coordinates range from 0 to 1 and cube face coordinates from -1 to 1, so scaling is done as well. 371 static const float s_cubeTransforms[][3*3] = 372 { 373 // Face -X: (x, y, 1) -> (-1, -(2*y-1), +(2*x-1)) 374 { 0.0f, 0.0f, -1.0f, 375 0.0f, -2.0f, 1.0f, 376 2.0f, 0.0f, -1.0f }, 377 // Face +X: (x, y, 1) -> (+1, -(2*y-1), -(2*x-1)) 378 { 0.0f, 0.0f, 1.0f, 379 0.0f, -2.0f, 1.0f, 380 -2.0f, 0.0f, 1.0f }, 381 // Face -Y: (x, y, 1) -> (+(2*x-1), -1, -(2*y-1)) 382 { 2.0f, 0.0f, -1.0f, 383 0.0f, 0.0f, -1.0f, 384 0.0f, -2.0f, 1.0f }, 385 // Face +Y: (x, y, 1) -> (+(2*x-1), +1, +(2*y-1)) 386 { 2.0f, 0.0f, -1.0f, 387 0.0f, 0.0f, 1.0f, 388 0.0f, 2.0f, -1.0f }, 389 // Face -Z: (x, y, 1) -> (-(2*x-1), -(2*y-1), -1) 390 { -2.0f, 0.0f, 1.0f, 391 0.0f, -2.0f, 1.0f, 392 0.0f, 0.0f, -1.0f }, 393 // Face +Z: (x, y, 1) -> (+(2*x-1), -(2*y-1), +1) 394 { 2.0f, 0.0f, -1.0f, 395 0.0f, -2.0f, 1.0f, 396 0.0f, 0.0f, 1.0f } 397 }; 398 399 // Generate transformation matrices. 400 401 de::Random rnd(randSeed); 402 403 m_transformations.reserve(m_numUnits); 404 m_lodDerivateParts.reserve(m_numUnits); 405 406 int tex2dArrayNdx = 0; // Keep track of 2d texture array index. 407 408 DE_ASSERT((int)m_unitTypes.size() == m_numUnits); 409 410 for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++) 411 { 412 if (m_unitTypes[unitNdx] == GL_TEXTURE_2D) 413 { 414 float rotAngle = rnd.getFloat(0.0f, 2.0f*DE_PI); 415 float xScaleFactor = rnd.getFloat(0.7f, 1.5f); 416 float yScaleFactor = rnd.getFloat(0.7f, 1.5f); 417 float xShearAmount = rnd.getFloat(0.0f, 0.5f); 418 float yShearAmount = rnd.getFloat(0.0f, 0.5f); 419 float xTranslationAmount = rnd.getFloat(-0.5f, 0.5f); 420 float yTranslationAmount = rnd.getFloat(-0.5f, 0.5f); 421 422 static const float tempOffsetData[3*3] = // For temporarily centering the coordinates to get nicer transformations. 423 { 424 1.0f, 0.0f, -0.5f, 425 0.0f, 1.0f, -0.5f, 426 0.0f, 0.0f, 1.0f 427 }; 428 float rotTransfData[3*3] = 429 { 430 deFloatCos(rotAngle), -deFloatSin(rotAngle), 0.0f, 431 deFloatSin(rotAngle), deFloatCos(rotAngle), 0.0f, 432 0.0f, 0.0f, 1.0f 433 }; 434 float scaleTransfData[3*3] = 435 { 436 xScaleFactor, 0.0f, 0.0f, 437 0.0f, yScaleFactor, 0.0f, 438 0.0f, 0.0f, 1.0f 439 }; 440 float xShearTransfData[3*3] = 441 { 442 1.0f, xShearAmount, 0.0f, 443 0.0f, 1.0f, 0.0f, 444 0.0f, 0.0f, 1.0f 445 }; 446 float yShearTransfData[3*3] = 447 { 448 1.0f, 0.0f, 0.0f, 449 yShearAmount, 1.0f, 0.0f, 450 0.0f, 0.0f, 1.0f 451 }; 452 float translationTransfData[3*3] = 453 { 454 1.0f, 0.0f, xTranslationAmount, 455 0.0f, 1.0f, yTranslationAmount, 456 0.0f, 0.0f, 1.0f 457 }; 458 459 Mat4 transformation = matExtend3To4(Mat3(tempOffsetData) * 460 Mat3(translationTransfData) * 461 Mat3(rotTransfData) * 462 Mat3(scaleTransfData) * 463 Mat3(xShearTransfData) * 464 Mat3(yShearTransfData) * 465 (Mat3(tempOffsetData) * (-1.0f))); 466 467 m_lodDerivateParts.push_back(calculateLodDerivateParts(transformation)); 468 m_transformations.push_back(transformation); 469 } 470 else if (m_unitTypes[unitNdx] == GL_TEXTURE_CUBE_MAP) 471 { 472 DE_STATIC_ASSERT((int)tcu::CUBEFACE_LAST == DE_LENGTH_OF_ARRAY(s_cubeTransforms)); 473 474 float planarTransData[3*3]; 475 476 // In case of a cube map, we only want to render one face, so the transformation needs to be restricted - only enlarging scaling is done. 477 478 for (int i = 0; i < DE_LENGTH_OF_ARRAY(planarTransData); i++) 479 { 480 if (i == 0 || i == 4) 481 planarTransData[i] = rnd.getFloat(0.1f, 0.9f); // Two first diagonal cells control the scaling. 482 else if (i == 8) 483 planarTransData[i] = 1.0f; 484 else 485 planarTransData[i] = 0.0f; 486 } 487 488 int faceNdx = rnd.getInt(0, (int)tcu::CUBEFACE_LAST - 1); 489 Mat3 planarTrans (planarTransData); // Planar, face-agnostic transformation. 490 Mat4 finalTrans = matExtend3To4(Mat3(s_cubeTransforms[faceNdx]) * planarTrans); // Final transformation from planar to cube map coordinates, including the transformation just generated. 491 Mat4 planarTrans4x4 = matExtend3To4(planarTrans); 492 493 m_lodDerivateParts.push_back(calculateLodDerivateParts(planarTrans4x4)); 494 m_transformations.push_back(finalTrans); 495 } 496 else 497 { 498 DE_ASSERT(m_unitTypes[unitNdx] == GL_TEXTURE_3D || m_unitTypes[unitNdx] == GL_TEXTURE_2D_ARRAY); 499 500 float transData[4*4]; 501 502 for (int i = 0; i < 4*4; i++) 503 { 504 float sign = rnd.getBool() ? 1.0f : -1.0f; 505 transData[i] = rnd.getFloat(0.7f, 1.4f) * sign; 506 } 507 508 Mat4 transformation(transData); 509 510 if (m_unitTypes[unitNdx] == GL_TEXTURE_2D_ARRAY) 511 { 512 // Z direction: Translate by 0.5 and scale by layer amount. 513 514 float numLayers = (float)num2dArrayLayers[tex2dArrayNdx]; 515 516 static const float zTranslationTransfData[4*4] = 517 { 518 1.0f, 0.0f, 0.0f, 0.0f, 519 0.0f, 1.0f, 0.0f, 0.0f, 520 0.0f, 0.0f, 1.0f, 0.5f, 521 0.0f, 0.0f, 0.0f, 1.0f 522 }; 523 524 float zScaleTransfData[4*4] = 525 { 526 1.0f, 0.0f, 0.0f, 0.0f, 527 0.0f, 1.0f, 0.0f, 0.0f, 528 0.0f, 0.0f, numLayers, 0.0f, 529 0.0f, 0.0f, 0.0f, 1.0f 530 }; 531 532 transformation = transformation * Mat4(zScaleTransfData) * Mat4(zTranslationTransfData); 533 534 tex2dArrayNdx++; 535 } 536 537 m_lodDerivateParts.push_back(calculateLodDerivateParts(transformation)); 538 m_transformations.push_back(Mat4(transformation)); 539 } 540 } 541} 542 543void MultiTexShader::setUniforms (sglr::Context& ctx, deUint32 program) const 544{ 545 ctx.useProgram(program); 546 547 // Sampler and matrix uniforms. 548 549 for (int ndx = 0; ndx < m_numUnits; ndx++) 550 { 551 string ndxStr = de::toString(ndx); 552 553 ctx.uniform1i(ctx.getUniformLocation(program, ("u_sampler" + ndxStr).c_str()), ndx); 554 ctx.uniformMatrix4fv(ctx.getUniformLocation(program, ("u_trans" + ndxStr).c_str()), 1, GL_FALSE, (GLfloat*)&m_transformations[ndx].getColumnMajorData()[0]); 555 ctx.uniform4fv(ctx.getUniformLocation(program, ("u_texScale" + ndxStr).c_str()), 1, m_texScales[ndx].getPtr()); 556 ctx.uniform4fv(ctx.getUniformLocation(program, ("u_texBias" + ndxStr).c_str()), 1, m_texBiases[ndx].getPtr()); 557 } 558} 559 560void MultiTexShader::makeSafeLods (const vector<IVec3>& textureSizes, const IVec2& viewportSize) 561{ 562 DE_ASSERT((int)textureSizes.size() == m_numUnits); 563 564 static const float shrinkScaleMat2dData[3*3] = 565 { 566 0.95f, 0.0f, 0.0f, 567 0.0f, 0.95f, 0.0f, 568 0.0f, 0.0f, 1.0f 569 }; 570 static const float shrinkScaleMat3dData[3*3] = 571 { 572 0.95f, 0.0f, 0.0f, 573 0.0f, 0.95f, 0.0f, 574 0.0f, 0.0f, 0.95f 575 }; 576 Mat4 shrinkScaleMat2d = matExtend3To4(Mat3(shrinkScaleMat2dData)); 577 Mat4 shrinkScaleMat3d = matExtend3To4(Mat3(shrinkScaleMat3dData)); 578 579 Vec2 screenDerivate(1.0f / (float)viewportSize.x(), 1.0f / (float)viewportSize.y()); 580 581 for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++) 582 { 583 // As long as LOD is too close to 0.0 or is positive and too close to a something-and-a-half (0.5, 1.5, 2.5 etc) or allowed lod range could round to different levels, zoom in a little to get a safer LOD. 584 for (;;) 585 { 586 const float threshold = 0.1f; 587 const float epsilon = 0.01f; 588 589 const float lodMax = calculateLodMax(m_lodDerivateParts[unitNdx], textureSizes[unitNdx], screenDerivate); 590 const float lodMin = calculateLodMin(m_lodDerivateParts[unitNdx], textureSizes[unitNdx], screenDerivate); 591 592 const deInt32 maxLevel = (lodMax + epsilon < 0.5f) ? (0) : (deCeilFloatToInt32(lodMax + epsilon + 0.5f) - 1); 593 const deInt32 minLevel = (lodMin - epsilon < 0.5f) ? (0) : (deCeilFloatToInt32(lodMin - epsilon + 0.5f) - 1); 594 595 if (de::abs(lodMax) < threshold || (lodMax > 0.0f && de::abs(deFloatFrac(lodMax) - 0.5f) < threshold) || 596 de::abs(lodMin) < threshold || (lodMin > 0.0f && de::abs(deFloatFrac(lodMin) - 0.5f) < threshold) || 597 maxLevel != minLevel) 598 { 599 m_transformations[unitNdx] = (m_unitTypes[unitNdx] == GL_TEXTURE_3D ? shrinkScaleMat3d : shrinkScaleMat2d) * m_transformations[unitNdx]; 600 m_lodDerivateParts[unitNdx] = calculateLodDerivateParts(m_transformations[unitNdx]); 601 } 602 else 603 break; 604 } 605 } 606} 607 608void MultiTexShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 609{ 610 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 611 { 612 rr::VertexPacket& packet = *(packets[packetNdx]); 613 614 packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx); 615 packet.outputs[0] = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx); 616 } 617} 618 619void MultiTexShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 620{ 621 DE_ASSERT((int)m_unitTypes.size() == m_numUnits); 622 DE_ASSERT((int)m_transformations.size() == m_numUnits); 623 DE_ASSERT((int)m_lodDerivateParts.size() == m_numUnits); 624 625 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 626 { 627 rr::FragmentPacket& packet = packets[packetNdx]; 628 const float colorMultiplier = 1.0f / (float)m_numUnits; 629 Vec4 outColors[4] = { Vec4(0.0f), Vec4(0.0f), Vec4(0.0f), Vec4(0.0f) }; 630 631 for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++) 632 { 633 tcu::Vec4 texSamples[4]; 634 635 // Read tex coords 636 const tcu::Vec2 texCoords[4] = 637 { 638 rr::readTriangleVarying<float>(packet, context, 0, 0).xy(), 639 rr::readTriangleVarying<float>(packet, context, 0, 1).xy(), 640 rr::readTriangleVarying<float>(packet, context, 0, 2).xy(), 641 rr::readTriangleVarying<float>(packet, context, 0, 3).xy(), 642 }; 643 644 // Transform 645 tcu::Vec3 coords3D[4] = 646 { 647 (m_transformations[unitNdx] * Vec4(texCoords[0].x(), texCoords[0].y(), 1.0f, 1.0f)).xyz(), 648 (m_transformations[unitNdx] * Vec4(texCoords[1].x(), texCoords[1].y(), 1.0f, 1.0f)).xyz(), 649 (m_transformations[unitNdx] * Vec4(texCoords[2].x(), texCoords[2].y(), 1.0f, 1.0f)).xyz(), 650 (m_transformations[unitNdx] * Vec4(texCoords[3].x(), texCoords[3].y(), 1.0f, 1.0f)).xyz(), 651 }; 652 653 // To 2D 654 const tcu::Vec2 coords2D[4] = 655 { 656 coords3D[0].xy(), 657 coords3D[1].xy(), 658 coords3D[2].xy(), 659 coords3D[3].xy(), 660 }; 661 662 // Sample 663 switch (m_unitTypes[unitNdx]) 664 { 665 case GL_TEXTURE_2D: m_uniforms[4*unitNdx].sampler.tex2D->sample4(texSamples, coords2D); break; 666 case GL_TEXTURE_CUBE_MAP: m_uniforms[4*unitNdx].sampler.texCube->sample4(texSamples, coords3D); break; 667 case GL_TEXTURE_2D_ARRAY: m_uniforms[4*unitNdx].sampler.tex2DArray->sample4(texSamples, coords3D); break; 668 case GL_TEXTURE_3D: m_uniforms[4*unitNdx].sampler.tex3D->sample4(texSamples, coords3D); break; 669 default: 670 DE_ASSERT(DE_FALSE); 671 } 672 673 // Add to sum 674 for (int fragNdx = 0; fragNdx < 4; ++fragNdx) 675 outColors[fragNdx] += colorMultiplier * (texSamples[fragNdx]*m_texScales[unitNdx] + m_texBiases[unitNdx]); 676 } 677 678 // output 679 for (int fragNdx = 0; fragNdx < 4; ++fragNdx) 680 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, outColors[fragNdx]); 681 } 682} 683 684class TextureUnitCase : public TestCase 685{ 686public: 687 enum CaseType 688 { 689 CASE_ONLY_2D = 0, 690 CASE_ONLY_CUBE, 691 CASE_ONLY_2D_ARRAY, 692 CASE_ONLY_3D, 693 CASE_MIXED, 694 695 CASE_LAST 696 }; 697 TextureUnitCase (Context& context, const char* name, const char* desc, int numUnits /* \note If non-positive, use all units */, CaseType caseType, deUint32 randSeed); 698 ~TextureUnitCase (void); 699 700 void init (void); 701 void deinit (void); 702 IterateResult iterate (void); 703 704private: 705 struct TextureParameters 706 { 707 GLenum internalFormat; 708 GLenum wrapModeS; 709 GLenum wrapModeT; 710 GLenum wrapModeR; 711 GLenum minFilter; 712 GLenum magFilter; 713 }; 714 715 TextureUnitCase (const TextureUnitCase& other); 716 TextureUnitCase& operator= (const TextureUnitCase& other); 717 718 void upload2dTexture (int texNdx, sglr::Context& context); 719 void uploadCubeTexture (int texNdx, sglr::Context& context); 720 void upload2dArrayTexture (int texNdx, sglr::Context& context); 721 void upload3dTexture (int texNdx, sglr::Context& context); 722 723 void render (sglr::Context& context); 724 725 const int m_numUnitsParam; 726 const CaseType m_caseType; 727 const deUint32 m_randSeed; 728 729 int m_numTextures; //!< \note Needed in addition to m_numUnits since same texture may be bound to many texture units. 730 int m_numUnits; //!< = m_numUnitsParam > 0 ? m_numUnitsParam : implementationDefinedMaximum 731 732 vector<GLenum> m_textureTypes; 733 vector<TextureParameters> m_textureParams; 734 vector<tcu::Texture2D*> m_textures2d; 735 vector<tcu::TextureCube*> m_texturesCube; 736 vector<tcu::Texture2DArray*> m_textures2dArray; 737 vector<tcu::Texture3D*> m_textures3d; 738 vector<int> m_unitTextures; //!< Which texture is used in a particular unit. 739 vector<int> m_ndxTexType; //!< Index of a texture in m_textures2d, m_texturesCube, m_textures2dArray or m_textures3d, depending on texture type. 740 MultiTexShader* m_shader; 741}; 742 743TextureUnitCase::TextureUnitCase (Context& context, const char* name, const char* desc, int numUnits, CaseType caseType, deUint32 randSeed) 744 : TestCase (context, tcu::NODETYPE_SELF_VALIDATE, name, desc) 745 , m_numUnitsParam (numUnits) 746 , m_caseType (caseType) 747 , m_randSeed (randSeed) 748 , m_shader (DE_NULL) 749{ 750} 751 752TextureUnitCase::~TextureUnitCase (void) 753{ 754 TextureUnitCase::deinit(); 755} 756 757void TextureUnitCase::deinit (void) 758{ 759 for (vector<tcu::Texture2D*>::iterator i = m_textures2d.begin(); i != m_textures2d.end(); i++) 760 delete *i; 761 m_textures2d.clear(); 762 763 for (vector<tcu::TextureCube*>::iterator i = m_texturesCube.begin(); i != m_texturesCube.end(); i++) 764 delete *i; 765 m_texturesCube.clear(); 766 767 for (vector<tcu::Texture2DArray*>::iterator i = m_textures2dArray.begin(); i != m_textures2dArray.end(); i++) 768 delete *i; 769 m_textures2dArray.clear(); 770 771 for (vector<tcu::Texture3D*>::iterator i = m_textures3d.begin(); i != m_textures3d.end(); i++) 772 delete *i; 773 m_textures3d.clear(); 774 775 delete m_shader; 776 m_shader = DE_NULL; 777} 778 779void TextureUnitCase::init (void) 780{ 781 m_numUnits = m_numUnitsParam > 0 ? m_numUnitsParam : m_context.getContextInfo().getInt(GL_MAX_TEXTURE_IMAGE_UNITS); 782 783 // Make the textures. 784 785 try 786 { 787 tcu::TestLog& log = m_testCtx.getLog(); 788 de::Random rnd (m_randSeed); 789 790 if (rnd.getFloat() < 0.7f) 791 m_numTextures = m_numUnits; // In most cases use one unit per texture. 792 else 793 m_numTextures = rnd.getInt(deMax32(1, m_numUnits - 2), m_numUnits); // Sometimes assign same texture to multiple units. 794 795 log << tcu::TestLog::Message << ("Using " + de::toString(m_numUnits) + " texture unit(s) and " + de::toString(m_numTextures) + " texture(s)").c_str() << tcu::TestLog::EndMessage; 796 797 m_textureTypes.reserve(m_numTextures); 798 m_textureParams.reserve(m_numTextures); 799 m_ndxTexType.reserve(m_numTextures); 800 801 // Generate textures. 802 803 for (int texNdx = 0; texNdx < m_numTextures; texNdx++) 804 { 805 // Either fixed or randomized target types, and randomized parameters for every texture. 806 807 TextureParameters params; 808 809 DE_STATIC_ASSERT(CASE_ONLY_2D == 0 && CASE_MIXED + 1 == CASE_LAST); 810 811 int texType = m_caseType == CASE_MIXED ? rnd.getInt(0, (int)CASE_MIXED - 1) : (int)m_caseType; 812 bool is2dTex = texType == 0; 813 bool isCubeTex = texType == 1; 814 bool is2dArrayTex = texType == 2; 815 bool is3dTex = texType == 3; 816 817 DE_ASSERT(is2dTex || isCubeTex || is2dArrayTex || is3dTex); 818 819 GLenum type = is2dTex ? GL_TEXTURE_2D : isCubeTex ? GL_TEXTURE_CUBE_MAP : is2dArrayTex ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_3D; 820 const int texWidth = is2dTex ? TEXTURE_WIDTH_2D : isCubeTex ? TEXTURE_WIDTH_CUBE : is2dArrayTex ? TEXTURE_WIDTH_2D_ARRAY : TEXTURE_WIDTH_3D; 821 const int texHeight = is2dTex ? TEXTURE_HEIGHT_2D : isCubeTex ? TEXTURE_HEIGHT_CUBE : is2dArrayTex ? TEXTURE_HEIGHT_2D_ARRAY : TEXTURE_HEIGHT_3D; 822 823 const int texDepth = is3dTex ? TEXTURE_DEPTH_3D : 1; 824 const int texLayers = is2dArrayTex ? TEXTURE_LAYERS_2D_ARRAY : 1; 825 826 bool mipmaps = (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight) && deIsPowerOfTwo32(texDepth)); 827 int numLevels = mipmaps ? deLog2Floor32(de::max(de::max(texWidth, texHeight), texDepth))+1 : 1; 828 829 params.internalFormat = s_testSizedInternalFormats[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testSizedInternalFormats) - 1)]; 830 831 bool isFilterable = glu::isGLInternalColorFormatFilterable(params.internalFormat); 832 833 params.wrapModeS = s_testWrapModes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testWrapModes) - 1)]; 834 params.wrapModeT = s_testWrapModes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testWrapModes) - 1)]; 835 params.wrapModeR = s_testWrapModes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testWrapModes) - 1)]; 836 837 params.magFilter = isFilterable ? s_testMagFilters[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testMagFilters) - 1)] : GL_NEAREST; 838 839 if (mipmaps) 840 params.minFilter = isFilterable ? 841 s_testMinFilters [rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testMinFilters) - 1)] : 842 s_testNearestMinFilters [rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testNearestMinFilters) - 1)]; 843 else 844 params.minFilter = isFilterable ? 845 s_testNonMipmapMinFilters [rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testNonMipmapMinFilters) - 1)] : 846 GL_NEAREST; 847 848 m_textureTypes.push_back(type); 849 m_textureParams.push_back(params); 850 851 // Create new texture. 852 853 tcu::TextureFormat texFormat = glu::mapGLInternalFormat((deUint32)params.internalFormat); 854 855 if (is2dTex) 856 { 857 m_ndxTexType.push_back((int)m_textures2d.size()); // Remember the index this texture has in the 2d texture vector. 858 m_textures2d.push_back(new tcu::Texture2D(texFormat, texWidth, texHeight)); 859 } 860 else if (isCubeTex) 861 { 862 m_ndxTexType.push_back((int)m_texturesCube.size()); // Remember the index this texture has in the cube texture vector. 863 DE_ASSERT(texWidth == texHeight); 864 m_texturesCube.push_back(new tcu::TextureCube(texFormat, texWidth)); 865 } 866 else if (is2dArrayTex) 867 { 868 m_ndxTexType.push_back((int)m_textures2dArray.size()); // Remember the index this texture has in the 2d array texture vector. 869 m_textures2dArray.push_back(new tcu::Texture2DArray(texFormat, texWidth, texHeight, texLayers)); 870 } 871 else 872 { 873 m_ndxTexType.push_back((int)m_textures3d.size()); // Remember the index this texture has in the 3d vector. 874 m_textures3d.push_back(new tcu::Texture3D(texFormat, texWidth, texHeight, texDepth)); 875 } 876 877 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFormat); 878 Vec4 cBias = fmtInfo.valueMin; 879 Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 880 881 // Fill with grid texture. 882 883 int numFaces = isCubeTex ? (int)tcu::CUBEFACE_LAST : 1; 884 885 for (int face = 0; face < numFaces; face++) 886 { 887 deUint32 rgb = rnd.getUint32() & 0x00ffffff; 888 deUint32 alpha = 0xff000000; 889 890 deUint32 colorA = alpha | rgb; 891 deUint32 colorB = alpha | ((~rgb) & 0x00ffffff); 892 893 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 894 { 895 if (is2dTex) 896 m_textures2d.back()->allocLevel(levelNdx); 897 else if (isCubeTex) 898 m_texturesCube.back()->allocLevel((tcu::CubeFace)face, levelNdx); 899 else if (is2dArrayTex) 900 m_textures2dArray.back()->allocLevel(levelNdx); 901 else 902 m_textures3d.back()->allocLevel(levelNdx); 903 904 int curCellSize = deMax32(1, GRID_CELL_SIZE >> levelNdx); // \note Scale grid cell size for mipmaps. 905 906 tcu::PixelBufferAccess access = is2dTex ? m_textures2d.back()->getLevel(levelNdx) 907 : isCubeTex ? m_texturesCube.back()->getLevelFace(levelNdx, (tcu::CubeFace)face) 908 : is2dArrayTex ? m_textures2dArray.back()->getLevel(levelNdx) 909 : m_textures3d.back()->getLevel(levelNdx); 910 911 tcu::fillWithGrid(access, curCellSize, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 912 } 913 } 914 } 915 916 // Assign a texture index to each unit. 917 918 m_unitTextures.reserve(m_numUnits); 919 920 // \note Every texture is used at least once. 921 for (int i = 0; i < m_numTextures; i++) 922 m_unitTextures.push_back(i); 923 924 // Assign a random texture to remaining units. 925 while ((int)m_unitTextures.size() < m_numUnits) 926 m_unitTextures.push_back(rnd.getInt(0, m_numTextures - 1)); 927 928 rnd.shuffle(m_unitTextures.begin(), m_unitTextures.end()); 929 930 // Generate information for shader. 931 932 vector<GLenum> unitTypes; 933 vector<Vec4> texScales; 934 vector<Vec4> texBiases; 935 vector<glu::DataType> samplerTypes; 936 vector<int> num2dArrayLayers; 937 938 unitTypes.reserve(m_numUnits); 939 texScales.reserve(m_numUnits); 940 texBiases.reserve(m_numUnits); 941 samplerTypes.reserve(m_numUnits); 942 num2dArrayLayers.reserve(m_numUnits); 943 944 for (int i = 0; i < m_numUnits; i++) 945 { 946 int texNdx = m_unitTextures[i]; 947 GLenum type = m_textureTypes[texNdx]; 948 tcu::TextureFormat fmt = glu::mapGLInternalFormat(m_textureParams[texNdx].internalFormat); 949 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(fmt); 950 951 unitTypes.push_back(type); 952 953 if (type == GL_TEXTURE_2D_ARRAY) 954 num2dArrayLayers.push_back(m_textures2dArray[m_ndxTexType[texNdx]]->getNumLayers()); 955 956 texScales.push_back(fmtInfo.lookupScale); 957 texBiases.push_back(fmtInfo.lookupBias); 958 959 switch (type) 960 { 961 case GL_TEXTURE_2D: samplerTypes.push_back(glu::getSampler2DType(fmt)); break; 962 case GL_TEXTURE_CUBE_MAP: samplerTypes.push_back(glu::getSamplerCubeType(fmt)); break; 963 case GL_TEXTURE_2D_ARRAY: samplerTypes.push_back(glu::getSampler2DArrayType(fmt)); break; 964 case GL_TEXTURE_3D: samplerTypes.push_back(glu::getSampler3DType(fmt)); break; 965 default: 966 DE_ASSERT(DE_FALSE); 967 } 968 } 969 970 // Create shader. 971 972 DE_ASSERT(m_shader == DE_NULL); 973 m_shader = new MultiTexShader(rnd.getUint32(), m_numUnits, unitTypes, samplerTypes, texScales, texBiases, num2dArrayLayers); 974 } 975 catch (const std::exception&) 976 { 977 // Clean up to save memory. 978 TextureUnitCase::deinit(); 979 throw; 980 } 981} 982 983TextureUnitCase::IterateResult TextureUnitCase::iterate (void) 984{ 985 glu::RenderContext& renderCtx = m_context.getRenderContext(); 986 const tcu::RenderTarget& renderTarget = renderCtx.getRenderTarget(); 987 tcu::TestLog& log = m_testCtx.getLog(); 988 de::Random rnd (m_randSeed); 989 990 int viewportWidth = deMin32(VIEWPORT_WIDTH, renderTarget.getWidth()); 991 int viewportHeight = deMin32(VIEWPORT_HEIGHT, renderTarget.getHeight()); 992 int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportWidth); 993 int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportHeight); 994 995 tcu::Surface gles3Frame (viewportWidth, viewportHeight); 996 tcu::Surface refFrame (viewportWidth, viewportHeight); 997 998 { 999 // First we do some tricks to make the LODs safer wrt. precision issues. See MultiTexShader::makeSafeLods(). 1000 1001 vector<IVec3> texSizes; 1002 texSizes.reserve(m_numUnits); 1003 1004 for (int i = 0; i < m_numUnits; i++) 1005 { 1006 int texNdx = m_unitTextures[i]; 1007 int texNdxInType = m_ndxTexType[texNdx]; 1008 GLenum type = m_textureTypes[texNdx]; 1009 1010 switch (type) 1011 { 1012 case GL_TEXTURE_2D: texSizes.push_back(IVec3(m_textures2d[texNdxInType]->getWidth(), m_textures2d[texNdxInType]->getHeight(), 0)); break; 1013 case GL_TEXTURE_CUBE_MAP: texSizes.push_back(IVec3(m_texturesCube[texNdxInType]->getSize(), m_texturesCube[texNdxInType]->getSize(), 0)); break; 1014 case GL_TEXTURE_2D_ARRAY: texSizes.push_back(IVec3(m_textures2dArray[texNdxInType]->getWidth(), m_textures2dArray[texNdxInType]->getHeight(), 0)); break; 1015 case GL_TEXTURE_3D: texSizes.push_back(IVec3(m_textures3d[texNdxInType]->getWidth(), m_textures3d[texNdxInType]->getHeight(), m_textures3d[texNdxInType]->getDepth())); break; 1016 default: 1017 DE_ASSERT(DE_FALSE); 1018 } 1019 } 1020 1021 m_shader->makeSafeLods(texSizes, IVec2(viewportWidth, viewportHeight)); 1022 } 1023 1024 // Render using GLES3. 1025 { 1026 sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS|sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(viewportX, viewportY, viewportWidth, viewportHeight)); 1027 1028 render(context); 1029 1030 context.readPixels(gles3Frame, 0, 0, viewportWidth, viewportHeight); 1031 } 1032 1033 // Render reference image. 1034 { 1035 sglr::ReferenceContextBuffers buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), 0 /* depth */, 0 /* stencil */, viewportWidth, viewportHeight); 1036 sglr::ReferenceContext context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); 1037 1038 render(context); 1039 1040 context.readPixels(refFrame, 0, 0, viewportWidth, viewportHeight); 1041 } 1042 1043 // Compare images. 1044 const float threshold = 0.001f; 1045 bool isOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, gles3Frame, threshold, tcu::COMPARE_LOG_RESULT); 1046 1047 // Store test result. 1048 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1049 isOk ? "Pass" : "Image comparison failed"); 1050 1051 return STOP; 1052} 1053 1054void TextureUnitCase::upload2dTexture (int texNdx, sglr::Context& context) 1055{ 1056 int ndx2d = m_ndxTexType[texNdx]; 1057 const tcu::Texture2D* texture = m_textures2d[ndx2d]; 1058 glu::TransferFormat formatGl = glu::getTransferFormat(glu::mapGLInternalFormat(m_textureParams[texNdx].internalFormat)); 1059 1060 context.pixelStorei(GL_UNPACK_ALIGNMENT, 1); 1061 1062 for (int levelNdx = 0; levelNdx < texture->getNumLevels(); levelNdx++) 1063 { 1064 if (texture->isLevelEmpty(levelNdx)) 1065 continue; 1066 1067 tcu::ConstPixelBufferAccess access = texture->getLevel(levelNdx); 1068 int width = access.getWidth(); 1069 int height = access.getHeight(); 1070 1071 DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*width); 1072 1073 context.texImage2D(GL_TEXTURE_2D, levelNdx, m_textureParams[texNdx].internalFormat, width, height, 0 /* border */, formatGl.format, formatGl.dataType, access.getDataPtr()); 1074 GLU_EXPECT_NO_ERROR(context.getError(), "Set 2d texture image data"); 1075 } 1076} 1077 1078void TextureUnitCase::uploadCubeTexture (int texNdx, sglr::Context& context) 1079{ 1080 int ndxCube = m_ndxTexType[texNdx]; 1081 const tcu::TextureCube* texture = m_texturesCube[ndxCube]; 1082 glu::TransferFormat formatGl = glu::getTransferFormat(glu::mapGLInternalFormat(m_textureParams[texNdx].internalFormat)); 1083 1084 context.pixelStorei(GL_UNPACK_ALIGNMENT, 1); 1085 1086 for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++) 1087 { 1088 for (int levelNdx = 0; levelNdx < texture->getNumLevels(); levelNdx++) 1089 { 1090 if (texture->isLevelEmpty((tcu::CubeFace)face, levelNdx)) 1091 continue; 1092 1093 tcu::ConstPixelBufferAccess access = texture->getLevelFace(levelNdx, (tcu::CubeFace)face); 1094 int width = access.getWidth(); 1095 int height = access.getHeight(); 1096 1097 DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*width); 1098 1099 context.texImage2D(s_cubeFaceTargets[face], levelNdx, m_textureParams[texNdx].internalFormat, width, height, 0 /* border */, formatGl.format, formatGl.dataType, access.getDataPtr()); 1100 GLU_EXPECT_NO_ERROR(context.getError(), "Set cube map image data"); 1101 } 1102 } 1103} 1104 1105void TextureUnitCase::upload2dArrayTexture (int texNdx, sglr::Context& context) 1106{ 1107 int ndx2dArray = m_ndxTexType[texNdx]; 1108 const tcu::Texture2DArray* texture = m_textures2dArray[ndx2dArray]; 1109 glu::TransferFormat formatGl = glu::getTransferFormat(glu::mapGLInternalFormat(m_textureParams[texNdx].internalFormat)); 1110 1111 context.pixelStorei(GL_UNPACK_ALIGNMENT, 1); 1112 1113 for (int levelNdx = 0; levelNdx < texture->getNumLevels(); levelNdx++) 1114 { 1115 if (texture->isLevelEmpty(levelNdx)) 1116 continue; 1117 1118 tcu::ConstPixelBufferAccess access = texture->getLevel(levelNdx); 1119 int width = access.getWidth(); 1120 int height = access.getHeight(); 1121 int layers = access.getDepth(); 1122 1123 DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*width); 1124 DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize()*width*height); 1125 1126 context.texImage3D(GL_TEXTURE_2D_ARRAY, levelNdx, m_textureParams[texNdx].internalFormat, width, height, layers, 0 /* border */, formatGl.format, formatGl.dataType, access.getDataPtr()); 1127 GLU_EXPECT_NO_ERROR(context.getError(), "Set 2d array texture image data"); 1128 } 1129} 1130 1131void TextureUnitCase::upload3dTexture (int texNdx, sglr::Context& context) 1132{ 1133 int ndx3d = m_ndxTexType[texNdx]; 1134 const tcu::Texture3D* texture = m_textures3d[ndx3d]; 1135 glu::TransferFormat formatGl = glu::getTransferFormat(glu::mapGLInternalFormat(m_textureParams[texNdx].internalFormat)); 1136 1137 context.pixelStorei(GL_UNPACK_ALIGNMENT, 1); 1138 1139 for (int levelNdx = 0; levelNdx < texture->getNumLevels(); levelNdx++) 1140 { 1141 if (texture->isLevelEmpty(levelNdx)) 1142 continue; 1143 1144 tcu::ConstPixelBufferAccess access = texture->getLevel(levelNdx); 1145 int width = access.getWidth(); 1146 int height = access.getHeight(); 1147 int depth = access.getDepth(); 1148 1149 DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*width); 1150 DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize()*width*height); 1151 1152 context.texImage3D(GL_TEXTURE_3D, levelNdx, m_textureParams[texNdx].internalFormat, width, height, depth, 0 /* border */, formatGl.format, formatGl.dataType, access.getDataPtr()); 1153 GLU_EXPECT_NO_ERROR(context.getError(), "Set 3d texture image data"); 1154 } 1155} 1156 1157void TextureUnitCase::render (sglr::Context& context) 1158{ 1159 // Setup textures. 1160 1161 vector<deUint32> textureGLNames; 1162 vector<bool> isTextureSetUp(m_numTextures, false); // \note Same texture may be bound to multiple units, but we only want to set up parameters and data once per texture. 1163 1164 textureGLNames.resize(m_numTextures); 1165 context.genTextures(m_numTextures, &textureGLNames[0]); 1166 GLU_EXPECT_NO_ERROR(context.getError(), "Generate textures"); 1167 1168 for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++) 1169 { 1170 int texNdx = m_unitTextures[unitNdx]; 1171 1172 // Bind texture to unit. 1173 context.activeTexture(GL_TEXTURE0 + unitNdx); 1174 GLU_EXPECT_NO_ERROR(context.getError(), "Set active texture"); 1175 context.bindTexture(m_textureTypes[texNdx], textureGLNames[texNdx]); 1176 GLU_EXPECT_NO_ERROR(context.getError(), "Bind texture"); 1177 1178 if (!isTextureSetUp[texNdx]) 1179 { 1180 // Binding this texture for first time, so set parameters and data. 1181 1182 context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_WRAP_S, m_textureParams[texNdx].wrapModeS); 1183 context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_WRAP_T, m_textureParams[texNdx].wrapModeT); 1184 if (m_textureTypes[texNdx] == GL_TEXTURE_3D) 1185 context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_WRAP_R, m_textureParams[texNdx].wrapModeR); 1186 context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_MIN_FILTER, m_textureParams[texNdx].minFilter); 1187 context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_MAG_FILTER, m_textureParams[texNdx].magFilter); 1188 GLU_EXPECT_NO_ERROR(context.getError(), "Set texture parameters"); 1189 1190 switch (m_textureTypes[texNdx]) 1191 { 1192 case GL_TEXTURE_2D: upload2dTexture(texNdx, context); break; 1193 case GL_TEXTURE_CUBE_MAP: uploadCubeTexture(texNdx, context); break; 1194 case GL_TEXTURE_2D_ARRAY: upload2dArrayTexture(texNdx, context); break; 1195 case GL_TEXTURE_3D: upload3dTexture(texNdx, context); break; 1196 default: 1197 DE_ASSERT(DE_FALSE); 1198 } 1199 1200 isTextureSetUp[texNdx] = true; // Don't set up this texture's parameters and data again later. 1201 } 1202 } 1203 1204 GLU_EXPECT_NO_ERROR(context.getError(), "Set textures"); 1205 1206 // Setup shader 1207 1208 deUint32 shaderID = context.createProgram(m_shader); 1209 1210 // Draw. 1211 1212 context.clearColor(0.125f, 0.25f, 0.5f, 1.0f); 1213 context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 1214 m_shader->setUniforms(context, shaderID); 1215 sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); 1216 GLU_EXPECT_NO_ERROR(context.getError(), "Draw"); 1217 1218 // Delete previously generated texture names. 1219 1220 context.deleteTextures(m_numTextures, &textureGLNames[0]); 1221 GLU_EXPECT_NO_ERROR(context.getError(), "Delete textures"); 1222} 1223 1224TextureUnitTests::TextureUnitTests (Context& context) 1225 : TestCaseGroup(context, "units", "Texture Unit Usage Tests") 1226{ 1227} 1228 1229TextureUnitTests::~TextureUnitTests (void) 1230{ 1231} 1232 1233void TextureUnitTests::init (void) 1234{ 1235 const int numTestsPerGroup = 10; 1236 1237 static const int unitCounts[] = 1238 { 1239 2, 1240 4, 1241 8, 1242 -1 // \note Negative stands for the implementation-specified maximum. 1243 }; 1244 1245 for (int unitCountNdx = 0; unitCountNdx < DE_LENGTH_OF_ARRAY(unitCounts); unitCountNdx++) 1246 { 1247 int numUnits = unitCounts[unitCountNdx]; 1248 1249 string countGroupName = (unitCounts[unitCountNdx] < 0 ? "all" : de::toString(numUnits)) + "_units"; 1250 1251 tcu::TestCaseGroup* countGroup = new tcu::TestCaseGroup(m_testCtx, countGroupName.c_str(), ""); 1252 addChild(countGroup); 1253 1254 DE_STATIC_ASSERT((int)TextureUnitCase::CASE_ONLY_2D == 0); 1255 1256 for (int caseType = (int)TextureUnitCase::CASE_ONLY_2D; caseType < (int)TextureUnitCase::CASE_LAST; caseType++) 1257 { 1258 const char* caseTypeGroupName = (TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_ONLY_2D ? "only_2d" 1259 : (TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_ONLY_CUBE ? "only_cube" 1260 : (TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_ONLY_2D_ARRAY ? "only_2d_array" 1261 : (TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_ONLY_3D ? "only_3d" 1262 : (TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_MIXED ? "mixed" 1263 : DE_NULL; 1264 1265 DE_ASSERT(caseTypeGroupName != DE_NULL); 1266 1267 tcu::TestCaseGroup* caseTypeGroup = new tcu::TestCaseGroup(m_testCtx, caseTypeGroupName, ""); 1268 countGroup->addChild(caseTypeGroup); 1269 1270 for (int testNdx = 0; testNdx < numTestsPerGroup; testNdx++) 1271 caseTypeGroup->addChild(new TextureUnitCase(m_context, de::toString(testNdx).c_str(), "", numUnits, (TextureUnitCase::CaseType)caseType, deUint32Hash((deUint32)testNdx))); 1272 } 1273 } 1274} 1275 1276} // Functional 1277} // gles3 1278} // deqp 1279