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