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