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 Vertex texture tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fVertexTextureTests.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 using gls::TextureTestUtil::TEXTURETYPE_2D_ARRAY; 62 using gls::TextureTestUtil::TEXTURETYPE_3D; 63 64 namespace gles3 65 { 66 namespace Functional 67 { 68 69 static const int WIDTH_2D_ARRAY = 128; 70 static const int HEIGHT_2D_ARRAY = 128; 71 static const int LAYERS_2D_ARRAY = 8; 72 73 static const int WIDTH_3D = 64; 74 static const int HEIGHT_3D = 64; 75 static const int DEPTH_3D = 64; 76 77 // The 2D case draws four images. 78 static const int MAX_2D_RENDER_WIDTH = 128*2; 79 static const int MAX_2D_RENDER_HEIGHT = 128*2; 80 81 // The cube map case draws four 3-by-2 image groups. 82 static const int MAX_CUBE_RENDER_WIDTH = 28*2*3; 83 static const int MAX_CUBE_RENDER_HEIGHT = 28*2*2; 84 85 static const int MAX_2D_ARRAY_RENDER_WIDTH = 128*2; 86 static const int MAX_2D_ARRAY_RENDER_HEIGHT = 128*2; 87 88 static const int MAX_3D_RENDER_WIDTH = 128*2; 89 static const int MAX_3D_RENDER_HEIGHT = 128*2; 90 91 static const int GRID_SIZE_2D = 127; 92 static const int GRID_SIZE_CUBE = 63; 93 static const int GRID_SIZE_2D_ARRAY = 127; 94 static const int GRID_SIZE_3D = 127; 95 96 // Helpers for making texture coordinates "safe", i.e. move them further from coordinate bounary. 97 98 // Moves x towards the closest K+targetFraction, where K is an integer. 99 // E.g. moveTowardsFraction(x, 0.5f) moves x away from integer boundaries. 100 static inline float moveTowardsFraction (float x, float targetFraction) 101 { 102 const float strictness = 0.5f; 103 DE_ASSERT(0.0f < strictness && strictness <= 1.0f); 104 DE_ASSERT(de::inBounds(targetFraction, 0.0f, 1.0f)); 105 const float y = x + 0.5f - targetFraction; 106 return deFloatFloor(y) + deFloatFrac(y)*(1.0f-strictness) + strictness*0.5f - 0.5f + targetFraction; 107 } 108 109 static inline float safeCoord (float raw, int scale, float fraction) 110 { 111 const float scaleFloat = (float)scale; 112 return moveTowardsFraction(raw*scaleFloat, fraction) / scaleFloat; 113 } 114 115 template <int Size> 116 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) 117 { 118 tcu::Vector<float, Size> result; 119 for (int i = 0; i < Size; i++) 120 result[i] = safeCoord(raw[i], scale[i], fraction[i]); 121 return result; 122 } 123 124 static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize) 125 { 126 return safeCoords(raw, textureSize, Vec2(0.5f)); 127 } 128 129 static inline Vec3 safe2DArrayTexCoords (const Vec3& raw, const IVec3& textureSize) 130 { 131 return safeCoords(raw, textureSize, Vec3(0.5f, 0.5f, 0.0f)); 132 } 133 134 static inline Vec3 safe3DTexCoords (const Vec3& raw, const IVec3& textureSize) 135 { 136 return safeCoords(raw, textureSize, Vec3(0.5f)); 137 } 138 139 namespace 140 { 141 142 struct Rect 143 { 144 Rect (int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {} 145 IVec2 pos (void) const { return IVec2(x, y); } 146 IVec2 size (void) const { return IVec2(w, h); } 147 148 int x; 149 int y; 150 int w; 151 int h; 152 }; 153 154 template <TextureType> struct TexTypeTcuClass; 155 template <> struct TexTypeTcuClass<TEXTURETYPE_2D> { typedef tcu::Texture2D t; }; 156 template <> struct TexTypeTcuClass<TEXTURETYPE_CUBE> { typedef tcu::TextureCube t; }; 157 template <> struct TexTypeTcuClass<TEXTURETYPE_2D_ARRAY> { typedef tcu::Texture2DArray t; }; 158 template <> struct TexTypeTcuClass<TEXTURETYPE_3D> { typedef tcu::Texture3D t; }; 159 160 template <TextureType> struct TexTypeSizeDims; 161 template <> struct TexTypeSizeDims<TEXTURETYPE_2D> { enum { V = 2 }; }; 162 template <> struct TexTypeSizeDims<TEXTURETYPE_CUBE> { enum { V = 2 }; }; 163 template <> struct TexTypeSizeDims<TEXTURETYPE_2D_ARRAY> { enum { V = 3 }; }; 164 template <> struct TexTypeSizeDims<TEXTURETYPE_3D> { enum { V = 3 }; }; 165 166 template <TextureType> struct TexTypeCoordDims; 167 template <> struct TexTypeCoordDims<TEXTURETYPE_2D> { enum { V = 2 }; }; 168 template <> struct TexTypeCoordDims<TEXTURETYPE_CUBE> { enum { V = 3 }; }; 169 template <> struct TexTypeCoordDims<TEXTURETYPE_2D_ARRAY> { enum { V = 3 }; }; 170 template <> struct TexTypeCoordDims<TEXTURETYPE_3D> { enum { V = 3 }; }; 171 172 template <TextureType TexType> struct TexTypeSizeIVec { typedef tcu::Vector<int, TexTypeSizeDims<TexType>::V> t; }; 173 template <TextureType TexType> struct TexTypeCoordVec { typedef tcu::Vector<float, TexTypeCoordDims<TexType>::V> t; }; 174 175 template <TextureType> struct TexTypeCoordParams; 176 177 template <> struct 178 TexTypeCoordParams<TEXTURETYPE_2D> 179 { 180 Vec2 scale; 181 Vec2 bias; 182 183 TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_) : scale(scale_), bias(bias_) {} 184 }; 185 186 template <> struct 187 TexTypeCoordParams<TEXTURETYPE_CUBE> 188 { 189 Vec2 scale; 190 Vec2 bias; 191 tcu::CubeFace face; 192 193 TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_, tcu::CubeFace face_) : scale(scale_), bias(bias_), face(face_) {} 194 }; 195 196 template <> struct 197 TexTypeCoordParams<TEXTURETYPE_2D_ARRAY> 198 { 199 Mat3 transform; 200 201 TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {} 202 }; 203 204 template <> struct 205 TexTypeCoordParams<TEXTURETYPE_3D> 206 { 207 Mat3 transform; 208 209 TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {} 210 }; 211 212 /*--------------------------------------------------------------------*//*! 213 * \brief Quad grid class containing position and texture coordinate data. 214 * 215 * A quad grid of size S means a grid consisting of S*S quads (S rows and 216 * S columns). The quads are rectangles with main axis aligned sides, and 217 * each consists of two triangles. Note that although there are only 218 * (S+1)*(S+1) distinct vertex positions, there are S*S*4 distinct vertices 219 * because we want texture coordinates to be constant across the vertices 220 * of a quad (to avoid interpolation issues), and thus each quad needs its 221 * own 4 vertices. 222 * 223 * Pointers returned by get*Ptr() are suitable for gl calls such as 224 * glVertexAttribPointer() (for position and tex coord) or glDrawElements() 225 * (for indices). 226 *//*--------------------------------------------------------------------*/ 227 template <TextureType TexType> 228 class PosTexCoordQuadGrid 229 { 230 private: 231 enum { TEX_COORD_DIMS = TexTypeCoordDims <TexType>::V }; 232 typedef typename TexTypeCoordVec<TexType>::t TexCoordVec; 233 typedef typename TexTypeSizeIVec<TexType>::t TexSizeIVec; 234 typedef TexTypeCoordParams<TexType> TexCoordParams; 235 236 public: 237 PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords); 238 239 int getSize (void) const { return m_gridSize; } 240 Vec4 getQuadLDRU (int col, int row) const; //!< Vec4(leftX, downY, rightX, upY) 241 const TexCoordVec& getQuadTexCoord (int col, int row) const; 242 243 int getNumIndices (void) const { return m_gridSize*m_gridSize*3*2; } 244 const float* getPositionPtr (void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; } 245 const float* getTexCoordPtr (void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; } 246 const deUint16* getIndexPtr (void) const { return &m_indices[0]; } 247 248 private: 249 void initializeTexCoords (const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords); 250 251 const int m_gridSize; 252 vector<Vec2> m_positions; 253 vector<TexCoordVec> m_texCoords; 254 vector<deUint16> m_indices; 255 }; 256 257 template <TextureType TexType> 258 Vec4 PosTexCoordQuadGrid<TexType>::getQuadLDRU (int col, int row) const 259 { 260 int ndx00 = (row*m_gridSize + col) * 4; 261 int ndx11 = ndx00 + 3; 262 263 return Vec4(m_positions[ndx00].x(), 264 m_positions[ndx00].y(), 265 m_positions[ndx11].x(), 266 m_positions[ndx11].y()); 267 } 268 269 template <TextureType TexType> 270 const typename TexTypeCoordVec<TexType>::t& PosTexCoordQuadGrid<TexType>::getQuadTexCoord (int col, int row) const 271 { 272 return m_texCoords[(row*m_gridSize + col) * 4]; 273 } 274 275 template <TextureType TexType> 276 PosTexCoordQuadGrid<TexType>::PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 277 : m_gridSize(gridSize) 278 { 279 DE_ASSERT(m_gridSize > 0 && m_gridSize*m_gridSize <= (int)std::numeric_limits<deUint16>::max() + 1); 280 281 const float gridSizeFloat = (float)m_gridSize; 282 283 m_positions.reserve(m_gridSize*m_gridSize*4); 284 m_indices.reserve(m_gridSize*m_gridSize*3*2); 285 286 for (int y = 0; y < m_gridSize; y++) 287 for (int x = 0; x < m_gridSize; x++) 288 { 289 float fx0 = (float)(x+0) / gridSizeFloat; 290 float fx1 = (float)(x+1) / gridSizeFloat; 291 float fy0 = (float)(y+0) / gridSizeFloat; 292 float fy1 = (float)(y+1) / gridSizeFloat; 293 294 Vec2 quadVertices[4] = { Vec2(fx0, fy0), Vec2(fx1, fy0), Vec2(fx0, fy1), Vec2(fx1, fy1) }; 295 296 int firstNdx = (int)m_positions.size(); 297 298 for (int i = 0; i < DE_LENGTH_OF_ARRAY(quadVertices); i++) 299 m_positions.push_back(safeCoords(quadVertices[i], renderSize, Vec2(0.0f)) * 2.0f - 1.0f); 300 301 m_indices.push_back(firstNdx + 0); 302 m_indices.push_back(firstNdx + 1); 303 m_indices.push_back(firstNdx + 2); 304 305 m_indices.push_back(firstNdx + 1); 306 m_indices.push_back(firstNdx + 3); 307 m_indices.push_back(firstNdx + 2); 308 } 309 310 m_texCoords.reserve(m_gridSize*m_gridSize*4); 311 initializeTexCoords(textureSize, texCoordParams, useSafeTexCoords); 312 313 DE_ASSERT((int)m_positions.size() == m_gridSize*m_gridSize*4); 314 DE_ASSERT((int)m_indices.size() == m_gridSize*m_gridSize*3*2); 315 DE_ASSERT((int)m_texCoords.size() == m_gridSize*m_gridSize*4); 316 } 317 318 template <> 319 void PosTexCoordQuadGrid<TEXTURETYPE_2D>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 320 { 321 DE_ASSERT(m_texCoords.empty()); 322 323 const float gridSizeFloat = (float)m_gridSize; 324 325 for (int y = 0; y < m_gridSize; y++) 326 for (int x = 0; x < m_gridSize; x++) 327 { 328 Vec2 rawCoord = Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) * texCoordParams.scale + texCoordParams.bias; 329 330 for (int i = 0; i < 4; i++) 331 m_texCoords.push_back(useSafeTexCoords ? safe2DTexCoords(rawCoord, textureSize) : rawCoord); 332 } 333 } 334 335 template <> 336 void PosTexCoordQuadGrid<TEXTURETYPE_CUBE>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 337 { 338 DE_ASSERT(m_texCoords.empty()); 339 340 const float gridSizeFloat = (float)m_gridSize; 341 vector<float> texBoundaries; 342 computeQuadTexCoordCube(texBoundaries, texCoordParams.face); 343 const Vec3 coordA = Vec3(texBoundaries[0], texBoundaries[1], texBoundaries[2]); 344 const Vec3 coordB = Vec3(texBoundaries[3], texBoundaries[4], texBoundaries[5]); 345 const Vec3 coordC = Vec3(texBoundaries[6], texBoundaries[7], texBoundaries[8]); 346 const Vec3 coordAB = coordB - coordA; 347 const Vec3 coordAC = coordC - coordA; 348 349 for (int y = 0; y < m_gridSize; y++) 350 for (int x = 0; x < m_gridSize; x++) 351 { 352 const Vec2 rawFaceCoord = texCoordParams.scale * Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) + texCoordParams.bias; 353 const Vec2 safeFaceCoord = useSafeTexCoords ? safe2DTexCoords(rawFaceCoord, textureSize) : rawFaceCoord; 354 const Vec3 texCoord = coordA + coordAC*safeFaceCoord.x() + coordAB*safeFaceCoord.y(); 355 356 for (int i = 0; i < 4; i++) 357 m_texCoords.push_back(texCoord); 358 } 359 } 360 361 template <> 362 void PosTexCoordQuadGrid<TEXTURETYPE_2D_ARRAY>::initializeTexCoords (const IVec3& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 363 { 364 DE_ASSERT(m_texCoords.empty()); 365 366 const float gridSizeFloat = (float)m_gridSize; 367 368 for (int y = 0; y < m_gridSize; y++) 369 for (int x = 0; x < m_gridSize; x++) 370 { 371 const Vec3 rawCoord = texCoordParams.transform * Vec3((float)x / gridSizeFloat, (float)y / gridSizeFloat, 1.0f); 372 373 for (int i = 0; i < 4; i++) 374 m_texCoords.push_back(useSafeTexCoords ? safe2DArrayTexCoords(rawCoord, textureSize) : rawCoord); 375 } 376 } 377 378 template <> 379 void PosTexCoordQuadGrid<TEXTURETYPE_3D>::initializeTexCoords (const IVec3& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) 380 { 381 DE_ASSERT(m_texCoords.empty()); 382 383 const float gridSizeFloat = (float)m_gridSize; 384 385 for (int y = 0; y < m_gridSize; y++) 386 for (int x = 0; x < m_gridSize; x++) 387 { 388 Vec3 rawCoord = texCoordParams.transform * Vec3((float)x / gridSizeFloat, (float)y / gridSizeFloat, 1.0f); 389 390 for (int i = 0; i < 4; i++) 391 m_texCoords.push_back(useSafeTexCoords ? safe3DTexCoords(rawCoord, textureSize) : rawCoord); 392 } 393 } 394 395 } // anonymous 396 397 static inline bool isLevelNearest (deUint32 filter) 398 { 399 return filter == GL_NEAREST || filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_NEAREST_MIPMAP_LINEAR; 400 } 401 402 static inline IVec2 getTextureSize (const glu::Texture2D& tex) 403 { 404 const tcu::Texture2D& ref = tex.getRefTexture(); 405 return IVec2(ref.getWidth(), ref.getHeight()); 406 } 407 408 static inline IVec2 getTextureSize (const glu::TextureCube& tex) 409 { 410 const tcu::TextureCube& ref = tex.getRefTexture(); 411 return IVec2(ref.getSize(), ref.getSize()); 412 } 413 414 static inline IVec3 getTextureSize (const glu::Texture2DArray& tex) 415 { 416 const tcu::Texture2DArray& ref = tex.getRefTexture(); 417 return IVec3(ref.getWidth(), ref.getHeight(), ref.getNumLayers()); 418 } 419 420 static inline IVec3 getTextureSize (const glu::Texture3D& tex) 421 { 422 const tcu::Texture3D& ref = tex.getRefTexture(); 423 return IVec3(ref.getWidth(), ref.getHeight(), ref.getDepth()); 424 } 425 426 template <TextureType TexType> 427 static void setPixelColors (const vector<Vec4>& quadColors, const Rect& region, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst) 428 { 429 const int gridSize = grid.getSize(); 430 431 for (int y = 0; y < gridSize; y++) 432 for (int x = 0; x < gridSize; x++) 433 { 434 const Vec4 color = quadColors[y*gridSize + x]; 435 const Vec4 ldru = grid.getQuadLDRU(x, y) * 0.5f + 0.5f; // [-1, 1] -> [0, 1] 436 const int ix0 = deCeilFloatToInt32(ldru.x() * (float)region.w - 0.5f); 437 const int ix1 = deCeilFloatToInt32(ldru.z() * (float)region.w - 0.5f); 438 const int iy0 = deCeilFloatToInt32(ldru.y() * (float)region.h - 0.5f); 439 const int iy1 = deCeilFloatToInt32(ldru.w() * (float)region.h - 0.5f); 440 441 for (int iy = iy0; iy < iy1; iy++) 442 for (int ix = ix0; ix < ix1; ix++) 443 { 444 DE_ASSERT(deInBounds32(ix + region.x, 0, dst.getWidth())); 445 DE_ASSERT(deInBounds32(iy + region.y, 0, dst.getHeight())); 446 447 dst.setPixel(ix + region.x, iy + region.y, toRGBA(color)); 448 } 449 } 450 } 451 452 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); } 453 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); } 454 static inline Vec4 sample (const tcu::Texture2DArray& tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); } 455 static inline Vec4 sample (const tcu::Texture3D& tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); } 456 457 template <TextureType TexType> 458 void computeReference (const typename TexTypeTcuClass<TexType>::t& texture, float lod, const tcu::Sampler& sampler, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst, const Rect& dstRegion) 459 { 460 const int gridSize = grid.getSize(); 461 vector<Vec4> quadColors (gridSize*gridSize); 462 463 for (int y = 0; y < gridSize; y++) 464 for (int x = 0; x < gridSize; x++) 465 { 466 const int ndx = y*gridSize + x; 467 const typename TexTypeCoordVec<TexType>::t& coord = grid.getQuadTexCoord(x, y); 468 469 quadColors[ndx] = sample(texture, coord, lod, sampler); 470 } 471 472 setPixelColors(quadColors, dstRegion, grid, dst); 473 } 474 475 static bool compareImages (const glu::RenderContext& renderCtx, tcu::TestLog& log, const tcu::Surface& ref, const tcu::Surface& res) 476 { 477 DE_ASSERT(renderCtx.getRenderTarget().getNumSamples() == 0); 478 479 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(15,15,15,15); 480 return tcu::pixelThresholdCompare(log, "Result", "Image compare result", ref, res, threshold, tcu::COMPARE_LOG_RESULT); 481 } 482 483 class Vertex2DTextureCase : public TestCase 484 { 485 public: 486 Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); 487 ~Vertex2DTextureCase (void); 488 489 void init (void); 490 void deinit (void); 491 IterateResult iterate (void); 492 493 private: 494 typedef PosTexCoordQuadGrid<TEXTURETYPE_2D> Grid; 495 496 Vertex2DTextureCase (const Vertex2DTextureCase& other); 497 Vertex2DTextureCase& operator= (const Vertex2DTextureCase& other); 498 499 float calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const; 500 void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; 501 void renderCell (int textureNdx, float lod, const Grid& grid) const; 502 void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; 503 504 const deUint32 m_minFilter; 505 const deUint32 m_magFilter; 506 const deUint32 m_wrapS; 507 const deUint32 m_wrapT; 508 509 const glu::ShaderProgram* m_program; 510 glu::Texture2D* m_textures[2]; // 2 textures, a gradient texture and a grid texture. 511 }; 512 513 Vertex2DTextureCase::Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) 514 : TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) 515 , m_minFilter (minFilter) 516 , m_magFilter (magFilter) 517 , m_wrapS (wrapS) 518 , m_wrapT (wrapT) 519 , m_program (DE_NULL) 520 { 521 m_textures[0] = DE_NULL; 522 m_textures[1] = DE_NULL; 523 } 524 525 Vertex2DTextureCase::~Vertex2DTextureCase(void) 526 { 527 Vertex2DTextureCase::deinit(); 528 } 529 530 void Vertex2DTextureCase::init (void) 531 { 532 const char* const vertexShader = 533 "#version 300 es\n" 534 "in highp vec2 a_position;\n" 535 "in highp vec2 a_texCoord;\n" 536 "uniform highp sampler2D u_texture;\n" 537 "uniform highp float u_lod;\n" 538 "out mediump vec4 v_color;\n" 539 "\n" 540 "void main()\n" 541 "{\n" 542 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 543 " v_color = textureLod(u_texture, a_texCoord, u_lod);\n" 544 "}\n"; 545 546 const char* const fragmentShader = 547 "#version 300 es\n" 548 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 549 "in mediump vec4 v_color;\n" 550 "\n" 551 "void main()\n" 552 "{\n" 553 " dEQP_FragColor = v_color;\n" 554 "}\n"; 555 556 if (m_context.getRenderTarget().getNumSamples() != 0) 557 throw tcu::NotSupportedError("MSAA config not supported by this test"); 558 559 DE_ASSERT(!m_program); 560 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader)); 561 562 if(!m_program->isOk()) 563 { 564 m_testCtx.getLog() << *m_program; 565 566 GLint maxVertexTextures; 567 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); 568 569 if (maxVertexTextures < 1) 570 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); 571 else 572 TCU_FAIL("Failed to compile shader"); 573 } 574 575 // Make the textures. 576 try 577 { 578 // Compute suitable power-of-two sizes (for mipmaps). 579 const int texWidth = 1 << deLog2Ceil32(MAX_2D_RENDER_WIDTH / 2); 580 const int texHeight = 1 << deLog2Ceil32(MAX_2D_RENDER_HEIGHT / 2); 581 582 for (int i = 0; i < 2; i++) 583 { 584 DE_ASSERT(!m_textures[i]); 585 m_textures[i] = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight); 586 } 587 588 const bool mipmaps = (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight)); 589 const int numLevels = mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1; 590 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 591 const Vec4 cBias = fmtInfo.valueMin; 592 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 593 594 // Fill first with gradient texture. 595 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 596 { 597 const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias; 598 const Vec4 gMax = Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 599 600 m_textures[0]->getRefTexture().allocLevel(levelNdx); 601 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); 602 } 603 604 // Fill second with grid texture. 605 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 606 { 607 const deUint32 step = 0x00ffffff / numLevels; 608 const deUint32 rgb = step*levelNdx; 609 const deUint32 colorA = 0xff000000 | rgb; 610 const deUint32 colorB = 0xff000000 | ~rgb; 611 612 m_textures[1]->getRefTexture().allocLevel(levelNdx); 613 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 614 } 615 616 // Upload. 617 for (int i = 0; i < 2; i++) 618 m_textures[i]->upload(); 619 } 620 catch (const std::exception&) 621 { 622 // Clean up to save memory. 623 Vertex2DTextureCase::deinit(); 624 throw; 625 } 626 } 627 628 void Vertex2DTextureCase::deinit (void) 629 { 630 for (int i = 0; i < 2; i++) 631 { 632 delete m_textures[i]; 633 m_textures[i] = DE_NULL; 634 } 635 636 delete m_program; 637 m_program = DE_NULL; 638 } 639 640 float Vertex2DTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const 641 { 642 const tcu::Texture2D& refTexture = m_textures[textureNdx]->getRefTexture(); 643 const Vec2 srcSize = Vec2((float)refTexture.getWidth(), (float)refTexture.getHeight()); 644 const Vec2 sizeRatio = texScale*srcSize / dstSize; 645 646 // \note In this particular case dv/dx and du/dy are zero, simplifying the expression. 647 return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y())); 648 } 649 650 Vertex2DTextureCase::IterateResult Vertex2DTextureCase::iterate (void) 651 { 652 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_RENDER_WIDTH); 653 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_RENDER_HEIGHT); 654 655 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; 656 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; 657 658 de::Random rnd (deStringHash(getName())); 659 660 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); 661 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); 662 663 glUseProgram(m_program->getProgram()); 664 665 // Divide viewport into 4 cells. 666 const int leftWidth = viewportWidth / 2; 667 const int rightWidth = viewportWidth - leftWidth; 668 const int bottomHeight = viewportHeight / 2; 669 const int topHeight = viewportHeight - bottomHeight; 670 671 // Clear. 672 glClearColor(0.125f, 0.25f, 0.5f, 1.0f); 673 glClear(GL_COLOR_BUFFER_BIT); 674 675 // Texture scaling and offsetting vectors. 676 const Vec2 texMinScale (+1.8f, +1.8f); 677 const Vec2 texMinOffset (-0.3f, -0.2f); 678 const Vec2 texMagScale (+0.3f, +0.3f); 679 const Vec2 texMagOffset (+0.9f, +0.8f); 680 681 // Surface for the reference image. 682 tcu::Surface refImage(viewportWidth, viewportHeight); 683 684 { 685 const struct Render 686 { 687 const Rect region; 688 int textureNdx; 689 const Vec2 texCoordScale; 690 const Vec2 texCoordOffset; 691 Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {} 692 } renders[] = 693 { 694 Render(Rect(0, 0, leftWidth, bottomHeight), 0, texMinScale, texMinOffset), 695 Render(Rect(leftWidth, 0, rightWidth, bottomHeight), 0, texMagScale, texMagOffset), 696 Render(Rect(0, bottomHeight, leftWidth, topHeight), 1, texMinScale, texMinOffset), 697 Render(Rect(leftWidth, bottomHeight, rightWidth, topHeight), 1, texMagScale, texMagOffset) 698 }; 699 700 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) 701 { 702 const Render& rend = renders[renderNdx]; 703 const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx); 704 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); 705 const Grid grid (GRID_SIZE_2D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), 706 TexTypeCoordParams<TEXTURETYPE_2D>(rend.texCoordScale, rend.texCoordOffset), useSafeTexCoords); 707 708 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); 709 renderCell (rend.textureNdx, lod, grid); 710 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); 711 } 712 } 713 714 // Read back rendered results. 715 tcu::Surface resImage(viewportWidth, viewportHeight); 716 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); 717 718 glUseProgram(0); 719 720 // Compare and log. 721 { 722 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); 723 724 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 725 isOk ? "Pass" : "Image comparison failed"); 726 } 727 728 return STOP; 729 } 730 731 void Vertex2DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const 732 { 733 const deUint32 programID = m_program->getProgram(); 734 735 // SETUP ATTRIBUTES. 736 737 { 738 const int positionLoc = glGetAttribLocation(programID, "a_position"); 739 if (positionLoc != -1) 740 { 741 glEnableVertexAttribArray(positionLoc); 742 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); 743 } 744 } 745 746 { 747 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); 748 if (texCoordLoc != -1) 749 { 750 glEnableVertexAttribArray(texCoordLoc); 751 glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); 752 } 753 } 754 755 // SETUP UNIFORMS. 756 757 { 758 const int lodLoc = glGetUniformLocation(programID, "u_lod"); 759 if (lodLoc != -1) 760 glUniform1f(lodLoc, lod); 761 } 762 763 glActiveTexture(GL_TEXTURE0); 764 glBindTexture(GL_TEXTURE_2D, m_textures[textureNdx]->getGLTexture()); 765 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); 766 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); 767 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); 768 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); 769 770 { 771 const int texLoc = glGetUniformLocation(programID, "u_texture"); 772 if (texLoc != -1) 773 glUniform1i(texLoc, 0); 774 } 775 } 776 777 // Renders one sub-image with given parameters. 778 void Vertex2DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const 779 { 780 setupShaderInputs(textureNdx, lod, grid); 781 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); 782 } 783 784 void Vertex2DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const 785 { 786 computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion); 787 } 788 789 class VertexCubeTextureCase : public TestCase 790 { 791 public: 792 VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); 793 ~VertexCubeTextureCase (void); 794 795 void init (void); 796 void deinit (void); 797 IterateResult iterate (void); 798 799 private: 800 typedef PosTexCoordQuadGrid<TEXTURETYPE_CUBE> Grid; 801 802 VertexCubeTextureCase (const VertexCubeTextureCase& other); 803 VertexCubeTextureCase& operator= (const VertexCubeTextureCase& other); 804 805 float calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const; 806 void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; 807 void renderCell (int textureNdx, float lod, const Grid& grid) const; 808 void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; 809 810 const deUint32 m_minFilter; 811 const deUint32 m_magFilter; 812 const deUint32 m_wrapS; 813 const deUint32 m_wrapT; 814 815 const glu::ShaderProgram* m_program; 816 glu::TextureCube* m_textures[2]; // 2 textures, a gradient texture and a grid texture. 817 }; 818 819 VertexCubeTextureCase::VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) 820 : TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) 821 , m_minFilter (minFilter) 822 , m_magFilter (magFilter) 823 , m_wrapS (wrapS) 824 , m_wrapT (wrapT) 825 , m_program (DE_NULL) 826 { 827 m_textures[0] = DE_NULL; 828 m_textures[1] = DE_NULL; 829 } 830 831 VertexCubeTextureCase::~VertexCubeTextureCase(void) 832 { 833 VertexCubeTextureCase::deinit(); 834 } 835 836 void VertexCubeTextureCase::init (void) 837 { 838 const char* const vertexShader = 839 "#version 300 es\n" 840 "in highp vec2 a_position;\n" 841 "in highp vec3 a_texCoord;\n" 842 "uniform highp samplerCube u_texture;\n" 843 "uniform highp float u_lod;\n" 844 "out mediump vec4 v_color;\n" 845 "\n" 846 "void main()\n" 847 "{\n" 848 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 849 " v_color = textureLod(u_texture, a_texCoord, u_lod);\n" 850 "}\n"; 851 852 const char* const fragmentShader = 853 "#version 300 es\n" 854 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 855 "in mediump vec4 v_color;\n" 856 "\n" 857 "void main()\n" 858 "{\n" 859 " dEQP_FragColor = v_color;\n" 860 "}\n"; 861 862 if (m_context.getRenderTarget().getNumSamples() != 0) 863 throw tcu::NotSupportedError("MSAA config not supported by this test"); 864 865 DE_ASSERT(!m_program); 866 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader)); 867 868 if(!m_program->isOk()) 869 { 870 m_testCtx.getLog() << *m_program; 871 872 GLint maxVertexTextures; 873 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); 874 875 if (maxVertexTextures < 1) 876 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); 877 else 878 TCU_FAIL("Failed to compile shader"); 879 } 880 881 // Make the textures. 882 try 883 { 884 // Compute suitable power-of-two sizes (for mipmaps). 885 const int texWidth = 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2); 886 const int texHeight = 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2); 887 888 DE_ASSERT(texWidth == texHeight); 889 DE_UNREF(texHeight); 890 891 for (int i = 0; i < 2; i++) 892 { 893 DE_ASSERT(!m_textures[i]); 894 m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth); 895 } 896 897 const bool mipmaps = deIsPowerOfTwo32(texWidth) != DE_FALSE; 898 const int numLevels = mipmaps ? deLog2Floor32(texWidth)+1 : 1; 899 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 900 const Vec4 cBias = fmtInfo.valueMin; 901 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 902 903 // Fill first with gradient texture. 904 static const Vec4 gradients[tcu::CUBEFACE_LAST][2] = 905 { 906 { Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x 907 { Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x 908 { Vec4(-1.0f, 0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y 909 { Vec4(-1.0f, -1.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y 910 { Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z 911 { Vec4( 0.0f, 0.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z 912 }; 913 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 914 { 915 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 916 { 917 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 918 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias); 919 } 920 } 921 922 // Fill second with grid texture. 923 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 924 { 925 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 926 { 927 const deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST); 928 const deUint32 rgb = step*levelNdx*face; 929 const deUint32 colorA = 0xff000000 | rgb; 930 const deUint32 colorB = 0xff000000 | ~rgb; 931 932 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 933 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 934 } 935 } 936 937 // Upload. 938 for (int i = 0; i < 2; i++) 939 m_textures[i]->upload(); 940 } 941 catch (const std::exception&) 942 { 943 // Clean up to save memory. 944 VertexCubeTextureCase::deinit(); 945 throw; 946 } 947 } 948 949 void VertexCubeTextureCase::deinit (void) 950 { 951 for (int i = 0; i < 2; i++) 952 { 953 delete m_textures[i]; 954 m_textures[i] = DE_NULL; 955 } 956 957 delete m_program; 958 m_program = DE_NULL; 959 } 960 961 float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const 962 { 963 const tcu::TextureCube& refTexture = m_textures[textureNdx]->getRefTexture(); 964 const Vec2 srcSize = Vec2((float)refTexture.getSize(), (float)refTexture.getSize()); 965 const Vec2 sizeRatio = texScale*srcSize / dstSize; 966 967 // \note In this particular case, dv/dx and du/dy are zero, simplifying the expression. 968 return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y())); 969 } 970 971 VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void) 972 { 973 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH); 974 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT); 975 976 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; 977 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; 978 979 de::Random rnd (deStringHash(getName())); 980 981 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); 982 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); 983 984 glUseProgram(m_program->getProgram()); 985 986 // Divide viewport into 4 areas. 987 const int leftWidth = viewportWidth / 2; 988 const int rightWidth = viewportWidth - leftWidth; 989 const int bottomHeight = viewportHeight / 2; 990 const int topHeight = viewportHeight - bottomHeight; 991 992 // Clear. 993 glClearColor(0.125f, 0.25f, 0.5f, 1.0f); 994 glClear(GL_COLOR_BUFFER_BIT); 995 996 // Texture scaling and offsetting vectors. 997 const Vec2 texMinScale (1.0f, 1.0f); 998 const Vec2 texMinOffset (0.0f, 0.0f); 999 const Vec2 texMagScale (0.3f, 0.3f); 1000 const Vec2 texMagOffset (0.5f, 0.3f); 1001 1002 // Surface for the reference image. 1003 tcu::Surface refImage(viewportWidth, viewportHeight); 1004 1005 // Each of the four areas is divided into 6 cells. 1006 const int defCellWidth = viewportWidth / 2 / 3; 1007 const int defCellHeight = viewportHeight / 2 / 2; 1008 1009 for (int i = 0; i < tcu::CUBEFACE_LAST; i++) 1010 { 1011 const int cellOffsetX = defCellWidth * (i % 3); 1012 const int cellOffsetY = defCellHeight * (i / 3); 1013 const bool isRightmostCell = i == 2 || i == 5; 1014 const bool isTopCell = i >= 3; 1015 const int leftCellWidth = isRightmostCell ? leftWidth - cellOffsetX : defCellWidth; 1016 const int rightCellWidth = isRightmostCell ? rightWidth - cellOffsetX : defCellWidth; 1017 const int bottomCellHeight = isTopCell ? bottomHeight - cellOffsetY : defCellHeight; 1018 const int topCellHeight = isTopCell ? topHeight - cellOffsetY : defCellHeight; 1019 1020 const struct Render 1021 { 1022 const Rect region; 1023 int textureNdx; 1024 const Vec2 texCoordScale; 1025 const Vec2 texCoordOffset; 1026 Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {} 1027 } renders[] = 1028 { 1029 Render(Rect(cellOffsetX + 0, cellOffsetY + 0, leftCellWidth, bottomCellHeight), 0, texMinScale, texMinOffset), 1030 Render(Rect(cellOffsetX + leftWidth, cellOffsetY + 0, rightCellWidth, bottomCellHeight), 0, texMagScale, texMagOffset), 1031 Render(Rect(cellOffsetX + 0, cellOffsetY + bottomHeight, leftCellWidth, topCellHeight), 1, texMinScale, texMinOffset), 1032 Render(Rect(cellOffsetX + leftWidth, cellOffsetY + bottomHeight, rightCellWidth, topCellHeight), 1, texMagScale, texMagOffset) 1033 }; 1034 1035 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) 1036 { 1037 const Render& rend = renders[renderNdx]; 1038 const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx); 1039 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); 1040 const Grid grid (GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), 1041 TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords); 1042 1043 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); 1044 renderCell (rend.textureNdx, lod, grid); 1045 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); 1046 } 1047 } 1048 1049 // Read back rendered results. 1050 tcu::Surface resImage(viewportWidth, viewportHeight); 1051 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); 1052 1053 glUseProgram(0); 1054 1055 // Compare and log. 1056 { 1057 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); 1058 1059 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1060 isOk ? "Pass" : "Image comparison failed"); 1061 } 1062 1063 return STOP; 1064 } 1065 1066 void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const 1067 { 1068 const deUint32 programID = m_program->getProgram(); 1069 1070 // SETUP ATTRIBUTES. 1071 1072 { 1073 const int positionLoc = glGetAttribLocation(programID, "a_position"); 1074 if (positionLoc != -1) 1075 { 1076 glEnableVertexAttribArray(positionLoc); 1077 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); 1078 } 1079 } 1080 1081 { 1082 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); 1083 if (texCoordLoc != -1) 1084 { 1085 glEnableVertexAttribArray(texCoordLoc); 1086 glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); 1087 } 1088 } 1089 1090 // SETUP UNIFORMS. 1091 1092 { 1093 const int lodLoc = glGetUniformLocation(programID, "u_lod"); 1094 if (lodLoc != -1) 1095 glUniform1f(lodLoc, lod); 1096 } 1097 1098 glActiveTexture(GL_TEXTURE0); 1099 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture()); 1100 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 1101 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 1102 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 1103 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 1104 1105 { 1106 const int texLoc = glGetUniformLocation(programID, "u_texture"); 1107 if (texLoc != -1) 1108 glUniform1i(texLoc, 0); 1109 } 1110 } 1111 1112 // Renders one cube face with given parameters. 1113 void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const 1114 { 1115 setupShaderInputs(textureNdx, lod, grid); 1116 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); 1117 } 1118 1119 // Computes reference for one cube face with given parameters. 1120 void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const 1121 { 1122 tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); 1123 sampler.seamlessCubeMap = true; 1124 computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion); 1125 } 1126 1127 class Vertex2DArrayTextureCase : public TestCase 1128 { 1129 public: 1130 Vertex2DArrayTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); 1131 ~Vertex2DArrayTextureCase (void); 1132 1133 void init (void); 1134 void deinit (void); 1135 IterateResult iterate (void); 1136 1137 private: 1138 typedef PosTexCoordQuadGrid<TEXTURETYPE_2D_ARRAY> Grid; 1139 1140 Vertex2DArrayTextureCase (const Vertex2DArrayTextureCase& other); 1141 Vertex2DArrayTextureCase& operator= (const Vertex2DArrayTextureCase& other); 1142 1143 float calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const; 1144 void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; 1145 void renderCell (int textureNdx, float lod, const Grid& grid) const; 1146 void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; 1147 1148 const deUint32 m_minFilter; 1149 const deUint32 m_magFilter; 1150 const deUint32 m_wrapS; 1151 const deUint32 m_wrapT; 1152 1153 const glu::ShaderProgram* m_program; 1154 glu::Texture2DArray* m_textures[2]; // 2 textures, a gradient texture and a grid texture. 1155 }; 1156 1157 Vertex2DArrayTextureCase::Vertex2DArrayTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) 1158 : TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) 1159 , m_minFilter (minFilter) 1160 , m_magFilter (magFilter) 1161 , m_wrapS (wrapS) 1162 , m_wrapT (wrapT) 1163 , m_program (DE_NULL) 1164 { 1165 m_textures[0] = DE_NULL; 1166 m_textures[1] = DE_NULL; 1167 } 1168 1169 Vertex2DArrayTextureCase::~Vertex2DArrayTextureCase(void) 1170 { 1171 Vertex2DArrayTextureCase::deinit(); 1172 } 1173 1174 void Vertex2DArrayTextureCase::init (void) 1175 { 1176 const char* const vertexShaderSource = 1177 "#version 300 es\n" 1178 "in highp vec2 a_position;\n" 1179 "in highp vec3 a_texCoord;\n" 1180 "uniform highp sampler2DArray u_texture;\n" 1181 "uniform highp float u_lod;\n" 1182 "out mediump vec4 v_color;\n" 1183 "\n" 1184 "void main()\n" 1185 "{\n" 1186 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 1187 " v_color = textureLod(u_texture, a_texCoord, u_lod);\n" 1188 "}\n"; 1189 1190 const char* const fragmentShaderSource = 1191 "#version 300 es\n" 1192 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 1193 "in mediump vec4 v_color;\n" 1194 "\n" 1195 "void main()\n" 1196 "{\n" 1197 " dEQP_FragColor = v_color;\n" 1198 "}\n"; 1199 1200 if (m_context.getRenderTarget().getNumSamples() != 0) 1201 throw tcu::NotSupportedError("MSAA config not supported by this test"); 1202 1203 // Create shader. 1204 1205 DE_ASSERT(!m_program); 1206 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource)); 1207 1208 if(!m_program->isOk()) 1209 { 1210 m_testCtx.getLog() << *m_program; 1211 1212 GLint maxVertexTextures; 1213 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); 1214 1215 if (maxVertexTextures < 1) 1216 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); 1217 else 1218 TCU_FAIL("Failed to compile shader"); 1219 } 1220 1221 // Make the textures. 1222 1223 try 1224 { 1225 const int texWidth = WIDTH_2D_ARRAY; 1226 const int texHeight = HEIGHT_2D_ARRAY; 1227 const int texLayers = LAYERS_2D_ARRAY; 1228 1229 for (int i = 0; i < 2; i++) 1230 { 1231 DE_ASSERT(!m_textures[i]); 1232 m_textures[i] = new glu::Texture2DArray(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight, texLayers); 1233 } 1234 1235 const int numLevels = deLog2Floor32(de::max(texWidth, texHeight)) + 1; 1236 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 1237 const Vec4 cBias = fmtInfo.valueMin; 1238 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 1239 1240 // Fill first with gradient texture. 1241 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 1242 { 1243 const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias; 1244 const Vec4 gMax = Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 1245 1246 m_textures[0]->getRefTexture().allocLevel(levelNdx); 1247 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); 1248 } 1249 1250 // Fill second with grid texture. 1251 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 1252 { 1253 const deUint32 step = 0x00ffffff / numLevels; 1254 const deUint32 rgb = step*levelNdx; 1255 const deUint32 colorA = 0xff000000 | rgb; 1256 const deUint32 colorB = 0xff000000 | ~rgb; 1257 1258 m_textures[1]->getRefTexture().allocLevel(levelNdx); 1259 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 1260 } 1261 1262 // Upload. 1263 for (int i = 0; i < 2; i++) 1264 m_textures[i]->upload(); 1265 } 1266 catch (const std::exception&) 1267 { 1268 // Clean up to save memory. 1269 Vertex2DArrayTextureCase::deinit(); 1270 throw; 1271 } 1272 } 1273 1274 void Vertex2DArrayTextureCase::deinit (void) 1275 { 1276 for (int i = 0; i < 2; i++) 1277 { 1278 delete m_textures[i]; 1279 m_textures[i] = DE_NULL; 1280 } 1281 1282 delete m_program; 1283 m_program = DE_NULL; 1284 } 1285 1286 float Vertex2DArrayTextureCase::calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const 1287 { 1288 const tcu::Texture2DArray& refTexture = m_textures[textureNdx]->getRefTexture(); 1289 const int texWidth = refTexture.getWidth(); 1290 const int texHeight = refTexture.getHeight(); 1291 1292 // Calculate transformed coordinates of three screen corners. 1293 const Vec2 trans00 = (transf * Vec3(0.0f, 0.0f, 1.0f)).xy(); 1294 const Vec2 trans01 = (transf * Vec3(0.0f, 1.0f, 1.0f)).xy(); 1295 const Vec2 trans10 = (transf * Vec3(1.0f, 0.0f, 1.0f)).xy(); 1296 1297 // Derivates. 1298 const float dudx = (trans10.x() - trans00.x()) * (float)texWidth / dstSize.x(); 1299 const float dudy = (trans01.x() - trans00.x()) * (float)texWidth / dstSize.y(); 1300 const float dvdx = (trans10.y() - trans00.y()) * (float)texHeight / dstSize.x(); 1301 const float dvdy = (trans01.y() - trans00.y()) * (float)texHeight / dstSize.y(); 1302 1303 return deFloatLog2(deFloatSqrt(de::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy))); 1304 } 1305 1306 Vertex2DArrayTextureCase::IterateResult Vertex2DArrayTextureCase::iterate (void) 1307 { 1308 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_ARRAY_RENDER_WIDTH); 1309 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_ARRAY_RENDER_HEIGHT); 1310 1311 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; 1312 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; 1313 1314 de::Random rnd (deStringHash(getName())); 1315 1316 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); 1317 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); 1318 1319 glUseProgram(m_program->getProgram()); 1320 1321 // Divide viewport into 4 cells. 1322 const int leftWidth = viewportWidth / 2; 1323 const int rightWidth = viewportWidth - leftWidth; 1324 const int bottomHeight = viewportHeight / 2; 1325 const int topHeight = viewportHeight - bottomHeight; 1326 1327 // Clear. 1328 glClearColor(0.125f, 0.25f, 0.5f, 1.0f); 1329 glClear(GL_COLOR_BUFFER_BIT); 1330 1331 // Shear by layer count to get all layers visible. 1332 static const float layerShearTransfData[] = 1333 { 1334 1.0f, 0.0f, 0.0f, 1335 0.0f, 1.0f, 0.0f, 1336 (float)LAYERS_2D_ARRAY, 0.0f, 0.0f 1337 }; 1338 1339 // Minification and magnification transformations. 1340 static const float texMinTransfData[] = 1341 { 1342 2.1f, 0.0f, -0.3f, 1343 0.0f, 2.1f, -0.3f, 1344 0.0f, 0.0f, 1.0f 1345 }; 1346 static const float texMagTransfData[] = 1347 { 1348 0.4f, 0.0f, 0.8f, 1349 0.0f, 0.4f, 0.8f, 1350 0.0f, 0.0f, 1.0f 1351 }; 1352 1353 // Transformation matrices for minification and magnification. 1354 const Mat3 texMinTransf = Mat3(layerShearTransfData) * Mat3(texMinTransfData); 1355 const Mat3 texMagTransf = Mat3(layerShearTransfData) * Mat3(texMagTransfData); 1356 1357 // Surface for the reference image. 1358 tcu::Surface refImage(viewportWidth, viewportHeight); 1359 1360 { 1361 const struct Render 1362 { 1363 const Rect region; 1364 int textureNdx; 1365 const Mat3 texTransform; 1366 Render (const Rect& r, int tN, const Mat3& tT) : region(r), textureNdx(tN), texTransform(tT) {} 1367 } renders[] = 1368 { 1369 Render(Rect(0, 0, leftWidth, bottomHeight), 0, texMinTransf), 1370 Render(Rect(leftWidth, 0, rightWidth, bottomHeight), 0, texMagTransf), 1371 Render(Rect(0, bottomHeight, leftWidth, topHeight), 1, texMinTransf), 1372 Render(Rect(leftWidth, bottomHeight, rightWidth, topHeight), 1, texMagTransf) 1373 }; 1374 1375 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) 1376 { 1377 const Render& rend = renders[renderNdx]; 1378 const float lod = calculateLod(rend.texTransform, rend.region.size().asFloat(), rend.textureNdx); 1379 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); 1380 const Grid grid (GRID_SIZE_2D_ARRAY, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), 1381 TexTypeCoordParams<TEXTURETYPE_2D_ARRAY>(rend.texTransform), useSafeTexCoords); 1382 1383 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); 1384 renderCell (rend.textureNdx, lod, grid); 1385 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); 1386 } 1387 } 1388 1389 // Read back rendered results. 1390 tcu::Surface resImage(viewportWidth, viewportHeight); 1391 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); 1392 1393 glUseProgram(0); 1394 1395 // Compare and log. 1396 { 1397 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); 1398 1399 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1400 isOk ? "Pass" : "Image comparison failed"); 1401 } 1402 1403 return STOP; 1404 } 1405 1406 void Vertex2DArrayTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const 1407 { 1408 const deUint32 programID = m_program->getProgram(); 1409 1410 // SETUP ATTRIBUTES. 1411 1412 { 1413 const int positionLoc = glGetAttribLocation(programID, "a_position"); 1414 if (positionLoc != -1) 1415 { 1416 glEnableVertexAttribArray(positionLoc); 1417 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); 1418 } 1419 } 1420 1421 { 1422 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); 1423 if (texCoordLoc != -1) 1424 { 1425 glEnableVertexAttribArray(texCoordLoc); 1426 glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); 1427 } 1428 } 1429 1430 // SETUP UNIFORMS. 1431 1432 { 1433 const int lodLoc = glGetUniformLocation(programID, "u_lod"); 1434 if (lodLoc != -1) 1435 glUniform1f(lodLoc, lod); 1436 } 1437 1438 glActiveTexture(GL_TEXTURE0); 1439 glBindTexture(GL_TEXTURE_2D_ARRAY, m_textures[textureNdx]->getGLTexture()); 1440 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS); 1441 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT); 1442 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter); 1443 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter); 1444 1445 { 1446 const int texLoc = glGetUniformLocation(programID, "u_texture"); 1447 if (texLoc != -1) 1448 glUniform1i(texLoc, 0); 1449 } 1450 } 1451 1452 // Renders one sub-image with given parameters. 1453 void Vertex2DArrayTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const 1454 { 1455 setupShaderInputs(textureNdx, lod, grid); 1456 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); 1457 } 1458 1459 // Computes reference for one sub-image with given parameters. 1460 void Vertex2DArrayTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const 1461 { 1462 computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion); 1463 } 1464 1465 class Vertex3DTextureCase : public TestCase 1466 { 1467 public: 1468 Vertex3DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR); 1469 ~Vertex3DTextureCase (void); 1470 1471 void init (void); 1472 void deinit (void); 1473 IterateResult iterate (void); 1474 1475 private: 1476 typedef PosTexCoordQuadGrid<TEXTURETYPE_3D> Grid; 1477 1478 Vertex3DTextureCase (const Vertex3DTextureCase& other); 1479 Vertex3DTextureCase& operator= (const Vertex3DTextureCase& other); 1480 1481 float calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const; 1482 void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; 1483 void renderCell (int textureNdx, float lod, const Grid& grid) const; 1484 void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; 1485 1486 const deUint32 m_minFilter; 1487 const deUint32 m_magFilter; 1488 const deUint32 m_wrapS; 1489 const deUint32 m_wrapT; 1490 const deUint32 m_wrapR; 1491 1492 const glu::ShaderProgram* m_program; 1493 glu::Texture3D* m_textures[2]; // 2 textures, a gradient texture and a grid texture. 1494 }; 1495 1496 Vertex3DTextureCase::Vertex3DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR) 1497 : TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) 1498 , m_minFilter (minFilter) 1499 , m_magFilter (magFilter) 1500 , m_wrapS (wrapS) 1501 , m_wrapT (wrapT) 1502 , m_wrapR (wrapR) 1503 , m_program (DE_NULL) 1504 { 1505 m_textures[0] = DE_NULL; 1506 m_textures[1] = DE_NULL; 1507 } 1508 1509 Vertex3DTextureCase::~Vertex3DTextureCase(void) 1510 { 1511 Vertex3DTextureCase::deinit(); 1512 } 1513 1514 void Vertex3DTextureCase::init (void) 1515 { 1516 const char* const vertexShaderSource = 1517 "#version 300 es\n" 1518 "in highp vec2 a_position;\n" 1519 "in highp vec3 a_texCoord;\n" 1520 "uniform highp sampler3D u_texture;\n" 1521 "uniform highp float u_lod;\n" 1522 "out mediump vec4 v_color;\n" 1523 "\n" 1524 "void main()\n" 1525 "{\n" 1526 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 1527 " v_color = textureLod(u_texture, a_texCoord, u_lod);\n" 1528 "}\n"; 1529 1530 const char* const fragmentShaderSource = 1531 "#version 300 es\n" 1532 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 1533 "in mediump vec4 v_color;\n" 1534 "\n" 1535 "void main()\n" 1536 "{\n" 1537 " dEQP_FragColor = v_color;\n" 1538 "}\n"; 1539 1540 if (m_context.getRenderTarget().getNumSamples() != 0) 1541 throw tcu::NotSupportedError("MSAA config not supported by this test"); 1542 1543 // Create shader. 1544 1545 DE_ASSERT(!m_program); 1546 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource)); 1547 1548 if(!m_program->isOk()) 1549 { 1550 m_testCtx.getLog() << *m_program; 1551 1552 GLint maxVertexTextures; 1553 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); 1554 1555 if (maxVertexTextures < 1) 1556 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); 1557 else 1558 TCU_FAIL("Failed to compile shader"); 1559 } 1560 1561 // Make the textures. 1562 1563 try 1564 { 1565 const int texWidth = WIDTH_3D; 1566 const int texHeight = HEIGHT_3D; 1567 const int texDepth = DEPTH_3D; 1568 1569 for (int i = 0; i < 2; i++) 1570 { 1571 DE_ASSERT(!m_textures[i]); 1572 m_textures[i] = new glu::Texture3D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight, texDepth); 1573 } 1574 1575 const int numLevels = deLog2Floor32(de::max(de::max(texWidth, texHeight), texDepth)) + 1; 1576 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 1577 const Vec4 cBias = fmtInfo.valueMin; 1578 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 1579 1580 // Fill first with gradient texture. 1581 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 1582 { 1583 const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias; 1584 const Vec4 gMax = Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 1585 1586 m_textures[0]->getRefTexture().allocLevel(levelNdx); 1587 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); 1588 } 1589 1590 // Fill second with grid texture. 1591 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 1592 { 1593 const deUint32 step = 0x00ffffff / numLevels; 1594 const deUint32 rgb = step*levelNdx; 1595 const deUint32 colorA = 0xff000000 | rgb; 1596 const deUint32 colorB = 0xff000000 | ~rgb; 1597 1598 m_textures[1]->getRefTexture().allocLevel(levelNdx); 1599 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias); 1600 } 1601 1602 // Upload. 1603 for (int i = 0; i < 2; i++) 1604 m_textures[i]->upload(); 1605 } 1606 catch (const std::exception&) 1607 { 1608 // Clean up to save memory. 1609 Vertex3DTextureCase::deinit(); 1610 throw; 1611 } 1612 } 1613 1614 void Vertex3DTextureCase::deinit (void) 1615 { 1616 for (int i = 0; i < 2; i++) 1617 { 1618 delete m_textures[i]; 1619 m_textures[i] = DE_NULL; 1620 } 1621 1622 delete m_program; 1623 m_program = DE_NULL; 1624 } 1625 1626 float Vertex3DTextureCase::calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const 1627 { 1628 const tcu::Texture3D& refTexture = m_textures[textureNdx]->getRefTexture(); 1629 const int srcWidth = refTexture.getWidth(); 1630 const int srcHeight = refTexture.getHeight(); 1631 const int srcDepth = refTexture.getDepth(); 1632 1633 // Calculate transformed coordinates of three screen corners. 1634 const Vec3 trans00 = transf * Vec3(0.0f, 0.0f, 1.0f); 1635 const Vec3 trans01 = transf * Vec3(0.0f, 1.0f, 1.0f); 1636 const Vec3 trans10 = transf * Vec3(1.0f, 0.0f, 1.0f); 1637 1638 // Derivates. 1639 const float dudx = (trans10.x() - trans00.x()) * (float)srcWidth / dstSize.x(); 1640 const float dudy = (trans01.x() - trans00.x()) * (float)srcWidth / dstSize.y(); 1641 const float dvdx = (trans10.y() - trans00.y()) * (float)srcHeight / dstSize.x(); 1642 const float dvdy = (trans01.y() - trans00.y()) * (float)srcHeight / dstSize.y(); 1643 const float dwdx = (trans10.z() - trans00.z()) * (float)srcDepth / dstSize.x(); 1644 const float dwdy = (trans01.z() - trans00.z()) * (float)srcDepth / dstSize.y(); 1645 1646 return deFloatLog2(deFloatSqrt(de::max(dudx*dudx + dvdx*dvdx + dwdx*dwdx, dudy*dudy + dvdy*dvdy + dwdy*dwdy))); 1647 } 1648 1649 Vertex3DTextureCase::IterateResult Vertex3DTextureCase::iterate (void) 1650 { 1651 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_3D_RENDER_WIDTH); 1652 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_3D_RENDER_HEIGHT); 1653 1654 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; 1655 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; 1656 1657 de::Random rnd (deStringHash(getName())); 1658 1659 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); 1660 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); 1661 1662 glUseProgram(m_program->getProgram()); 1663 1664 // Divide viewport into 4 cells. 1665 const int leftWidth = viewportWidth / 2; 1666 const int rightWidth = viewportWidth - leftWidth; 1667 const int bottomHeight = viewportHeight / 2; 1668 const int topHeight = viewportHeight - bottomHeight; 1669 1670 // Clear. 1671 glClearColor(0.125f, 0.25f, 0.5f, 1.0f); 1672 glClear(GL_COLOR_BUFFER_BIT); 1673 1674 // Shear to get all slices visible. 1675 static const float depthShearTransfData[] = 1676 { 1677 1.0f, 0.0f, 0.0f, 1678 0.0f, 1.0f, 0.0f, 1679 1.0f, 1.0f, 0.0f 1680 }; 1681 1682 // Minification and magnification transformations. 1683 static const float texMinTransfData[] = 1684 { 1685 2.2f, 0.0f, -0.3f, 1686 0.0f, 2.2f, -0.3f, 1687 0.0f, 0.0f, 1.0f 1688 }; 1689 static const float texMagTransfData[] = 1690 { 1691 0.4f, 0.0f, 0.8f, 1692 0.0f, 0.4f, 0.8f, 1693 0.0f, 0.0f, 1.0f 1694 }; 1695 1696 // Transformation matrices for minification and magnification. 1697 const Mat3 texMinTransf = Mat3(depthShearTransfData) * Mat3(texMinTransfData); 1698 const Mat3 texMagTransf = Mat3(depthShearTransfData) * Mat3(texMagTransfData); 1699 1700 // Surface for the reference image. 1701 tcu::Surface refImage(viewportWidth, viewportHeight); 1702 1703 { 1704 const struct Render 1705 { 1706 const Rect region; 1707 int textureNdx; 1708 const Mat3 texTransform; 1709 Render (const Rect& r, int tN, const Mat3& tT) : region(r), textureNdx(tN), texTransform(tT) {} 1710 } renders[] = 1711 { 1712 Render(Rect(0, 0, leftWidth, bottomHeight), 0, texMinTransf), 1713 Render(Rect(leftWidth, 0, rightWidth, bottomHeight), 0, texMagTransf), 1714 Render(Rect(0, bottomHeight, leftWidth, topHeight), 1, texMinTransf), 1715 Render(Rect(leftWidth, bottomHeight, rightWidth, topHeight), 1, texMagTransf) 1716 }; 1717 1718 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) 1719 { 1720 const Render& rend = renders[renderNdx]; 1721 const float lod = calculateLod(rend.texTransform, rend.region.size().asFloat(), rend.textureNdx); 1722 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); 1723 const Grid grid (GRID_SIZE_3D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), 1724 TexTypeCoordParams<TEXTURETYPE_3D>(rend.texTransform), useSafeTexCoords); 1725 1726 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); 1727 renderCell (rend.textureNdx, lod, grid); 1728 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); 1729 } 1730 } 1731 1732 // Read back rendered results. 1733 tcu::Surface resImage(viewportWidth, viewportHeight); 1734 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); 1735 1736 glUseProgram(0); 1737 1738 // Compare and log. 1739 { 1740 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); 1741 1742 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1743 isOk ? "Pass" : "Image comparison failed"); 1744 } 1745 1746 return STOP; 1747 } 1748 1749 void Vertex3DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const 1750 { 1751 const deUint32 programID = m_program->getProgram(); 1752 1753 // SETUP ATTRIBUTES. 1754 1755 { 1756 const int positionLoc = glGetAttribLocation(programID, "a_position"); 1757 if (positionLoc != -1) 1758 { 1759 glEnableVertexAttribArray(positionLoc); 1760 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); 1761 } 1762 } 1763 1764 { 1765 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); 1766 if (texCoordLoc != -1) 1767 { 1768 glEnableVertexAttribArray(texCoordLoc); 1769 glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); 1770 } 1771 } 1772 1773 // SETUP UNIFORMS. 1774 1775 { 1776 const int lodLoc = glGetUniformLocation(programID, "u_lod"); 1777 if (lodLoc != -1) 1778 glUniform1f(lodLoc, lod); 1779 } 1780 1781 glActiveTexture(GL_TEXTURE0); 1782 glBindTexture(GL_TEXTURE_3D, m_textures[textureNdx]->getGLTexture()); 1783 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, m_wrapS); 1784 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, m_wrapT); 1785 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, m_wrapR); 1786 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, m_minFilter); 1787 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, m_magFilter); 1788 1789 { 1790 const int texLoc = glGetUniformLocation(programID, "u_texture"); 1791 if (texLoc != -1) 1792 glUniform1i(texLoc, 0); 1793 } 1794 } 1795 1796 // Renders one sub-image with given parameters. 1797 void Vertex3DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const 1798 { 1799 setupShaderInputs(textureNdx, lod, grid); 1800 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); 1801 } 1802 1803 // Computes reference for one sub-image with given parameters. 1804 void Vertex3DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const 1805 { 1806 computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter), grid, dst, dstRegion); 1807 } 1808 1809 VertexTextureTests::VertexTextureTests (Context& context) 1810 : TestCaseGroup(context, "vertex", "Vertex Texture Tests") 1811 { 1812 } 1813 1814 VertexTextureTests::~VertexTextureTests(void) 1815 { 1816 } 1817 1818 void VertexTextureTests::init (void) 1819 { 1820 // 2D and cube map groups, and their filtering and wrap sub-groups. 1821 TestCaseGroup* const group2D = new TestCaseGroup(m_context, "2d", "2D Vertex Texture Tests"); 1822 TestCaseGroup* const groupCube = new TestCaseGroup(m_context, "cube", "Cube Map Vertex Texture Tests"); 1823 TestCaseGroup* const group2DArray = new TestCaseGroup(m_context, "2d_array", "2D Array Vertex Texture Tests"); 1824 TestCaseGroup* const group3D = new TestCaseGroup(m_context, "3d", "3D Vertex Texture Tests"); 1825 TestCaseGroup* const filteringGroup2D = new TestCaseGroup(m_context, "filtering", "2D Vertex Texture Filtering Tests"); 1826 TestCaseGroup* const wrapGroup2D = new TestCaseGroup(m_context, "wrap", "2D Vertex Texture Wrap Tests"); 1827 TestCaseGroup* const filteringGroupCube = new TestCaseGroup(m_context, "filtering", "Cube Map Vertex Texture Filtering Tests"); 1828 TestCaseGroup* const wrapGroupCube = new TestCaseGroup(m_context, "wrap", "Cube Map Vertex Texture Wrap Tests"); 1829 TestCaseGroup* const filteringGroup2DArray = new TestCaseGroup(m_context, "filtering", "2D Array Vertex Texture Filtering Tests"); 1830 TestCaseGroup* const wrapGroup2DArray = new TestCaseGroup(m_context, "wrap", "2D Array Vertex Texture Wrap Tests"); 1831 TestCaseGroup* const filteringGroup3D = new TestCaseGroup(m_context, "filtering", "3D Vertex Texture Filtering Tests"); 1832 TestCaseGroup* const wrapGroup3D = new TestCaseGroup(m_context, "wrap", "3D Vertex Texture Wrap Tests"); 1833 1834 group2D->addChild(filteringGroup2D); 1835 group2D->addChild(wrapGroup2D); 1836 groupCube->addChild(filteringGroupCube); 1837 groupCube->addChild(wrapGroupCube); 1838 group2DArray->addChild(filteringGroup2DArray); 1839 group2DArray->addChild(wrapGroup2DArray); 1840 group3D->addChild(filteringGroup3D); 1841 group3D->addChild(wrapGroup3D); 1842 1843 addChild(group2D); 1844 addChild(groupCube); 1845 addChild(group2DArray); 1846 addChild(group3D); 1847 1848 static const struct 1849 { 1850 const char* name; 1851 GLenum mode; 1852 } wrapModes[] = 1853 { 1854 { "clamp", GL_CLAMP_TO_EDGE }, 1855 { "repeat", GL_REPEAT }, 1856 { "mirror", GL_MIRRORED_REPEAT } 1857 }; 1858 1859 static const struct 1860 { 1861 const char* name; 1862 GLenum mode; 1863 } minFilterModes[] = 1864 { 1865 { "nearest", GL_NEAREST }, 1866 { "linear", GL_LINEAR }, 1867 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, 1868 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, 1869 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, 1870 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } 1871 }; 1872 1873 static const struct 1874 { 1875 const char* name; 1876 GLenum mode; 1877 } magFilterModes[] = 1878 { 1879 { "nearest", GL_NEAREST }, 1880 { "linear", GL_LINEAR } 1881 }; 1882 1883 #define FOR_EACH(ITERATOR, ARRAY, BODY) \ 1884 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \ 1885 BODY 1886 1887 // 2D cases. 1888 1889 FOR_EACH(minFilter, minFilterModes, 1890 FOR_EACH(magFilter, magFilterModes, 1891 FOR_EACH(wrapMode, wrapModes, 1892 { 1893 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; 1894 1895 filteringGroup2D->addChild(new Vertex2DTextureCase(m_context, 1896 name.c_str(), "", 1897 minFilterModes[minFilter].mode, 1898 magFilterModes[magFilter].mode, 1899 wrapModes[wrapMode].mode, 1900 wrapModes[wrapMode].mode)); 1901 }))); 1902 1903 FOR_EACH(wrapSMode, wrapModes, 1904 FOR_EACH(wrapTMode, wrapModes, 1905 { 1906 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; 1907 1908 wrapGroup2D->addChild(new Vertex2DTextureCase(m_context, 1909 name.c_str(), "", 1910 GL_LINEAR_MIPMAP_LINEAR, 1911 GL_LINEAR, 1912 wrapModes[wrapSMode].mode, 1913 wrapModes[wrapTMode].mode)); 1914 })); 1915 1916 // Cube map cases. 1917 1918 FOR_EACH(minFilter, minFilterModes, 1919 FOR_EACH(magFilter, magFilterModes, 1920 FOR_EACH(wrapMode, wrapModes, 1921 { 1922 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; 1923 1924 filteringGroupCube->addChild(new VertexCubeTextureCase(m_context, 1925 name.c_str(), "", 1926 minFilterModes[minFilter].mode, 1927 magFilterModes[magFilter].mode, 1928 wrapModes[wrapMode].mode, 1929 wrapModes[wrapMode].mode)); 1930 }))); 1931 1932 FOR_EACH(wrapSMode, wrapModes, 1933 FOR_EACH(wrapTMode, wrapModes, 1934 { 1935 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; 1936 1937 wrapGroupCube->addChild(new VertexCubeTextureCase(m_context, 1938 name.c_str(), "", 1939 GL_LINEAR_MIPMAP_LINEAR, 1940 GL_LINEAR, 1941 wrapModes[wrapSMode].mode, 1942 wrapModes[wrapTMode].mode)); 1943 })); 1944 1945 // 2D array cases. 1946 1947 FOR_EACH(minFilter, minFilterModes, 1948 FOR_EACH(magFilter, magFilterModes, 1949 FOR_EACH(wrapMode, wrapModes, 1950 { 1951 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; 1952 1953 filteringGroup2DArray->addChild(new Vertex2DArrayTextureCase(m_context, 1954 name.c_str(), "", 1955 minFilterModes[minFilter].mode, 1956 magFilterModes[magFilter].mode, 1957 wrapModes[wrapMode].mode, 1958 wrapModes[wrapMode].mode)); 1959 }))); 1960 1961 FOR_EACH(wrapSMode, wrapModes, 1962 FOR_EACH(wrapTMode, wrapModes, 1963 { 1964 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; 1965 1966 wrapGroup2DArray->addChild(new Vertex2DArrayTextureCase(m_context, 1967 name.c_str(), "", 1968 GL_LINEAR_MIPMAP_LINEAR, 1969 GL_LINEAR, 1970 wrapModes[wrapSMode].mode, 1971 wrapModes[wrapTMode].mode)); 1972 })); 1973 1974 // 3D cases. 1975 1976 FOR_EACH(minFilter, minFilterModes, 1977 FOR_EACH(magFilter, magFilterModes, 1978 FOR_EACH(wrapMode, wrapModes, 1979 { 1980 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; 1981 1982 filteringGroup3D->addChild(new Vertex3DTextureCase(m_context, 1983 name.c_str(), "", 1984 minFilterModes[minFilter].mode, 1985 magFilterModes[magFilter].mode, 1986 wrapModes[wrapMode].mode, 1987 wrapModes[wrapMode].mode, 1988 wrapModes[wrapMode].mode)); 1989 }))); 1990 1991 FOR_EACH(wrapSMode, wrapModes, 1992 FOR_EACH(wrapTMode, wrapModes, 1993 FOR_EACH(wrapRMode, wrapModes, 1994 { 1995 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name + "_" + wrapModes[wrapRMode].name; 1996 1997 wrapGroup3D->addChild(new Vertex3DTextureCase(m_context, 1998 name.c_str(), "", 1999 GL_LINEAR_MIPMAP_LINEAR, 2000 GL_LINEAR, 2001 wrapModes[wrapSMode].mode, 2002 wrapModes[wrapTMode].mode, 2003 wrapModes[wrapRMode].mode)); 2004 }))); 2005 } 2006 2007 } // Functional 2008 } // gles3 2009 } // deqp 2010