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