1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 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 Shader Image Load & Store Tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fShaderImageLoadStoreTests.hpp" 25 #include "glsTextureTestUtil.hpp" 26 #include "gluContextInfo.hpp" 27 #include "gluRenderContext.hpp" 28 #include "gluShaderProgram.hpp" 29 #include "gluObjectWrapper.hpp" 30 #include "gluPixelTransfer.hpp" 31 #include "gluTextureUtil.hpp" 32 #include "gluStrUtil.hpp" 33 #include "gluCallLogWrapper.hpp" 34 #include "gluProgramInterfaceQuery.hpp" 35 #include "gluDrawUtil.hpp" 36 #include "tcuTestLog.hpp" 37 #include "tcuTextureUtil.hpp" 38 #include "tcuVector.hpp" 39 #include "tcuImageCompare.hpp" 40 #include "tcuFloat.hpp" 41 #include "tcuVectorUtil.hpp" 42 #include "deStringUtil.hpp" 43 #include "deSharedPtr.hpp" 44 #include "deUniquePtr.hpp" 45 #include "deRandom.hpp" 46 #include "deMemory.h" 47 #include "glwFunctions.hpp" 48 #include "glwDefs.hpp" 49 #include "glwEnums.hpp" 50 51 #include <vector> 52 #include <string> 53 #include <algorithm> 54 #include <map> 55 56 using glu::RenderContext; 57 using tcu::TestLog; 58 using tcu::Vec2; 59 using tcu::Vec3; 60 using tcu::Vec4; 61 using tcu::IVec2; 62 using tcu::IVec3; 63 using tcu::IVec4; 64 using tcu::UVec2; 65 using tcu::UVec3; 66 using tcu::UVec4; 67 using tcu::TextureFormat; 68 using tcu::ConstPixelBufferAccess; 69 using tcu::PixelBufferAccess; 70 using de::toString; 71 using de::SharedPtr; 72 using de::UniquePtr; 73 74 using std::vector; 75 using std::string; 76 77 namespace deqp 78 { 79 80 using namespace gls::TextureTestUtil; 81 82 namespace gles31 83 { 84 namespace Functional 85 { 86 87 //! Default image sizes used in most test cases. 88 static inline IVec3 defaultImageSize (TextureType type) 89 { 90 switch (type) 91 { 92 case TEXTURETYPE_BUFFER: return IVec3(64, 1, 1); 93 case TEXTURETYPE_2D: return IVec3(64, 64, 1); 94 case TEXTURETYPE_CUBE: return IVec3(64, 64, 1); 95 case TEXTURETYPE_3D: return IVec3(64, 64, 8); 96 case TEXTURETYPE_2D_ARRAY: return IVec3(64, 64, 8); 97 default: 98 DE_ASSERT(false); 99 return IVec3(-1); 100 } 101 } 102 103 template <typename T, int Size> 104 static string arrayStr (const T (&arr)[Size]) 105 { 106 string result = "{ "; 107 for (int i = 0; i < Size; i++) 108 result += (i > 0 ? ", " : "") + toString(arr[i]); 109 result += " }"; 110 return result; 111 } 112 113 template <typename T, int N> 114 static int arrayIndexOf (const T (&arr)[N], const T& e) 115 { 116 return (int)(std::find(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), e) - DE_ARRAY_BEGIN(arr)); 117 } 118 119 static const char* getTextureTypeName (TextureType type) 120 { 121 switch (type) 122 { 123 case TEXTURETYPE_BUFFER: return "buffer"; 124 case TEXTURETYPE_2D: return "2d"; 125 case TEXTURETYPE_CUBE: return "cube"; 126 case TEXTURETYPE_3D: return "3d"; 127 case TEXTURETYPE_2D_ARRAY: return "2d_array"; 128 default: 129 DE_ASSERT(false); 130 return DE_NULL; 131 } 132 } 133 134 static inline bool isFormatTypeUnsignedInteger (TextureFormat::ChannelType type) 135 { 136 return type == TextureFormat::UNSIGNED_INT8 || 137 type == TextureFormat::UNSIGNED_INT16 || 138 type == TextureFormat::UNSIGNED_INT32; 139 } 140 141 static inline bool isFormatTypeSignedInteger (TextureFormat::ChannelType type) 142 { 143 return type == TextureFormat::SIGNED_INT8 || 144 type == TextureFormat::SIGNED_INT16 || 145 type == TextureFormat::SIGNED_INT32; 146 } 147 148 static inline bool isFormatTypeInteger (TextureFormat::ChannelType type) 149 { 150 return isFormatTypeUnsignedInteger(type) || isFormatTypeSignedInteger(type); 151 } 152 153 static inline bool isFormatTypeUnorm (TextureFormat::ChannelType type) 154 { 155 return type == TextureFormat::UNORM_INT8 || 156 type == TextureFormat::UNORM_INT16 || 157 type == TextureFormat::UNORM_INT32; 158 } 159 160 static inline bool isFormatTypeSnorm (TextureFormat::ChannelType type) 161 { 162 return type == TextureFormat::SNORM_INT8 || 163 type == TextureFormat::SNORM_INT16 || 164 type == TextureFormat::SNORM_INT32; 165 } 166 167 static inline bool isFormatSupportedForTextureBuffer (const TextureFormat& format) 168 { 169 switch (format.order) 170 { 171 case TextureFormat::RGB: 172 return format.type == TextureFormat::FLOAT || 173 format.type == TextureFormat::SIGNED_INT32 || 174 format.type == TextureFormat::UNSIGNED_INT32; 175 176 // \note Fallthroughs. 177 case TextureFormat::R: 178 case TextureFormat::RG: 179 case TextureFormat::RGBA: 180 return format.type == TextureFormat::UNORM_INT8 || 181 format.type == TextureFormat::HALF_FLOAT || 182 format.type == TextureFormat::FLOAT || 183 format.type == TextureFormat::SIGNED_INT8 || 184 format.type == TextureFormat::SIGNED_INT16 || 185 format.type == TextureFormat::SIGNED_INT32 || 186 format.type == TextureFormat::UNSIGNED_INT8 || 187 format.type == TextureFormat::UNSIGNED_INT16 || 188 format.type == TextureFormat::UNSIGNED_INT32; 189 190 default: 191 return false; 192 } 193 } 194 195 static inline string getShaderImageFormatQualifier (const TextureFormat& format) 196 { 197 const char* orderPart; 198 const char* typePart; 199 200 switch (format.order) 201 { 202 case TextureFormat::R: orderPart = "r"; break; 203 case TextureFormat::RGBA: orderPart = "rgba"; break; 204 default: 205 DE_ASSERT(false); 206 orderPart = DE_NULL; 207 } 208 209 switch (format.type) 210 { 211 case TextureFormat::FLOAT: typePart = "32f"; break; 212 case TextureFormat::HALF_FLOAT: typePart = "16f"; break; 213 214 case TextureFormat::UNSIGNED_INT32: typePart = "32ui"; break; 215 case TextureFormat::UNSIGNED_INT16: typePart = "16ui"; break; 216 case TextureFormat::UNSIGNED_INT8: typePart = "8ui"; break; 217 218 case TextureFormat::SIGNED_INT32: typePart = "32i"; break; 219 case TextureFormat::SIGNED_INT16: typePart = "16i"; break; 220 case TextureFormat::SIGNED_INT8: typePart = "8i"; break; 221 222 case TextureFormat::UNORM_INT16: typePart = "16"; break; 223 case TextureFormat::UNORM_INT8: typePart = "8"; break; 224 225 case TextureFormat::SNORM_INT16: typePart = "16_snorm"; break; 226 case TextureFormat::SNORM_INT8: typePart = "8_snorm"; break; 227 228 default: 229 DE_ASSERT(false); 230 typePart = DE_NULL; 231 } 232 233 return string() + orderPart + typePart; 234 } 235 236 static inline string getShaderSamplerOrImageType (TextureFormat::ChannelType formatType, TextureType textureType, bool isSampler) 237 { 238 const char* const formatPart = isFormatTypeUnsignedInteger(formatType) ? "u" 239 : isFormatTypeSignedInteger(formatType) ? "i" 240 : ""; 241 242 const char* const imageTypePart = textureType == TEXTURETYPE_BUFFER ? "Buffer" 243 : textureType == TEXTURETYPE_2D ? "2D" 244 : textureType == TEXTURETYPE_3D ? "3D" 245 : textureType == TEXTURETYPE_CUBE ? "Cube" 246 : textureType == TEXTURETYPE_2D_ARRAY ? "2DArray" 247 : DE_NULL; 248 249 return string() + formatPart + (isSampler ? "sampler" : "image") + imageTypePart; 250 } 251 252 static inline string getShaderImageType (TextureFormat::ChannelType formatType, TextureType imageType) 253 { 254 return getShaderSamplerOrImageType(formatType, imageType, false); 255 } 256 257 static inline string getShaderSamplerType (TextureFormat::ChannelType formatType, TextureType imageType) 258 { 259 return getShaderSamplerOrImageType(formatType, imageType, true); 260 } 261 262 static inline deUint32 getGLTextureTarget (TextureType texType) 263 { 264 switch (texType) 265 { 266 case TEXTURETYPE_BUFFER: return GL_TEXTURE_BUFFER; 267 case TEXTURETYPE_2D: return GL_TEXTURE_2D; 268 case TEXTURETYPE_3D: return GL_TEXTURE_3D; 269 case TEXTURETYPE_CUBE: return GL_TEXTURE_CUBE_MAP; 270 case TEXTURETYPE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY; 271 default: 272 DE_ASSERT(false); 273 return (deUint32)-1; 274 } 275 } 276 277 static deUint32 cubeFaceToGLFace (tcu::CubeFace face) 278 { 279 switch (face) 280 { 281 case tcu::CUBEFACE_NEGATIVE_X: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; 282 case tcu::CUBEFACE_POSITIVE_X: return GL_TEXTURE_CUBE_MAP_POSITIVE_X; 283 case tcu::CUBEFACE_NEGATIVE_Y: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; 284 case tcu::CUBEFACE_POSITIVE_Y: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; 285 case tcu::CUBEFACE_NEGATIVE_Z: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; 286 case tcu::CUBEFACE_POSITIVE_Z: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; 287 default: 288 DE_ASSERT(false); 289 return GL_NONE; 290 } 291 } 292 293 static inline tcu::Texture1D* newOneLevelTexture1D (const tcu::TextureFormat& format, int w) 294 { 295 tcu::Texture1D* const res = new tcu::Texture1D(format, w); 296 res->allocLevel(0); 297 return res; 298 } 299 300 static inline tcu::Texture2D* newOneLevelTexture2D (const tcu::TextureFormat& format, int w, int h) 301 { 302 tcu::Texture2D* const res = new tcu::Texture2D(format, w, h); 303 res->allocLevel(0); 304 return res; 305 } 306 307 static inline tcu::TextureCube* newOneLevelTextureCube (const tcu::TextureFormat& format, int size) 308 { 309 tcu::TextureCube* const res = new tcu::TextureCube(format, size); 310 for (int i = 0; i < tcu::CUBEFACE_LAST; i++) 311 res->allocLevel((tcu::CubeFace)i, 0); 312 return res; 313 } 314 315 static inline tcu::Texture3D* newOneLevelTexture3D (const tcu::TextureFormat& format, int w, int h, int d) 316 { 317 tcu::Texture3D* const res = new tcu::Texture3D(format, w, h, d); 318 res->allocLevel(0); 319 return res; 320 } 321 322 static inline tcu::Texture2DArray* newOneLevelTexture2DArray (const tcu::TextureFormat& format, int w, int h, int d) 323 { 324 tcu::Texture2DArray* const res = new tcu::Texture2DArray(format, w, h, d); 325 res->allocLevel(0); 326 return res; 327 } 328 329 static inline TextureType textureLayerType (TextureType entireTextureType) 330 { 331 switch (entireTextureType) 332 { 333 // Single-layer types. 334 // \note Fallthrough. 335 case TEXTURETYPE_BUFFER: 336 case TEXTURETYPE_2D: 337 return entireTextureType; 338 339 // Multi-layer types with 2d layers. 340 case TEXTURETYPE_3D: 341 case TEXTURETYPE_CUBE: 342 case TEXTURETYPE_2D_ARRAY: 343 return TEXTURETYPE_2D; 344 345 default: 346 DE_ASSERT(false); 347 return TEXTURETYPE_LAST; 348 } 349 } 350 351 static const char* const s_texBufExtString = "GL_EXT_texture_buffer"; 352 353 static inline void checkTextureTypeExtensions (const glu::ContextInfo& contextInfo, TextureType type) 354 { 355 if (type == TEXTURETYPE_BUFFER && !contextInfo.isExtensionSupported(s_texBufExtString)) 356 throw tcu::NotSupportedError("Test requires " + string(s_texBufExtString) + " extension"); 357 } 358 359 static inline string textureTypeExtensionShaderRequires (TextureType type) 360 { 361 if (type == TEXTURETYPE_BUFFER) 362 return "#extension " + string(s_texBufExtString) + " : require\n"; 363 else 364 return ""; 365 } 366 367 namespace 368 { 369 370 enum AtomicOperation 371 { 372 ATOMIC_OPERATION_ADD = 0, 373 ATOMIC_OPERATION_MIN, 374 ATOMIC_OPERATION_MAX, 375 ATOMIC_OPERATION_AND, 376 ATOMIC_OPERATION_OR, 377 ATOMIC_OPERATION_XOR, 378 ATOMIC_OPERATION_EXCHANGE, 379 ATOMIC_OPERATION_COMP_SWAP, 380 381 ATOMIC_OPERATION_LAST 382 }; 383 384 //! An order-independent operation is one for which the end result doesn't depend on the order in which the operations are carried (i.e. is both commutative and associative). 385 static bool isOrderIndependentAtomicOperation (AtomicOperation op) 386 { 387 return op == ATOMIC_OPERATION_ADD || 388 op == ATOMIC_OPERATION_MIN || 389 op == ATOMIC_OPERATION_MAX || 390 op == ATOMIC_OPERATION_AND || 391 op == ATOMIC_OPERATION_OR || 392 op == ATOMIC_OPERATION_XOR; 393 } 394 395 //! Computes the result of an atomic operation where "a" is the data operated on and "b" is the parameter to the atomic function. 396 int computeBinaryAtomicOperationResult (AtomicOperation op, int a, int b) 397 { 398 switch (op) 399 { 400 case ATOMIC_OPERATION_ADD: return a + b; 401 case ATOMIC_OPERATION_MIN: return de::min(a, b); 402 case ATOMIC_OPERATION_MAX: return de::max(a, b); 403 case ATOMIC_OPERATION_AND: return a & b; 404 case ATOMIC_OPERATION_OR: return a | b; 405 case ATOMIC_OPERATION_XOR: return a ^ b; 406 case ATOMIC_OPERATION_EXCHANGE: return b; 407 default: 408 DE_ASSERT(false); 409 return -1; 410 } 411 } 412 413 //! \note For floats, only the exchange operation is supported. 414 float computeBinaryAtomicOperationResult (AtomicOperation op, float /*a*/, float b) 415 { 416 switch (op) 417 { 418 case ATOMIC_OPERATION_EXCHANGE: return b; 419 default: 420 DE_ASSERT(false); 421 return -1; 422 } 423 } 424 425 static const char* getAtomicOperationCaseName (AtomicOperation op) 426 { 427 switch (op) 428 { 429 case ATOMIC_OPERATION_ADD: return "add"; 430 case ATOMIC_OPERATION_MIN: return "min"; 431 case ATOMIC_OPERATION_MAX: return "max"; 432 case ATOMIC_OPERATION_AND: return "and"; 433 case ATOMIC_OPERATION_OR: return "or"; 434 case ATOMIC_OPERATION_XOR: return "xor"; 435 case ATOMIC_OPERATION_EXCHANGE: return "exchange"; 436 case ATOMIC_OPERATION_COMP_SWAP: return "comp_swap"; 437 default: 438 DE_ASSERT(false); 439 return DE_NULL; 440 } 441 } 442 443 static const char* getAtomicOperationShaderFuncName (AtomicOperation op) 444 { 445 switch (op) 446 { 447 case ATOMIC_OPERATION_ADD: return "imageAtomicAdd"; 448 case ATOMIC_OPERATION_MIN: return "imageAtomicMin"; 449 case ATOMIC_OPERATION_MAX: return "imageAtomicMax"; 450 case ATOMIC_OPERATION_AND: return "imageAtomicAnd"; 451 case ATOMIC_OPERATION_OR: return "imageAtomicOr"; 452 case ATOMIC_OPERATION_XOR: return "imageAtomicXor"; 453 case ATOMIC_OPERATION_EXCHANGE: return "imageAtomicExchange"; 454 case ATOMIC_OPERATION_COMP_SWAP: return "imageAtomicCompSwap"; 455 default: 456 DE_ASSERT(false); 457 return DE_NULL; 458 } 459 } 460 461 //! In GLSL, when accessing cube images, the z coordinate is mapped to a cube face. 462 //! \note This is _not_ the same as casting the z to a tcu::CubeFace. 463 static inline tcu::CubeFace glslImageFuncZToCubeFace (int z) 464 { 465 static const tcu::CubeFace faces[6] = 466 { 467 tcu::CUBEFACE_POSITIVE_X, 468 tcu::CUBEFACE_NEGATIVE_X, 469 tcu::CUBEFACE_POSITIVE_Y, 470 tcu::CUBEFACE_NEGATIVE_Y, 471 tcu::CUBEFACE_POSITIVE_Z, 472 tcu::CUBEFACE_NEGATIVE_Z 473 }; 474 475 DE_ASSERT(de::inBounds(z, 0, DE_LENGTH_OF_ARRAY(faces))); 476 return faces[z]; 477 } 478 479 class BufferMemMap 480 { 481 public: 482 BufferMemMap (const glw::Functions& gl, deUint32 target, int offset, int size, deUint32 access) 483 : m_gl (gl) 484 , m_target (target) 485 , m_ptr (DE_NULL) 486 { 487 m_ptr = gl.mapBufferRange(target, offset, size, access); 488 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 489 TCU_CHECK(m_ptr); 490 } 491 492 ~BufferMemMap (void) 493 { 494 m_gl.unmapBuffer(m_target); 495 } 496 497 void* getPtr (void) const { return m_ptr; } 498 void* operator* (void) const { return m_ptr; } 499 500 private: 501 BufferMemMap (const BufferMemMap& other); 502 BufferMemMap& operator= (const BufferMemMap& other); 503 504 const glw::Functions& m_gl; 505 const deUint32 m_target; 506 void* m_ptr; 507 }; 508 509 //! Utility for more readable uniform assignment logging; logs the name of the uniform when assigning. Handles the locations, querying them the first time they're assigned 510 // \note Assumes that the appropriate program is in use when assigning uniforms. 511 class UniformAccessLogger 512 { 513 public: 514 UniformAccessLogger (const glw::Functions& gl, TestLog& log, deUint32 programGL) 515 : m_gl (gl) 516 , m_log (log) 517 , m_programGL (programGL) 518 { 519 } 520 521 void assign1i (const string& name, int x); 522 void assign3f (const string& name, float x, float y, float z); 523 524 private: 525 int getLocation (const string& name); 526 527 const glw::Functions& m_gl; 528 TestLog& m_log; 529 const deUint32 m_programGL; 530 531 std::map<string, int> m_uniformLocations; 532 }; 533 534 int UniformAccessLogger::getLocation (const string& name) 535 { 536 if (m_uniformLocations.find(name) == m_uniformLocations.end()) 537 { 538 const int loc = m_gl.getUniformLocation(m_programGL, name.c_str()); 539 TCU_CHECK(loc != -1); 540 m_uniformLocations[name] = loc; 541 } 542 return m_uniformLocations[name]; 543 } 544 545 void UniformAccessLogger::assign1i (const string& name, int x) 546 { 547 const int loc = getLocation(name); 548 m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << x << TestLog::EndMessage; 549 m_gl.uniform1i(loc, x); 550 } 551 552 void UniformAccessLogger::assign3f (const string& name, float x, float y, float z) 553 { 554 const int loc = getLocation(name); 555 m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << Vec3(x, y, z) << TestLog::EndMessage; 556 m_gl.uniform3f(loc, x, y, z); 557 } 558 559 //! Class containing a (single-level) texture of a given type. Supports accessing pixels with coordinate convention similar to that in imageStore() and imageLoad() in shaders; useful especially for cube maps. 560 class LayeredImage 561 { 562 public: 563 LayeredImage (TextureType type, const TextureFormat& format, int w, int h, int d); 564 565 TextureType getImageType (void) const { return m_type; } 566 const IVec3& getSize (void) const { return m_size; } 567 const TextureFormat& getFormat (void) const { return m_format; } 568 569 // \note For cube maps, set/getPixel's z parameter specifies the cube face in the same manner as in imageStore/imageLoad in GL shaders (see glslImageFuncZToCubeFace), instead of directly as a tcu::CubeFace. 570 571 template <typename ColorT> 572 void setPixel (int x, int y, int z, const ColorT& color) const; 573 574 Vec4 getPixel (int x, int y, int z) const; 575 IVec4 getPixelInt (int x, int y, int z) const; 576 UVec4 getPixelUint (int x, int y, int z) const { return getPixelInt(x, y, z).asUint(); } 577 578 PixelBufferAccess getAccess (void) { return getAccessInternal(); } 579 PixelBufferAccess getSliceAccess (int slice) { return getSliceAccessInternal(slice); } 580 PixelBufferAccess getCubeFaceAccess (tcu::CubeFace face) { return getCubeFaceAccessInternal(face); } 581 582 ConstPixelBufferAccess getAccess (void) const { return getAccessInternal(); } 583 ConstPixelBufferAccess getSliceAccess (int slice) const { return getSliceAccessInternal(slice); } 584 ConstPixelBufferAccess getCubeFaceAccess (tcu::CubeFace face) const { return getCubeFaceAccessInternal(face); } 585 586 private: 587 LayeredImage (const LayeredImage&); 588 LayeredImage& operator= (const LayeredImage&); 589 590 // Some helpers to reduce code duplication between const/non-const versions of getAccess and others. 591 PixelBufferAccess getAccessInternal (void) const; 592 PixelBufferAccess getSliceAccessInternal (int slice) const; 593 PixelBufferAccess getCubeFaceAccessInternal (tcu::CubeFace face) const; 594 595 const TextureType m_type; 596 const IVec3 m_size; 597 const TextureFormat m_format; 598 599 // \note Depending on m_type, exactly one of the following will contain non-null. 600 const SharedPtr<tcu::Texture1D> m_texBuffer; 601 const SharedPtr<tcu::Texture2D> m_tex2D; 602 const SharedPtr<tcu::TextureCube> m_texCube; 603 const SharedPtr<tcu::Texture3D> m_tex3D; 604 const SharedPtr<tcu::Texture2DArray> m_tex2DArray; 605 }; 606 607 LayeredImage::LayeredImage (TextureType type, const TextureFormat& format, int w, int h, int d) 608 : m_type (type) 609 , m_size (w, h, d) 610 , m_format (format) 611 , m_texBuffer (type == TEXTURETYPE_BUFFER ? SharedPtr<tcu::Texture1D> (newOneLevelTexture1D (format, w)) : SharedPtr<tcu::Texture1D>()) 612 , m_tex2D (type == TEXTURETYPE_2D ? SharedPtr<tcu::Texture2D> (newOneLevelTexture2D (format, w, h)) : SharedPtr<tcu::Texture2D>()) 613 , m_texCube (type == TEXTURETYPE_CUBE ? SharedPtr<tcu::TextureCube> (newOneLevelTextureCube (format, w)) : SharedPtr<tcu::TextureCube>()) 614 , m_tex3D (type == TEXTURETYPE_3D ? SharedPtr<tcu::Texture3D> (newOneLevelTexture3D (format, w, h, d)) : SharedPtr<tcu::Texture3D>()) 615 , m_tex2DArray (type == TEXTURETYPE_2D_ARRAY ? SharedPtr<tcu::Texture2DArray> (newOneLevelTexture2DArray (format, w, h, d)) : SharedPtr<tcu::Texture2DArray>()) 616 { 617 DE_ASSERT(m_size.z() == 1 || 618 m_type == TEXTURETYPE_3D || 619 m_type == TEXTURETYPE_2D_ARRAY); 620 621 DE_ASSERT(m_size.y() == 1 || 622 m_type == TEXTURETYPE_2D || 623 m_type == TEXTURETYPE_CUBE || 624 m_type == TEXTURETYPE_3D || 625 m_type == TEXTURETYPE_2D_ARRAY); 626 627 DE_ASSERT(w == h || type != TEXTURETYPE_CUBE); 628 629 DE_ASSERT(m_texBuffer != DE_NULL || 630 m_tex2D != DE_NULL || 631 m_texCube != DE_NULL || 632 m_tex3D != DE_NULL || 633 m_tex2DArray != DE_NULL); 634 } 635 636 template <typename ColorT> 637 void LayeredImage::setPixel (int x, int y, int z, const ColorT& color) const 638 { 639 const PixelBufferAccess access = m_type == TEXTURETYPE_BUFFER ? m_texBuffer->getLevel(0) 640 : m_type == TEXTURETYPE_2D ? m_tex2D->getLevel(0) 641 : m_type == TEXTURETYPE_CUBE ? m_texCube->getLevelFace(0, glslImageFuncZToCubeFace(z)) 642 : m_type == TEXTURETYPE_3D ? m_tex3D->getLevel(0) 643 : m_type == TEXTURETYPE_2D_ARRAY ? m_tex2DArray->getLevel(0) 644 : PixelBufferAccess(TextureFormat(), -1, -1, -1, DE_NULL); 645 646 access.setPixel(color, x, y, m_type == TEXTURETYPE_CUBE ? 0 : z); 647 } 648 649 Vec4 LayeredImage::getPixel (int x, int y, int z) const 650 { 651 const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess(); 652 return access.getPixel(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z); 653 } 654 655 IVec4 LayeredImage::getPixelInt (int x, int y, int z) const 656 { 657 const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess(); 658 return access.getPixelInt(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z); 659 } 660 661 PixelBufferAccess LayeredImage::getAccessInternal (void) const 662 { 663 DE_ASSERT(m_type == TEXTURETYPE_BUFFER || m_type == TEXTURETYPE_2D || m_type == TEXTURETYPE_3D || m_type == TEXTURETYPE_2D_ARRAY); 664 665 return m_type == TEXTURETYPE_BUFFER ? m_texBuffer->getLevel(0) 666 : m_type == TEXTURETYPE_2D ? m_tex2D->getLevel(0) 667 : m_type == TEXTURETYPE_3D ? m_tex3D->getLevel(0) 668 : m_type == TEXTURETYPE_2D_ARRAY ? m_tex2DArray->getLevel(0) 669 : PixelBufferAccess(TextureFormat(), -1, -1, -1, DE_NULL); 670 } 671 672 PixelBufferAccess LayeredImage::getSliceAccessInternal (int slice) const 673 { 674 const PixelBufferAccess srcAccess = getAccessInternal(); 675 return tcu::getSubregion(srcAccess, 0, 0, slice, srcAccess.getWidth(), srcAccess.getHeight(), 1); 676 } 677 678 PixelBufferAccess LayeredImage::getCubeFaceAccessInternal (tcu::CubeFace face) const 679 { 680 DE_ASSERT(m_type == TEXTURETYPE_CUBE); 681 return m_texCube->getLevelFace(0, face); 682 } 683 684 //! Set texture storage or, if using buffer texture, setup buffer and attach to texture. 685 static void setTextureStorage (glu::CallLogWrapper& glLog, TextureType imageType, deUint32 internalFormat, const IVec3& imageSize, deUint32 textureBufGL) 686 { 687 const deUint32 textureTarget = getGLTextureTarget(imageType); 688 689 switch (imageType) 690 { 691 case TEXTURETYPE_BUFFER: 692 { 693 const TextureFormat format = glu::mapGLInternalFormat(internalFormat); 694 const int numBytes = format.getPixelSize() * imageSize.x(); 695 DE_ASSERT(isFormatSupportedForTextureBuffer(format)); 696 glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL); 697 glLog.glBufferData(GL_TEXTURE_BUFFER, numBytes, DE_NULL, GL_STATIC_DRAW); 698 glLog.glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, textureBufGL); 699 DE_ASSERT(imageSize.y() == 1 && imageSize.z() == 1); 700 break; 701 } 702 703 // \note Fall-throughs. 704 705 case TEXTURETYPE_2D: 706 case TEXTURETYPE_CUBE: 707 glLog.glTexStorage2D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y()); 708 DE_ASSERT(imageSize.z() == 1); 709 break; 710 711 case TEXTURETYPE_3D: 712 case TEXTURETYPE_2D_ARRAY: 713 glLog.glTexStorage3D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y(), imageSize.z()); 714 break; 715 716 default: 717 DE_ASSERT(false); 718 } 719 } 720 721 static void uploadTexture (glu::CallLogWrapper& glLog, const LayeredImage& src, deUint32 textureBufGL) 722 { 723 const deUint32 internalFormat = glu::getInternalFormat(src.getFormat()); 724 const glu::TransferFormat transferFormat = glu::getTransferFormat(src.getFormat()); 725 const IVec3& imageSize = src.getSize(); 726 727 setTextureStorage(glLog, src.getImageType(), internalFormat, imageSize, textureBufGL); 728 729 { 730 const int pixelSize = src.getFormat().getPixelSize(); 731 int unpackAlignment; 732 733 if (deIsPowerOfTwo32(pixelSize)) 734 unpackAlignment = 8; 735 else 736 unpackAlignment = 1; 737 738 glLog.glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment); 739 } 740 741 if (src.getImageType() == TEXTURETYPE_BUFFER) 742 { 743 glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL); 744 glLog.glBufferData(GL_TEXTURE_BUFFER, src.getFormat().getPixelSize() * imageSize.x(), src.getAccess().getDataPtr(), GL_STATIC_DRAW); 745 } 746 else if (src.getImageType() == TEXTURETYPE_2D) 747 glLog.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageSize.x(), imageSize.y(), transferFormat.format, transferFormat.dataType, src.getAccess().getDataPtr()); 748 else if (src.getImageType() == TEXTURETYPE_CUBE) 749 { 750 for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++) 751 { 752 const tcu::CubeFace face = (tcu::CubeFace)faceI; 753 glLog.glTexSubImage2D(cubeFaceToGLFace(face), 0, 0, 0, imageSize.x(), imageSize.y(), transferFormat.format, transferFormat.dataType, src.getCubeFaceAccess(face).getDataPtr()); 754 } 755 } 756 else 757 { 758 DE_ASSERT(src.getImageType() == TEXTURETYPE_3D || src.getImageType() == TEXTURETYPE_2D_ARRAY); 759 const deUint32 textureTarget = getGLTextureTarget(src.getImageType()); 760 glLog.glTexSubImage3D(textureTarget, 0, 0, 0, 0, imageSize.x(), imageSize.y(), imageSize.z(), transferFormat.format, transferFormat.dataType, src.getAccess().getDataPtr()); 761 } 762 } 763 764 static void readPixelsRGBAInteger32 (const PixelBufferAccess& dst, int originX, int originY, glu::CallLogWrapper& glLog) 765 { 766 DE_ASSERT(dst.getDepth() == 1); 767 768 if (isFormatTypeUnsignedInteger(dst.getFormat().type)) 769 { 770 vector<UVec4> data(dst.getWidth()*dst.getHeight()); 771 772 glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]); 773 774 for (int y = 0; y < dst.getHeight(); y++) 775 for (int x = 0; x < dst.getWidth(); x++) 776 dst.setPixel(data[y*dst.getWidth() + x], x, y); 777 } 778 else if (isFormatTypeSignedInteger(dst.getFormat().type)) 779 { 780 vector<IVec4> data(dst.getWidth()*dst.getHeight()); 781 782 glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]); 783 784 for (int y = 0; y < dst.getHeight(); y++) 785 for (int x = 0; x < dst.getWidth(); x++) 786 dst.setPixel(data[y*dst.getWidth() + x], x, y); 787 } 788 else 789 DE_ASSERT(false); 790 } 791 792 //! Base for a functor for verifying and logging a 2d texture layer (2d image, cube face, 3d slice, 2d layer). 793 class ImageLayerVerifier 794 { 795 public: 796 virtual bool operator() (TestLog&, const ConstPixelBufferAccess&, int sliceOrFaceNdx) const = 0; 797 virtual ~ImageLayerVerifier (void) {} 798 }; 799 800 static void setTexParameteri (glu::CallLogWrapper& glLog, deUint32 target) 801 { 802 if (target != GL_TEXTURE_BUFFER) 803 { 804 glLog.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 805 glLog.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 806 } 807 } 808 809 //! Binds texture (one layer at a time) to color attachment of FBO and does glReadPixels(). Calls the verifier for each layer. 810 //! \note Not for buffer textures. 811 static bool readIntegerTextureViaFBOAndVerify (const RenderContext& renderCtx, 812 glu::CallLogWrapper& glLog, 813 deUint32 textureGL, 814 TextureType textureType, 815 const TextureFormat& textureFormat, 816 const IVec3& textureSize, 817 const ImageLayerVerifier& verifyLayer) 818 { 819 DE_ASSERT(isFormatTypeInteger(textureFormat.type)); 820 DE_ASSERT(textureType != TEXTURETYPE_BUFFER); 821 822 TestLog& log = glLog.getLog(); 823 824 const tcu::ScopedLogSection section(log, "Verification", "Result verification (bind texture layer-by-layer to FBO, read with glReadPixels())"); 825 826 const int numSlicesOrFaces = textureType == TEXTURETYPE_CUBE ? 6 : textureSize.z(); 827 const deUint32 textureTargetGL = getGLTextureTarget(textureType); 828 glu::Framebuffer fbo (renderCtx); 829 tcu::TextureLevel resultSlice (textureFormat, textureSize.x(), textureSize.y()); 830 831 glLog.glBindFramebuffer(GL_FRAMEBUFFER, *fbo); 832 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind FBO"); 833 834 glLog.glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); 835 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glMemoryBarrier"); 836 837 glLog.glActiveTexture(GL_TEXTURE0); 838 glLog.glBindTexture(textureTargetGL, textureGL); 839 setTexParameteri(glLog, textureTargetGL); 840 841 for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++) 842 { 843 if (textureType == TEXTURETYPE_CUBE) 844 glLog.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)), textureGL, 0); 845 else if (textureType == TEXTURETYPE_2D) 846 glLog.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureGL, 0); 847 else if (textureType == TEXTURETYPE_3D || textureType == TEXTURETYPE_2D_ARRAY) 848 glLog.glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureGL, 0, sliceOrFaceNdx); 849 else 850 DE_ASSERT(false); 851 852 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind texture to framebuffer color attachment 0"); 853 854 TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 855 856 readPixelsRGBAInteger32(resultSlice.getAccess(), 0, 0, glLog); 857 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glReadPixels"); 858 859 if (!verifyLayer(log, resultSlice, sliceOrFaceNdx)) 860 return false; 861 } 862 863 return true; 864 } 865 866 //! Reads texture with texture() in compute shader, one layer at a time, putting values into a SSBO and reading with a mapping. Calls the verifier for each layer. 867 //! \note Not for buffer textures. 868 static bool readFloatOrNormTextureWithLookupsAndVerify (const RenderContext& renderCtx, 869 glu::CallLogWrapper& glLog, 870 deUint32 textureGL, 871 TextureType textureType, 872 const TextureFormat& textureFormat, 873 const IVec3& textureSize, 874 const ImageLayerVerifier& verifyLayer) 875 { 876 DE_ASSERT(!isFormatTypeInteger(textureFormat.type)); 877 DE_ASSERT(textureType != TEXTURETYPE_BUFFER); 878 879 TestLog& log = glLog.getLog(); 880 881 const tcu::ScopedLogSection section(log, "Verification", "Result verification (read texture layer-by-layer in compute shader with texture() into SSBO)"); 882 883 const glu::ShaderProgram program(renderCtx, 884 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 885 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 886 "layout (binding = 0) buffer Output\n" 887 "{\n" 888 " vec4 color[" + toString(textureSize.x()*textureSize.y()) + "];\n" 889 "} sb_out;\n" 890 "\n" 891 "precision highp " + getShaderSamplerType(textureFormat.type, textureType) + ";\n" 892 "\n" 893 "uniform highp " + getShaderSamplerType(textureFormat.type, textureType) + " u_texture;\n" 894 "uniform highp vec3 u_texCoordLD;\n" 895 "uniform highp vec3 u_texCoordRD;\n" 896 "uniform highp vec3 u_texCoordLU;\n" 897 "uniform highp vec3 u_texCoordRU;\n" 898 "\n" 899 "void main (void)\n" 900 "{\n" 901 " int gx = int(gl_GlobalInvocationID.x);\n" 902 " int gy = int(gl_GlobalInvocationID.y);\n" 903 " highp float s = (float(gx) + 0.5) / float(" + toString(textureSize.x()) + ");\n" 904 " highp float t = (float(gy) + 0.5) / float(" + toString(textureType == TEXTURETYPE_CUBE ? textureSize.x() : textureSize.y()) + ");\n" 905 " highp vec3 texCoord = u_texCoordLD*(1.0-s)*(1.0-t)\n" 906 " + u_texCoordRD*( s)*(1.0-t)\n" 907 " + u_texCoordLU*(1.0-s)*( t)\n" 908 " + u_texCoordRU*( s)*( t);\n" 909 " int ndx = gy*" + toString(textureSize.x()) + " + gx;\n" 910 " sb_out.color[ndx] = texture(u_texture, texCoord" + (textureType == TEXTURETYPE_2D ? ".xy" : "") + ");\n" 911 "}\n")); 912 913 glLog.glUseProgram(program.getProgram()); 914 915 log << program; 916 917 if (!program.isOk()) 918 { 919 log << TestLog::Message << "// Failure: failed to compile program" << TestLog::EndMessage; 920 TCU_FAIL("Program compilation failed"); 921 } 922 923 { 924 const deUint32 textureTargetGL = getGLTextureTarget(textureType); 925 const glu::Buffer outputBuffer (renderCtx); 926 UniformAccessLogger uniforms (renderCtx.getFunctions(), log, program.getProgram()); 927 928 // Setup texture. 929 930 glLog.glActiveTexture(GL_TEXTURE0); 931 glLog.glBindTexture(textureTargetGL, textureGL); 932 setTexParameteri(glLog, textureTargetGL); 933 934 uniforms.assign1i("u_texture", 0); 935 936 // Setup output buffer. 937 { 938 const deUint32 blockIndex = glLog.glGetProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); 939 const int blockSize = glu::getProgramResourceInt(renderCtx.getFunctions(), program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, GL_BUFFER_DATA_SIZE); 940 941 log << TestLog::Message << "// Got buffer data size = " << blockSize << TestLog::EndMessage; 942 TCU_CHECK(blockSize > 0); 943 944 glLog.glBindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); 945 glLog.glBufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); 946 glLog.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); 947 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "SSB setup failed"); 948 } 949 950 // Dispatch one layer at a time, read back and verify. 951 { 952 const int numSlicesOrFaces = textureType == TEXTURETYPE_CUBE ? 6 : textureSize.z(); 953 tcu::TextureLevel resultSlice (textureFormat, textureSize.x(), textureSize.y()); 954 const PixelBufferAccess resultSliceAccess = resultSlice.getAccess(); 955 const deUint32 blockIndex = glLog.glGetProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); 956 const int blockSize = glu::getProgramResourceInt(renderCtx.getFunctions(), program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, GL_BUFFER_DATA_SIZE); 957 const deUint32 valueIndex = glLog.glGetProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.color"); 958 const glu::InterfaceVariableInfo valueInfo = glu::getProgramInterfaceVariableInfo(renderCtx.getFunctions(), program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); 959 960 TCU_CHECK(valueInfo.arraySize == (deUint32)(textureSize.x()*textureSize.y())); 961 962 glLog.glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); 963 964 for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++) 965 { 966 if (textureType == TEXTURETYPE_CUBE) 967 { 968 vector<float> coords; 969 computeQuadTexCoordCube(coords, glslImageFuncZToCubeFace(sliceOrFaceNdx)); 970 uniforms.assign3f("u_texCoordLD", coords[3*0 + 0], coords[3*0 + 1], coords[3*0 + 2]); 971 uniforms.assign3f("u_texCoordRD", coords[3*2 + 0], coords[3*2 + 1], coords[3*2 + 2]); 972 uniforms.assign3f("u_texCoordLU", coords[3*1 + 0], coords[3*1 + 1], coords[3*1 + 2]); 973 uniforms.assign3f("u_texCoordRU", coords[3*3 + 0], coords[3*3 + 1], coords[3*3 + 2]); 974 } 975 else 976 { 977 const float z = textureType == TEXTURETYPE_3D ? 978 ((float)sliceOrFaceNdx + 0.5f) / (float)numSlicesOrFaces : 979 (float)sliceOrFaceNdx; 980 uniforms.assign3f("u_texCoordLD", 0.0f, 0.0f, z); 981 uniforms.assign3f("u_texCoordRD", 1.0f, 0.0f, z); 982 uniforms.assign3f("u_texCoordLU", 0.0f, 1.0f, z); 983 uniforms.assign3f("u_texCoordRU", 1.0f, 1.0f, z); 984 } 985 986 glLog.glDispatchCompute(textureSize.x(), textureSize.y(), 1); 987 988 { 989 log << TestLog::Message << "// Note: mapping buffer and reading color values written" << TestLog::EndMessage; 990 991 const BufferMemMap bufMap(renderCtx.getFunctions(), GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); 992 993 for (int y = 0; y < textureSize.y(); y++) 994 for (int x = 0; x < textureSize.x(); x++) 995 { 996 const int ndx = y*textureSize.x() + x; 997 const float* const clrData = (const float*)((const deUint8*)bufMap.getPtr() + valueInfo.offset + valueInfo.arrayStride*ndx); 998 999 switch (textureFormat.order) 1000 { 1001 case TextureFormat::R: resultSliceAccess.setPixel(Vec4(clrData[0]), x, y); break; 1002 case TextureFormat::RGBA: resultSliceAccess.setPixel(Vec4(clrData[0], clrData[1], clrData[2], clrData[3]), x, y); break; 1003 default: 1004 DE_ASSERT(false); 1005 } 1006 } 1007 } 1008 1009 if (!verifyLayer(log, resultSliceAccess, sliceOrFaceNdx)) 1010 return false; 1011 } 1012 } 1013 1014 return true; 1015 } 1016 } 1017 1018 //! Read buffer texture by reading the corresponding buffer with a mapping. 1019 static bool readBufferTextureWithMappingAndVerify (const RenderContext& renderCtx, 1020 glu::CallLogWrapper& glLog, 1021 deUint32 bufferGL, 1022 const TextureFormat& textureFormat, 1023 int imageSize, 1024 const ImageLayerVerifier& verifyLayer) 1025 { 1026 tcu::TextureLevel result (textureFormat, imageSize, 1); 1027 const PixelBufferAccess resultAccess = result.getAccess(); 1028 DE_ASSERT(resultAccess.getDataSize() == imageSize * textureFormat.getPixelSize()); 1029 1030 const tcu::ScopedLogSection section(glLog.getLog(), "Verification", "Result verification (read texture's buffer with a mapping)"); 1031 glLog.glBindBuffer(GL_TEXTURE_BUFFER, bufferGL); 1032 1033 { 1034 const BufferMemMap bufMap(renderCtx.getFunctions(), GL_TEXTURE_BUFFER, 0, resultAccess.getDataSize(), GL_MAP_READ_BIT); 1035 deMemcpy(resultAccess.getDataPtr(), bufMap.getPtr(), resultAccess.getDataSize()); 1036 } 1037 1038 return verifyLayer(glLog.getLog(), resultAccess, 0); 1039 } 1040 1041 //! Calls the appropriate texture verification function depending on texture format or type. 1042 static bool readTextureAndVerify (const RenderContext& renderCtx, 1043 glu::CallLogWrapper& glLog, 1044 deUint32 textureGL, 1045 deUint32 bufferGL, 1046 TextureType textureType, 1047 const TextureFormat& textureFormat, 1048 const IVec3& imageSize, 1049 const ImageLayerVerifier& verifyLayer) 1050 { 1051 if (textureType == TEXTURETYPE_BUFFER) 1052 return readBufferTextureWithMappingAndVerify(renderCtx, glLog, bufferGL, textureFormat, imageSize.x(), verifyLayer); 1053 else 1054 return isFormatTypeInteger(textureFormat.type) ? readIntegerTextureViaFBOAndVerify (renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer) 1055 : readFloatOrNormTextureWithLookupsAndVerify (renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer); 1056 } 1057 1058 //! An ImageLayerVerifier that simply compares the result slice to a slice in a reference image. 1059 //! \note Holds the reference image as a reference (no pun intended) instead of a copy; caller must be aware of lifetime issues. 1060 class ImageLayerComparer : public ImageLayerVerifier 1061 { 1062 public: 1063 ImageLayerComparer (const LayeredImage& reference, 1064 const IVec2& relevantRegion = IVec2(0) /* If given, only check this region of each slice. */) 1065 : m_reference (reference) 1066 , m_relevantRegion (relevantRegion.x() > 0 && relevantRegion.y() > 0 ? relevantRegion : reference.getSize().swizzle(0, 1)) 1067 { 1068 } 1069 1070 bool operator() (TestLog& log, const tcu::ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const 1071 { 1072 const bool isCube = m_reference.getImageType() == TEXTURETYPE_CUBE; 1073 const ConstPixelBufferAccess referenceSlice = tcu::getSubregion(isCube ? m_reference.getCubeFaceAccess(glslImageFuncZToCubeFace(sliceOrFaceNdx)) 1074 : m_reference.getSliceAccess(sliceOrFaceNdx), 1075 0, 0, m_relevantRegion.x(), m_relevantRegion.y()); 1076 1077 const string comparisonName = "Comparison" + toString(sliceOrFaceNdx); 1078 const string comparisonDesc = "Image Comparison, " 1079 + (isCube ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)))) 1080 : "slice " + toString(sliceOrFaceNdx)); 1081 1082 if (isFormatTypeInteger(m_reference.getFormat().type)) 1083 return tcu::intThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, UVec4(0), tcu::COMPARE_LOG_RESULT); 1084 else 1085 return tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, Vec4(0.01f), tcu::COMPARE_LOG_RESULT); 1086 } 1087 1088 private: 1089 const LayeredImage& m_reference; 1090 const IVec2 m_relevantRegion; 1091 }; 1092 1093 //! Case that just stores some computation results into an image. 1094 class ImageStoreCase : public TestCase 1095 { 1096 public: 1097 enum CaseFlag 1098 { 1099 CASEFLAG_SINGLE_LAYER_BIND = 1 << 0 //!< If given, glBindImageTexture() is called with GL_FALSE <layered> argument, and for each layer the compute shader is separately dispatched. 1100 }; 1101 1102 ImageStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0) 1103 : TestCase (context, name, description) 1104 , m_format (format) 1105 , m_textureType (textureType) 1106 , m_singleLayerBind ((caseFlags & CASEFLAG_SINGLE_LAYER_BIND) != 0) 1107 { 1108 } 1109 1110 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType); } 1111 IterateResult iterate (void); 1112 1113 private: 1114 const TextureFormat m_format; 1115 const TextureType m_textureType; 1116 const bool m_singleLayerBind; 1117 }; 1118 1119 ImageStoreCase::IterateResult ImageStoreCase::iterate (void) 1120 { 1121 const RenderContext& renderCtx = m_context.getRenderContext(); 1122 TestLog& log (m_testCtx.getLog()); 1123 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 1124 const deUint32 internalFormatGL = glu::getInternalFormat(m_format); 1125 const deUint32 textureTargetGL = getGLTextureTarget(m_textureType); 1126 const IVec3& imageSize = defaultImageSize(m_textureType); 1127 const int numSlicesOrFaces = m_textureType == TEXTURETYPE_CUBE ? 6 : imageSize.z(); 1128 const int maxImageDimension = de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z())); 1129 const float storeColorScale = isFormatTypeUnorm(m_format.type) ? 1.0f / (float)(maxImageDimension - 1) 1130 : isFormatTypeSnorm(m_format.type) ? 2.0f / (float)(maxImageDimension - 1) 1131 : 1.0f; 1132 const float storeColorBias = isFormatTypeSnorm(m_format.type) ? -1.0f : 0.0f; 1133 const glu::Buffer textureBuf (renderCtx); // \note Only really used if using buffer texture. 1134 const glu::Texture texture (renderCtx); 1135 1136 glLog.enableLogging(true); 1137 1138 // Setup texture. 1139 1140 log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage; 1141 if (m_textureType == TEXTURETYPE_BUFFER) 1142 log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage; 1143 1144 glLog.glActiveTexture(GL_TEXTURE0); 1145 glLog.glBindTexture(textureTargetGL, *texture); 1146 setTexParameteri(glLog, textureTargetGL); 1147 setTextureStorage(glLog, m_textureType, internalFormatGL, imageSize, *textureBuf); 1148 1149 // Perform image stores in compute shader. 1150 1151 { 1152 // Generate compute shader. 1153 1154 const string shaderImageFormatStr = getShaderImageFormatQualifier(m_format); 1155 const TextureType shaderImageType = m_singleLayerBind ? textureLayerType(m_textureType) : m_textureType; 1156 const string shaderImageTypeStr = getShaderImageType(m_format.type, shaderImageType); 1157 const bool isUintFormat = isFormatTypeUnsignedInteger(m_format.type); 1158 const bool isIntFormat = isFormatTypeSignedInteger(m_format.type); 1159 const string colorBaseExpr = string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4(gx^gy^gz, " 1160 "(" + toString(imageSize.x()-1) + "-gx)^gy^gz, " 1161 "gx^(" + toString(imageSize.y()-1) + "-gy)^gz, " 1162 "(" + toString(imageSize.x()-1) + "-gx)^(" + toString(imageSize.y()-1) + "-gy)^gz)"; 1163 const string colorExpr = colorBaseExpr + (storeColorScale == 1.0f ? "" : "*" + toString(storeColorScale)) 1164 + (storeColorBias == 0.0f ? "" : " + float(" + toString(storeColorBias) + ")"); 1165 1166 const glu::ShaderProgram program(renderCtx, 1167 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 1168 + textureTypeExtensionShaderRequires(shaderImageType) + 1169 "\n" 1170 "precision highp " + shaderImageTypeStr + ";\n" 1171 "\n" 1172 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 1173 "layout (" + shaderImageFormatStr + ", binding=0) writeonly uniform " + shaderImageTypeStr + " u_image;\n" 1174 + (m_singleLayerBind ? "uniform int u_layerNdx;\n" : "") + 1175 "\n" 1176 "void main (void)\n" 1177 "{\n" 1178 " int gx = int(gl_GlobalInvocationID.x);\n" 1179 " int gy = int(gl_GlobalInvocationID.y);\n" 1180 " int gz = " + (m_singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") + ";\n" 1181 + (shaderImageType == TEXTURETYPE_BUFFER ? 1182 " imageStore(u_image, gx, " + colorExpr + ");\n" 1183 : shaderImageType == TEXTURETYPE_2D ? 1184 " imageStore(u_image, ivec2(gx, gy), " + colorExpr + ");\n" 1185 : shaderImageType == TEXTURETYPE_3D || shaderImageType == TEXTURETYPE_CUBE || shaderImageType == TEXTURETYPE_2D_ARRAY ? 1186 " imageStore(u_image, ivec3(gx, gy, gz), " + colorExpr + ");\n" 1187 : DE_NULL) + 1188 "}\n")); 1189 1190 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 1191 1192 log << program; 1193 1194 if (!program.isOk()) 1195 { 1196 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 1197 return STOP; 1198 } 1199 1200 // Setup and dispatch. 1201 1202 glLog.glUseProgram(program.getProgram()); 1203 1204 if (m_singleLayerBind) 1205 { 1206 for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++) 1207 { 1208 if (layerNdx > 0) 1209 glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 1210 1211 uniforms.assign1i("u_layerNdx", layerNdx); 1212 1213 glLog.glBindImageTexture(0, *texture, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, internalFormatGL); 1214 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1215 1216 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1); 1217 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 1218 } 1219 } 1220 else 1221 { 1222 glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL); 1223 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1224 1225 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces); 1226 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 1227 } 1228 } 1229 1230 // Create reference, read texture and compare to reference. 1231 { 1232 const int isIntegerFormat = isFormatTypeInteger(m_format.type); 1233 LayeredImage reference (m_textureType, m_format, imageSize.x(), imageSize.y(), imageSize.z()); 1234 1235 DE_ASSERT(!isIntegerFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f)); 1236 1237 for (int z = 0; z < numSlicesOrFaces; z++) 1238 for (int y = 0; y < imageSize.y(); y++) 1239 for (int x = 0; x < imageSize.x(); x++) 1240 { 1241 const IVec4 color(x^y^z, (imageSize.x()-1-x)^y^z, x^(imageSize.y()-1-y)^z, (imageSize.x()-1-x)^(imageSize.y()-1-y)^z); 1242 1243 if (isIntegerFormat) 1244 reference.setPixel(x, y, z, color); 1245 else 1246 reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias); 1247 } 1248 1249 const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_textureType, m_format, imageSize, ImageLayerComparer(reference)); 1250 1251 m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed"); 1252 return STOP; 1253 } 1254 } 1255 1256 //! Case that copies an image to another, using imageLoad() and imageStore(). Texture formats don't necessarily match image formats. 1257 class ImageLoadAndStoreCase : public TestCase 1258 { 1259 public: 1260 enum CaseFlag 1261 { 1262 CASEFLAG_SINGLE_LAYER_BIND = 1 << 0, //!< If given, glBindImageTexture() is called with GL_FALSE <layered> argument, and for each layer the compute shader is separately dispatched. 1263 CASEFLAG_RESTRICT_IMAGES = 1 << 1 //!< If given, images in shader will be qualified with "restrict". 1264 }; 1265 1266 ImageLoadAndStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0) 1267 : TestCase (context, name, description) 1268 , m_textureFormat (format) 1269 , m_imageFormat (format) 1270 , m_textureType (textureType) 1271 , m_restrictImages ((caseFlags & CASEFLAG_RESTRICT_IMAGES) != 0) 1272 , m_singleLayerBind ((caseFlags & CASEFLAG_SINGLE_LAYER_BIND) != 0) 1273 { 1274 } 1275 1276 ImageLoadAndStoreCase (Context& context, const char* name, const char* description, const TextureFormat& textureFormat, const TextureFormat& imageFormat, TextureType textureType, deUint32 caseFlags = 0) 1277 : TestCase (context, name, description) 1278 , m_textureFormat (textureFormat) 1279 , m_imageFormat (imageFormat) 1280 , m_textureType (textureType) 1281 , m_restrictImages ((caseFlags & CASEFLAG_RESTRICT_IMAGES) != 0) 1282 , m_singleLayerBind ((caseFlags & CASEFLAG_SINGLE_LAYER_BIND) != 0) 1283 { 1284 DE_ASSERT(textureFormat.getPixelSize() == imageFormat.getPixelSize()); 1285 } 1286 1287 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType); } 1288 IterateResult iterate (void); 1289 1290 private: 1291 template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatStorageType> 1292 static void replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat); 1293 1294 const TextureFormat m_textureFormat; 1295 const TextureFormat m_imageFormat; 1296 const TextureType m_textureType; 1297 const bool m_restrictImages; 1298 const bool m_singleLayerBind; 1299 }; 1300 1301 template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatTypeStorageType> 1302 void ImageLoadAndStoreCase::replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat) 1303 { 1304 // Find potential bad values, such as nan or inf, and replace with something else. 1305 const int pixelSize = imageFormat.getPixelSize(); 1306 const int imageNumChannels = imageFormat.order == tcu::TextureFormat::R ? 1 1307 : imageFormat.order == tcu::TextureFormat::RGBA ? 4 1308 : 0; 1309 const IVec3 imageSize = image.getSize(); 1310 const int numSlicesOrFaces = image.getImageType() == TEXTURETYPE_CUBE ? 6 : imageSize.z(); 1311 1312 DE_ASSERT(pixelSize % imageNumChannels == 0); 1313 1314 for (int z = 0; z < numSlicesOrFaces; z++) 1315 { 1316 const PixelBufferAccess sliceAccess = image.getImageType() == TEXTURETYPE_CUBE ? image.getCubeFaceAccess((tcu::CubeFace)z) : image.getSliceAccess(z); 1317 const int rowPitch = sliceAccess.getRowPitch(); 1318 void *const data = sliceAccess.getDataPtr(); 1319 1320 for (int y = 0; y < imageSize.y(); y++) 1321 for (int x = 0; x < imageSize.x(); x++) 1322 { 1323 void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize; 1324 1325 for (int c = 0; c < imageNumChannels; c++) 1326 { 1327 void *const channelData = (deUint8*)pixelData + c*pixelSize/imageNumChannels; 1328 const TcuFloatType f (*(TcuFloatTypeStorageType*)channelData); 1329 1330 if (f.isDenorm() || f.isInf() || f.isNaN()) 1331 *(TcuFloatTypeStorageType*)channelData = TcuFloatType(0.0f).bits(); 1332 } 1333 } 1334 } 1335 } 1336 1337 ImageLoadAndStoreCase::IterateResult ImageLoadAndStoreCase::iterate (void) 1338 { 1339 const RenderContext& renderCtx = m_context.getRenderContext(); 1340 TestLog& log (m_testCtx.getLog()); 1341 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 1342 const deUint32 textureInternalFormatGL = glu::getInternalFormat(m_textureFormat); 1343 const deUint32 imageInternalFormatGL = glu::getInternalFormat(m_imageFormat); 1344 const deUint32 textureTargetGL = getGLTextureTarget(m_textureType); 1345 const IVec3& imageSize = defaultImageSize(m_textureType); 1346 const int maxImageDimension = de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z())); 1347 const float storeColorScale = isFormatTypeUnorm(m_textureFormat.type) ? 1.0f / (float)(maxImageDimension - 1) 1348 : isFormatTypeSnorm(m_textureFormat.type) ? 2.0f / (float)(maxImageDimension - 1) 1349 : 1.0f; 1350 const float storeColorBias = isFormatTypeSnorm(m_textureFormat.type) ? -1.0f : 0.0f; 1351 const int numSlicesOrFaces = m_textureType == TEXTURETYPE_CUBE ? 6 : imageSize.z(); 1352 const bool isIntegerTextureFormat = isFormatTypeInteger(m_textureFormat.type); 1353 const glu::Buffer texture0Buf (renderCtx); 1354 const glu::Buffer texture1Buf (renderCtx); 1355 const glu::Texture texture0 (renderCtx); 1356 const glu::Texture texture1 (renderCtx); 1357 LayeredImage reference (m_textureType, m_textureFormat, imageSize.x(), imageSize.y(), imageSize.z()); 1358 1359 glLog.enableLogging(true); 1360 1361 // Setup textures. 1362 1363 log << TestLog::Message << "// Created 2 textures (names " << *texture0 << " and " << *texture1 << ")" << TestLog::EndMessage; 1364 if (m_textureType == TEXTURETYPE_BUFFER) 1365 log << TestLog::Message << "// Created buffers for the textures (names " << *texture0Buf << " and " << *texture1Buf << ")" << TestLog::EndMessage; 1366 1367 // First, fill reference with (a fairly arbitrary) initial pattern. This will be used as texture upload source data as well as for actual reference computation later on. 1368 1369 DE_ASSERT(!isIntegerTextureFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f)); 1370 1371 for (int z = 0; z < numSlicesOrFaces; z++) 1372 for (int y = 0; y < imageSize.y(); y++) 1373 for (int x = 0; x < imageSize.x(); x++) 1374 { 1375 const IVec4 color(x^y^z, (imageSize.x()-1-x)^y^z, x^(imageSize.y()-1-y)^z, (imageSize.x()-1-x)^(imageSize.y()-1-y)^z); 1376 1377 if (isIntegerTextureFormat) 1378 reference.setPixel(x, y, z, color); 1379 else 1380 reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias); 1381 } 1382 1383 // If re-interpreting the texture contents as floating point values, need to get rid of inf, nan etc. 1384 if (m_imageFormat.type == TextureFormat::HALF_FLOAT && m_textureFormat.type != TextureFormat::HALF_FLOAT) 1385 replaceBadFloatReinterpretValues<TextureFormat::HALF_FLOAT, tcu::Float16, deUint16>(reference, m_imageFormat); 1386 else if (m_imageFormat.type == TextureFormat::FLOAT && m_textureFormat.type != TextureFormat::FLOAT) 1387 replaceBadFloatReinterpretValues<TextureFormat::FLOAT, tcu::Float32, deUint32>(reference, m_imageFormat); 1388 1389 // Upload initial pattern to texture 0. 1390 1391 glLog.glActiveTexture(GL_TEXTURE0); 1392 glLog.glBindTexture(textureTargetGL, *texture0); 1393 setTexParameteri(glLog, textureTargetGL); 1394 1395 log << TestLog::Message << "// Filling texture " << *texture0 << " with xor pattern" << TestLog::EndMessage; 1396 1397 uploadTexture(glLog, reference, *texture0Buf); 1398 1399 // Set storage for texture 1. 1400 1401 glLog.glActiveTexture(GL_TEXTURE1); 1402 glLog.glBindTexture(textureTargetGL, *texture1); 1403 setTexParameteri(glLog, textureTargetGL); 1404 setTextureStorage(glLog, m_textureType, textureInternalFormatGL, imageSize, *texture1Buf); 1405 1406 // Perform image loads and stores in compute shader and finalize reference computation. 1407 1408 { 1409 // Generate compute shader. 1410 1411 const char* const maybeRestrict = m_restrictImages ? "restrict" : ""; 1412 const string shaderImageFormatStr = getShaderImageFormatQualifier(m_imageFormat); 1413 const TextureType shaderImageType = m_singleLayerBind ? textureLayerType(m_textureType) : m_textureType; 1414 const string shaderImageTypeStr = getShaderImageType(m_imageFormat.type, shaderImageType); 1415 1416 const glu::ShaderProgram program(renderCtx, 1417 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 1418 + textureTypeExtensionShaderRequires(shaderImageType) + 1419 "\n" 1420 "precision highp " + shaderImageTypeStr + ";\n" 1421 "\n" 1422 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 1423 "layout (" + shaderImageFormatStr + ", binding=0) " + maybeRestrict + " readonly uniform " + shaderImageTypeStr + " u_image0;\n" 1424 "layout (" + shaderImageFormatStr + ", binding=1) " + maybeRestrict + " writeonly uniform " + shaderImageTypeStr + " u_image1;\n" 1425 "\n" 1426 "void main (void)\n" 1427 "{\n" 1428 + (shaderImageType == TEXTURETYPE_BUFFER ? 1429 " int pos = int(gl_GlobalInvocationID.x);\n" 1430 " imageStore(u_image1, pos, imageLoad(u_image0, " + toString(imageSize.x()-1) + "-pos));\n" 1431 : shaderImageType == TEXTURETYPE_2D ? 1432 " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n" 1433 " imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" + toString(imageSize.x()-1) + "-pos.x, pos.y)));\n" 1434 : shaderImageType == TEXTURETYPE_3D || shaderImageType == TEXTURETYPE_CUBE || shaderImageType == TEXTURETYPE_2D_ARRAY ? 1435 " ivec3 pos = ivec3(gl_GlobalInvocationID);\n" 1436 " imageStore(u_image1, pos, imageLoad(u_image0, ivec3(" + toString(imageSize.x()-1) + "-pos.x, pos.y, pos.z)));\n" 1437 : DE_NULL) + 1438 "}\n")); 1439 1440 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 1441 1442 log << program; 1443 1444 if (!program.isOk()) 1445 { 1446 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 1447 return STOP; 1448 } 1449 1450 // Setup and dispatch. 1451 1452 glLog.glUseProgram(program.getProgram()); 1453 1454 if (m_singleLayerBind) 1455 { 1456 for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++) 1457 { 1458 if (layerNdx > 0) 1459 glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 1460 1461 glLog.glBindImageTexture(0, *texture0, 0, GL_FALSE, layerNdx, GL_READ_ONLY, imageInternalFormatGL); 1462 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1463 1464 glLog.glBindImageTexture(1, *texture1, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, imageInternalFormatGL); 1465 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1466 1467 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1); 1468 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 1469 } 1470 } 1471 else 1472 { 1473 glLog.glBindImageTexture(0, *texture0, 0, GL_TRUE, 0, GL_READ_ONLY, imageInternalFormatGL); 1474 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1475 1476 glLog.glBindImageTexture(1, *texture1, 0, GL_TRUE, 0, GL_WRITE_ONLY, imageInternalFormatGL); 1477 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1478 1479 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces); 1480 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 1481 } 1482 1483 // Finalize reference. 1484 1485 if (m_textureFormat != m_imageFormat) 1486 { 1487 // Format re-interpretation case. Read data with image format and write back, with the same image format. 1488 // We do this because the data may change a little during lookups (e.g. unorm8 -> float; not all unorms can be exactly represented as floats). 1489 1490 const int pixelSize = m_imageFormat.getPixelSize(); 1491 tcu::TextureLevel scratch (m_imageFormat, 1, 1); 1492 const PixelBufferAccess scratchAccess = scratch.getAccess(); 1493 1494 for (int z = 0; z < numSlicesOrFaces; z++) 1495 { 1496 const PixelBufferAccess sliceAccess = m_textureType == TEXTURETYPE_CUBE ? reference.getCubeFaceAccess((tcu::CubeFace)z) : reference.getSliceAccess(z); 1497 const int rowPitch = sliceAccess.getRowPitch(); 1498 void *const data = sliceAccess.getDataPtr(); 1499 1500 for (int y = 0; y < imageSize.y(); y++) 1501 for (int x = 0; x < imageSize.x(); x++) 1502 { 1503 void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize; 1504 1505 deMemcpy(scratchAccess.getDataPtr(), pixelData, pixelSize); 1506 1507 if (isFormatTypeInteger(m_imageFormat.type)) 1508 scratchAccess.setPixel(scratchAccess.getPixelUint(0, 0), 0, 0); 1509 else 1510 scratchAccess.setPixel(scratchAccess.getPixel(0, 0), 0, 0); 1511 1512 deMemcpy(pixelData, scratchAccess.getDataPtr(), pixelSize); 1513 } 1514 } 1515 } 1516 1517 for (int z = 0; z < numSlicesOrFaces; z++) 1518 for (int y = 0; y < imageSize.y(); y++) 1519 for (int x = 0; x < imageSize.x()/2; x++) 1520 { 1521 if (isIntegerTextureFormat) 1522 { 1523 const UVec4 temp = reference.getPixelUint(imageSize.x()-1-x, y, z); 1524 reference.setPixel(imageSize.x()-1-x, y, z, reference.getPixelUint(x, y, z)); 1525 reference.setPixel(x, y, z, temp); 1526 } 1527 else 1528 { 1529 const Vec4 temp = reference.getPixel(imageSize.x()-1-x, y, z); 1530 reference.setPixel(imageSize.x()-1-x, y, z, reference.getPixel(x, y, z)); 1531 reference.setPixel(x, y, z, temp); 1532 } 1533 } 1534 } 1535 1536 // Read texture 1 and compare to reference. 1537 1538 const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture1, *texture1Buf, m_textureType, m_textureFormat, imageSize, ImageLayerComparer(reference)); 1539 1540 m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed"); 1541 return STOP; 1542 } 1543 1544 enum AtomicOperationCaseType 1545 { 1546 ATOMIC_OPERATION_CASE_TYPE_END_RESULT = 0, //!< Atomic case checks the end result of the operations, and not the return values. 1547 ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES, //!< Atomic case checks the return values of the atomic function, and not the end result. 1548 1549 ATOMIC_OPERATION_CASE_TYPE_LAST 1550 }; 1551 1552 /*--------------------------------------------------------------------*//*! 1553 * \brief Binary atomic operation case. 1554 * 1555 * Case that performs binary atomic operations (i.e. any but compSwap) and 1556 * verifies according to the given AtomicOperationCaseType. 1557 * 1558 * For the "end result" case type, a single texture (and image) is created, 1559 * upon which the atomic operations operate. A compute shader is dispatched 1560 * with dimensions equal to the image size, except with a bigger X size 1561 * so that every pixel is operated on by multiple invocations. The end 1562 * results are verified in BinaryAtomicOperationCase::EndResultVerifier. 1563 * The return values of the atomic function calls are ignored. 1564 * 1565 * For the "return value" case type, the case does much the same operations 1566 * as in the "end result" case, but also creates an additional texture, 1567 * of size equal to the dispatch size, into which the return values of the 1568 * atomic functions are stored (with imageStore()). The return values are 1569 * verified in BinaryAtomicOperationCase::ReturnValueVerifier. 1570 * The end result values are not checked. 1571 * 1572 * The compute shader invocations contributing to a pixel (X, Y, Z) in the 1573 * end result image are the invocations with global IDs 1574 * (X, Y, Z), (X+W, Y, Z), (X+2*W, Y, Z), ..., (X+(N-1)*W, Y, W), where W 1575 * is the width of the end result image and N is 1576 * BinaryAtomicOperationCase::NUM_INVOCATIONS_PER_PIXEL. 1577 *//*--------------------------------------------------------------------*/ 1578 class BinaryAtomicOperationCase : public TestCase 1579 { 1580 public: 1581 BinaryAtomicOperationCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperation operation, AtomicOperationCaseType caseType) 1582 : TestCase (context, name, description) 1583 , m_format (format) 1584 , m_imageType (imageType) 1585 , m_operation (operation) 1586 , m_caseType (caseType) 1587 { 1588 DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32) || 1589 m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32) || 1590 (m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT) && m_operation == ATOMIC_OPERATION_EXCHANGE)); 1591 1592 DE_ASSERT(m_operation != ATOMIC_OPERATION_COMP_SWAP); 1593 } 1594 1595 void init (void); 1596 IterateResult iterate (void); 1597 1598 private: 1599 class EndResultVerifier; 1600 class ReturnValueVerifier; 1601 1602 static int getOperationInitialValue (AtomicOperation op); //!< Appropriate value with which to initialize the texture. 1603 //! Compute the argument given to the atomic function at the given invocation ID, when the entire dispatch has the given width and height. 1604 static int getAtomicFuncArgument (AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY); 1605 //! Generate the shader expression for the argument given to the atomic function. x, y and z are the identifiers for the invocation ID components. 1606 static string getAtomicFuncArgumentShaderStr (AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY); 1607 1608 static const int NUM_INVOCATIONS_PER_PIXEL = 5; 1609 1610 const TextureFormat m_format; 1611 const TextureType m_imageType; 1612 const AtomicOperation m_operation; 1613 const AtomicOperationCaseType m_caseType; 1614 }; 1615 1616 int BinaryAtomicOperationCase::getOperationInitialValue (AtomicOperation op) 1617 { 1618 switch (op) 1619 { 1620 // \note 18 is just an arbitrary small nonzero value. 1621 case ATOMIC_OPERATION_ADD: return 18; 1622 case ATOMIC_OPERATION_MIN: return (1<<15) - 1; 1623 case ATOMIC_OPERATION_MAX: return 18; 1624 case ATOMIC_OPERATION_AND: return (1<<15) - 1; 1625 case ATOMIC_OPERATION_OR: return 18; 1626 case ATOMIC_OPERATION_XOR: return 18; 1627 case ATOMIC_OPERATION_EXCHANGE: return 18; 1628 default: 1629 DE_ASSERT(false); 1630 return -1; 1631 } 1632 } 1633 1634 int BinaryAtomicOperationCase::getAtomicFuncArgument (AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY) 1635 { 1636 const int x = invocationID.x(); 1637 const int y = invocationID.y(); 1638 const int z = invocationID.z(); 1639 const int wid = dispatchSizeXY.x(); 1640 const int hei = dispatchSizeXY.y(); 1641 1642 switch (op) 1643 { 1644 // \note Fall-throughs. 1645 case ATOMIC_OPERATION_ADD: 1646 case ATOMIC_OPERATION_MIN: 1647 case ATOMIC_OPERATION_MAX: 1648 case ATOMIC_OPERATION_AND: 1649 case ATOMIC_OPERATION_OR: 1650 case ATOMIC_OPERATION_XOR: 1651 return x*x + y*y + z*z; 1652 1653 case ATOMIC_OPERATION_EXCHANGE: 1654 return (z*wid + x)*hei + y; 1655 1656 default: 1657 DE_ASSERT(false); 1658 return -1; 1659 } 1660 } 1661 1662 string BinaryAtomicOperationCase::getAtomicFuncArgumentShaderStr (AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY) 1663 { 1664 switch (op) 1665 { 1666 // \note Fall-throughs. 1667 case ATOMIC_OPERATION_ADD: 1668 case ATOMIC_OPERATION_MIN: 1669 case ATOMIC_OPERATION_MAX: 1670 case ATOMIC_OPERATION_AND: 1671 case ATOMIC_OPERATION_OR: 1672 case ATOMIC_OPERATION_XOR: 1673 return "("+ x+"*"+x +" + "+ y+"*"+y +" + "+ z+"*"+z +")"; 1674 1675 case ATOMIC_OPERATION_EXCHANGE: 1676 return "((" + z + "*" + toString(dispatchSizeXY.x()) + " + " + x + ")*" + toString(dispatchSizeXY.y()) + " + " + y + ")"; 1677 1678 default: 1679 DE_ASSERT(false); 1680 return DE_NULL; 1681 } 1682 } 1683 1684 class BinaryAtomicOperationCase::EndResultVerifier : public ImageLayerVerifier 1685 { 1686 public: 1687 EndResultVerifier (AtomicOperation operation, TextureType imageType) : m_operation(operation), m_imageType(imageType) {} 1688 1689 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const 1690 { 1691 const bool isIntegerFormat = isFormatTypeInteger(resultSlice.getFormat().type); 1692 const IVec2 dispatchSizeXY (NUM_INVOCATIONS_PER_PIXEL*resultSlice.getWidth(), resultSlice.getHeight()); 1693 1694 log << TestLog::Image("EndResults" + toString(sliceOrFaceNdx), 1695 "Result Values, " + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)))) 1696 : "slice " + toString(sliceOrFaceNdx)), 1697 resultSlice); 1698 1699 for (int y = 0; y < resultSlice.getHeight(); y++) 1700 for (int x = 0; x < resultSlice.getWidth(); x++) 1701 { 1702 union 1703 { 1704 int i; 1705 float f; 1706 } result; 1707 1708 if (isIntegerFormat) 1709 result.i = resultSlice.getPixelInt(x, y).x(); 1710 else 1711 result.f = resultSlice.getPixel(x, y).x(); 1712 1713 // Compute the arguments that were given to the atomic function in the invocations that contribute to this pixel. 1714 1715 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL]; 1716 int atomicArgs[NUM_INVOCATIONS_PER_PIXEL]; 1717 1718 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 1719 { 1720 const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx); 1721 1722 invocationGlobalIDs[i] = gid; 1723 atomicArgs[i] = getAtomicFuncArgument(m_operation, gid, dispatchSizeXY); 1724 } 1725 1726 if (isOrderIndependentAtomicOperation(m_operation)) 1727 { 1728 // Just accumulate the atomic args (and the initial value) according to the operation, and compare. 1729 1730 DE_ASSERT(isIntegerFormat); 1731 1732 int reference = getOperationInitialValue(m_operation); 1733 1734 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 1735 reference = computeBinaryAtomicOperationResult(m_operation, reference, atomicArgs[i]); 1736 1737 if (result.i != reference) 1738 { 1739 log << TestLog::Message << "// Failure: end result at pixel " << IVec2(x, y) << " of current layer is " << result.i << TestLog::EndMessage 1740 << TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage 1741 << TestLog::Message << "// Note: data expression values for the IDs are " << arrayStr(atomicArgs) << TestLog::EndMessage 1742 << TestLog::Message << "// Note: reference value is " << reference << TestLog::EndMessage; 1743 return false; 1744 } 1745 } 1746 else if (m_operation == ATOMIC_OPERATION_EXCHANGE) 1747 { 1748 // Check that the end result equals one of the atomic args. 1749 1750 bool matchFound = false; 1751 1752 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++) 1753 matchFound = isIntegerFormat ? result.i == atomicArgs[i] 1754 : de::abs(result.f - (float)atomicArgs[i]) <= 0.01f; 1755 1756 if (!matchFound) 1757 { 1758 log << TestLog::Message << "// Failure: invalid value at pixel " << IVec2(x, y) << ": got " << (isIntegerFormat ? toString(result.i) : toString(result.f)) << TestLog::EndMessage 1759 << TestLog::Message << "// Note: expected one of " << arrayStr(atomicArgs) << TestLog::EndMessage; 1760 1761 return false; 1762 } 1763 } 1764 else 1765 DE_ASSERT(false); 1766 } 1767 1768 return true; 1769 } 1770 1771 private: 1772 const AtomicOperation m_operation; 1773 const TextureType m_imageType; 1774 }; 1775 1776 class BinaryAtomicOperationCase::ReturnValueVerifier : public ImageLayerVerifier 1777 { 1778 public: 1779 //! \note endResultImageLayerSize is (width, height) of the image operated on by the atomic ops, and not the size of the image where the return values are stored. 1780 ReturnValueVerifier (AtomicOperation operation, TextureType imageType, const IVec2& endResultImageLayerSize) : m_operation(operation), m_imageType(imageType), m_endResultImageLayerSize(endResultImageLayerSize) {} 1781 1782 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const 1783 { 1784 const bool isIntegerFormat (isFormatTypeInteger(resultSlice.getFormat().type)); 1785 const IVec2 dispatchSizeXY (resultSlice.getWidth(), resultSlice.getHeight()); 1786 1787 DE_ASSERT(resultSlice.getWidth() == NUM_INVOCATIONS_PER_PIXEL*m_endResultImageLayerSize.x() && 1788 resultSlice.getHeight() == m_endResultImageLayerSize.y() && 1789 resultSlice.getDepth() == 1); 1790 1791 log << TestLog::Image("ReturnValues" + toString(sliceOrFaceNdx), 1792 "Per-Invocation Return Values, " 1793 + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)))) 1794 : "slice " + toString(sliceOrFaceNdx)), 1795 resultSlice); 1796 1797 for (int y = 0; y < m_endResultImageLayerSize.y(); y++) 1798 for (int x = 0; x < m_endResultImageLayerSize.x(); x++) 1799 { 1800 union IntFloatArr 1801 { 1802 int i[NUM_INVOCATIONS_PER_PIXEL]; 1803 float f[NUM_INVOCATIONS_PER_PIXEL]; 1804 }; 1805 1806 // Get the atomic function args and return values for all the invocations that contribute to the pixel (x, y) in the current end result slice. 1807 1808 IntFloatArr returnValues; 1809 IntFloatArr atomicArgs; 1810 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL]; 1811 IVec2 pixelCoords[NUM_INVOCATIONS_PER_PIXEL]; 1812 1813 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 1814 { 1815 const IVec2 pixCoord (x + i*m_endResultImageLayerSize.x(), y); 1816 const IVec3 gid (pixCoord.x(), pixCoord.y(), sliceOrFaceNdx); 1817 1818 invocationGlobalIDs[i] = gid; 1819 pixelCoords[i] = pixCoord; 1820 1821 if (isIntegerFormat) 1822 { 1823 returnValues.i[i] = resultSlice.getPixelInt(gid.x(), y).x(); 1824 atomicArgs.i[i] = getAtomicFuncArgument(m_operation, gid, dispatchSizeXY); 1825 } 1826 else 1827 { 1828 returnValues.f[i] = resultSlice.getPixel(gid.x(), y).x(); 1829 atomicArgs.f[i] = (float)getAtomicFuncArgument(m_operation, gid, dispatchSizeXY); 1830 } 1831 } 1832 1833 // Verify that the return values form a valid sequence. 1834 1835 { 1836 const bool success = isIntegerFormat ? verifyOperationAccumulationIntermediateValues(m_operation, 1837 getOperationInitialValue(m_operation), 1838 atomicArgs.i, 1839 returnValues.i) 1840 1841 : verifyOperationAccumulationIntermediateValues(m_operation, 1842 (float)getOperationInitialValue(m_operation), 1843 atomicArgs.f, 1844 returnValues.f); 1845 1846 if (!success) 1847 { 1848 log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are " 1849 << (isIntegerFormat ? arrayStr(returnValues.i) : arrayStr(returnValues.f)) << TestLog::EndMessage 1850 << TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage 1851 << TestLog::Message << "// Note: data expression values for the IDs are " 1852 << (isIntegerFormat ? arrayStr(atomicArgs.i) : arrayStr(atomicArgs.f)) 1853 << "; return values are not a valid result for any order of operations" << TestLog::EndMessage; 1854 return false; 1855 } 1856 } 1857 } 1858 1859 return true; 1860 } 1861 1862 private: 1863 const AtomicOperation m_operation; 1864 const TextureType m_imageType; 1865 const IVec2 m_endResultImageLayerSize; 1866 1867 //! Check whether there exists an ordering of args such that { init*A", init*A*B, ..., init*A*B*...*LAST } is the "returnValues" sequence, where { A, B, ..., LAST } is args, and * denotes the operation. 1868 // That is, whether "returnValues" is a valid sequence of intermediate return values when "operation" has been accumulated on "args" (and "init") in some arbitrary order. 1869 template <typename T> 1870 static bool verifyOperationAccumulationIntermediateValues (AtomicOperation operation, T init, const T (&args)[NUM_INVOCATIONS_PER_PIXEL], const T (&returnValues)[NUM_INVOCATIONS_PER_PIXEL]) 1871 { 1872 bool argsUsed[NUM_INVOCATIONS_PER_PIXEL] = { false }; 1873 1874 return verifyRecursive(operation, 0, init, argsUsed, args, returnValues); 1875 } 1876 1877 static bool compare (int a, int b) { return a == b; } 1878 static bool compare (float a, float b) { return de::abs(a - b) <= 0.01f; } 1879 1880 //! Depth-first search for verifying the return value sequence. 1881 template <typename T> 1882 static bool verifyRecursive (AtomicOperation operation, int index, T valueSoFar, bool (&argsUsed)[NUM_INVOCATIONS_PER_PIXEL], const T (&args)[NUM_INVOCATIONS_PER_PIXEL], const T (&returnValues)[NUM_INVOCATIONS_PER_PIXEL]) 1883 { 1884 if (index < NUM_INVOCATIONS_PER_PIXEL) 1885 { 1886 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 1887 { 1888 if (!argsUsed[i] && compare(returnValues[i], valueSoFar)) 1889 { 1890 argsUsed[i] = true; 1891 if (verifyRecursive(operation, index+1, computeBinaryAtomicOperationResult(operation, valueSoFar, args[i]), argsUsed, args, returnValues)) 1892 return true; 1893 argsUsed[i] = false; 1894 } 1895 } 1896 1897 return false; 1898 } 1899 else 1900 return true; 1901 } 1902 }; 1903 1904 void BinaryAtomicOperationCase::init (void) 1905 { 1906 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic")) 1907 throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension"); 1908 1909 checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType); 1910 } 1911 1912 BinaryAtomicOperationCase::IterateResult BinaryAtomicOperationCase::iterate (void) 1913 { 1914 const RenderContext& renderCtx = m_context.getRenderContext(); 1915 TestLog& log (m_testCtx.getLog()); 1916 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 1917 const deUint32 internalFormatGL = glu::getInternalFormat(m_format); 1918 const deUint32 textureTargetGL = getGLTextureTarget(m_imageType); 1919 const IVec3& imageSize = defaultImageSize(m_imageType); 1920 const int numSlicesOrFaces = m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z(); 1921 const bool isUintFormat = isFormatTypeUnsignedInteger(m_format.type); 1922 const bool isIntFormat = isFormatTypeSignedInteger(m_format.type); 1923 const glu::Buffer endResultTextureBuf (renderCtx); 1924 const glu::Buffer returnValueTextureBuf (renderCtx); 1925 const glu::Texture endResultTexture (renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize. 1926 const glu::Texture returnValueTexture (renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES. 1927 // Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL. 1928 1929 glLog.enableLogging(true); 1930 1931 // Setup textures. 1932 1933 log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage; 1934 if (m_imageType == TEXTURETYPE_BUFFER) 1935 log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage; 1936 1937 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES) 1938 { 1939 log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage; 1940 if (m_imageType == TEXTURETYPE_BUFFER) 1941 log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage; 1942 } 1943 1944 // Fill endResultTexture with initial pattern. 1945 1946 { 1947 const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z()); 1948 1949 { 1950 const IVec4 initial(getOperationInitialValue(m_operation)); 1951 1952 for (int z = 0; z < numSlicesOrFaces; z++) 1953 for (int y = 0; y < imageSize.y(); y++) 1954 for (int x = 0; x < imageSize.x(); x++) 1955 imageData.setPixel(x, y, z, initial); 1956 } 1957 1958 // Upload initial pattern to endResultTexture and bind to image. 1959 1960 glLog.glActiveTexture(GL_TEXTURE0); 1961 glLog.glBindTexture(textureTargetGL, *endResultTexture); 1962 setTexParameteri(glLog, textureTargetGL); 1963 1964 log << TestLog::Message << "// Filling end-result texture with initial pattern (initial value " << getOperationInitialValue(m_operation) << ")" << TestLog::EndMessage; 1965 1966 uploadTexture(glLog, imageData, *endResultTextureBuf); 1967 } 1968 1969 glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL); 1970 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1971 1972 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES) 1973 { 1974 // Set storage for returnValueTexture and bind to image. 1975 1976 glLog.glActiveTexture(GL_TEXTURE1); 1977 glLog.glBindTexture(textureTargetGL, *returnValueTexture); 1978 setTexParameteri(glLog, textureTargetGL); 1979 1980 log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage; 1981 setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL, 1) 1982 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1, 1)), 1983 *returnValueTextureBuf); 1984 1985 glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL); 1986 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 1987 } 1988 1989 // Perform image stores in compute shader and finalize reference computation. 1990 1991 { 1992 // Generate compute shader. 1993 1994 const string colorVecTypeName = string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4"; 1995 const string atomicCoord = m_imageType == TEXTURETYPE_BUFFER ? "gx % " + toString(imageSize.x()) 1996 : m_imageType == TEXTURETYPE_2D ? "ivec2(gx % " + toString(imageSize.x()) + ", gy)" 1997 : "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)"; 1998 const string invocationCoord = m_imageType == TEXTURETYPE_BUFFER ? "gx" 1999 : m_imageType == TEXTURETYPE_2D ? "ivec2(gx, gy)" 2000 : "ivec3(gx, gy, gz)"; 2001 const string atomicArgExpr = (isUintFormat ? "uint" 2002 : isIntFormat ? "" 2003 : "float") 2004 + getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec2(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y())); 2005 const string atomicInvocation = string() + getAtomicOperationShaderFuncName(m_operation) + "(u_results, " + atomicCoord + ", " + atomicArgExpr + ")"; 2006 const string shaderImageFormatStr = getShaderImageFormatQualifier(m_format); 2007 const string shaderImageTypeStr = getShaderImageType(m_format.type, m_imageType); 2008 2009 const glu::ShaderProgram program(renderCtx, 2010 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 2011 "#extension GL_OES_shader_image_atomic : require\n" 2012 + textureTypeExtensionShaderRequires(m_imageType) + 2013 "\n" 2014 "precision highp " + shaderImageTypeStr + ";\n" 2015 "\n" 2016 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2017 "layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n" 2018 + (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? 2019 "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n" 2020 : "") + 2021 "\n" 2022 "void main (void)\n" 2023 "{\n" 2024 " int gx = int(gl_GlobalInvocationID.x);\n" 2025 " int gy = int(gl_GlobalInvocationID.y);\n" 2026 " int gz = int(gl_GlobalInvocationID.z);\n" 2027 + (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? 2028 " imageStore(u_returnValues, " + invocationCoord + ", " + colorVecTypeName + "(" + atomicInvocation + "));\n" 2029 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? 2030 " " + atomicInvocation + ";\n" 2031 : DE_NULL) + 2032 "}\n")); 2033 2034 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 2035 2036 log << program; 2037 2038 if (!program.isOk()) 2039 { 2040 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 2041 return STOP; 2042 } 2043 2044 // Setup and dispatch. 2045 2046 glLog.glUseProgram(program.getProgram()); 2047 2048 glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces); 2049 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 2050 } 2051 2052 // Read texture and check. 2053 2054 { 2055 const deUint32 textureToCheckGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTexture 2056 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTexture 2057 : (deUint32)-1; 2058 const deUint32 textureToCheckBufGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTextureBuf 2059 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTextureBuf 2060 : (deUint32)-1; 2061 2062 const IVec3 textureToCheckSize = imageSize * IVec3(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? 1 : NUM_INVOCATIONS_PER_PIXEL, 1, 1); 2063 const UniquePtr<const ImageLayerVerifier> verifier (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? new EndResultVerifier(m_operation, m_imageType) 2064 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? new ReturnValueVerifier(m_operation, m_imageType, imageSize.swizzle(0, 1)) 2065 : (ImageLayerVerifier*)DE_NULL); 2066 2067 if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, textureToCheckSize, *verifier)) 2068 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2069 else 2070 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 2071 2072 return STOP; 2073 } 2074 } 2075 2076 /*--------------------------------------------------------------------*//*! 2077 * \brief Atomic compSwap operation case. 2078 * 2079 * Similar in principle to BinaryAtomicOperationCase, but separated for 2080 * convenience, since the atomic function is somewhat different. Like 2081 * BinaryAtomicOperationCase, this has separate cases for checking end 2082 * result and return values. 2083 *//*--------------------------------------------------------------------*/ 2084 class AtomicCompSwapCase : public TestCase 2085 { 2086 public: 2087 AtomicCompSwapCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperationCaseType caseType) 2088 : TestCase (context, name, description) 2089 , m_format (format) 2090 , m_imageType (imageType) 2091 , m_caseType (caseType) 2092 { 2093 DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32) || 2094 m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32)); 2095 } 2096 2097 void init (void); 2098 IterateResult iterate (void); 2099 2100 private: 2101 class EndResultVerifier; 2102 class ReturnValueVerifier; 2103 2104 static int getCompareArg (const IVec3& invocationID, int imageWidth); 2105 static int getAssignArg (const IVec3& invocationID, int imageWidth); 2106 static string getCompareArgShaderStr (const string& x, const string& y, const string& z, int imageWidth); 2107 static string getAssignArgShaderStr (const string& x, const string& y, const string& z, int imageWidth); 2108 2109 static const int NUM_INVOCATIONS_PER_PIXEL = 5; 2110 2111 const TextureFormat m_format; 2112 const TextureType m_imageType; 2113 const AtomicOperationCaseType m_caseType; 2114 }; 2115 2116 int AtomicCompSwapCase::getCompareArg (const IVec3& invocationID, int imageWidth) 2117 { 2118 const int x = invocationID.x(); 2119 const int y = invocationID.y(); 2120 const int z = invocationID.z(); 2121 const int wrapX = x % imageWidth; 2122 const int curPixelInvocationNdx = x / imageWidth; 2123 2124 return wrapX*wrapX + y*y + z*z + curPixelInvocationNdx*42; 2125 } 2126 2127 int AtomicCompSwapCase::getAssignArg (const IVec3& invocationID, int imageWidth) 2128 { 2129 return getCompareArg(IVec3(invocationID.x() + imageWidth, invocationID.y(), invocationID.z()), imageWidth); 2130 } 2131 2132 string AtomicCompSwapCase::getCompareArgShaderStr (const string& x, const string& y, const string& z, int imageWidth) 2133 { 2134 const string wrapX = "(" + x + "%" + toString(imageWidth) + ")"; 2135 const string curPixelInvocationNdx = "(" + x + "/" + toString(imageWidth) + ")"; 2136 2137 return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)"; 2138 } 2139 2140 string AtomicCompSwapCase::getAssignArgShaderStr (const string& x, const string& y, const string& z, int imageWidth) 2141 { 2142 const string wrapX = "(" + x + "%" + toString(imageWidth) + ")"; 2143 const string curPixelInvocationNdx = "(" + x + "/" + toString(imageWidth) + " + 1)"; 2144 2145 return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)"; 2146 } 2147 2148 void AtomicCompSwapCase::init (void) 2149 { 2150 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic")) 2151 throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension"); 2152 2153 checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType); 2154 } 2155 2156 class AtomicCompSwapCase::EndResultVerifier : public ImageLayerVerifier 2157 { 2158 public: 2159 EndResultVerifier (TextureType imageType, int imageWidth) : m_imageType(imageType), m_imageWidth(imageWidth) {} 2160 2161 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const 2162 { 2163 DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type)); 2164 DE_ASSERT(resultSlice.getWidth() == m_imageWidth); 2165 2166 log << TestLog::Image("EndResults" + toString(sliceOrFaceNdx), 2167 "Result Values, " + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)))) 2168 : "slice " + toString(sliceOrFaceNdx)), 2169 resultSlice); 2170 2171 for (int y = 0; y < resultSlice.getHeight(); y++) 2172 for (int x = 0; x < resultSlice.getWidth(); x++) 2173 { 2174 // Compute the value-to-assign arguments that were given to the atomic function in the invocations that contribute to this pixel. 2175 // One of those should be the result. 2176 2177 const int result = resultSlice.getPixelInt(x, y).x(); 2178 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL]; 2179 int assignArgs[NUM_INVOCATIONS_PER_PIXEL]; 2180 2181 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 2182 { 2183 const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx); 2184 2185 invocationGlobalIDs[i] = gid; 2186 assignArgs[i] = getAssignArg(gid, m_imageWidth); 2187 } 2188 2189 { 2190 bool matchFound = false; 2191 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++) 2192 matchFound = result == assignArgs[i]; 2193 2194 if (!matchFound) 2195 { 2196 log << TestLog::Message << "// Failure: invalid value at pixel " << IVec2(x, y) << ": got " << result << TestLog::EndMessage 2197 << TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage 2198 << TestLog::Message << "// Note: expected one of " << arrayStr(assignArgs) 2199 << " (those are the values given as the 'data' argument in the invocations that contribute to this pixel)" 2200 << TestLog::EndMessage; 2201 return false; 2202 } 2203 } 2204 } 2205 2206 return true; 2207 } 2208 2209 private: 2210 const TextureType m_imageType; 2211 const int m_imageWidth; 2212 }; 2213 2214 class AtomicCompSwapCase::ReturnValueVerifier : public ImageLayerVerifier 2215 { 2216 public: 2217 //! \note endResultImageLayerSize is (width, height) of the image operated on by the atomic ops, and not the size of the image where the return values are stored. 2218 ReturnValueVerifier (TextureType imageType, int endResultImageWidth) : m_imageType(imageType), m_endResultImageWidth(endResultImageWidth) {} 2219 2220 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const 2221 { 2222 DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type)); 2223 DE_ASSERT(resultSlice.getWidth() == NUM_INVOCATIONS_PER_PIXEL*m_endResultImageWidth); 2224 2225 log << TestLog::Image("ReturnValues" + toString(sliceOrFaceNdx), 2226 "Per-Invocation Return Values, " 2227 + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)))) 2228 : "slice " + toString(sliceOrFaceNdx)), 2229 resultSlice); 2230 2231 for (int y = 0; y < resultSlice.getHeight(); y++) 2232 for (int x = 0; x < m_endResultImageWidth; x++) 2233 { 2234 // Get the atomic function args and return values for all the invocations that contribute to the pixel (x, y) in the current end result slice. 2235 2236 int returnValues[NUM_INVOCATIONS_PER_PIXEL]; 2237 int compareArgs[NUM_INVOCATIONS_PER_PIXEL]; 2238 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL]; 2239 IVec2 pixelCoords[NUM_INVOCATIONS_PER_PIXEL]; 2240 2241 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 2242 { 2243 const IVec2 pixCoord (x + i*m_endResultImageWidth, y); 2244 const IVec3 gid (pixCoord.x(), pixCoord.y(), sliceOrFaceNdx); 2245 2246 pixelCoords[i] = pixCoord; 2247 invocationGlobalIDs[i] = gid; 2248 returnValues[i] = resultSlice.getPixelInt(gid.x(), y).x(); 2249 compareArgs[i] = getCompareArg(gid, m_endResultImageWidth); 2250 } 2251 2252 // Verify that the return values form a valid sequence. 2253 // Due to the way the compare and assign arguments to the atomic calls are organized 2254 // among the different invocations contributing to the same pixel -- i.e. one invocation 2255 // compares to A and assigns B, another compares to B and assigns C, and so on, where 2256 // A<B<C etc -- the first value in the return value sequence must be A, and each following 2257 // value must be either the same as or the smallest value (among A, B, C, ...) bigger than 2258 // the one just before it. E.g. sequences A A A A A A A A, A B C D E F G H and 2259 // A A B B B C D E are all valid sequences (if there were 8 invocations contributing 2260 // to each pixel). 2261 2262 { 2263 int failingNdx = -1; 2264 2265 { 2266 int currentAtomicValueNdx = 0; 2267 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++) 2268 { 2269 if (returnValues[i] == compareArgs[currentAtomicValueNdx]) 2270 continue; 2271 if (i > 0 && returnValues[i] == compareArgs[currentAtomicValueNdx+1]) 2272 { 2273 currentAtomicValueNdx++; 2274 continue; 2275 } 2276 failingNdx = i; 2277 break; 2278 } 2279 } 2280 2281 if (failingNdx >= 0) 2282 { 2283 log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are " 2284 << arrayStr(returnValues) << TestLog::EndMessage 2285 << TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage 2286 << TestLog::Message << "// Note: 'compare' argument values for the IDs are " << arrayStr(compareArgs) << TestLog::EndMessage 2287 << TestLog::Message << "// Note: expected the return value sequence to fulfill the following conditions:\n" 2288 << "// - first value is " << compareArgs[0] << "\n" 2289 << "// - each value other than the first is either the same as the one just before it, or the smallest value (in the sequence " 2290 << arrayStr(compareArgs) << ") bigger than the one just before it" << TestLog::EndMessage; 2291 if (failingNdx == 0) 2292 log << TestLog::Message << "// Note: the first return value (" << returnValues[0] << ") isn't " << compareArgs[0] << TestLog::EndMessage; 2293 else 2294 log << TestLog::Message << "// Note: the return value at index " << failingNdx << " (value " << returnValues[failingNdx] << ") " 2295 << "is neither " << returnValues[failingNdx-1] << " (the one just before it) " 2296 << "nor " << compareArgs[arrayIndexOf(compareArgs, returnValues[failingNdx-1])+1] << " (the smallest value bigger than the one just before it)" 2297 << TestLog::EndMessage; 2298 2299 return false; 2300 } 2301 } 2302 } 2303 2304 return true; 2305 } 2306 2307 private: 2308 const TextureType m_imageType; 2309 const int m_endResultImageWidth; 2310 }; 2311 2312 AtomicCompSwapCase::IterateResult AtomicCompSwapCase::iterate (void) 2313 { 2314 const RenderContext& renderCtx = m_context.getRenderContext(); 2315 TestLog& log (m_testCtx.getLog()); 2316 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 2317 const deUint32 internalFormatGL = glu::getInternalFormat(m_format); 2318 const deUint32 textureTargetGL = getGLTextureTarget(m_imageType); 2319 const IVec3& imageSize = defaultImageSize(m_imageType); 2320 const int numSlicesOrFaces = m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z(); 2321 const bool isUintFormat = isFormatTypeUnsignedInteger(m_format.type); 2322 const bool isIntFormat = isFormatTypeSignedInteger(m_format.type); 2323 const glu::Buffer endResultTextureBuf (renderCtx); 2324 const glu::Buffer returnValueTextureBuf (renderCtx); 2325 const glu::Texture endResultTexture (renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize. 2326 const glu::Texture returnValueTexture (renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES. 2327 // Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL. 2328 2329 DE_ASSERT(isUintFormat || isIntFormat); 2330 2331 glLog.enableLogging(true); 2332 2333 // Setup textures. 2334 2335 log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage; 2336 if (m_imageType == TEXTURETYPE_BUFFER) 2337 log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage; 2338 2339 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES) 2340 { 2341 log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage; 2342 if (m_imageType == TEXTURETYPE_BUFFER) 2343 log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage; 2344 } 2345 2346 // Fill endResultTexture with initial pattern. 2347 2348 { 2349 const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z()); 2350 2351 { 2352 for (int z = 0; z < numSlicesOrFaces; z++) 2353 for (int y = 0; y < imageSize.y(); y++) 2354 for (int x = 0; x < imageSize.x(); x++) 2355 imageData.setPixel(x, y, z, IVec4(getCompareArg(IVec3(x, y, z), imageSize.x()))); 2356 } 2357 2358 // Upload initial pattern to endResultTexture and bind to image. 2359 2360 glLog.glActiveTexture(GL_TEXTURE0); 2361 glLog.glBindTexture(textureTargetGL, *endResultTexture); 2362 setTexParameteri(glLog, textureTargetGL); 2363 2364 log << TestLog::Message << "// Filling end-result texture with initial pattern" << TestLog::EndMessage; 2365 2366 uploadTexture(glLog, imageData, *endResultTextureBuf); 2367 } 2368 2369 glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL); 2370 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 2371 2372 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES) 2373 { 2374 // Set storage for returnValueTexture and bind to image. 2375 2376 glLog.glActiveTexture(GL_TEXTURE1); 2377 glLog.glBindTexture(textureTargetGL, *returnValueTexture); 2378 setTexParameteri(glLog, textureTargetGL); 2379 2380 log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage; 2381 setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL, 1) 2382 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1, 1)), 2383 *returnValueTextureBuf); 2384 2385 glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL); 2386 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 2387 } 2388 2389 // Perform atomics in compute shader. 2390 2391 { 2392 // Generate compute shader. 2393 2394 const string colorScalarTypeName = isUintFormat ? "uint" : isIntFormat ? "int" : DE_NULL; 2395 const string colorVecTypeName = string(isUintFormat ? "u" : isIntFormat ? "i" : DE_NULL) + "vec4"; 2396 const string atomicCoord = m_imageType == TEXTURETYPE_BUFFER ? "gx % " + toString(imageSize.x()) 2397 : m_imageType == TEXTURETYPE_2D ? "ivec2(gx % " + toString(imageSize.x()) + ", gy)" 2398 : "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)"; 2399 const string invocationCoord = m_imageType == TEXTURETYPE_BUFFER ? "gx" 2400 : m_imageType == TEXTURETYPE_2D ? "ivec2(gx, gy)" 2401 : "ivec3(gx, gy, gz)"; 2402 const string shaderImageFormatStr = getShaderImageFormatQualifier(m_format); 2403 const string shaderImageTypeStr = getShaderImageType(m_format.type, m_imageType); 2404 2405 const glu::ShaderProgram program(renderCtx, 2406 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 2407 "#extension GL_OES_shader_image_atomic : require\n" 2408 + textureTypeExtensionShaderRequires(m_imageType) + 2409 "\n" 2410 "precision highp " + shaderImageTypeStr + ";\n" 2411 "\n" 2412 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2413 "layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n" 2414 + (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? 2415 "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n" 2416 : "") + 2417 "\n" 2418 "void main (void)\n" 2419 "{\n" 2420 " int gx = int(gl_GlobalInvocationID.x);\n" 2421 " int gy = int(gl_GlobalInvocationID.y);\n" 2422 " int gz = int(gl_GlobalInvocationID.z);\n" 2423 " " + colorScalarTypeName + " compare = " + colorScalarTypeName + getCompareArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n" 2424 " " + colorScalarTypeName + " data = " + colorScalarTypeName + getAssignArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n" 2425 " " + colorScalarTypeName + " status = " + colorScalarTypeName + "(-1);\n" 2426 " status = imageAtomicCompSwap(u_results, " + atomicCoord + ", compare, data);\n" 2427 + (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? 2428 " imageStore(u_returnValues, " + invocationCoord + ", " + colorVecTypeName + "(status));\n" : 2429 "") + 2430 "}\n")); 2431 2432 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 2433 2434 log << program; 2435 2436 if (!program.isOk()) 2437 { 2438 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 2439 return STOP; 2440 } 2441 2442 // Setup and dispatch. 2443 2444 glLog.glUseProgram(program.getProgram()); 2445 2446 glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces); 2447 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 2448 } 2449 2450 // Create reference, read texture and compare. 2451 2452 { 2453 const deUint32 textureToCheckGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTexture 2454 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTexture 2455 : (deUint32)-1; 2456 2457 const deUint32 textureToCheckBufGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTextureBuf 2458 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTextureBuf 2459 : (deUint32)-1; 2460 2461 // Actual size of the texture being checked. 2462 const IVec3 textureToCheckSize = imageSize * (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? IVec3(1, 1, 1) 2463 : m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL, 1) 2464 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1, 1)); 2465 2466 // The relevant region of the texture being checked (potentially 2467 // different from actual texture size for cube maps, because cube maps 2468 // may have unused pixels due to square size restriction). 2469 const IVec3 relevantRegion = imageSize * (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? IVec3(1, 1, 1) 2470 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1, 1)); 2471 2472 const UniquePtr<const ImageLayerVerifier> verifier (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? new EndResultVerifier(m_imageType, imageSize.x()) 2473 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? new ReturnValueVerifier(m_imageType, imageSize.x()) 2474 : (ImageLayerVerifier*)DE_NULL); 2475 2476 if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, relevantRegion, *verifier)) 2477 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2478 else 2479 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 2480 2481 return STOP; 2482 } 2483 } 2484 2485 //! Case testing the "coherent" or "volatile" qualifier, along with memoryBarrier() and barrier(). 2486 class CoherenceCase : public TestCase 2487 { 2488 public: 2489 enum Qualifier 2490 { 2491 QUALIFIER_COHERENT = 0, 2492 QUALIFIER_VOLATILE, 2493 2494 QUALIFIER_LAST 2495 }; 2496 2497 CoherenceCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, Qualifier qualifier) 2498 : TestCase (context, name, description) 2499 , m_format (format) 2500 , m_imageType (imageType) 2501 , m_qualifier (qualifier) 2502 { 2503 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Y) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X) && 2504 DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Z) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X)); 2505 2506 DE_ASSERT(qualifier == QUALIFIER_COHERENT || qualifier == QUALIFIER_VOLATILE); 2507 2508 DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32) || 2509 m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32) || 2510 m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT)); 2511 } 2512 2513 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType); } 2514 IterateResult iterate (void); 2515 2516 private: 2517 static const int SHADER_READ_OFFSETS_X[4]; 2518 static const int SHADER_READ_OFFSETS_Y[4]; 2519 static const int SHADER_READ_OFFSETS_Z[4]; 2520 static const char* const SHADER_READ_OFFSETS_X_STR; 2521 static const char* const SHADER_READ_OFFSETS_Y_STR; 2522 static const char* const SHADER_READ_OFFSETS_Z_STR; 2523 2524 const TextureFormat m_format; 2525 const TextureType m_imageType; 2526 const Qualifier m_qualifier; 2527 }; 2528 2529 const int CoherenceCase::SHADER_READ_OFFSETS_X[4] = { 1, 4, 7, 10 }; 2530 const int CoherenceCase::SHADER_READ_OFFSETS_Y[4] = { 2, 5, 8, 11 }; 2531 const int CoherenceCase::SHADER_READ_OFFSETS_Z[4] = { 3, 6, 9, 12 }; 2532 const char* const CoherenceCase::SHADER_READ_OFFSETS_X_STR = "int[]( 1, 4, 7, 10 )"; 2533 const char* const CoherenceCase::SHADER_READ_OFFSETS_Y_STR = "int[]( 2, 5, 8, 11 )"; 2534 const char* const CoherenceCase::SHADER_READ_OFFSETS_Z_STR = "int[]( 3, 6, 9, 12 )"; 2535 2536 CoherenceCase::IterateResult CoherenceCase::iterate (void) 2537 { 2538 const RenderContext& renderCtx = m_context.getRenderContext(); 2539 TestLog& log (m_testCtx.getLog()); 2540 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 2541 const deUint32 internalFormatGL = glu::getInternalFormat(m_format); 2542 const deUint32 textureTargetGL = getGLTextureTarget(m_imageType); 2543 const IVec3& imageSize = defaultImageSize(m_imageType); 2544 const int numSlicesOrFaces = m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z(); 2545 const bool isUintFormat = isFormatTypeUnsignedInteger(m_format.type); 2546 const bool isIntFormat = isFormatTypeSignedInteger(m_format.type); 2547 const char* const qualifierName = m_qualifier == QUALIFIER_COHERENT ? "coherent" 2548 : m_qualifier == QUALIFIER_VOLATILE ? "volatile" 2549 : DE_NULL; 2550 const glu::Buffer textureBuf (renderCtx); 2551 const glu::Texture texture (renderCtx); 2552 const IVec3 numGroups = IVec3(16, de::min(16, imageSize.y()), de::min(2, numSlicesOrFaces)); 2553 const IVec3 workItemSize = IVec3(imageSize.x(), imageSize.y(), numSlicesOrFaces); 2554 const IVec3 localSize = workItemSize / numGroups; 2555 const IVec3 minReqMaxLocalSize = IVec3(128, 128, 64); 2556 const int minReqMaxLocalInvocations = 128; 2557 2558 DE_ASSERT(workItemSize == localSize*numGroups); 2559 DE_ASSERT(tcu::boolAll(tcu::lessThanEqual(localSize, minReqMaxLocalSize))); 2560 DE_ASSERT(localSize.x()*localSize.y()*localSize.z() <= minReqMaxLocalInvocations); 2561 DE_UNREF(minReqMaxLocalSize); 2562 DE_UNREF(minReqMaxLocalInvocations); 2563 2564 glLog.enableLogging(true); 2565 2566 // Setup texture. 2567 2568 log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage; 2569 if (m_imageType == TEXTURETYPE_BUFFER) 2570 log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage; 2571 2572 glLog.glActiveTexture(GL_TEXTURE0); 2573 glLog.glBindTexture(textureTargetGL, *texture); 2574 setTexParameteri(glLog, textureTargetGL); 2575 setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize, *textureBuf); 2576 glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL); 2577 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 2578 2579 // Perform computations in compute shader. 2580 2581 { 2582 // Generate compute shader. 2583 2584 const string colorVecTypeName = string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4"; 2585 const char* const colorScalarTypeName = isUintFormat ? "uint" : isIntFormat ? "int" : "float"; 2586 const string invocationCoord = m_imageType == TEXTURETYPE_BUFFER ? "gx" 2587 : m_imageType == TEXTURETYPE_2D ? "ivec2(gx, gy)" 2588 : "ivec3(gx, gy, gz)"; 2589 const string shaderImageFormatStr = getShaderImageFormatQualifier(m_format); 2590 const string shaderImageTypeStr = getShaderImageType(m_format.type, m_imageType); 2591 const string localSizeX = de::toString(localSize.x()); 2592 const string localSizeY = de::toString(localSize.y()); 2593 const string localSizeZ = de::toString(localSize.z()); 2594 2595 const glu::ShaderProgram program(renderCtx, 2596 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 2597 + textureTypeExtensionShaderRequires(m_imageType) + 2598 "\n" 2599 "precision highp " + shaderImageTypeStr + ";\n" 2600 "\n" 2601 "layout (local_size_x = " + localSizeX 2602 + ", local_size_y = " + localSizeY 2603 + ", local_size_z = " + localSizeZ 2604 + ") in;\n" 2605 "layout (" + shaderImageFormatStr + ", binding=0) " + qualifierName + " uniform " + shaderImageTypeStr + " u_image;\n" 2606 "void main (void)\n" 2607 "{\n" 2608 " int gx = int(gl_GlobalInvocationID.x);\n" 2609 " int gy = int(gl_GlobalInvocationID.y);\n" 2610 " int gz = int(gl_GlobalInvocationID.z);\n" 2611 " imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(gx^gy^gz));\n" 2612 "\n" 2613 " memoryBarrier();\n" 2614 " barrier();\n" 2615 "\n" 2616 " " + colorScalarTypeName + " sum = " + colorScalarTypeName + "(0);\n" 2617 " int groupBaseX = gx/" + localSizeX + "*" + localSizeX + ";\n" 2618 " int groupBaseY = gy/" + localSizeY + "*" + localSizeY + ";\n" 2619 " int groupBaseZ = gz/" + localSizeZ + "*" + localSizeZ + ";\n" 2620 " int xOffsets[] = " + SHADER_READ_OFFSETS_X_STR + ";\n" 2621 " int yOffsets[] = " + SHADER_READ_OFFSETS_Y_STR + ";\n" 2622 " int zOffsets[] = " + SHADER_READ_OFFSETS_Z_STR + ";\n" 2623 " for (int i = 0; i < " + toString(DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X)) + "; i++)\n" 2624 " {\n" 2625 " int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n" 2626 " int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n" 2627 " int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n" 2628 " sum += imageLoad(u_image, " + (m_imageType == TEXTURETYPE_BUFFER ? "readX" 2629 : m_imageType == TEXTURETYPE_2D ? "ivec2(readX, readY)" 2630 : "ivec3(readX, readY, readZ)") + ").x;\n" 2631 " }\n" 2632 "\n" 2633 " memoryBarrier();\n" 2634 " barrier();\n" 2635 "\n" 2636 " imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n" 2637 "}\n")); 2638 2639 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 2640 2641 log << program; 2642 2643 if (!program.isOk()) 2644 { 2645 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 2646 return STOP; 2647 } 2648 2649 // Setup and dispatch. 2650 2651 glLog.glUseProgram(program.getProgram()); 2652 2653 glLog.glDispatchCompute(numGroups.x(), numGroups.y(), numGroups.z()); 2654 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 2655 } 2656 2657 // Create reference, read texture and compare. 2658 2659 { 2660 LayeredImage reference(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z()); 2661 2662 { 2663 LayeredImage base(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z()); 2664 for (int z = 0; z < numSlicesOrFaces; z++) 2665 for (int y = 0; y < imageSize.y(); y++) 2666 for (int x = 0; x < imageSize.x(); x++) 2667 base.setPixel(x, y, z, IVec4(x^y^z)); 2668 2669 for (int z = 0; z < numSlicesOrFaces; z++) 2670 for (int y = 0; y < imageSize.y(); y++) 2671 for (int x = 0; x < imageSize.x(); x++) 2672 { 2673 const int groupBaseX = x / localSize.x() * localSize.x(); 2674 const int groupBaseY = y / localSize.y() * localSize.y(); 2675 const int groupBaseZ = z / localSize.z() * localSize.z(); 2676 int sum = 0; 2677 for (int i = 0; i < DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X); i++) 2678 sum += base.getPixelInt(groupBaseX + (x + SHADER_READ_OFFSETS_X[i]) % localSize.x(), 2679 groupBaseY + (y + SHADER_READ_OFFSETS_Y[i]) % localSize.y(), 2680 groupBaseZ + (z + SHADER_READ_OFFSETS_Z[i]) % localSize.z()).x(); 2681 2682 reference.setPixel(x, y, z, IVec4(sum)); 2683 } 2684 } 2685 2686 if (readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_imageType, m_format, imageSize, ImageLayerComparer(reference))) 2687 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2688 else 2689 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 2690 2691 return STOP; 2692 } 2693 } 2694 2695 class R32UIImageSingleValueVerifier : public ImageLayerVerifier 2696 { 2697 public: 2698 R32UIImageSingleValueVerifier (const deUint32 value) : m_min(value), m_max(value) {} 2699 R32UIImageSingleValueVerifier (const deUint32 min, const deUint32 max) : m_min(min), m_max(max) {} 2700 2701 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int) const 2702 { 2703 DE_ASSERT(resultSlice.getWidth() == 1 && resultSlice.getHeight() == 1 && resultSlice.getDepth() == 1); 2704 DE_ASSERT(resultSlice.getFormat() == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)); 2705 2706 log << TestLog::Message << "// Note: expecting to get value " << (m_min == m_max ? toString(m_min) : "in range [" + toString(m_min) + ", " + toString(m_max) + "]") << TestLog::EndMessage; 2707 2708 const deUint32 resultValue = resultSlice.getPixelUint(0, 0).x(); 2709 if (!de::inRange(resultValue, m_min, m_max)) 2710 { 2711 log << TestLog::Message << "// Failure: got value " << resultValue << TestLog::EndMessage; 2712 return false; 2713 } 2714 else 2715 { 2716 log << TestLog::Message << "// Success: got value " << resultValue << TestLog::EndMessage; 2717 return true; 2718 } 2719 } 2720 2721 private: 2722 const deUint32 m_min; 2723 const deUint32 m_max; 2724 }; 2725 2726 //! Tests the imageSize() GLSL function. Stores result in a 1x1 R32UI image. The image with which imageSize() is called isn't read or written, and 2727 // can thus be qualifier readonly, writeonly, or both. 2728 class ImageSizeCase : public TestCase 2729 { 2730 public: 2731 enum ImageAccess 2732 { 2733 IMAGEACCESS_READ_ONLY = 0, 2734 IMAGEACCESS_WRITE_ONLY, 2735 IMAGEACCESS_READ_ONLY_WRITE_ONLY, 2736 2737 IMAGEACCESS_LAST 2738 }; 2739 2740 ImageSizeCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, const IVec3& size, ImageAccess imageAccess) 2741 : TestCase (context, name, description) 2742 , m_format (format) 2743 , m_imageType (imageType) 2744 , m_imageSize (size) 2745 , m_imageAccess (imageAccess) 2746 { 2747 } 2748 2749 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType); } 2750 IterateResult iterate (void); 2751 2752 private: 2753 const TextureFormat m_format; 2754 const TextureType m_imageType; 2755 const IVec3 m_imageSize; 2756 const ImageAccess m_imageAccess; 2757 }; 2758 2759 ImageSizeCase::IterateResult ImageSizeCase::iterate (void) 2760 { 2761 const RenderContext& renderCtx = m_context.getRenderContext(); 2762 TestLog& log (m_testCtx.getLog()); 2763 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 2764 const deUint32 internalFormatGL = glu::getInternalFormat(m_format); 2765 const deUint32 textureTargetGL = getGLTextureTarget(m_imageType); 2766 const glu::Buffer mainTextureBuf (renderCtx); 2767 const glu::Texture mainTexture (renderCtx); 2768 const glu::Texture shaderOutResultTexture (renderCtx); 2769 2770 glLog.enableLogging(true); 2771 2772 // Setup textures. 2773 2774 log << TestLog::Message << "// Created a texture (name " << *mainTexture << ")" << TestLog::EndMessage; 2775 if (m_imageType == TEXTURETYPE_BUFFER) 2776 log << TestLog::Message << "// Created a buffer for the texture (name " << *mainTextureBuf << ")" << TestLog::EndMessage; 2777 log << TestLog::Message << "// Created a texture (name " << *shaderOutResultTexture << ") for storing the shader output" << TestLog::EndMessage; 2778 2779 glLog.glActiveTexture(GL_TEXTURE0); 2780 glLog.glBindTexture(textureTargetGL, *mainTexture); 2781 setTexParameteri(glLog, textureTargetGL); 2782 setTextureStorage(glLog, m_imageType, internalFormatGL, m_imageSize, *mainTextureBuf); 2783 glLog.glBindImageTexture(0, *mainTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL); 2784 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 2785 2786 glLog.glActiveTexture(GL_TEXTURE1); 2787 glLog.glBindTexture(GL_TEXTURE_2D, *shaderOutResultTexture); 2788 setTexParameteri(glLog, GL_TEXTURE_2D); 2789 setTextureStorage(glLog, TEXTURETYPE_2D, GL_R32UI, IVec3(1, 1, 1), 0 /* always 2d texture, no buffer needed */); 2790 glLog.glBindImageTexture(1, *shaderOutResultTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI); 2791 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 2792 2793 // Read texture size in compute shader. 2794 2795 { 2796 // Generate compute shader. 2797 2798 const char* const shaderImageAccessStr = m_imageAccess == IMAGEACCESS_READ_ONLY ? "readonly" 2799 : m_imageAccess == IMAGEACCESS_WRITE_ONLY ? "writeonly" 2800 : m_imageAccess == IMAGEACCESS_READ_ONLY_WRITE_ONLY ? "readonly writeonly" 2801 : DE_NULL; 2802 const string shaderImageFormatStr = getShaderImageFormatQualifier(m_format); 2803 const string shaderImageTypeStr = getShaderImageType(m_format.type, m_imageType); 2804 2805 const glu::ShaderProgram program(renderCtx, 2806 glu::ProgramSources() << glu::ComputeSource("#version 310 es\n" 2807 + textureTypeExtensionShaderRequires(m_imageType) + 2808 "\n" 2809 "precision highp " + shaderImageTypeStr + ";\n" 2810 "precision highp uimage2D;\n" 2811 "\n" 2812 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2813 "layout (" + shaderImageFormatStr + ", binding=0) " + shaderImageAccessStr + " uniform " + shaderImageTypeStr + " u_image;\n" 2814 "layout (r32ui, binding=1) writeonly uniform uimage2D u_result;\n" 2815 "void main (void)\n" 2816 "{\n" 2817 + (m_imageType == TEXTURETYPE_BUFFER ? 2818 " int result = imageSize(u_image);\n" 2819 : m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE ? 2820 " ivec2 size = imageSize(u_image);\n" 2821 " int result = size.y*1000 + size.x;\n" 2822 : m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY ? 2823 " ivec3 size = imageSize(u_image);\n" 2824 " int result = size.z*1000000 + size.y*1000 + size.x;\n" 2825 : DE_NULL) + 2826 " imageStore(u_result, ivec2(0, 0), uvec4(result));\n" 2827 "}\n")); 2828 2829 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 2830 2831 log << program; 2832 2833 if (!program.isOk()) 2834 { 2835 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 2836 return STOP; 2837 } 2838 2839 // Setup and dispatch. 2840 2841 glLog.glUseProgram(program.getProgram()); 2842 2843 glLog.glDispatchCompute(1, 1, 1); 2844 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute"); 2845 } 2846 2847 // Read texture and compare to reference. 2848 2849 { 2850 const deUint32 referenceOutput = m_imageType == TEXTURETYPE_BUFFER ? (deUint32)( m_imageSize.x()) 2851 : m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE ? (deUint32)( m_imageSize.y()*1000 + m_imageSize.x()) 2852 : m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY ? (deUint32)(m_imageSize.z()*1000000 + m_imageSize.y()*1000 + m_imageSize.x()) 2853 : (deUint32)-1; 2854 2855 if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *shaderOutResultTexture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 2856 IVec3(1, 1, 1), R32UIImageSingleValueVerifier(referenceOutput))) 2857 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2858 else 2859 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value"); 2860 2861 return STOP; 2862 } 2863 } 2864 2865 //! Case testing the control over early/late fragment tests. 2866 class EarlyFragmentTestsCase : public TestCase 2867 { 2868 public: 2869 enum TestType 2870 { 2871 TESTTYPE_DEPTH = 0, 2872 TESTTYPE_STENCIL, 2873 2874 TESTTYPE_LAST 2875 }; 2876 2877 enum RenderTargetType 2878 { 2879 RENDERTARGET_DEFAULT = 0, 2880 RENDERTARGET_FBO, 2881 RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT, 2882 2883 RENDERTARGET_LAST 2884 }; 2885 2886 2887 EarlyFragmentTestsCase (Context& context, const char* name, const char* description, TestType type, bool useEarlyTests, RenderTargetType renderTarget) 2888 : TestCase (context, name, description) 2889 , m_type (type) 2890 , m_useEarlyTests (useEarlyTests) 2891 , m_renderTarget (renderTarget) 2892 { 2893 } 2894 2895 void init (void) 2896 { 2897 if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) == 0) 2898 throw tcu::NotSupportedError("GL_MAX_FRAGMENT_IMAGE_UNIFORMS is zero"); 2899 2900 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic")) 2901 throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension"); 2902 2903 if (m_type == TESTTYPE_DEPTH && 2904 m_renderTarget == RENDERTARGET_DEFAULT && 2905 m_context.getRenderTarget().getDepthBits() == 0) 2906 { 2907 throw tcu::NotSupportedError("Test requires depth buffer"); 2908 } 2909 2910 if (m_type == TESTTYPE_STENCIL && 2911 m_renderTarget == RENDERTARGET_DEFAULT && 2912 m_context.getRenderTarget().getStencilBits() == 0) 2913 { 2914 throw tcu::NotSupportedError("Test requires stencil buffer"); 2915 } 2916 2917 if (m_renderTarget == RENDERTARGET_DEFAULT && 2918 (m_context.getRenderTarget().getWidth() < RENDER_SIZE || m_context.getRenderTarget().getHeight() < RENDER_SIZE)) 2919 throw tcu::NotSupportedError("Render target must have at least " + toString(RENDER_SIZE) + " width and height"); 2920 } 2921 2922 IterateResult iterate (void); 2923 2924 private: 2925 static const int RENDER_SIZE; 2926 2927 const TestType m_type; 2928 const bool m_useEarlyTests; 2929 const RenderTargetType m_renderTarget; 2930 }; 2931 2932 const int EarlyFragmentTestsCase::RENDER_SIZE = 32; 2933 2934 EarlyFragmentTestsCase::IterateResult EarlyFragmentTestsCase::iterate (void) 2935 { 2936 const RenderContext& renderCtx = m_context.getRenderContext(); 2937 TestLog& log (m_testCtx.getLog()); 2938 glu::CallLogWrapper glLog (renderCtx.getFunctions(), log); 2939 de::Random rnd (deStringHash(getName())); 2940 const bool expectPartialResult = m_useEarlyTests && m_renderTarget != RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT; 2941 const int viewportWidth = RENDER_SIZE; 2942 const int viewportHeight = RENDER_SIZE; 2943 const int viewportX = (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getWidth() - viewportWidth)) : (0); 2944 const int viewportY = (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getHeight() - viewportHeight)) : (0); 2945 const IVec3 imageSize = defaultImageSize(TEXTURETYPE_2D); 2946 const glu::Texture texture (renderCtx); 2947 de::MovePtr<glu::Framebuffer> fbo; 2948 de::MovePtr<glu::Renderbuffer> colorAttachment; 2949 de::MovePtr<glu::Renderbuffer> testAttachment; 2950 2951 glLog.enableLogging(true); 2952 2953 // Setup texture. 2954 2955 log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage; 2956 2957 glLog.glActiveTexture(GL_TEXTURE0); 2958 glLog.glBindTexture(GL_TEXTURE_2D, *texture); 2959 setTexParameteri(glLog, GL_TEXTURE_2D); 2960 { 2961 LayeredImage src(TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 1, 1, 1); 2962 src.setPixel(0, 0, 0, IVec4(0)); 2963 uploadTexture(glLog, src, 0 /* always 2d texture, no buffer needed */); 2964 } 2965 glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32UI); 2966 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture"); 2967 2968 // Set up framebuffer 2969 if (m_renderTarget == RENDERTARGET_FBO || 2970 m_renderTarget == RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT) 2971 { 2972 fbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx)); 2973 colorAttachment = de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx)); 2974 testAttachment = de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx)); 2975 2976 glLog.glBindRenderbuffer(GL_RENDERBUFFER, **colorAttachment); 2977 glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE); 2978 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen color attachment rb"); 2979 2980 glLog.glBindFramebuffer(GL_FRAMEBUFFER, **fbo); 2981 glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment); 2982 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo color attachment"); 2983 2984 if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_DEPTH) 2985 { 2986 glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment); 2987 glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, RENDER_SIZE, RENDER_SIZE); 2988 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen depth attachment rb"); 2989 2990 glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, **testAttachment); 2991 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo depth attachment"); 2992 } 2993 else if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_STENCIL) 2994 { 2995 glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment); 2996 glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, RENDER_SIZE, RENDER_SIZE); 2997 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen stencil attachment rb"); 2998 2999 glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, **testAttachment); 3000 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo stencil attachment"); 3001 } 3002 3003 glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment); 3004 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "setup fbo"); 3005 TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 3006 } 3007 3008 // Set up appropriate conditions for the test. 3009 3010 glLog.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 3011 glLog.glClear(GL_COLOR_BUFFER_BIT); 3012 3013 if (m_type == TESTTYPE_DEPTH) 3014 { 3015 glLog.glClearDepthf(0.5f); 3016 glLog.glClear(GL_DEPTH_BUFFER_BIT); 3017 glLog.glEnable(GL_DEPTH_TEST); 3018 } 3019 else if (m_type == TESTTYPE_STENCIL) 3020 { 3021 glLog.glClearStencil(0); 3022 glLog.glClear(GL_STENCIL_BUFFER_BIT); 3023 glLog.glScissor(viewportX, viewportY, viewportWidth/2, viewportHeight); 3024 glLog.glEnable(GL_SCISSOR_TEST); 3025 glLog.glClearStencil(1); 3026 glLog.glClear(GL_STENCIL_BUFFER_BIT); 3027 glLog.glDisable(GL_SCISSOR_TEST); 3028 glLog.glStencilFunc(GL_EQUAL, 1, 1); 3029 glLog.glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 3030 glLog.glEnable(GL_STENCIL_TEST); 3031 } 3032 else 3033 DE_ASSERT(false); 3034 3035 // Perform image stores in fragment shader. 3036 3037 { 3038 // Generate fragment shader. 3039 3040 const glu::ShaderProgram program(renderCtx, 3041 glu::ProgramSources() << glu::VertexSource( "#version 310 es\n" 3042 "\n" 3043 "highp in vec3 a_position;\n" 3044 "\n" 3045 "void main (void)\n" 3046 "{\n" 3047 " gl_Position = vec4(a_position, 1.0);\n" 3048 "}\n") 3049 3050 << glu::FragmentSource( "#version 310 es\n" 3051 "#extension GL_OES_shader_image_atomic : require\n" 3052 "\n" 3053 + string(m_useEarlyTests ? "layout (early_fragment_tests) in;\n\n" : "") + 3054 "layout (location = 0) out highp vec4 o_color;\n" 3055 "\n" 3056 "precision highp uimage2D;\n" 3057 "\n" 3058 "layout (r32ui, binding=0) coherent uniform uimage2D u_image;\n" 3059 "\n" 3060 "void main (void)\n" 3061 "{\n" 3062 " imageAtomicAdd(u_image, ivec2(0, 0), uint(1));\n" 3063 " o_color = vec4(1.0);\n" 3064 "}\n")); 3065 3066 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram()); 3067 3068 log << program; 3069 3070 if (!program.isOk()) 3071 { 3072 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed"); 3073 return STOP; 3074 } 3075 3076 // Setup and draw full-viewport quad. 3077 3078 glLog.glUseProgram(program.getProgram()); 3079 3080 { 3081 static const float vertexPositions[4*3] = 3082 { 3083 -1.0, -1.0, -1.0f, 3084 1.0, -1.0, 0.0f, 3085 -1.0, 1.0, 0.0f, 3086 1.0, 1.0, 1.0f, 3087 }; 3088 3089 static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; 3090 3091 const glu::VertexArrayBinding attrBindings[] = 3092 { 3093 glu::va::Float("a_position", 3, 4, 0, &vertexPositions[0]) 3094 }; 3095 3096 glLog.glViewport(viewportX, viewportY, viewportWidth, viewportHeight); 3097 3098 glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0], 3099 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 3100 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Draw failed"); 3101 } 3102 } 3103 3104 // Log rendered result for convenience. 3105 { 3106 tcu::Surface rendered(viewportWidth, viewportHeight); 3107 glu::readPixels(renderCtx, viewportX, viewportY, rendered.getAccess()); 3108 log << TestLog::Image("Rendered", "Rendered image", rendered); 3109 } 3110 3111 // Read counter value and check. 3112 { 3113 const int numSamples = de::max(1, renderCtx.getRenderTarget().getNumSamples()); 3114 const int expectedCounter = expectPartialResult ? viewportWidth*viewportHeight/2 : viewportWidth*viewportHeight; 3115 const int tolerance = expectPartialResult ? de::max(viewportWidth, viewportHeight)*3 : 0; 3116 const int expectedMin = de::max(0, expectedCounter - tolerance); 3117 const int expectedMax = (expectedCounter + tolerance) * numSamples; 3118 3119 if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *texture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 3120 IVec3(1, 1, 1), R32UIImageSingleValueVerifier(expectedMin, expectedMax))) 3121 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 3122 else 3123 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value"); 3124 3125 return STOP; 3126 } 3127 } 3128 3129 } // anonymous 3130 3131 ShaderImageLoadStoreTests::ShaderImageLoadStoreTests (Context& context) 3132 : TestCaseGroup(context, "image_load_store", "Shader Image Load & Store Tests") 3133 { 3134 } 3135 3136 ShaderImageLoadStoreTests::~ShaderImageLoadStoreTests (void) 3137 { 3138 } 3139 3140 void ShaderImageLoadStoreTests::init (void) 3141 { 3142 // Per-image-type tests. 3143 3144 { 3145 static const TextureType imageTypes[] = 3146 { 3147 TEXTURETYPE_2D, 3148 TEXTURETYPE_CUBE, 3149 TEXTURETYPE_3D, 3150 TEXTURETYPE_2D_ARRAY, 3151 TEXTURETYPE_BUFFER 3152 }; 3153 3154 static const TextureFormat formats[] = 3155 { 3156 TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), 3157 TextureFormat(TextureFormat::RGBA, TextureFormat::HALF_FLOAT), 3158 TextureFormat(TextureFormat::R, TextureFormat::FLOAT), 3159 3160 TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), 3161 TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT16), 3162 TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT8), 3163 TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 3164 3165 TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT32), 3166 TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT16), 3167 TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT8), 3168 TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32), 3169 3170 TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), 3171 3172 TextureFormat(TextureFormat::RGBA, TextureFormat::SNORM_INT8) 3173 }; 3174 3175 for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageTypes); imageTypeNdx++) 3176 { 3177 const TextureType imageType = imageTypes[imageTypeNdx]; 3178 TestCaseGroup* const imageTypeGroup = new TestCaseGroup(m_context, getTextureTypeName(imageType), ""); 3179 addChild(imageTypeGroup); 3180 3181 TestCaseGroup* const storeGroup = new TestCaseGroup(m_context, "store", "Plain imageStore() cases"); 3182 TestCaseGroup* const loadStoreGroup = new TestCaseGroup(m_context, "load_store", "Cases with imageLoad() followed by imageStore()"); 3183 TestCaseGroup* const atomicGroup = new TestCaseGroup(m_context, "atomic", "Atomic image operation cases"); 3184 TestCaseGroup* const qualifierGroup = new TestCaseGroup(m_context, "qualifiers", "Coherent, volatile and restrict"); 3185 TestCaseGroup* const reinterpretGroup = new TestCaseGroup(m_context, "format_reinterpret", "Cases with differing texture and image formats"); 3186 TestCaseGroup* const imageSizeGroup = new TestCaseGroup(m_context, "image_size", "imageSize() cases"); 3187 imageTypeGroup->addChild(storeGroup); 3188 imageTypeGroup->addChild(loadStoreGroup); 3189 imageTypeGroup->addChild(atomicGroup); 3190 imageTypeGroup->addChild(qualifierGroup); 3191 imageTypeGroup->addChild(reinterpretGroup); 3192 imageTypeGroup->addChild(imageSizeGroup); 3193 3194 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 3195 { 3196 const TextureFormat& format = formats[formatNdx]; 3197 const string formatName = getShaderImageFormatQualifier(formats[formatNdx]); 3198 3199 if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(format)) 3200 continue; 3201 3202 // Store cases. 3203 3204 storeGroup->addChild(new ImageStoreCase(m_context, formatName.c_str(), "", format, imageType)); 3205 if (textureLayerType(imageType) != imageType) 3206 storeGroup->addChild(new ImageStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageStoreCase::CASEFLAG_SINGLE_LAYER_BIND)); 3207 3208 // Load & store. 3209 3210 loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, formatName.c_str(), "", format, imageType)); 3211 if (textureLayerType(imageType) != imageType) 3212 loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageLoadAndStoreCase::CASEFLAG_SINGLE_LAYER_BIND)); 3213 3214 if (format.order == TextureFormat::R) 3215 { 3216 // Atomic operations. 3217 3218 for (int operationI = 0; operationI < ATOMIC_OPERATION_LAST; operationI++) 3219 { 3220 for (int atomicCaseTypeI = 0; atomicCaseTypeI < ATOMIC_OPERATION_CASE_TYPE_LAST; atomicCaseTypeI++) 3221 { 3222 const AtomicOperation operation = (AtomicOperation)operationI; 3223 3224 if (format.type == TextureFormat::FLOAT && operation != ATOMIC_OPERATION_EXCHANGE) 3225 continue; 3226 3227 const AtomicOperationCaseType caseType = (AtomicOperationCaseType)atomicCaseTypeI; 3228 const string caseTypeName = caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? "result" 3229 : caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? "return_value" 3230 : DE_NULL; 3231 const string caseName = string() + getAtomicOperationCaseName(operation) + "_" + formatName + "_" + caseTypeName; 3232 3233 if (operation == ATOMIC_OPERATION_COMP_SWAP) 3234 atomicGroup->addChild(new AtomicCompSwapCase(m_context, caseName.c_str(), "", format, imageType, caseType)); 3235 else 3236 atomicGroup->addChild(new BinaryAtomicOperationCase(m_context, caseName.c_str(), "", format, imageType, operation, caseType)); 3237 } 3238 } 3239 3240 // Coherence. 3241 3242 for (int coherenceQualifierI = 0; coherenceQualifierI < CoherenceCase::QUALIFIER_LAST; coherenceQualifierI++) 3243 { 3244 const CoherenceCase::Qualifier coherenceQualifier = (CoherenceCase::Qualifier)coherenceQualifierI; 3245 const char* const coherenceQualifierName = coherenceQualifier == CoherenceCase::QUALIFIER_COHERENT ? "coherent" 3246 : coherenceQualifier == CoherenceCase::QUALIFIER_VOLATILE ? "volatile" 3247 : DE_NULL; 3248 const string caseName = string() + coherenceQualifierName + "_" + formatName; 3249 3250 qualifierGroup->addChild(new CoherenceCase(m_context, caseName.c_str(), "", format, imageType, coherenceQualifier)); 3251 } 3252 } 3253 } 3254 3255 // Restrict. 3256 qualifierGroup->addChild(new ImageLoadAndStoreCase(m_context, "restrict", "", TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), imageType, ImageLoadAndStoreCase::CASEFLAG_RESTRICT_IMAGES)); 3257 3258 // Format re-interpretation. 3259 3260 for (int texFmtNdx = 0; texFmtNdx < DE_LENGTH_OF_ARRAY(formats); texFmtNdx++) 3261 for (int imgFmtNdx = 0; imgFmtNdx < DE_LENGTH_OF_ARRAY(formats); imgFmtNdx++) 3262 { 3263 const TextureFormat& texFmt = formats[texFmtNdx]; 3264 const TextureFormat& imgFmt = formats[imgFmtNdx]; 3265 3266 if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(texFmt)) 3267 continue; 3268 3269 if (texFmt != imgFmt && texFmt.getPixelSize() == imgFmt.getPixelSize()) 3270 reinterpretGroup->addChild(new ImageLoadAndStoreCase(m_context, 3271 (getShaderImageFormatQualifier(texFmt) + "_" + getShaderImageFormatQualifier(imgFmt)).c_str(), "", 3272 texFmt, imgFmt, imageType)); 3273 } 3274 3275 // imageSize(). 3276 3277 { 3278 static const IVec3 baseImageSizes[] = 3279 { 3280 IVec3(32, 32, 32), 3281 IVec3(12, 34, 56), 3282 IVec3(1, 1, 1), 3283 IVec3(7, 1, 1) 3284 }; 3285 3286 for (int imageAccessI = 0; imageAccessI < ImageSizeCase::IMAGEACCESS_LAST; imageAccessI++) 3287 { 3288 const ImageSizeCase::ImageAccess imageAccess = (ImageSizeCase::ImageAccess)imageAccessI; 3289 const char* const imageAccessStr = imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY ? "readonly" 3290 : imageAccess == ImageSizeCase::IMAGEACCESS_WRITE_ONLY ? "writeonly" 3291 : imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY_WRITE_ONLY ? "readonly_writeonly" 3292 : DE_NULL; 3293 3294 for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(baseImageSizes); imageSizeNdx++) 3295 { 3296 const IVec3& baseSize = baseImageSizes[imageSizeNdx]; 3297 const IVec3 imageSize = imageType == TEXTURETYPE_BUFFER ? IVec3(baseSize.x(), 1, 1) 3298 : imageType == TEXTURETYPE_2D ? IVec3(baseSize.x(), baseSize.y(), 1) 3299 : imageType == TEXTURETYPE_CUBE ? IVec3(baseSize.x(), baseSize.x(), 1) 3300 : imageType == TEXTURETYPE_3D ? baseSize 3301 : imageType == TEXTURETYPE_2D_ARRAY ? baseSize 3302 : IVec3(-1, -1, -1); 3303 3304 const string sizeStr = imageType == TEXTURETYPE_BUFFER ? toString(imageSize.x()) 3305 : imageType == TEXTURETYPE_2D ? toString(imageSize.x()) + "x" + toString(imageSize.y()) 3306 : imageType == TEXTURETYPE_CUBE ? toString(imageSize.x()) + "x" + toString(imageSize.y()) 3307 : imageType == TEXTURETYPE_3D ? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z()) 3308 : imageType == TEXTURETYPE_2D_ARRAY ? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z()) 3309 : DE_NULL; 3310 3311 const string caseName = string() + imageAccessStr + "_" + sizeStr; 3312 3313 imageSizeGroup->addChild(new ImageSizeCase(m_context, caseName.c_str(), "", TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), imageType, imageSize, imageAccess)); 3314 } 3315 } 3316 } 3317 } 3318 } 3319 3320 // early_fragment_tests cases. 3321 3322 { 3323 TestCaseGroup* const earlyTestsGroup = new TestCaseGroup(m_context, "early_fragment_tests", ""); 3324 addChild(earlyTestsGroup); 3325 3326 for (int testRenderTargetI = 0; testRenderTargetI < EarlyFragmentTestsCase::RENDERTARGET_LAST; testRenderTargetI++) 3327 for (int useEarlyTestsI = 0; useEarlyTestsI <= 1; useEarlyTestsI++) 3328 for (int testTypeI = 0; testTypeI < EarlyFragmentTestsCase::TESTTYPE_LAST; testTypeI++) 3329 { 3330 const EarlyFragmentTestsCase::RenderTargetType targetType = (EarlyFragmentTestsCase::RenderTargetType)testRenderTargetI; 3331 const bool useEarlyTests = useEarlyTestsI != 0; 3332 const EarlyFragmentTestsCase::TestType testType = (EarlyFragmentTestsCase::TestType)testTypeI; 3333 3334 const string testTypeName = testType == EarlyFragmentTestsCase::TESTTYPE_DEPTH ? "depth" 3335 : testType == EarlyFragmentTestsCase::TESTTYPE_STENCIL ? "stencil" 3336 : DE_NULL; 3337 3338 const string targetName = targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO ? (std::string("_fbo")) 3339 : targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT ? (std::string("_fbo_with_no_") + testTypeName) 3340 : std::string(""); 3341 3342 const string caseName = string(useEarlyTests ? "" : "no_") + "early_fragment_tests_" + testTypeName + targetName; 3343 3344 const string caseDesc = string(useEarlyTests ? "Specify" : "Don't specify") 3345 + " early_fragment_tests, use the " + testTypeName + " test" 3346 + ((targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO) ? (", render to fbo") 3347 : (targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT) ? (", render to fbo without relevant buffer") 3348 : ("")); 3349 3350 earlyTestsGroup->addChild(new EarlyFragmentTestsCase(m_context, caseName.c_str(), caseDesc.c_str(), testType, useEarlyTests, targetType)); 3351 } 3352 } 3353 } 3354 3355 } // Functional 3356 } // gles31 3357 } // deqp 3358