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