1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * Copyright (c) 2016 The Android Open Source Project 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 *//*! 21 * \file 22 * \brief Memory qualifiers tests 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktImageQualifiersTests.hpp" 26#include "vktImageLoadStoreTests.hpp" 27#include "vktImageTestsUtil.hpp" 28 29#include "vkDefs.hpp" 30#include "vkImageUtil.hpp" 31#include "vkRef.hpp" 32#include "vkRefUtil.hpp" 33#include "vktTestCase.hpp" 34#include "vktTestCaseUtil.hpp" 35#include "vkPlatform.hpp" 36#include "vkPrograms.hpp" 37#include "vkMemUtil.hpp" 38#include "vkBuilderUtil.hpp" 39#include "vkQueryUtil.hpp" 40#include "vkTypeUtil.hpp" 41 42#include "deDefs.hpp" 43#include "deStringUtil.hpp" 44#include "deUniquePtr.hpp" 45 46#include "tcuImageCompare.hpp" 47#include "tcuTexture.hpp" 48#include "tcuTextureUtil.hpp" 49#include "tcuVectorType.hpp" 50 51using namespace vk; 52 53namespace vkt 54{ 55namespace image 56{ 57namespace 58{ 59 60static const tcu::UVec3 g_localWorkGroupSizeBase = tcu::UVec3(8, 8, 2); 61static const deInt32 g_ShaderReadOffsetsX[4] = { 1, 4, 7, 10 }; 62static const deInt32 g_ShaderReadOffsetsY[4] = { 2, 5, 8, 11 }; 63static const deInt32 g_ShaderReadOffsetsZ[4] = { 3, 6, 9, 12 }; 64static const char* const g_ShaderReadOffsetsXStr = "int[]( 1, 4, 7, 10 )"; 65static const char* const g_ShaderReadOffsetsYStr = "int[]( 2, 5, 8, 11 )"; 66static const char* const g_ShaderReadOffsetsZStr = "int[]( 3, 6, 9, 12 )"; 67 68const tcu::UVec3 getLocalWorkGroupSize (const ImageType imageType, const tcu::UVec3& imageSize) 69{ 70 const tcu::UVec3 computeGridSize = getShaderGridSize(imageType, imageSize); 71 72 const tcu::UVec3 localWorkGroupSize = tcu::UVec3(de::min(g_localWorkGroupSizeBase.x(), computeGridSize.x()), 73 de::min(g_localWorkGroupSizeBase.y(), computeGridSize.y()), 74 de::min(g_localWorkGroupSizeBase.z(), computeGridSize.z())); 75 return localWorkGroupSize; 76} 77 78const tcu::UVec3 getNumWorkGroups (const ImageType imageType, const tcu::UVec3& imageSize) 79{ 80 const tcu::UVec3 computeGridSize = getShaderGridSize(imageType, imageSize); 81 const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(imageType, imageSize); 82 83 return computeGridSize / localWorkGroupSize; 84} 85 86tcu::ConstPixelBufferAccess getLayerOrSlice (const ImageType imageType, 87 const tcu::ConstPixelBufferAccess& access, 88 const deUint32 layer) 89{ 90 switch (imageType) 91 { 92 case IMAGE_TYPE_1D: 93 case IMAGE_TYPE_2D: 94 case IMAGE_TYPE_BUFFER: 95 DE_ASSERT(layer == 0); 96 return access; 97 98 case IMAGE_TYPE_1D_ARRAY: 99 return tcu::getSubregion(access, 0, layer, access.getWidth(), 1); 100 101 case IMAGE_TYPE_2D_ARRAY: 102 case IMAGE_TYPE_3D: 103 case IMAGE_TYPE_CUBE: 104 case IMAGE_TYPE_CUBE_ARRAY: 105 return tcu::getSubregion(access, 0, 0, layer, access.getWidth(), access.getHeight(), 1); 106 107 default: 108 DE_FATAL("Unknown image type"); 109 return tcu::ConstPixelBufferAccess(); 110 } 111} 112 113bool comparePixelBuffers (tcu::TestContext& testCtx, 114 const ImageType imageType, 115 const tcu::UVec3& imageSize, 116 const tcu::TextureFormat& format, 117 const tcu::ConstPixelBufferAccess& reference, 118 const tcu::ConstPixelBufferAccess& result) 119{ 120 DE_ASSERT(reference.getFormat() == result.getFormat()); 121 DE_ASSERT(reference.getSize() == result.getSize()); 122 123 const bool intFormat = isIntFormat(mapTextureFormat(format)) || isUintFormat(mapTextureFormat(format)); 124 deUint32 passedLayers = 0; 125 126 for (deUint32 layerNdx = 0; layerNdx < getNumLayers(imageType, imageSize); ++layerNdx) 127 { 128 const std::string comparisonName = "Comparison" + de::toString(layerNdx); 129 130 std::string comparisonDesc = "Image Comparison, "; 131 switch (imageType) 132 { 133 case IMAGE_TYPE_3D: 134 comparisonDesc = comparisonDesc + "slice " + de::toString(layerNdx); 135 break; 136 137 case IMAGE_TYPE_CUBE: 138 case IMAGE_TYPE_CUBE_ARRAY: 139 comparisonDesc = comparisonDesc + "face " + de::toString(layerNdx % 6) + ", cube " + de::toString(layerNdx / 6); 140 break; 141 142 default: 143 comparisonDesc = comparisonDesc + "layer " + de::toString(layerNdx); 144 break; 145 } 146 147 const tcu::ConstPixelBufferAccess refLayer = getLayerOrSlice(imageType, reference, layerNdx); 148 const tcu::ConstPixelBufferAccess resultLayer = getLayerOrSlice(imageType, result, layerNdx); 149 150 bool ok = false; 151 if (intFormat) 152 ok = tcu::intThresholdCompare(testCtx.getLog(), comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT); 153 else 154 ok = tcu::floatThresholdCompare(testCtx.getLog(), comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT); 155 156 if (ok) 157 ++passedLayers; 158 } 159 160 return passedLayers == getNumLayers(imageType, imageSize); 161} 162 163const std::string getCoordStr (const ImageType imageType, 164 const std::string& x, 165 const std::string& y, 166 const std::string& z) 167{ 168 switch (imageType) 169 { 170 case IMAGE_TYPE_1D: 171 case IMAGE_TYPE_BUFFER: 172 return x; 173 174 case IMAGE_TYPE_1D_ARRAY: 175 case IMAGE_TYPE_2D: 176 return "ivec2(" + x + "," + y + ")"; 177 178 case IMAGE_TYPE_2D_ARRAY: 179 case IMAGE_TYPE_3D: 180 case IMAGE_TYPE_CUBE: 181 case IMAGE_TYPE_CUBE_ARRAY: 182 return "ivec3(" + x + "," + y + "," + z + ")"; 183 184 default: 185 DE_ASSERT(false); 186 return ""; 187 } 188} 189 190class MemoryQualifierTestCase : public vkt::TestCase 191{ 192public: 193 194 enum Qualifier 195 { 196 QUALIFIER_COHERENT = 0, 197 QUALIFIER_VOLATILE, 198 QUALIFIER_RESTRICT, 199 QUALIFIER_LAST 200 }; 201 202 MemoryQualifierTestCase (tcu::TestContext& testCtx, 203 const std::string& name, 204 const std::string& description, 205 const Qualifier qualifier, 206 const ImageType imageType, 207 const tcu::UVec3& imageSize, 208 const tcu::TextureFormat& format, 209 const glu::GLSLVersion glslVersion); 210 211 virtual ~MemoryQualifierTestCase (void) {} 212 213 virtual void initPrograms (SourceCollections& programCollection) const; 214 virtual TestInstance* createInstance (Context& context) const; 215 216protected: 217 218 const Qualifier m_qualifier; 219 const ImageType m_imageType; 220 const tcu::UVec3 m_imageSize; 221 const tcu::TextureFormat m_format; 222 const glu::GLSLVersion m_glslVersion; 223}; 224 225MemoryQualifierTestCase::MemoryQualifierTestCase (tcu::TestContext& testCtx, 226 const std::string& name, 227 const std::string& description, 228 const Qualifier qualifier, 229 const ImageType imageType, 230 const tcu::UVec3& imageSize, 231 const tcu::TextureFormat& format, 232 const glu::GLSLVersion glslVersion) 233 : vkt::TestCase(testCtx, name, description) 234 , m_qualifier(qualifier) 235 , m_imageType(imageType) 236 , m_imageSize(imageSize) 237 , m_format(format) 238 , m_glslVersion(glslVersion) 239{ 240} 241 242void MemoryQualifierTestCase::initPrograms (SourceCollections& programCollection) const 243{ 244 const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion); 245 246 const char* const qualifierName = m_qualifier == QUALIFIER_COHERENT ? "coherent" 247 : m_qualifier == QUALIFIER_VOLATILE ? "volatile" 248 : DE_NULL; 249 250 const bool uintFormat = isUintFormat(mapTextureFormat(m_format)); 251 const bool intFormat = isIntFormat(mapTextureFormat(m_format)); 252 const std::string colorVecTypeName = std::string(uintFormat ? "u" : intFormat ? "i" : "") + "vec4"; 253 const std::string colorScalarTypeName = std::string(uintFormat ? "uint" : intFormat ? "int" : "float"); 254 const std::string invocationCoord = getCoordStr(m_imageType, "gx", "gy", "gz"); 255 const std::string shaderImageFormat = getShaderImageFormatQualifier(m_format); 256 const std::string shaderImageType = getShaderImageType(m_format, m_imageType); 257 258 const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(m_imageType, m_imageSize); 259 const std::string localSizeX = de::toString(localWorkGroupSize.x()); 260 const std::string localSizeY = de::toString(localWorkGroupSize.y()); 261 const std::string localSizeZ = de::toString(localWorkGroupSize.z()); 262 263 std::ostringstream programBuffer; 264 265 programBuffer 266 << versionDecl << "\n" 267 << "\n" 268 << "precision highp " << shaderImageType << ";\n" 269 << "\n" 270 << "layout (local_size_x = " << localSizeX << ", local_size_y = " << localSizeY << ", local_size_z = " + localSizeZ << ") in;\n" 271 << "layout (" << shaderImageFormat << ", binding=0) " << qualifierName << " uniform " << shaderImageType << " u_image;\n" 272 << "void main (void)\n" 273 << "{\n" 274 << " int gx = int(gl_GlobalInvocationID.x);\n" 275 << " int gy = int(gl_GlobalInvocationID.y);\n" 276 << " int gz = int(gl_GlobalInvocationID.z);\n" 277 << " imageStore(u_image, " << invocationCoord << ", " << colorVecTypeName << "(gx^gy^gz));\n" 278 << "\n" 279 << " memoryBarrier();\n" 280 << " barrier();\n" 281 << "\n" 282 << " " << colorScalarTypeName << " sum = " << colorScalarTypeName << "(0);\n" 283 << " int groupBaseX = gx/" << localSizeX << "*" << localSizeX << ";\n" 284 << " int groupBaseY = gy/" << localSizeY << "*" << localSizeY << ";\n" 285 << " int groupBaseZ = gz/" << localSizeZ << "*" << localSizeZ << ";\n" 286 << " int xOffsets[] = " << g_ShaderReadOffsetsXStr << ";\n" 287 << " int yOffsets[] = " << g_ShaderReadOffsetsYStr << ";\n" 288 << " int zOffsets[] = " << g_ShaderReadOffsetsZStr << ";\n" 289 << " for (int i = 0; i < " << de::toString(DE_LENGTH_OF_ARRAY(g_ShaderReadOffsetsX)) << "; i++)\n" 290 << " {\n" 291 << " int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n" 292 << " int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n" 293 << " int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n" 294 << " sum += imageLoad(u_image, " << getCoordStr(m_imageType, "readX", "readY", "readZ") << ").x;\n" 295 << " }\n" 296 << "\n" 297 << " memoryBarrier();\n" 298 << " barrier();\n" 299 << "\n" 300 << " imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n" 301 << "}\n"; 302 303 programCollection.glslSources.add(m_name) << glu::ComputeSource(programBuffer.str()); 304} 305 306class MemoryQualifierInstanceBase : public vkt::TestInstance 307{ 308public: 309 MemoryQualifierInstanceBase (Context& context, 310 const std::string& name, 311 const ImageType imageType, 312 const tcu::UVec3& imageSize, 313 const tcu::TextureFormat& format); 314 315 virtual ~MemoryQualifierInstanceBase (void) {}; 316 317 virtual tcu::TestStatus iterate (void); 318 319 virtual void prepareResources (const VkDeviceSize bufferSizeInBytes) = 0; 320 321 virtual void prepareDescriptors (void) = 0; 322 323 virtual void commandsBeforeCompute (const VkCommandBuffer cmdBuffer, 324 const VkDeviceSize bufferSizeInBytes) const = 0; 325 326 virtual void commandsAfterCompute (const VkCommandBuffer cmdBuffer, 327 const VkDeviceSize bufferSizeInBytes) const = 0; 328protected: 329 330 tcu::TextureLevel generateReferenceImage (void) const; 331 332 const std::string m_name; 333 const ImageType m_imageType; 334 const tcu::UVec3 m_imageSize; 335 const tcu::TextureFormat m_format; 336 337 de::MovePtr<Buffer> m_buffer; 338 Move<VkDescriptorPool> m_descriptorPool; 339 Move<VkDescriptorSetLayout> m_descriptorSetLayout; 340 Move<VkDescriptorSet> m_descriptorSet; 341}; 342 343MemoryQualifierInstanceBase::MemoryQualifierInstanceBase (Context& context, 344 const std::string& name, 345 const ImageType imageType, 346 const tcu::UVec3& imageSize, 347 const tcu::TextureFormat& format) 348 : vkt::TestInstance(context) 349 , m_name(name) 350 , m_imageType(imageType) 351 , m_imageSize(imageSize) 352 , m_format(format) 353{ 354} 355 356tcu::TestStatus MemoryQualifierInstanceBase::iterate (void) 357{ 358 const VkDevice device = m_context.getDevice(); 359 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 360 const VkQueue queue = m_context.getUniversalQueue(); 361 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 362 363 const VkDeviceSize bufferSizeInBytes = getNumPixels(m_imageType, m_imageSize) * tcu::getPixelSize(m_format); 364 365 // Prepare resources for the test 366 prepareResources(bufferSizeInBytes); 367 368 // Prepare descriptor sets 369 prepareDescriptors(); 370 371 // Create compute shader 372 const vk::Unique<VkShaderModule> shaderModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get(m_name), 0u)); 373 374 // Create compute pipeline 375 const vk::Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, device, *m_descriptorSetLayout)); 376 const vk::Unique<VkPipeline> pipeline(makeComputePipeline(deviceInterface, device, *pipelineLayout, *shaderModule)); 377 378 // Create command buffer 379 const Unique<VkCommandPool> cmdPool(makeCommandPool(deviceInterface, device, queueFamilyIndex)); 380 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(deviceInterface, device, *cmdPool)); 381 382 // Start recording commands 383 beginCommandBuffer(deviceInterface, *cmdBuffer); 384 385 deviceInterface.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); 386 deviceInterface.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL); 387 388 commandsBeforeCompute(*cmdBuffer, bufferSizeInBytes); 389 390 const tcu::UVec3 numGroups = getNumWorkGroups(m_imageType, m_imageSize); 391 deviceInterface.cmdDispatch(*cmdBuffer, numGroups.x(), numGroups.y(), numGroups.z()); 392 393 commandsAfterCompute(*cmdBuffer, bufferSizeInBytes); 394 395 endCommandBuffer(deviceInterface, *cmdBuffer); 396 397 // Submit and wait for completion 398 submitCommandsAndWait(deviceInterface, device, queue, *cmdBuffer); 399 400 // Retrieve data from buffer to host memory 401 const Allocation& allocation = m_buffer->getAllocation(); 402 invalidateMappedMemoryRange(deviceInterface, device, allocation.getMemory(), allocation.getOffset(), bufferSizeInBytes); 403 404 const tcu::UVec3 computeGridSize = getShaderGridSize(m_imageType, m_imageSize); 405 tcu::ConstPixelBufferAccess resultPixelBuffer(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z(), allocation.getHostPtr()); 406 407 // Create a reference image 408 tcu::TextureLevel referenceImage = generateReferenceImage(); 409 tcu::ConstPixelBufferAccess referencePixelBuffer = referenceImage.getAccess(); 410 411 // Validate the result 412 if (comparePixelBuffers(m_context.getTestContext(), m_imageType, m_imageSize, m_format, referencePixelBuffer, resultPixelBuffer)) 413 return tcu::TestStatus::pass("Passed"); 414 else 415 return tcu::TestStatus::fail("Image comparison failed"); 416} 417 418tcu::TextureLevel MemoryQualifierInstanceBase::generateReferenceImage (void) const 419{ 420 // Generate a reference image data using the storage format 421 const tcu::UVec3 computeGridSize = getShaderGridSize(m_imageType, m_imageSize); 422 423 tcu::TextureLevel base(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z()); 424 tcu::PixelBufferAccess baseAccess = base.getAccess(); 425 426 tcu::TextureLevel reference(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z()); 427 tcu::PixelBufferAccess referenceAccess = reference.getAccess(); 428 429 for (deInt32 z = 0; z < baseAccess.getDepth(); ++z) 430 for (deInt32 y = 0; y < baseAccess.getHeight(); ++y) 431 for (deInt32 x = 0; x < baseAccess.getWidth(); ++x) 432 { 433 baseAccess.setPixel(tcu::IVec4(x^y^z), x, y, z); 434 } 435 436 const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(m_imageType, m_imageSize); 437 438 for (deInt32 z = 0; z < referenceAccess.getDepth(); ++z) 439 for (deInt32 y = 0; y < referenceAccess.getHeight(); ++y) 440 for (deInt32 x = 0; x < referenceAccess.getWidth(); ++x) 441 { 442 const deInt32 groupBaseX = x / localWorkGroupSize.x() * localWorkGroupSize.x(); 443 const deInt32 groupBaseY = y / localWorkGroupSize.y() * localWorkGroupSize.y(); 444 const deInt32 groupBaseZ = z / localWorkGroupSize.z() * localWorkGroupSize.z(); 445 deInt32 sum = 0; 446 447 for (deInt32 i = 0; i < DE_LENGTH_OF_ARRAY(g_ShaderReadOffsetsX); i++) 448 { 449 sum += baseAccess.getPixelInt( 450 groupBaseX + (x + g_ShaderReadOffsetsX[i]) % localWorkGroupSize.x(), 451 groupBaseY + (y + g_ShaderReadOffsetsY[i]) % localWorkGroupSize.y(), 452 groupBaseZ + (z + g_ShaderReadOffsetsZ[i]) % localWorkGroupSize.z()).x(); 453 } 454 455 referenceAccess.setPixel(tcu::IVec4(sum), x, y, z); 456 } 457 458 return reference; 459} 460 461class MemoryQualifierInstanceImage : public MemoryQualifierInstanceBase 462{ 463public: 464 MemoryQualifierInstanceImage (Context& context, 465 const std::string& name, 466 const ImageType imageType, 467 const tcu::UVec3& imageSize, 468 const tcu::TextureFormat& format) 469 : MemoryQualifierInstanceBase(context, name, imageType, imageSize, format) {} 470 471 virtual ~MemoryQualifierInstanceImage (void) {}; 472 473 virtual void prepareResources (const VkDeviceSize bufferSizeInBytes); 474 475 virtual void prepareDescriptors (void); 476 477 virtual void commandsBeforeCompute (const VkCommandBuffer cmdBuffer, 478 const VkDeviceSize bufferSizeInBytes) const; 479 480 virtual void commandsAfterCompute (const VkCommandBuffer cmdBuffer, 481 const VkDeviceSize bufferSizeInBytes) const; 482protected: 483 484 de::MovePtr<Image> m_image; 485 Move<VkImageView> m_imageView; 486}; 487 488void MemoryQualifierInstanceImage::prepareResources (const VkDeviceSize bufferSizeInBytes) 489{ 490 const VkDevice device = m_context.getDevice(); 491 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 492 Allocator& allocator = m_context.getDefaultAllocator(); 493 494 // Create image 495 const VkImageCreateInfo imageCreateInfo = 496 { 497 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 498 DE_NULL, // const void* pNext; 499 m_imageType == IMAGE_TYPE_CUBE || 500 m_imageType == IMAGE_TYPE_CUBE_ARRAY 501 ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u, // VkImageCreateFlags flags; 502 mapImageType(m_imageType), // VkImageType imageType; 503 mapTextureFormat(m_format), // VkFormat format; 504 makeExtent3D(getLayerSize(m_imageType, m_imageSize)), // VkExtent3D extent; 505 1u, // deUint32 mipLevels; 506 getNumLayers(m_imageType, m_imageSize), // deUint32 arrayLayers; 507 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 508 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 509 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT, // VkImageUsageFlags usage; 510 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 511 0u, // deUint32 queueFamilyIndexCount; 512 DE_NULL, // const deUint32* pQueueFamilyIndices; 513 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 514 }; 515 516 m_image = de::MovePtr<Image>(new Image(deviceInterface, device, allocator, imageCreateInfo, MemoryRequirement::Any)); 517 518 // Create imageView 519 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize)); 520 m_imageView = makeImageView(deviceInterface, device, m_image->get(), mapImageViewType(m_imageType), mapTextureFormat(m_format), subresourceRange); 521 522 // Create a buffer to store shader output (copied from image data) 523 const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 524 m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); 525} 526 527void MemoryQualifierInstanceImage::prepareDescriptors (void) 528{ 529 const VkDevice device = m_context.getDevice(); 530 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 531 532 // Create descriptor pool 533 m_descriptorPool = 534 DescriptorPoolBuilder() 535 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) 536 .build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 537 538 // Create descriptor set layout 539 m_descriptorSetLayout = 540 DescriptorSetLayoutBuilder() 541 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT) 542 .build(deviceInterface, device); 543 544 // Allocate descriptor set 545 m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *m_descriptorSetLayout); 546 547 // Set the bindings 548 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL); 549 550 DescriptorSetUpdateBuilder() 551 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo) 552 .update(deviceInterface, device); 553} 554 555void MemoryQualifierInstanceImage::commandsBeforeCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const 556{ 557 DE_UNREF(bufferSizeInBytes); 558 559 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 560 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize)); 561 562 const VkImageMemoryBarrier imageLayoutBarrier 563 = makeImageMemoryBarrier(0u, 564 VK_ACCESS_SHADER_READ_BIT, 565 VK_IMAGE_LAYOUT_UNDEFINED, 566 VK_IMAGE_LAYOUT_GENERAL, 567 m_image->get(), 568 subresourceRange); 569 570 deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutBarrier); 571} 572 573void MemoryQualifierInstanceImage::commandsAfterCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const 574{ 575 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 576 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize)); 577 578 const VkImageMemoryBarrier imagePreCopyBarrier 579 = makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, 580 VK_ACCESS_TRANSFER_READ_BIT, 581 VK_IMAGE_LAYOUT_GENERAL, 582 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 583 m_image->get(), 584 subresourceRange); 585 586 deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imagePreCopyBarrier); 587 588 const VkBufferImageCopy copyParams = makeBufferImageCopy(makeExtent3D(getLayerSize(m_imageType, m_imageSize)), getNumLayers(m_imageType, m_imageSize)); 589 deviceInterface.cmdCopyImageToBuffer(cmdBuffer, m_image->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer->get(), 1u, ©Params); 590 591 const VkBufferMemoryBarrier bufferPostCopyBarrier 592 = makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, 593 VK_ACCESS_HOST_READ_BIT, 594 m_buffer->get(), 595 0ull, 596 bufferSizeInBytes); 597 598 deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferPostCopyBarrier, 0u, DE_NULL); 599} 600 601class MemoryQualifierInstanceBuffer : public MemoryQualifierInstanceBase 602{ 603public: 604 MemoryQualifierInstanceBuffer (Context& context, 605 const std::string& name, 606 const ImageType imageType, 607 const tcu::UVec3& imageSize, 608 const tcu::TextureFormat& format) 609 : MemoryQualifierInstanceBase(context, name, imageType, imageSize, format) {} 610 611 virtual ~MemoryQualifierInstanceBuffer (void) {}; 612 613 virtual void prepareResources (const VkDeviceSize bufferSizeInBytes); 614 615 virtual void prepareDescriptors (void); 616 617 virtual void commandsBeforeCompute (const VkCommandBuffer, 618 const VkDeviceSize) const {} 619 620 virtual void commandsAfterCompute (const VkCommandBuffer cmdBuffer, 621 const VkDeviceSize bufferSizeInBytes) const; 622protected: 623 624 Move<VkBufferView> m_bufferView; 625}; 626 627void MemoryQualifierInstanceBuffer::prepareResources (const VkDeviceSize bufferSizeInBytes) 628{ 629 const VkDevice device = m_context.getDevice(); 630 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 631 Allocator& allocator = m_context.getDefaultAllocator(); 632 633 // Create a buffer to store shader output 634 const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSizeInBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT); 635 m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); 636 637 m_bufferView = makeBufferView(deviceInterface, device, m_buffer->get(), mapTextureFormat(m_format), 0ull, bufferSizeInBytes); 638} 639 640void MemoryQualifierInstanceBuffer::prepareDescriptors (void) 641{ 642 const VkDevice device = m_context.getDevice(); 643 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 644 645 // Create descriptor pool 646 m_descriptorPool = 647 DescriptorPoolBuilder() 648 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) 649 .build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 650 651 // Create descriptor set layout 652 m_descriptorSetLayout = 653 DescriptorSetLayoutBuilder() 654 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) 655 .build(deviceInterface, device); 656 657 // Allocate descriptor set 658 m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *m_descriptorSetLayout); 659 660 // Set the bindings 661 DescriptorSetUpdateBuilder() 662 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get()) 663 .update(deviceInterface, device); 664} 665 666void MemoryQualifierInstanceBuffer::commandsAfterCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const 667{ 668 const DeviceInterface& deviceInterface = m_context.getDeviceInterface(); 669 670 const VkBufferMemoryBarrier shaderWriteBarrier 671 = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, 672 VK_ACCESS_HOST_READ_BIT, 673 m_buffer->get(), 674 0ull, 675 bufferSizeInBytes); 676 677 deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL); 678} 679 680TestInstance* MemoryQualifierTestCase::createInstance (Context& context) const 681{ 682 if ( m_imageType == IMAGE_TYPE_BUFFER ) 683 return new MemoryQualifierInstanceBuffer(context, m_name, m_imageType, m_imageSize, m_format); 684 else 685 return new MemoryQualifierInstanceImage(context, m_name, m_imageType, m_imageSize, m_format); 686} 687 688} // anonymous ns 689 690tcu::TestCaseGroup* createImageQualifiersTests (tcu::TestContext& testCtx) 691{ 692 de::MovePtr<tcu::TestCaseGroup> imageQualifiersTests(new tcu::TestCaseGroup(testCtx, "qualifiers", "Coherent, volatile and restrict")); 693 694 struct ImageParams 695 { 696 ImageParams(const ImageType imageType, const tcu::UVec3& imageSize) 697 : m_imageType (imageType) 698 , m_imageSize (imageSize) 699 { 700 } 701 ImageType m_imageType; 702 tcu::UVec3 m_imageSize; 703 }; 704 705 static const ImageParams imageParamsArray[] = 706 { 707 ImageParams(IMAGE_TYPE_1D, tcu::UVec3(64u, 1u, 1u)), 708 ImageParams(IMAGE_TYPE_1D_ARRAY, tcu::UVec3(64u, 1u, 8u)), 709 ImageParams(IMAGE_TYPE_2D, tcu::UVec3(64u, 64u, 1u)), 710 ImageParams(IMAGE_TYPE_2D_ARRAY, tcu::UVec3(64u, 64u, 8u)), 711 ImageParams(IMAGE_TYPE_3D, tcu::UVec3(64u, 64u, 8u)), 712 ImageParams(IMAGE_TYPE_CUBE, tcu::UVec3(64u, 64u, 1u)), 713 ImageParams(IMAGE_TYPE_CUBE_ARRAY, tcu::UVec3(64u, 64u, 2u)), 714 ImageParams(IMAGE_TYPE_BUFFER, tcu::UVec3(64u, 1u, 1u)) 715 }; 716 717 static const tcu::TextureFormat formats[] = 718 { 719 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), 720 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT32), 721 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT32), 722 }; 723 724 for (deUint32 qualifierI = 0; qualifierI < MemoryQualifierTestCase::QUALIFIER_LAST; ++qualifierI) 725 { 726 const MemoryQualifierTestCase::Qualifier memoryQualifier = (MemoryQualifierTestCase::Qualifier)qualifierI; 727 const char* const memoryQualifierName = 728 memoryQualifier == MemoryQualifierTestCase::QUALIFIER_COHERENT ? "coherent" : 729 memoryQualifier == MemoryQualifierTestCase::QUALIFIER_VOLATILE ? "volatile" : 730 memoryQualifier == MemoryQualifierTestCase::QUALIFIER_RESTRICT ? "restrict" : 731 DE_NULL; 732 733 de::MovePtr<tcu::TestCaseGroup> qualifierGroup(new tcu::TestCaseGroup(testCtx, memoryQualifierName, "")); 734 735 for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParamsArray); imageTypeNdx++) 736 { 737 const ImageType imageType = imageParamsArray[imageTypeNdx].m_imageType; 738 const tcu::UVec3 imageSize = imageParamsArray[imageTypeNdx].m_imageSize; 739 740 if (memoryQualifier == MemoryQualifierTestCase::QUALIFIER_RESTRICT) 741 { 742 de::MovePtr<TestCase> restrictCase = createImageQualifierRestrictCase(testCtx, imageType, getImageTypeName(imageType)); 743 qualifierGroup->addChild(restrictCase.release()); 744 } 745 else 746 { 747 for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 748 { 749 const tcu::TextureFormat& format = formats[formatNdx]; 750 const std::string formatName = getShaderImageFormatQualifier(formats[formatNdx]); 751 752 qualifierGroup->addChild( 753 new MemoryQualifierTestCase(testCtx, getImageTypeName(imageType) + std::string("_") + formatName, 754 "", memoryQualifier, imageType, imageSize, format, glu::GLSL_VERSION_440)); 755 } 756 } 757 } 758 759 imageQualifiersTests->addChild(qualifierGroup.release()); 760 } 761 762 return imageQualifiersTests.release(); 763} 764 765} // image 766} // vkt 767