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