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