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