1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.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 Vertex texture tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2fVertexTextureTests.hpp" 25 #include "glsTextureTestUtil.hpp" 26 #include "gluTexture.hpp" 27 #include "gluPixelTransfer.hpp" 28 #include "gluTextureUtil.hpp" 29 #include "tcuVector.hpp" 30 #include "tcuMatrix.hpp" 31 #include "tcuTextureUtil.hpp" 32 #include "tcuImageCompare.hpp" 33 #include "deRandom.hpp" 34 #include "deString.h" 35 36 #include <string> 37 #include <vector> 38 39 #include <limits> 40 41 #include "glw.h" 42 43 using tcu::TestLog; 44 using tcu::Vec2; 45 using tcu::Vec3; 46 using tcu::Vec4; 47 using tcu::IVec2; 48 using tcu::IVec3; 49 using tcu::IVec4; 50 using tcu::Mat3; 51 using std::string; 52 using std::vector; 53 54 namespace deqp 55 { 56 57 using namespace gls::TextureTestUtil; 58 59 using gls::TextureTestUtil::TEXTURETYPE_2D; 60 using gls::TextureTestUtil::TEXTURETYPE_CUBE; 61 62 namespace gles2 63 { 64 namespace Functional 65 { 66 67 // The 2D case draws four images. 68 static const int MAX_2D_RENDER_WIDTH = 128*2; 69 static const int MAX_2D_RENDER_HEIGHT = 128*2; 70 71 // The cube map case draws four 3-by-2 image groups. 72 static const int MAX_CUBE_RENDER_WIDTH = 28*2*3; 73 static const int MAX_CUBE_RENDER_HEIGHT = 28*2*2; 74 75 static const int GRID_SIZE_2D = 127; 76 static const int GRID_SIZE_CUBE = 63; 77 78 // Helpers for making texture coordinates "safe", i.e. move them further from coordinate bounary. 79 80 // Moves x towards the closest K+targetFraction, where K is an integer. 81 // E.g. moveTowardsFraction(x, 0.5f) moves x away from integer boundaries. 82 static inline float moveTowardsFraction (float x, float targetFraction) 83 { 84 const float strictness = 0.5f; 85 DE_ASSERT(0.0f < strictness && strictness <= 1.0f); 86 DE_ASSERT(de::inBounds(targetFraction, 0.0f, 1.0f)); 87 const float y = x + 0.5f - targetFraction; 88 return deFloatFloor(y) + deFloatFrac(y)*(1.0f-strictness) + strictness*0.5f - 0.5f + targetFraction; 89 } 90 91 static inline float safeCoord (float raw, int scale, float fraction) 92 { 93 const float scaleFloat = (float)scale; 94 return moveTowardsFraction(raw*scaleFloat, fraction) / scaleFloat; 95 } 96 97 template <int Size> 98 static inline tcu::Vector<float, Size> safeCoords (const tcu::Vector<float, Size>& raw, const tcu::Vector<int, Size>& scale, const tcu::Vector<float, Size>& fraction) 99 { 100 tcu::Vector<float, Size> result; 101 for (int i = 0; i < Size; i++) 102 result[i] = safeCoord(raw[i], scale[i], fraction[i]); 103 return result; 104 } 105 106 static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize) 107 { 108 return safeCoords(raw, textureSize, Vec2(0.5f)); 109 } 110 111 namespace 112 { 113 114 struct Rect 115 { 116 Rect (int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {} 117 IVec2 pos (void) const { return IVec2(x, y); } 118 IVec2 size (void) const { return IVec2(w, h); } 119 120 int x; 121 int y; 122 int w; 123 int h; 124 }; 125 126 template <TextureType> struct TexTypeTcuClass; 127 template <> struct TexTypeTcuClass<TEXTURETYPE_2D> { typedef tcu::Texture2D t; }; 128 template <> struct TexTypeTcuClass<TEXTURETYPE_CUBE> { typedef tcu::TextureCube t; }; 129 130 template <TextureType> struct TexTypeSizeDims; 131 template <> struct TexTypeSizeDims<TEXTURETYPE_2D> { enum { V = 2 }; }; 132 template <> struct TexTypeSizeDims<TEXTURETYPE_CUBE> { enum { V = 2 }; }; 133 134 template <TextureType> struct TexTypeCoordDims; 135 template <> struct TexTypeCoordDims<TEXTURETYPE_2D> { enum { V = 2 }; }; 136 template <> struct TexTypeCoordDims<TEXTURETYPE_CUBE> { enum { V = 3 }; }; 137 138 template <TextureType TexType> struct TexTypeSizeIVec { typedef tcu::Vector<int, TexTypeSizeDims<TexType>::V> t; }; 139 template <TextureType TexType> struct TexTypeCoordVec { typedef tcu::Vector<float, TexTypeCoordDims<TexType>::V> t; }; 140 141 template <TextureType> struct TexTypeCoordParams; 142 143 template <> struct 144 TexTypeCoordParams<TEXTURETYPE_2D> 145 { 146 Vec2 scale; 147 Vec2 bias; 148 149 TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_) : scale(scale_), bias(bias_) {} 150 }; 151 152 template <> struct 153 TexTypeCoordParams<TEXTURETYPE_CUBE> 154 { 155 Vec2 scale; 156 Vec2 bias; 157 tcu::CubeFace face; 158 159 TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_, tcu::CubeFace face_) : scale(scale_), bias(bias_), face(face_) {} 160 }; 161 162 /*--------------------------------------------------------------------*//*! 163 * \brief Quad grid class containing position and texture coordinate data. 164 * 165 * A quad grid of size S means a grid consisting of S*S quads (S rows and 166 * S columns). The quads are rectangles with main axis aligned sides, and 167 * each consists of two triangles. Note that although there are only 168 * (S+1)*(S+1) distinct vertex positions, there are S*S*4 distinct vertices 169 * because we want texture coordinates to be constant across the vertices 170 * of a quad (to avoid interpolation issues), and thus each quad needs its 171 * own 4 vertices. 172 * 173 * Pointers returned by get*Ptr() are suitable for gl calls such as 174 * glVertexAttribPointer() (for position and tex coord) or glDrawElements() 175 * (for indices). 176 *//*--------------------------------------------------------------------*/ 177 template <TextureType TexType> 178 class PosTexCoordQuadGrid 179 { 180 private: 181 enum { TEX_COORD_DIMS = TexTypeCoordDims <TexType>::V }; 182 typedef typename TexTypeCoordVec<TexType>::t TexCoordVec; 183 typedef typename TexTypeSizeIVec<TexType>::t TexSizeIVec; 184 typedef TexTypeCoordParams<TexType> TexCoordParams; 185 186 public: 187 PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords); 188 189 int getSize (void) const { return m_gridSize; } 190 Vec4 getQuadLDRU (int col, int row) const; //!< Vec4(leftX, downY, rightX, upY) 191 const TexCoordVec& getQuadTexCoord (int col, int row) const; 192 193 int getNumIndices (void) const { return m_gridSize*m_gridSize*3*2; } 194 const float* getPositionPtr (void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; } 195 const float* getTexCoordPtr (void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; } 196 const deUint16* getIndexPtr (void) const { return &m_indices[0]; } 197 198 private: 199 void initializeTexCoords (const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords); 200 201 const int m_gridSize; 202 vector<Vec2> m_positions; 203 vector<TexCoordVec> m_texCoords; 204 vector<deUint16> m_indices; 205 }; 206 207 template <TextureType TexType> 208 Vec4 PosTexCoordQuadGrid<TexType>::getQuadLDRU (int col, int row) const 209 { 210 int ndx00 = (row*m_gridSize + col) * 4; 211 int ndx11 = ndx00 + 3; 212 213 return Vec4(m_positions[ndx00].x(), 214 m_positions[ndx00].y(), 215 m_positions[ndx11].x(), 216 m_positions[ndx11].y()); 217 } 218 219 template <TextureType TexType> 220 const typename TexTypeCoordVec<TexType>::t& PosTexCoordQuadGrid<TexType>::getQuadTexCoord (int col, int row) const 221 { 222 return m_texCoords[(row*m_gridSize + col) * 4]; 223 } 224 225 template <TextureType TexType> 226 PosTexCoordQuadGrid<TexType>::PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 227 : m_gridSize(gridSize) 228 { 229 DE_ASSERT(m_gridSize > 0 && m_gridSize*m_gridSize <= (int)std::numeric_limits<deUint16>::max() + 1); 230 231 const float gridSizeFloat = (float)m_gridSize; 232 233 m_positions.reserve(m_gridSize*m_gridSize*4); 234 m_indices.reserve(m_gridSize*m_gridSize*3*2); 235 236 for (int y = 0; y < m_gridSize; y++) 237 for (int x = 0; x < m_gridSize; x++) 238 { 239 float fx0 = (float)(x+0) / gridSizeFloat; 240 float fx1 = (float)(x+1) / gridSizeFloat; 241 float fy0 = (float)(y+0) / gridSizeFloat; 242 float fy1 = (float)(y+1) / gridSizeFloat; 243 244 Vec2 quadVertices[4] = { Vec2(fx0, fy0), Vec2(fx1, fy0), Vec2(fx0, fy1), Vec2(fx1, fy1) }; 245 246 int firstNdx = (int)m_positions.size(); 247 248 for (int i = 0; i < DE_LENGTH_OF_ARRAY(quadVertices); i++) 249 m_positions.push_back(safeCoords(quadVertices[i], renderSize, Vec2(0.0f)) * 2.0f - 1.0f); 250 251 m_indices.push_back(deUint16(firstNdx + 0)); 252 m_indices.push_back(deUint16(firstNdx + 1)); 253 m_indices.push_back(deUint16(firstNdx + 2)); 254 255 m_indices.push_back(deUint16(firstNdx + 1)); 256 m_indices.push_back(deUint16(firstNdx + 3)); 257 m_indices.push_back(deUint16(firstNdx + 2)); 258 } 259 260 m_texCoords.reserve(m_gridSize*m_gridSize*4); 261 initializeTexCoords(textureSize, texCoordParams, useSafeTexCoords); 262 263 DE_ASSERT((int)m_positions.size() == m_gridSize*m_gridSize*4); 264 DE_ASSERT((int)m_indices.size() == m_gridSize*m_gridSize*3*2); 265 DE_ASSERT((int)m_texCoords.size() == m_gridSize*m_gridSize*4); 266 } 267 268 template <> 269 void PosTexCoordQuadGrid<TEXTURETYPE_2D>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 270 { 271 DE_ASSERT(m_texCoords.empty()); 272 273 const float gridSizeFloat = (float)m_gridSize; 274 275 for (int y = 0; y < m_gridSize; y++) 276 for (int x = 0; x < m_gridSize; x++) 277 { 278 Vec2 rawCoord = Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) * texCoordParams.scale + texCoordParams.bias; 279 280 for (int i = 0; i < 4; i++) 281 m_texCoords.push_back(useSafeTexCoords ? safe2DTexCoords(rawCoord, textureSize) : rawCoord); 282 } 283 } 284 285 template <> 286 void PosTexCoordQuadGrid<TEXTURETYPE_CUBE>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 287 { 288 DE_ASSERT(m_texCoords.empty()); 289 290 const float gridSizeFloat = (float)m_gridSize; 291 vector<float> texBoundaries; 292 computeQuadTexCoordCube(texBoundaries, texCoordParams.face); 293 const Vec3 coordA = Vec3(texBoundaries[0], texBoundaries[1], texBoundaries[2]); 294 const Vec3 coordB = Vec3(texBoundaries[3], texBoundaries[4], texBoundaries[5]); 295 const Vec3 coordC = Vec3(texBoundaries[6], texBoundaries[7], texBoundaries[8]); 296 const Vec3 coordAB = coordB - coordA; 297 const Vec3 coordAC = coordC - coordA; 298 299 for (int y = 0; y < m_gridSize; y++) 300 for (int x = 0; x < m_gridSize; x++) 301 { 302 const Vec2 rawFaceCoord = texCoordParams.scale * Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) + texCoordParams.bias; 303 const Vec2 safeFaceCoord = useSafeTexCoords ? safe2DTexCoords(rawFaceCoord, textureSize) : rawFaceCoord; 304 const Vec3 texCoord = coordA + coordAC*safeFaceCoord.x() + coordAB*safeFaceCoord.y(); 305 306 for (int i = 0; i < 4; i++) 307 m_texCoords.push_back(texCoord); 308 } 309 } 310 311 } // anonymous 312 313 static inline bool isLevelNearest (deUint32 filter) 314 { 315 return filter == GL_NEAREST || filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_NEAREST_MIPMAP_LINEAR; 316 } 317 318 static inline IVec2 getTextureSize (const glu::Texture2D& tex) 319 { 320 const tcu::Texture2D& ref = tex.getRefTexture(); 321 return IVec2(ref.getWidth(), ref.getHeight()); 322 } 323 324 static inline IVec2 getTextureSize (const glu::TextureCube& tex) 325 { 326 const tcu::TextureCube& ref = tex.getRefTexture(); 327 return IVec2(ref.getSize(), ref.getSize()); 328 } 329 330 template <TextureType TexType> 331 static void setPixelColors (const vector<Vec4>& quadColors, const Rect& region, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst) 332 { 333 const int gridSize = grid.getSize(); 334 335 for (int y = 0; y < gridSize; y++) 336 for (int x = 0; x < gridSize; x++) 337 { 338 const Vec4 color = quadColors[y*gridSize + x]; 339 const Vec4 ldru = grid.getQuadLDRU(x, y) * 0.5f + 0.5f; // [-1, 1] -> [0, 1] 340 const int ix0 = deCeilFloatToInt32(ldru.x() * (float)region.w - 0.5f); 341 const int ix1 = deCeilFloatToInt32(ldru.z() * (float)region.w - 0.5f); 342 const int iy0 = deCeilFloatToInt32(ldru.y() * (float)region.h - 0.5f); 343 const int iy1 = deCeilFloatToInt32(ldru.w() * (float)region.h - 0.5f); 344 345 for (int iy = iy0; iy < iy1; iy++) 346 for (int ix = ix0; ix < ix1; ix++) 347 { 348 DE_ASSERT(deInBounds32(ix + region.x, 0, dst.getWidth())); 349 DE_ASSERT(deInBounds32(iy + region.y, 0, dst.getHeight())); 350 351 dst.setPixel(ix + region.x, iy + region.y, tcu::RGBA(color)); 352 } 353 } 354 } 355 356 static inline Vec4 sample (const tcu::Texture2D& tex, const Vec2& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), lod); } 357 static inline Vec4 sample (const tcu::TextureCube& tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); } 358 359 template <TextureType TexType> 360 void computeReference (const typename TexTypeTcuClass<TexType>::t& texture, float lod, const tcu::Sampler& sampler, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst, const Rect& dstRegion) 361 { 362 const int gridSize = grid.getSize(); 363 vector<Vec4> quadColors (gridSize*gridSize); 364 365 for (int y = 0; y < gridSize; y++) 366 for (int x = 0; x < gridSize; x++) 367 { 368 const int ndx = y*gridSize + x; 369 const typename TexTypeCoordVec<TexType>::t& coord = grid.getQuadTexCoord(x, y); 370 371 quadColors[ndx] = sample(texture, coord, lod, sampler); 372 } 373 374 setPixelColors(quadColors, dstRegion, grid, dst); 375 } 376 377 static bool compareImages (const glu::RenderContext& renderCtx, tcu::TestLog& log, const tcu::Surface& ref, const tcu::Surface& res) 378 { 379 DE_ASSERT(renderCtx.getRenderTarget().getNumSamples() == 0); 380 381 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(15,15,15,15); 382 return tcu::pixelThresholdCompare(log, "Result", "Image compare result", ref, res, threshold, tcu::COMPARE_LOG_RESULT); 383 } 384 385 class Vertex2DTextureCase : public TestCase 386 { 387 public: 388 Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); 389 ~Vertex2DTextureCase (void); 390 391 void init (void); 392 void deinit (void); 393 IterateResult iterate (void); 394 395 private: 396 typedef PosTexCoordQuadGrid<TEXTURETYPE_2D> Grid; 397 398 Vertex2DTextureCase (const Vertex2DTextureCase& other); 399 Vertex2DTextureCase& operator= (const Vertex2DTextureCase& other); 400 401 float calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const; 402 void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; 403 void renderCell (int textureNdx, float lod, const Grid& grid) const; 404 void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; 405 406 const deUint32 m_minFilter; 407 const deUint32 m_magFilter; 408 const deUint32 m_wrapS; 409 const deUint32 m_wrapT; 410 411 const glu::ShaderProgram* m_program; 412 glu::Texture2D* m_textures[2]; // 2 textures, a gradient texture and a grid texture. 413 }; 414 415 Vertex2DTextureCase::Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) 416 : TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) 417 , m_minFilter (minFilter) 418 , m_magFilter (magFilter) 419 , m_wrapS (wrapS) 420 , m_wrapT (wrapT) 421 , m_program (DE_NULL) 422 { 423 m_textures[0] = DE_NULL; 424 m_textures[1] = DE_NULL; 425 } 426 427 Vertex2DTextureCase::~Vertex2DTextureCase(void) 428 { 429 Vertex2DTextureCase::deinit(); 430 } 431 432 void Vertex2DTextureCase::init (void) 433 { 434 const char* const vertexShader = 435 "attribute highp vec2 a_position;\n" 436 "attribute highp vec2 a_texCoord;\n" 437 "uniform highp sampler2D u_texture;\n" 438 "uniform highp float u_lod;\n" 439 "varying mediump vec4 v_color;\n" 440 "\n" 441 "void main()\n" 442 "{\n" 443 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 444 " v_color = texture2DLod(u_texture, a_texCoord, u_lod);\n" 445 "}\n"; 446 447 const char* const fragmentShader = 448 "varying mediump vec4 v_color;\n" 449 "\n" 450 "void main()\n" 451 "{\n" 452 " gl_FragColor = v_color;\n" 453 "}\n"; 454 455 if (m_context.getRenderTarget().getNumSamples() != 0) 456 throw tcu::NotSupportedError("MSAA config not supported by this test"); 457 458 DE_ASSERT(!m_program); 459 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader)); 460 461 if(!m_program->isOk()) 462 { 463 m_testCtx.getLog() << *m_program; 464 465 GLint maxVertexTextures; 466 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); 467 468 if (maxVertexTextures < 1) 469 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); 470 else 471 TCU_FAIL("Failed to compile shader"); 472 } 473 474 // Make the textures. 475 try 476 { 477 // Compute suitable power-of-two sizes (for mipmaps). 478 const int texWidth = 1 << deLog2Ceil32(MAX_2D_RENDER_WIDTH / 2); 479 const int texHeight = 1 << deLog2Ceil32(MAX_2D_RENDER_HEIGHT / 2); 480 481 for (int i = 0; i < 2; i++) 482 { 483 DE_ASSERT(!m_textures[i]); 484 m_textures[i] = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight); 485 } 486 487 const bool mipmaps = (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight)); 488 const int numLevels = mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1; 489 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 490 const Vec4 cBias = fmtInfo.valueMin; 491 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 492 493 // Fill first with gradient texture. 494 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 495 { 496 const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias; 497 const Vec4 gMax = Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 498 499 m_textures[0]->getRefTexture().allocLevel(levelNdx); 500 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); 501 } 502 503 // Fill second with grid texture. 504 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 505 { 506 const deUint32 step = 0x00ffffff / numLevels; 507 const deUint32 rgb = step*levelNdx; 508 const deUint32 colorA = 0xff000000 | rgb; 509 const deUint32 colorB = 0xff000000 | ~rgb; 510 511 m_textures[1]->getRefTexture().allocLevel(levelNdx); 512 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 513 } 514 515 // Upload. 516 for (int i = 0; i < 2; i++) 517 m_textures[i]->upload(); 518 } 519 catch (const std::exception&) 520 { 521 // Clean up to save memory. 522 Vertex2DTextureCase::deinit(); 523 throw; 524 } 525 } 526 527 void Vertex2DTextureCase::deinit (void) 528 { 529 for (int i = 0; i < 2; i++) 530 { 531 delete m_textures[i]; 532 m_textures[i] = DE_NULL; 533 } 534 535 delete m_program; 536 m_program = DE_NULL; 537 } 538 539 float Vertex2DTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const 540 { 541 const tcu::Texture2D& refTexture = m_textures[textureNdx]->getRefTexture(); 542 const Vec2 srcSize = Vec2((float)refTexture.getWidth(), (float)refTexture.getHeight()); 543 const Vec2 sizeRatio = texScale*srcSize / dstSize; 544 545 // \note In this particular case dv/dx and du/dy are zero, simplifying the expression. 546 return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y())); 547 } 548 549 Vertex2DTextureCase::IterateResult Vertex2DTextureCase::iterate (void) 550 { 551 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_RENDER_WIDTH); 552 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_RENDER_HEIGHT); 553 554 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; 555 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; 556 557 de::Random rnd (deStringHash(getName())); 558 559 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); 560 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); 561 562 glUseProgram(m_program->getProgram()); 563 564 // Divide viewport into 4 cells. 565 const int leftWidth = viewportWidth / 2; 566 const int rightWidth = viewportWidth - leftWidth; 567 const int bottomHeight = viewportHeight / 2; 568 const int topHeight = viewportHeight - bottomHeight; 569 570 // Clear. 571 glClearColor(0.125f, 0.25f, 0.5f, 1.0f); 572 glClear(GL_COLOR_BUFFER_BIT); 573 574 // Texture scaling and offsetting vectors. 575 const Vec2 texMinScale (+1.8f, +1.8f); 576 const Vec2 texMinOffset (-0.3f, -0.2f); 577 const Vec2 texMagScale (+0.3f, +0.3f); 578 const Vec2 texMagOffset (+0.9f, +0.8f); 579 580 // Surface for the reference image. 581 tcu::Surface refImage(viewportWidth, viewportHeight); 582 583 { 584 const struct Render 585 { 586 const Rect region; 587 int textureNdx; 588 const Vec2 texCoordScale; 589 const Vec2 texCoordOffset; 590 Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {} 591 } renders[] = 592 { 593 Render(Rect(0, 0, leftWidth, bottomHeight), 0, texMinScale, texMinOffset), 594 Render(Rect(leftWidth, 0, rightWidth, bottomHeight), 0, texMagScale, texMagOffset), 595 Render(Rect(0, bottomHeight, leftWidth, topHeight), 1, texMinScale, texMinOffset), 596 Render(Rect(leftWidth, bottomHeight, rightWidth, topHeight), 1, texMagScale, texMagOffset) 597 }; 598 599 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) 600 { 601 const Render& rend = renders[renderNdx]; 602 const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx); 603 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); 604 const Grid grid (GRID_SIZE_2D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), 605 TexTypeCoordParams<TEXTURETYPE_2D>(rend.texCoordScale, rend.texCoordOffset), useSafeTexCoords); 606 607 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); 608 renderCell (rend.textureNdx, lod, grid); 609 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); 610 } 611 } 612 613 // Read back rendered results. 614 tcu::Surface resImage(viewportWidth, viewportHeight); 615 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); 616 617 glUseProgram(0); 618 619 // Compare and log. 620 { 621 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); 622 623 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 624 isOk ? "Pass" : "Image comparison failed"); 625 } 626 627 return STOP; 628 } 629 630 void Vertex2DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const 631 { 632 const deUint32 programID = m_program->getProgram(); 633 634 // SETUP ATTRIBUTES. 635 636 { 637 const int positionLoc = glGetAttribLocation(programID, "a_position"); 638 if (positionLoc != -1) 639 { 640 glEnableVertexAttribArray(positionLoc); 641 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); 642 } 643 } 644 645 { 646 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); 647 if (texCoordLoc != -1) 648 { 649 glEnableVertexAttribArray(texCoordLoc); 650 glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); 651 } 652 } 653 654 // SETUP UNIFORMS. 655 656 { 657 const int lodLoc = glGetUniformLocation(programID, "u_lod"); 658 if (lodLoc != -1) 659 glUniform1f(lodLoc, lod); 660 } 661 662 glActiveTexture(GL_TEXTURE0); 663 glBindTexture(GL_TEXTURE_2D, m_textures[textureNdx]->getGLTexture()); 664 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); 665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); 666 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); 667 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); 668 669 { 670 const int texLoc = glGetUniformLocation(programID, "u_texture"); 671 if (texLoc != -1) 672 glUniform1i(texLoc, 0); 673 } 674 } 675 676 // Renders one sub-image with given parameters. 677 void Vertex2DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const 678 { 679 setupShaderInputs(textureNdx, lod, grid); 680 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); 681 } 682 683 void Vertex2DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const 684 { 685 computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion); 686 } 687 688 class VertexCubeTextureCase : public TestCase 689 { 690 public: 691 VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); 692 ~VertexCubeTextureCase (void); 693 694 void init (void); 695 void deinit (void); 696 IterateResult iterate (void); 697 698 private: 699 typedef PosTexCoordQuadGrid<TEXTURETYPE_CUBE> Grid; 700 701 VertexCubeTextureCase (const VertexCubeTextureCase& other); 702 VertexCubeTextureCase& operator= (const VertexCubeTextureCase& other); 703 704 float calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const; 705 void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; 706 void renderCell (int textureNdx, float lod, const Grid& grid) const; 707 void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; 708 709 const deUint32 m_minFilter; 710 const deUint32 m_magFilter; 711 const deUint32 m_wrapS; 712 const deUint32 m_wrapT; 713 714 const glu::ShaderProgram* m_program; 715 glu::TextureCube* m_textures[2]; // 2 textures, a gradient texture and a grid texture. 716 }; 717 718 VertexCubeTextureCase::VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) 719 : TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) 720 , m_minFilter (minFilter) 721 , m_magFilter (magFilter) 722 , m_wrapS (wrapS) 723 , m_wrapT (wrapT) 724 , m_program (DE_NULL) 725 { 726 m_textures[0] = DE_NULL; 727 m_textures[1] = DE_NULL; 728 } 729 730 VertexCubeTextureCase::~VertexCubeTextureCase(void) 731 { 732 VertexCubeTextureCase::deinit(); 733 } 734 735 void VertexCubeTextureCase::init (void) 736 { 737 const char* const vertexShader = 738 "attribute highp vec2 a_position;\n" 739 "attribute highp vec3 a_texCoord;\n" 740 "uniform highp samplerCube u_texture;\n" 741 "uniform highp float u_lod;\n" 742 "varying mediump vec4 v_color;\n" 743 "\n" 744 "void main()\n" 745 "{\n" 746 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 747 " v_color = textureCubeLod(u_texture, a_texCoord, u_lod);\n" 748 "}\n"; 749 750 const char* const fragmentShader = 751 "varying mediump vec4 v_color;\n" 752 "\n" 753 "void main()\n" 754 "{\n" 755 " gl_FragColor = v_color;\n" 756 "}\n"; 757 758 if (m_context.getRenderTarget().getNumSamples() != 0) 759 throw tcu::NotSupportedError("MSAA config not supported by this test"); 760 761 DE_ASSERT(!m_program); 762 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader)); 763 764 if(!m_program->isOk()) 765 { 766 m_testCtx.getLog() << *m_program; 767 768 GLint maxVertexTextures; 769 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); 770 771 if (maxVertexTextures < 1) 772 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); 773 else 774 TCU_FAIL("Failed to compile shader"); 775 } 776 777 // Make the textures. 778 try 779 { 780 // Compute suitable power-of-two sizes (for mipmaps). 781 const int texWidth = 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2); 782 const int texHeight = 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2); 783 784 DE_ASSERT(texWidth == texHeight); 785 DE_UNREF(texHeight); 786 787 for (int i = 0; i < 2; i++) 788 { 789 DE_ASSERT(!m_textures[i]); 790 m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth); 791 } 792 793 const bool mipmaps = deIsPowerOfTwo32(texWidth) != DE_FALSE; 794 const int numLevels = mipmaps ? deLog2Floor32(texWidth)+1 : 1; 795 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 796 const Vec4 cBias = fmtInfo.valueMin; 797 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 798 799 // Fill first with gradient texture. 800 static const Vec4 gradients[tcu::CUBEFACE_LAST][2] = 801 { 802 { Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x 803 { Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x 804 { Vec4(-1.0f, 0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y 805 { Vec4(-1.0f, -1.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y 806 { Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z 807 { Vec4( 0.0f, 0.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z 808 }; 809 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 810 { 811 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 812 { 813 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 814 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias); 815 } 816 } 817 818 // Fill second with grid texture. 819 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 820 { 821 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 822 { 823 const deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST); 824 const deUint32 rgb = step*levelNdx*face; 825 const deUint32 colorA = 0xff000000 | rgb; 826 const deUint32 colorB = 0xff000000 | ~rgb; 827 828 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 829 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 830 } 831 } 832 833 // Upload. 834 for (int i = 0; i < 2; i++) 835 m_textures[i]->upload(); 836 } 837 catch (const std::exception&) 838 { 839 // Clean up to save memory. 840 VertexCubeTextureCase::deinit(); 841 throw; 842 } 843 } 844 845 void VertexCubeTextureCase::deinit (void) 846 { 847 for (int i = 0; i < 2; i++) 848 { 849 delete m_textures[i]; 850 m_textures[i] = DE_NULL; 851 } 852 853 delete m_program; 854 m_program = DE_NULL; 855 } 856 857 float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const 858 { 859 const tcu::TextureCube& refTexture = m_textures[textureNdx]->getRefTexture(); 860 const Vec2 srcSize = Vec2((float)refTexture.getSize(), (float)refTexture.getSize()); 861 const Vec2 sizeRatio = texScale*srcSize / dstSize; 862 863 // \note In this particular case, dv/dx and du/dy are zero, simplifying the expression. 864 return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y())); 865 } 866 867 VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void) 868 { 869 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH); 870 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT); 871 872 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; 873 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; 874 875 de::Random rnd (deStringHash(getName())); 876 877 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); 878 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); 879 880 glUseProgram(m_program->getProgram()); 881 882 // Divide viewport into 4 areas. 883 const int leftWidth = viewportWidth / 2; 884 const int rightWidth = viewportWidth - leftWidth; 885 const int bottomHeight = viewportHeight / 2; 886 const int topHeight = viewportHeight - bottomHeight; 887 888 // Clear. 889 glClearColor(0.125f, 0.25f, 0.5f, 1.0f); 890 glClear(GL_COLOR_BUFFER_BIT); 891 892 // Texture scaling and offsetting vectors. 893 const Vec2 texMinScale (1.0f, 1.0f); 894 const Vec2 texMinOffset (0.0f, 0.0f); 895 const Vec2 texMagScale (0.3f, 0.3f); 896 const Vec2 texMagOffset (0.5f, 0.3f); 897 898 // Surface for the reference image. 899 tcu::Surface refImage(viewportWidth, viewportHeight); 900 901 // Each of the four areas is divided into 6 cells. 902 const int defCellWidth = viewportWidth / 2 / 3; 903 const int defCellHeight = viewportHeight / 2 / 2; 904 905 for (int i = 0; i < tcu::CUBEFACE_LAST; i++) 906 { 907 const int cellOffsetX = defCellWidth * (i % 3); 908 const int cellOffsetY = defCellHeight * (i / 3); 909 const bool isRightmostCell = i == 2 || i == 5; 910 const bool isTopCell = i >= 3; 911 const int leftCellWidth = isRightmostCell ? leftWidth - cellOffsetX : defCellWidth; 912 const int rightCellWidth = isRightmostCell ? rightWidth - cellOffsetX : defCellWidth; 913 const int bottomCellHeight = isTopCell ? bottomHeight - cellOffsetY : defCellHeight; 914 const int topCellHeight = isTopCell ? topHeight - cellOffsetY : defCellHeight; 915 916 const struct Render 917 { 918 const Rect region; 919 int textureNdx; 920 const Vec2 texCoordScale; 921 const Vec2 texCoordOffset; 922 Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {} 923 } renders[] = 924 { 925 Render(Rect(cellOffsetX + 0, cellOffsetY + 0, leftCellWidth, bottomCellHeight), 0, texMinScale, texMinOffset), 926 Render(Rect(cellOffsetX + leftWidth, cellOffsetY + 0, rightCellWidth, bottomCellHeight), 0, texMagScale, texMagOffset), 927 Render(Rect(cellOffsetX + 0, cellOffsetY + bottomHeight, leftCellWidth, topCellHeight), 1, texMinScale, texMinOffset), 928 Render(Rect(cellOffsetX + leftWidth, cellOffsetY + bottomHeight, rightCellWidth, topCellHeight), 1, texMagScale, texMagOffset) 929 }; 930 931 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) 932 { 933 const Render& rend = renders[renderNdx]; 934 const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx); 935 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); 936 const Grid grid (GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), 937 TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords); 938 939 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); 940 renderCell (rend.textureNdx, lod, grid); 941 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); 942 } 943 } 944 945 // Read back rendered results. 946 tcu::Surface resImage(viewportWidth, viewportHeight); 947 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); 948 949 glUseProgram(0); 950 951 // Compare and log. 952 { 953 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); 954 955 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 956 isOk ? "Pass" : "Image comparison failed"); 957 } 958 959 return STOP; 960 } 961 962 void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const 963 { 964 const deUint32 programID = m_program->getProgram(); 965 966 // SETUP ATTRIBUTES. 967 968 { 969 const int positionLoc = glGetAttribLocation(programID, "a_position"); 970 if (positionLoc != -1) 971 { 972 glEnableVertexAttribArray(positionLoc); 973 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); 974 } 975 } 976 977 { 978 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); 979 if (texCoordLoc != -1) 980 { 981 glEnableVertexAttribArray(texCoordLoc); 982 glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); 983 } 984 } 985 986 // SETUP UNIFORMS. 987 988 { 989 const int lodLoc = glGetUniformLocation(programID, "u_lod"); 990 if (lodLoc != -1) 991 glUniform1f(lodLoc, lod); 992 } 993 994 glActiveTexture(GL_TEXTURE0); 995 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture()); 996 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 997 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 998 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 999 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 1000 1001 { 1002 const int texLoc = glGetUniformLocation(programID, "u_texture"); 1003 if (texLoc != -1) 1004 glUniform1i(texLoc, 0); 1005 } 1006 } 1007 1008 // Renders one cube face with given parameters. 1009 void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const 1010 { 1011 setupShaderInputs(textureNdx, lod, grid); 1012 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); 1013 } 1014 1015 // Computes reference for one cube face with given parameters. 1016 void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const 1017 { 1018 tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); 1019 computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion); 1020 } 1021 1022 VertexTextureTests::VertexTextureTests (Context& context) 1023 : TestCaseGroup(context, "vertex", "Vertex Texture Tests") 1024 { 1025 } 1026 1027 VertexTextureTests::~VertexTextureTests(void) 1028 { 1029 } 1030 1031 void VertexTextureTests::init (void) 1032 { 1033 // 2D and cube map groups, and their filtering and wrap sub-groups. 1034 TestCaseGroup* const group2D = new TestCaseGroup(m_context, "2d", "2D Vertex Texture Tests"); 1035 TestCaseGroup* const groupCube = new TestCaseGroup(m_context, "cube", "Cube Map Vertex Texture Tests"); 1036 TestCaseGroup* const filteringGroup2D = new TestCaseGroup(m_context, "filtering", "2D Vertex Texture Filtering Tests"); 1037 TestCaseGroup* const wrapGroup2D = new TestCaseGroup(m_context, "wrap", "2D Vertex Texture Wrap Tests"); 1038 TestCaseGroup* const filteringGroupCube = new TestCaseGroup(m_context, "filtering", "Cube Map Vertex Texture Filtering Tests"); 1039 TestCaseGroup* const wrapGroupCube = new TestCaseGroup(m_context, "wrap", "Cube Map Vertex Texture Wrap Tests"); 1040 1041 group2D->addChild(filteringGroup2D); 1042 group2D->addChild(wrapGroup2D); 1043 groupCube->addChild(filteringGroupCube); 1044 groupCube->addChild(wrapGroupCube); 1045 1046 addChild(group2D); 1047 addChild(groupCube); 1048 1049 static const struct 1050 { 1051 const char* name; 1052 GLenum mode; 1053 } wrapModes[] = 1054 { 1055 { "clamp", GL_CLAMP_TO_EDGE }, 1056 { "repeat", GL_REPEAT }, 1057 { "mirror", GL_MIRRORED_REPEAT } 1058 }; 1059 1060 static const struct 1061 { 1062 const char* name; 1063 GLenum mode; 1064 } minFilterModes[] = 1065 { 1066 { "nearest", GL_NEAREST }, 1067 { "linear", GL_LINEAR }, 1068 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, 1069 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, 1070 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, 1071 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } 1072 }; 1073 1074 static const struct 1075 { 1076 const char* name; 1077 GLenum mode; 1078 } magFilterModes[] = 1079 { 1080 { "nearest", GL_NEAREST }, 1081 { "linear", GL_LINEAR } 1082 }; 1083 1084 #define FOR_EACH(ITERATOR, ARRAY, BODY) \ 1085 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \ 1086 BODY 1087 1088 // 2D cases. 1089 1090 FOR_EACH(minFilter, minFilterModes, 1091 FOR_EACH(magFilter, magFilterModes, 1092 FOR_EACH(wrapMode, wrapModes, 1093 { 1094 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; 1095 1096 filteringGroup2D->addChild(new Vertex2DTextureCase(m_context, 1097 name.c_str(), "", 1098 minFilterModes[minFilter].mode, 1099 magFilterModes[magFilter].mode, 1100 wrapModes[wrapMode].mode, 1101 wrapModes[wrapMode].mode)); 1102 }))); 1103 1104 FOR_EACH(wrapSMode, wrapModes, 1105 FOR_EACH(wrapTMode, wrapModes, 1106 { 1107 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; 1108 1109 wrapGroup2D->addChild(new Vertex2DTextureCase(m_context, 1110 name.c_str(), "", 1111 GL_LINEAR_MIPMAP_LINEAR, 1112 GL_LINEAR, 1113 wrapModes[wrapSMode].mode, 1114 wrapModes[wrapTMode].mode)); 1115 })); 1116 1117 // Cube map cases. 1118 1119 FOR_EACH(minFilter, minFilterModes, 1120 FOR_EACH(magFilter, magFilterModes, 1121 FOR_EACH(wrapMode, wrapModes, 1122 { 1123 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; 1124 1125 filteringGroupCube->addChild(new VertexCubeTextureCase(m_context, 1126 name.c_str(), "", 1127 minFilterModes[minFilter].mode, 1128 magFilterModes[magFilter].mode, 1129 wrapModes[wrapMode].mode, 1130 wrapModes[wrapMode].mode)); 1131 }))); 1132 1133 FOR_EACH(wrapSMode, wrapModes, 1134 FOR_EACH(wrapTMode, wrapModes, 1135 { 1136 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; 1137 1138 wrapGroupCube->addChild(new VertexCubeTextureCase(m_context, 1139 name.c_str(), "", 1140 GL_LINEAR_MIPMAP_LINEAR, 1141 GL_LINEAR, 1142 wrapModes[wrapSMode].mode, 1143 wrapModes[wrapTMode].mode)); 1144 })); 1145 } 1146 1147 } // Functional 1148 } // gles2 1149 } // deqp 1150