• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Image load/store Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktImageLoadStoreTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageLoadStoreUtil.hpp"
29 #include "vktImageTexture.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkQueryUtil.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 #include "vkBufferWithMemory.hpp"
44 
45 #include "deMath.h"
46 #include "deUniquePtr.hpp"
47 #include "deSharedPtr.hpp"
48 #include "deStringUtil.hpp"
49 
50 #include "tcuImageCompare.hpp"
51 #include "tcuTexture.hpp"
52 #include "tcuTextureUtil.hpp"
53 #include "tcuFloat.hpp"
54 #include "tcuFloatFormat.hpp"
55 #include "tcuStringTemplate.hpp"
56 #include "tcuVectorUtil.hpp"
57 
58 #include <string>
59 #include <vector>
60 #include <map>
61 
62 using namespace vk;
63 
64 namespace vkt
65 {
66 namespace image
67 {
68 namespace
69 {
70 
71 enum DeviceScopeType
72 {
73     DEVICESCOPE_NONE,
74     DEVICESCOPE_STORE,
75     DEVICESCOPE_LOAD
76 };
77 
78 enum TestConfigurationType
79 {
80     TC_NONE,
81     TC_COMP_COMP,
82     TC_COMP_DRAW
83 };
84 
85 // Check for three-component (non-packed) format, i.e. pixel size is a multiple of 3.
formatHasThreeComponents(VkFormat format)86 bool formatHasThreeComponents(VkFormat format)
87 {
88     const tcu::TextureFormat texFormat = mapVkFormat(format);
89     return (getPixelSize(texFormat) % 3) == 0;
90 }
91 
getSingleComponentFormat(VkFormat format)92 VkFormat getSingleComponentFormat(VkFormat format)
93 {
94     tcu::TextureFormat texFormat = mapVkFormat(format);
95     texFormat                    = tcu::TextureFormat(tcu::TextureFormat::R, texFormat.type);
96     return mapTextureFormat(texFormat);
97 }
98 
getImageAspect(VkFormat format)99 VkImageAspectFlags getImageAspect(VkFormat format)
100 {
101     return isDepthStencilFormat(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
102 }
103 
makeBufferImageCopy(const Texture & texture)104 inline VkBufferImageCopy makeBufferImageCopy(const Texture &texture)
105 {
106     return image::makeBufferImageCopy(makeExtent3D(texture.layerSize()), texture.numLayers());
107 }
108 
makeBufferImageCopy(const Texture & texture,const VkImageAspectFlags & aspect)109 VkBufferImageCopy makeBufferImageCopy(const Texture &texture, const VkImageAspectFlags &aspect)
110 {
111     const VkBufferImageCopy copyParams = {
112         0ull,                                                            // VkDeviceSize bufferOffset;
113         0u,                                                              // uint32_t bufferRowLength;
114         0u,                                                              // uint32_t bufferImageHeight;
115         makeImageSubresourceLayers(aspect, 0u, 0u, texture.numLayers()), // VkImageSubresourceLayers imageSubresource;
116         makeOffset3D(0, 0, 0),                                           // VkOffset3D imageOffset;
117         makeExtent3D(texture.layerSize()),                               // VkExtent3D imageExtent;
118     };
119     return copyParams;
120 }
121 
getShaderImageFormatQualifierStr(const VkFormat & format)122 std::string getShaderImageFormatQualifierStr(const VkFormat &format)
123 {
124     VkFormat testFormat;
125     switch (format)
126     {
127     case VK_FORMAT_D16_UNORM:
128         testFormat = VK_FORMAT_R16_UNORM;
129         break;
130     case VK_FORMAT_D32_SFLOAT:
131         testFormat = VK_FORMAT_R32_SFLOAT;
132         break;
133     default:
134         testFormat = format;
135     }
136     return getShaderImageFormatQualifier(mapVkFormat(testFormat));
137 }
138 
getLayerOrSlice(const Texture & texture,const tcu::ConstPixelBufferAccess access,const int layer)139 tcu::ConstPixelBufferAccess getLayerOrSlice(const Texture &texture, const tcu::ConstPixelBufferAccess access,
140                                             const int layer)
141 {
142     switch (texture.type())
143     {
144     case IMAGE_TYPE_1D:
145     case IMAGE_TYPE_2D:
146     case IMAGE_TYPE_BUFFER:
147         // Not layered
148         DE_ASSERT(layer == 0);
149         return access;
150 
151     case IMAGE_TYPE_1D_ARRAY:
152         return tcu::getSubregion(access, 0, layer, access.getWidth(), 1);
153 
154     case IMAGE_TYPE_2D_ARRAY:
155     case IMAGE_TYPE_CUBE:
156     case IMAGE_TYPE_CUBE_ARRAY:
157     case IMAGE_TYPE_3D: // 3d texture is treated as if depth was the layers
158         return tcu::getSubregion(access, 0, 0, layer, access.getWidth(), access.getHeight(), 1);
159 
160     default:
161         DE_FATAL("Internal test error");
162         return tcu::ConstPixelBufferAccess();
163     }
164 }
165 
166 //! \return the size in bytes of a given level of a mipmap image, including array layers.
getMipmapLevelImageSizeBytes(const Texture & texture,const vk::VkFormat format,const uint32_t mipmapLevel)167 vk::VkDeviceSize getMipmapLevelImageSizeBytes(const Texture &texture, const vk::VkFormat format,
168                                               const uint32_t mipmapLevel)
169 {
170     tcu::IVec3 size = texture.size(mipmapLevel);
171     return tcu::getPixelSize(vk::mapVkFormat(format)) * size.x() * size.y() * size.z();
172 }
173 
174 //! \return the size in bytes of the whole mipmap image, including all mipmap levels and array layers
getMipmapImageTotalSizeBytes(const Texture & texture,const vk::VkFormat format)175 vk::VkDeviceSize getMipmapImageTotalSizeBytes(const Texture &texture, const vk::VkFormat format)
176 {
177     vk::VkDeviceSize size = 0u;
178     int32_t levelCount    = 0u;
179 
180     do
181     {
182         size += getMipmapLevelImageSizeBytes(texture, format, levelCount);
183         levelCount++;
184     } while (levelCount < texture.numMipmapLevels());
185     return size;
186 }
187 
188 //! \return true if all layers match in both pixel buffers
comparePixelBuffers(tcu::TestLog & log,const Texture & texture,const VkFormat format,const tcu::ConstPixelBufferAccess reference,const tcu::ConstPixelBufferAccess result,const uint32_t mipmapLevel=0u)189 bool comparePixelBuffers(tcu::TestLog &log, const Texture &texture, const VkFormat format,
190                          const tcu::ConstPixelBufferAccess reference, const tcu::ConstPixelBufferAccess result,
191                          const uint32_t mipmapLevel = 0u)
192 {
193     DE_ASSERT(reference.getFormat() == result.getFormat());
194     DE_ASSERT(reference.getSize() == result.getSize());
195 
196     const bool is3d             = (texture.type() == IMAGE_TYPE_3D);
197     const int numLayersOrSlices = (is3d ? texture.size(mipmapLevel).z() : texture.numLayers());
198     const int numCubeFaces      = 6;
199 
200     int passedLayers = 0;
201     for (int layerNdx = 0; layerNdx < numLayersOrSlices; ++layerNdx)
202     {
203         const std::string comparisonName = "Comparison" + de::toString(layerNdx);
204         const std::string comparisonDesc =
205             "Image Comparison, " + (isCube(texture) ? "face " + de::toString(layerNdx % numCubeFaces) + ", cube " +
206                                                           de::toString(layerNdx / numCubeFaces) :
207                                     is3d ? "slice " + de::toString(layerNdx) :
208                                            "layer " + de::toString(layerNdx) + " , level " + de::toString(mipmapLevel));
209 
210         const tcu::ConstPixelBufferAccess refLayer    = getLayerOrSlice(texture, reference, layerNdx);
211         const tcu::ConstPixelBufferAccess resultLayer = getLayerOrSlice(texture, result, layerNdx);
212 
213         bool ok = false;
214 
215         switch (tcu::getTextureChannelClass(mapVkFormat(format).type))
216         {
217         case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
218         case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
219         {
220             ok = tcu::intThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer,
221                                           tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
222             break;
223         }
224 
225         case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
226         {
227             // Allow error of minimum representable difference
228             tcu::Vec4 threshold(
229                 1.0f /
230                 ((tcu::UVec4(1u) << tcu::getTextureFormatMantissaBitDepth(mapVkFormat(format)).cast<uint32_t>()) - 1u)
231                     .cast<float>());
232 
233             // Add 1 ULP of fp32 imprecision to account for image comparison fp32 math with unorm->float conversions.
234             threshold += tcu::Vec4(std::numeric_limits<float>::epsilon());
235 
236             ok = tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer,
237                                             threshold, tcu::COMPARE_LOG_RESULT);
238             break;
239         }
240 
241         case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
242         {
243             const tcu::UVec4 bitDepth =
244                 tcu::getTextureFormatMantissaBitDepth(mapVkFormat(format)).cast<uint32_t>() - 1u;
245             // To avoid bit-shifting with negative value, which is undefined behaviour.
246             const tcu::UVec4 fixedBitDepth =
247                 tcu::select(bitDepth, tcu::UVec4(0u, 0u, 0u, 0u),
248                             tcu::greaterThanEqual(bitDepth.cast<int32_t>(), tcu::IVec4(0, 0, 0, 0)));
249 
250             // Allow error of minimum representable difference
251             const tcu::Vec4 threshold(1.0f / ((tcu::UVec4(1u) << fixedBitDepth) - 1u).cast<float>());
252 
253             ok = tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer,
254                                             threshold, tcu::COMPARE_LOG_RESULT);
255             break;
256         }
257 
258         case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
259         {
260             // Convert target format ulps to float ulps and allow 1 ulp difference
261             const tcu::UVec4 threshold(
262                 tcu::UVec4(1u) << (tcu::UVec4(23) -
263                                    tcu::getTextureFormatMantissaBitDepth(mapVkFormat(format)).cast<uint32_t>()));
264 
265             ok = tcu::floatUlpThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer,
266                                                resultLayer, threshold, tcu::COMPARE_LOG_RESULT);
267             break;
268         }
269 
270         default:
271             DE_FATAL("Unknown channel class");
272         }
273 
274         if (ok)
275             ++passedLayers;
276     }
277 
278     return passedLayers == numLayersOrSlices;
279 }
280 
281 //!< Zero out invalid pixels in the image (denormalized, infinite, NaN values)
replaceBadFloatReinterpretValues(const tcu::PixelBufferAccess access)282 void replaceBadFloatReinterpretValues(const tcu::PixelBufferAccess access)
283 {
284     DE_ASSERT(tcu::getTextureChannelClass(access.getFormat().type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
285 
286     for (int z = 0; z < access.getDepth(); ++z)
287         for (int y = 0; y < access.getHeight(); ++y)
288             for (int x = 0; x < access.getWidth(); ++x)
289             {
290                 const tcu::Vec4 color(access.getPixel(x, y, z));
291                 tcu::Vec4 newColor = color;
292 
293                 for (int i = 0; i < 4; ++i)
294                 {
295                     if (access.getFormat().type == tcu::TextureFormat::HALF_FLOAT)
296                     {
297                         const tcu::Float16 f(color[i]);
298                         if (f.isDenorm() || f.isInf() || f.isNaN())
299                             newColor[i] = 0.0f;
300                     }
301                     else
302                     {
303                         const tcu::Float32 f(color[i]);
304                         if (f.isDenorm() || f.isInf() || f.isNaN())
305                             newColor[i] = 0.0f;
306                     }
307                 }
308 
309                 if (newColor != color)
310                     access.setPixel(newColor, x, y, z);
311             }
312 }
313 
314 //!< replace invalid pixels in the image (-128)
replaceSnormReinterpretValues(const tcu::PixelBufferAccess access)315 void replaceSnormReinterpretValues(const tcu::PixelBufferAccess access)
316 {
317     DE_ASSERT(tcu::getTextureChannelClass(access.getFormat().type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT);
318 
319     for (int z = 0; z < access.getDepth(); ++z)
320         for (int y = 0; y < access.getHeight(); ++y)
321             for (int x = 0; x < access.getWidth(); ++x)
322             {
323                 const tcu::IVec4 color(access.getPixelInt(x, y, z));
324                 tcu::IVec4 newColor = color;
325 
326                 for (int i = 0; i < 4; ++i)
327                 {
328                     const int32_t oldColor(color[i]);
329                     if (oldColor == -128)
330                         newColor[i] = -127;
331                 }
332 
333                 if (newColor != color)
334                     access.setPixel(newColor, x, y, z);
335             }
336 }
337 
getMiddleValue(VkFormat imageFormat)338 tcu::Vec4 getMiddleValue(VkFormat imageFormat)
339 {
340     tcu::TextureFormat format      = mapVkFormat(imageFormat);
341     tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(format);
342     tcu::Vec4 val                  = (fmtInfo.valueMax - fmtInfo.valueMin) * tcu::Vec4(0.5f);
343 
344     if (isIntegerFormat(imageFormat))
345         val = floor(val);
346 
347     return val;
348 }
349 
generateReferenceImage(const tcu::IVec3 & imageSize,const VkFormat imageFormat,const VkFormat readFormat,bool constantValue=false)350 tcu::TextureLevel generateReferenceImage(const tcu::IVec3 &imageSize, const VkFormat imageFormat,
351                                          const VkFormat readFormat, bool constantValue = false)
352 {
353     // Generate a reference image data using the storage format
354 
355     tcu::TextureLevel reference(mapVkFormat(imageFormat), imageSize.x(), imageSize.y(), imageSize.z());
356     const tcu::PixelBufferAccess access = reference.getAccess();
357 
358     const float storeColorScale = computeStoreColorScale(imageFormat, imageSize);
359     const float storeColorBias  = computeStoreColorBias(imageFormat);
360 
361     const bool srgbFormat          = isSrgbFormat(imageFormat);
362     const bool intFormat           = isIntegerFormat(imageFormat);
363     const bool storeNegativeValues = isSignedFormat(imageFormat) && (storeColorBias == 0);
364     const int xMax                 = imageSize.x() - 1;
365     const int yMax                 = imageSize.y() - 1;
366 
367     for (int z = 0; z < imageSize.z(); ++z)
368         for (int y = 0; y < imageSize.y(); ++y)
369             for (int x = 0; x < imageSize.x(); ++x)
370             {
371                 if (constantValue)
372                 {
373                     access.setPixel(getMiddleValue(imageFormat), x, y, z);
374                 }
375                 else
376                 {
377                     tcu::IVec4 color =
378                         tcu::IVec4(x ^ y ^ z, (xMax - x) ^ y ^ z, x ^ (yMax - y) ^ z, (xMax - x) ^ (yMax - y) ^ z);
379 
380                     if (storeNegativeValues)
381                         color -= tcu::IVec4(deRoundFloatToInt32((float)de::max(xMax, yMax) / 2.0f));
382 
383                     if (intFormat)
384                         access.setPixel(color, x, y, z);
385                     else
386                     {
387                         if (srgbFormat)
388                             access.setPixel(tcu::linearToSRGB(color.asFloat() * storeColorScale + storeColorBias), x, y,
389                                             z);
390                         else
391                             access.setPixel(color.asFloat() * storeColorScale + storeColorBias, x, y, z);
392                     }
393                 }
394             }
395 
396     // If the image is to be accessed as a float texture, get rid of invalid values
397 
398     if (isFloatFormat(readFormat) && imageFormat != readFormat)
399         replaceBadFloatReinterpretValues(
400             tcu::PixelBufferAccess(mapVkFormat(readFormat), imageSize, access.getDataPtr()));
401     if (isSnormFormat(readFormat) && imageFormat != readFormat)
402         replaceSnormReinterpretValues(tcu::PixelBufferAccess(mapVkFormat(readFormat), imageSize, access.getDataPtr()));
403 
404     return reference;
405 }
406 
generateReferenceImage(const tcu::IVec3 & imageSize,const VkFormat imageFormat,bool constantValue=false)407 inline tcu::TextureLevel generateReferenceImage(const tcu::IVec3 &imageSize, const VkFormat imageFormat,
408                                                 bool constantValue = false)
409 {
410     return generateReferenceImage(imageSize, imageFormat, imageFormat, constantValue);
411 }
412 
flipHorizontally(const tcu::PixelBufferAccess access)413 void flipHorizontally(const tcu::PixelBufferAccess access)
414 {
415     const int xMax      = access.getWidth() - 1;
416     const int halfWidth = access.getWidth() / 2;
417 
418     if (isIntegerFormat(mapTextureFormat(access.getFormat())))
419         for (int z = 0; z < access.getDepth(); z++)
420             for (int y = 0; y < access.getHeight(); y++)
421                 for (int x = 0; x < halfWidth; x++)
422                 {
423                     const tcu::UVec4 temp = access.getPixelUint(xMax - x, y, z);
424                     access.setPixel(access.getPixelUint(x, y, z), xMax - x, y, z);
425                     access.setPixel(temp, x, y, z);
426                 }
427     else
428         for (int z = 0; z < access.getDepth(); z++)
429             for (int y = 0; y < access.getHeight(); y++)
430                 for (int x = 0; x < halfWidth; x++)
431                 {
432                     const tcu::Vec4 temp = access.getPixel(xMax - x, y, z);
433                     access.setPixel(access.getPixel(x, y, z), xMax - x, y, z);
434                     access.setPixel(temp, x, y, z);
435                 }
436 }
437 
formatsAreCompatible(const VkFormat format0,const VkFormat format1)438 inline bool formatsAreCompatible(const VkFormat format0, const VkFormat format1)
439 {
440     const bool isAlphaOnly = (isAlphaOnlyFormat(format0) || isAlphaOnlyFormat(format1));
441     return format0 == format1 ||
442            (mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize() && !isAlphaOnly);
443 }
444 
commandImageWriteBarrierBetweenShaderInvocations(Context & context,const VkCommandBuffer cmdBuffer,const VkImage image,const Texture & texture,VkImageAspectFlags aspectMask=VK_IMAGE_ASPECT_COLOR_BIT)445 void commandImageWriteBarrierBetweenShaderInvocations(Context &context, const VkCommandBuffer cmdBuffer,
446                                                       const VkImage image, const Texture &texture,
447                                                       VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT)
448 {
449     const DeviceInterface &vk = context.getDeviceInterface();
450 
451     const VkImageSubresourceRange fullImageSubresourceRange =
452         makeImageSubresourceRange(aspectMask, 0u, texture.numMipmapLevels(), 0u, texture.numLayers());
453     const VkImageMemoryBarrier shaderWriteBarrier =
454         makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, 0u, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, image,
455                                fullImageSubresourceRange);
456 
457     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
458                           (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &shaderWriteBarrier);
459 }
460 
commandBufferWriteBarrierBeforeHostRead(Context & context,const VkCommandBuffer cmdBuffer,const VkBuffer buffer,const VkDeviceSize bufferSizeBytes)461 void commandBufferWriteBarrierBeforeHostRead(Context &context, const VkCommandBuffer cmdBuffer, const VkBuffer buffer,
462                                              const VkDeviceSize bufferSizeBytes)
463 {
464     const DeviceInterface &vk = context.getDeviceInterface();
465 
466     const VkBufferMemoryBarrier shaderWriteBarrier =
467         makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, 0ull, bufferSizeBytes);
468 
469     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
470                           (VkDependencyFlags)0, 0, nullptr, 1, &shaderWriteBarrier, 0, nullptr);
471 }
472 
473 //! Copy all layers of an image to a buffer.
commandCopyImageToBuffer(Context & context,const VkCommandBuffer cmdBuffer,const VkImage image,const VkBuffer buffer,const VkDeviceSize bufferSizeBytes,const Texture & texture,VkImageAspectFlags aspectMask=VK_IMAGE_ASPECT_COLOR_BIT)474 void commandCopyImageToBuffer(Context &context, const VkCommandBuffer cmdBuffer, const VkImage image,
475                               const VkBuffer buffer, const VkDeviceSize bufferSizeBytes, const Texture &texture,
476                               VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT)
477 {
478     const DeviceInterface &vk = context.getDeviceInterface();
479 
480     const VkImageSubresourceRange fullImageSubresourceRange =
481         makeImageSubresourceRange(aspectMask, 0u, 1u, 0u, texture.numLayers());
482     const VkImageMemoryBarrier prepareForTransferBarrier =
483         makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
484                                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, fullImageSubresourceRange);
485 
486     const VkBufferImageCopy copyRegion = makeBufferImageCopy(texture, aspectMask);
487 
488     const VkBufferMemoryBarrier copyBarrier =
489         makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, 0ull, bufferSizeBytes);
490 
491     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
492                           (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &prepareForTransferBarrier);
493     vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, &copyRegion);
494     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
495                           0, nullptr, 1, &copyBarrier, 0, nullptr);
496 }
497 
498 //! Copy all layers of a mipmap image to a buffer.
commandCopyMipmapImageToBuffer(Context & context,const VkCommandBuffer cmdBuffer,const VkImage image,const VkFormat imageFormat,const VkBuffer buffer,const VkDeviceSize bufferSizeBytes,const Texture & texture)499 void commandCopyMipmapImageToBuffer(Context &context, const VkCommandBuffer cmdBuffer, const VkImage image,
500                                     const VkFormat imageFormat, const VkBuffer buffer,
501                                     const VkDeviceSize bufferSizeBytes, const Texture &texture)
502 {
503     const DeviceInterface &vk = context.getDeviceInterface();
504 
505     const VkImageSubresourceRange fullImageSubresourceRange =
506         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, texture.numMipmapLevels(), 0u, texture.numLayers());
507     const VkImageMemoryBarrier prepareForTransferBarrier =
508         makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
509                                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, fullImageSubresourceRange);
510 
511     std::vector<VkBufferImageCopy> copyRegions;
512     VkDeviceSize bufferOffset = 0u;
513     for (int32_t levelNdx = 0; levelNdx < texture.numMipmapLevels(); levelNdx++)
514     {
515         const VkBufferImageCopy copyParams = {
516             bufferOffset, // VkDeviceSize bufferOffset;
517             0u,           // uint32_t bufferRowLength;
518             0u,           // uint32_t bufferImageHeight;
519             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, levelNdx, 0u,
520                                        texture.numLayers()), // VkImageSubresourceLayers imageSubresource;
521             makeOffset3D(0, 0, 0),                           // VkOffset3D imageOffset;
522             makeExtent3D(texture.layerSize(levelNdx)),       // VkExtent3D imageExtent;
523         };
524         copyRegions.push_back(copyParams);
525         bufferOffset += getMipmapLevelImageSizeBytes(texture, imageFormat, levelNdx);
526     }
527 
528     const VkBufferMemoryBarrier copyBarrier =
529         makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, 0ull, bufferSizeBytes);
530 
531     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
532                           (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &prepareForTransferBarrier);
533     vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer,
534                             (uint32_t)copyRegions.size(), copyRegions.data());
535     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
536                           0, nullptr, 1, &copyBarrier, 0, nullptr);
537 }
538 
539 class StoreTest : public TestCase
540 {
541 public:
542     enum TestFlags
543     {
544         FLAG_SINGLE_LAYER_BIND = 0x1, //!< Run the shader multiple times, each time binding a different layer.
545         FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER = 0x2, //!< Declare the format of the images in the shader code
546         FLAG_MINALIGN             = 0x4, //!< Use bufferview offset that matches the advertised minimum alignment
547         FLAG_STORE_CONSTANT_VALUE = 0x8, //!< Store constant value
548     };
549 
550     StoreTest(tcu::TestContext &testCtx, const std::string &name, const Texture &texture, const VkFormat format,
551               const VkImageTiling tiling, const uint32_t flags = FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER);
552 
553     virtual void checkSupport(Context &context) const;
554     void initPrograms(SourceCollections &programCollection) const;
555     TestInstance *createInstance(Context &context) const;
556 
557 private:
558     const Texture m_texture;
559     const VkFormat m_format;
560     const VkImageTiling m_tiling;
561     const bool m_declareImageFormatInShader;
562     const bool m_singleLayerBind;
563     const bool m_minalign;
564     const bool m_storeConstantValue;
565 };
566 
StoreTest(tcu::TestContext & testCtx,const std::string & name,const Texture & texture,const VkFormat format,const VkImageTiling tiling,const uint32_t flags)567 StoreTest::StoreTest(tcu::TestContext &testCtx, const std::string &name, const Texture &texture, const VkFormat format,
568                      const VkImageTiling tiling, const uint32_t flags)
569     : TestCase(testCtx, name)
570     , m_texture(texture)
571     , m_format(format)
572     , m_tiling(tiling)
573     , m_declareImageFormatInShader((flags & FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER) != 0)
574     , m_singleLayerBind((flags & FLAG_SINGLE_LAYER_BIND) != 0)
575     , m_minalign((flags & FLAG_MINALIGN) != 0)
576     , m_storeConstantValue((flags & FLAG_STORE_CONSTANT_VALUE) != 0)
577 {
578     if (m_singleLayerBind)
579         DE_ASSERT(m_texture.numLayers() > 1);
580 }
581 
checkSupport(Context & context) const582 void StoreTest::checkSupport(Context &context) const
583 {
584 #ifndef CTS_USES_VULKANSC
585     if (m_format == VK_FORMAT_A8_UNORM_KHR || m_format == VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR)
586         context.requireDeviceFunctionality("VK_KHR_maintenance5");
587 
588     const VkFormatProperties3 formatProperties(context.getFormatProperties(m_format));
589 
590     const auto &tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures :
591                                                                              formatProperties.linearTilingFeatures;
592 
593     if ((m_texture.type() == IMAGE_TYPE_BUFFER) && !m_declareImageFormatInShader &&
594         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR))
595         TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via storage buffer");
596 
597     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !m_declareImageFormatInShader &&
598         !(tilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR))
599         TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via storage images");
600 
601     if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
602         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
603 
604     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
605         TCU_THROW(NotSupportedError, "Format not supported for storage images");
606 
607     if (m_texture.type() == IMAGE_TYPE_BUFFER &&
608         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
609         TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
610 #else
611     const VkFormatProperties formatProperties(
612         getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), m_format));
613     const auto tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures :
614                                                                             formatProperties.linearTilingFeatures;
615 
616     if (!m_declareImageFormatInShader)
617         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT);
618 
619     if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
620         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
621 
622     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
623         TCU_THROW(NotSupportedError, "Format not supported for storage images");
624 
625     if (m_texture.type() == IMAGE_TYPE_BUFFER &&
626         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
627         TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
628 #endif // CTS_USES_VULKANSC
629 
630     const auto &vki           = context.getInstanceInterface();
631     const auto physicalDevice = context.getPhysicalDevice();
632 
633     VkImageFormatProperties imageFormatProperties;
634     const auto result = vki.getPhysicalDeviceImageFormatProperties(
635         physicalDevice, m_format, mapImageType(m_texture.type()), m_tiling,
636         (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), 0, &imageFormatProperties);
637 
638     if (result != VK_SUCCESS)
639     {
640         if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
641             TCU_THROW(NotSupportedError, "Format unsupported for tiling");
642         else
643             TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned unexpected error");
644     }
645 
646     if (imageFormatProperties.maxArrayLayers < (uint32_t)m_texture.numLayers())
647     {
648         TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of aray layers");
649     }
650 
651     if (imageFormatProperties.maxMipLevels < (uint32_t)m_texture.numMipmapLevels())
652     {
653         TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of miplevels");
654     }
655 }
656 
initPrograms(SourceCollections & programCollection) const657 void StoreTest::initPrograms(SourceCollections &programCollection) const
658 {
659     const float storeColorScale = computeStoreColorScale(m_format, m_texture.size());
660     const float storeColorBias  = computeStoreColorBias(m_format);
661     DE_ASSERT(colorScaleAndBiasAreValid(m_format, storeColorScale, storeColorBias));
662 
663     const uint32_t xMax                = m_texture.size().x() - 1;
664     const uint32_t yMax                = m_texture.size().y() - 1;
665     const std::string signednessPrefix = isUintFormat(m_format) ? "u" : isIntFormat(m_format) ? "i" : "";
666     const bool storeNegativeValues     = isSignedFormat(m_format) && (storeColorBias == 0);
667     bool useClamp                      = false;
668     const std::string colorType        = signednessPrefix + "vec4";
669     std::string colorBaseExpr          = colorType + "(";
670 
671     std::string colorExpr;
672 
673     if (m_storeConstantValue)
674     {
675         tcu::Vec4 val = getMiddleValue(m_format);
676 
677         if (isIntegerFormat(m_format))
678         {
679             colorExpr = colorBaseExpr + de::toString(static_cast<int64_t>(val.x())) + ", " +
680                         de::toString(static_cast<int64_t>(val.y())) + ", " +
681                         de::toString(static_cast<int64_t>(val.z())) + ", " +
682                         de::toString(static_cast<int64_t>(val.w())) + ")";
683         }
684         else
685         {
686             colorExpr = colorBaseExpr + de::toString(val.x()) + ", " + de::toString(val.y()) + ", " +
687                         de::toString(val.z()) + ", " + de::toString(val.w()) + ")";
688         }
689     }
690     else
691     {
692         colorBaseExpr = colorBaseExpr + "gx^gy^gz, " + "(" + de::toString(xMax) + "-gx)^gy^gz, " + "gx^(" +
693                         de::toString(yMax) + "-gy)^gz, " + "(" + de::toString(xMax) + "-gx)^(" + de::toString(yMax) +
694                         "-gy)^gz)";
695 
696         // Large integer values may not be represented with formats with low bit depths
697         if (isIntegerFormat(m_format))
698         {
699             const int64_t minStoreValue =
700                 storeNegativeValues ? 0 - deRoundFloatToInt64((float)de::max(xMax, yMax) / 2.0f) : 0;
701             const int64_t maxStoreValue =
702                 storeNegativeValues ? deRoundFloatToInt64((float)de::max(xMax, yMax) / 2.0f) : de::max(xMax, yMax);
703 
704             useClamp = !isRepresentableIntegerValue(tcu::Vector<int64_t, 4>(minStoreValue), mapVkFormat(m_format)) ||
705                        !isRepresentableIntegerValue(tcu::Vector<int64_t, 4>(maxStoreValue), mapVkFormat(m_format));
706         }
707 
708         // Clamp if integer value cannot be represented with the current format
709         if (useClamp)
710         {
711             const tcu::IVec4 bitDepths = tcu::getTextureFormatBitDepth(mapVkFormat(m_format));
712             tcu::IVec4 minRepresentableValue;
713             tcu::IVec4 maxRepresentableValue;
714 
715             switch (tcu::getTextureChannelClass(mapVkFormat(m_format).type))
716             {
717             case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
718             {
719                 minRepresentableValue = tcu::IVec4(0);
720                 maxRepresentableValue = (tcu::IVec4(1) << bitDepths) - tcu::IVec4(1);
721                 break;
722             }
723 
724             case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
725             {
726                 minRepresentableValue = -(tcu::IVec4(1) << bitDepths - tcu::IVec4(1));
727                 maxRepresentableValue = (tcu::IVec4(1) << (bitDepths - tcu::IVec4(1))) - tcu::IVec4(1);
728                 break;
729             }
730 
731             default:
732                 DE_ASSERT(isIntegerFormat(m_format));
733             }
734 
735             colorBaseExpr = "clamp(" + colorBaseExpr + ", " + signednessPrefix + "vec4" +
736                             de::toString(minRepresentableValue) + ", " + signednessPrefix + "vec4" +
737                             de::toString(maxRepresentableValue) + ")";
738         }
739 
740         colorExpr = colorBaseExpr + (storeColorScale == 1.0f ? "" : "*" + de::toString(storeColorScale)) +
741                     (storeColorBias == 0.0f ? "" : " + float(" + de::toString(storeColorBias) + ")");
742 
743         if (storeNegativeValues)
744             colorExpr += "-" + de::toString(deRoundFloatToInt32((float)deMax32(xMax, yMax) / 2.0f));
745     }
746 
747     const int dimension             = (m_singleLayerBind ? m_texture.layerDimension() : m_texture.dimension());
748     const std::string texelCoordStr = (dimension == 1 ? "gx" :
749                                        dimension == 2 ? "ivec2(gx, gy)" :
750                                        dimension == 3 ? "ivec3(gx, gy, gz)" :
751                                                         "");
752 
753     const ImageType usedImageType =
754         (m_singleLayerBind ? getImageTypeForSingleLayer(m_texture.type()) : m_texture.type());
755     const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), usedImageType);
756 
757     std::string maybeFmtQualStr = m_declareImageFormatInShader ? ", " + getShaderImageFormatQualifierStr(m_format) : "";
758 
759     std::ostringstream src;
760     src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
761         << "\n"
762         << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
763         << "layout (binding = 0" << maybeFmtQualStr << ") writeonly uniform " << imageTypeStr << " u_image;\n";
764 
765     if (m_singleLayerBind)
766         src << "layout (binding = 1) readonly uniform Constants {\n"
767             << "    int u_layerNdx;\n"
768             << "};\n";
769 
770     src << "\n"
771         << "void main (void)\n"
772         << "{\n"
773         << "    int gx = int(gl_GlobalInvocationID.x);\n"
774         << "    int gy = int(gl_GlobalInvocationID.y);\n"
775         << "    int gz = " << (m_singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
776         << "    " << colorType << " storedColor = " << colorExpr << ";\n"
777         << "    imageStore(u_image, " << texelCoordStr << ", storedColor);\n"
778         << "}\n";
779 
780     programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
781 }
782 
783 //! Generic test iteration algorithm for image tests
784 class BaseTestInstance : public TestInstance
785 {
786 public:
787     BaseTestInstance(Context &context, const Texture &texture, const VkFormat format,
788                      const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign,
789                      const bool bufferLoadUniform);
790 
791     virtual tcu::TestStatus iterate(void);
792 
~BaseTestInstance(void)793     virtual ~BaseTestInstance(void)
794     {
795     }
796 
797 protected:
798     virtual VkDescriptorSetLayout prepareDescriptors(void) = 0;
799     virtual tcu::TestStatus verifyResult(void)             = 0;
800 
801     virtual void commandBeforeCompute(const VkCommandBuffer cmdBuffer)            = 0;
802     virtual void commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer) = 0;
803     virtual void commandAfterCompute(const VkCommandBuffer cmdBuffer)             = 0;
804 
805     virtual void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
806                                                 const int layerNdx) = 0;
807     virtual uint32_t getViewOffset(Context &context, const VkFormat format, bool uniform);
808 
809     const Texture m_texture;
810     const VkFormat m_format;
811     const bool m_declareImageFormatInShader;
812     const bool m_singleLayerBind;
813     const bool m_minalign;
814     const bool m_bufferLoadUniform;
815     const uint32_t m_srcViewOffset;
816     const uint32_t m_dstViewOffset;
817 };
818 
BaseTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)819 BaseTestInstance::BaseTestInstance(Context &context, const Texture &texture, const VkFormat format,
820                                    const bool declareImageFormatInShader, const bool singleLayerBind,
821                                    const bool minalign, const bool bufferLoadUniform)
822     : TestInstance(context)
823     , m_texture(texture)
824     , m_format(format)
825     , m_declareImageFormatInShader(declareImageFormatInShader)
826     , m_singleLayerBind(singleLayerBind)
827     , m_minalign(minalign)
828     , m_bufferLoadUniform(bufferLoadUniform)
829     , m_srcViewOffset(getViewOffset(context, format, m_bufferLoadUniform))
830     , m_dstViewOffset(
831           getViewOffset(context, formatHasThreeComponents(format) ? getSingleComponentFormat(format) : format, false))
832 {
833 }
834 
iterate(void)835 tcu::TestStatus BaseTestInstance::iterate(void)
836 {
837     const DeviceInterface &vk       = m_context.getDeviceInterface();
838     const VkDevice device           = m_context.getDevice();
839     const VkQueue queue             = m_context.getUniversalQueue();
840     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
841 
842     const Unique<VkShaderModule> shaderModule(
843         createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
844 
845     const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
846     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
847     const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
848 
849     const Unique<VkCommandPool> cmdPool(
850         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex));
851     const Unique<VkCommandBuffer> cmdBuffer(
852         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
853 
854     beginCommandBuffer(vk, *cmdBuffer);
855 
856     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
857     commandBeforeCompute(*cmdBuffer);
858 
859     const tcu::IVec3 workSize = (m_singleLayerBind ? m_texture.layerSize() : m_texture.size());
860     const int loopNumLayers   = (m_singleLayerBind ? m_texture.numLayers() : 1);
861     for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
862     {
863         commandBindDescriptorsForLayer(*cmdBuffer, *pipelineLayout, layerNdx);
864 
865         if (layerNdx > 0)
866             commandBetweenShaderInvocations(*cmdBuffer);
867 
868         vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
869     }
870 
871     commandAfterCompute(*cmdBuffer);
872 
873     endCommandBuffer(vk, *cmdBuffer);
874 
875     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
876 
877     return verifyResult();
878 }
879 
880 //! Base store test implementation
881 class StoreTestInstance : public BaseTestInstance
882 {
883 public:
884     StoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
885                       const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign,
886                       const bool storeConstantValue);
887 
888 protected:
889     virtual tcu::TestStatus verifyResult(void);
890 
891     // Add empty implementations for functions that might be not needed
commandBeforeCompute(const VkCommandBuffer)892     void commandBeforeCompute(const VkCommandBuffer)
893     {
894     }
commandBetweenShaderInvocations(const VkCommandBuffer)895     void commandBetweenShaderInvocations(const VkCommandBuffer)
896     {
897     }
commandAfterCompute(const VkCommandBuffer)898     void commandAfterCompute(const VkCommandBuffer)
899     {
900     }
901 
902     de::MovePtr<BufferWithMemory> m_imageBuffer;
903     const VkDeviceSize m_imageSizeBytes;
904     bool m_storeConstantValue;
905 };
906 
getViewOffset(Context & context,const VkFormat format,bool uniform)907 uint32_t BaseTestInstance::getViewOffset(Context &context, const VkFormat format, bool uniform)
908 {
909     if (m_minalign)
910     {
911         if (!context.getTexelBufferAlignmentFeaturesEXT().texelBufferAlignment)
912             return (uint32_t)context.getDeviceProperties().limits.minTexelBufferOffsetAlignment;
913 
914         VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT alignmentProperties;
915         deMemset(&alignmentProperties, 0, sizeof(alignmentProperties));
916         alignmentProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT;
917 
918         VkPhysicalDeviceProperties2 properties2;
919         deMemset(&properties2, 0, sizeof(properties2));
920         properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
921         properties2.pNext = &alignmentProperties;
922 
923         context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties2);
924 
925         VkBool32 singleTexelAlignment = uniform ? alignmentProperties.uniformTexelBufferOffsetSingleTexelAlignment :
926                                                   alignmentProperties.storageTexelBufferOffsetSingleTexelAlignment;
927         VkDeviceSize align            = uniform ? alignmentProperties.uniformTexelBufferOffsetAlignmentBytes :
928                                                   alignmentProperties.storageTexelBufferOffsetAlignmentBytes;
929 
930         VkDeviceSize texelSize = formatHasThreeComponents(format) ? tcu::getChannelSize(vk::mapVkFormat(format).type) :
931                                                                     tcu::getPixelSize(vk::mapVkFormat(format));
932 
933         if (singleTexelAlignment)
934             align = de::min(align, texelSize);
935 
936         return (uint32_t)align;
937     }
938 
939     return 0;
940 }
941 
StoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool storeConstantValue)942 StoreTestInstance::StoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
943                                      const bool declareImageFormatInShader, const bool singleLayerBind,
944                                      const bool minalign, const bool storeConstantValue)
945     : BaseTestInstance(context, texture, format, declareImageFormatInShader, singleLayerBind, minalign, false)
946     , m_imageSizeBytes(getImageSizeBytes(texture.size(), format))
947     , m_storeConstantValue(storeConstantValue)
948 {
949     const DeviceInterface &vk = m_context.getDeviceInterface();
950     const VkDevice device     = m_context.getDevice();
951     Allocator &allocator      = m_context.getDefaultAllocator();
952 
953     // A helper buffer with enough space to hold the whole image. Usage flags accommodate all derived test instances.
954 
955     m_imageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
956         vk, device, allocator,
957         makeBufferCreateInfo(m_imageSizeBytes + m_dstViewOffset,
958                              VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
959         MemoryRequirement::HostVisible));
960 }
961 
verifyResult(void)962 tcu::TestStatus StoreTestInstance::verifyResult(void)
963 {
964     const DeviceInterface &vk = m_context.getDeviceInterface();
965     const VkDevice device     = m_context.getDevice();
966 
967     const tcu::IVec3 imageSize        = m_texture.size();
968     const tcu::TextureLevel reference = generateReferenceImage(imageSize, m_format, m_storeConstantValue);
969 
970     const Allocation &alloc = m_imageBuffer->getAllocation();
971     invalidateAlloc(vk, device, alloc);
972     const tcu::ConstPixelBufferAccess result(mapVkFormat(m_format), imageSize,
973                                              (const char *)alloc.getHostPtr() + m_dstViewOffset);
974 
975     if (comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_format, reference.getAccess(), result))
976         return tcu::TestStatus::pass("Passed");
977     else
978         return tcu::TestStatus::fail("Image comparison failed");
979 }
980 
981 //! Store test for images
982 class ImageStoreTestInstance : public StoreTestInstance
983 {
984 public:
985     ImageStoreTestInstance(Context &context, const Texture &texture, const VkFormat format, const VkImageTiling tiling,
986                            const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign,
987                            const bool storeConstantValue);
988 
989 protected:
990     VkDescriptorSetLayout prepareDescriptors(void);
991     void commandBeforeCompute(const VkCommandBuffer cmdBuffer);
992     void commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer);
993     void commandAfterCompute(const VkCommandBuffer cmdBuffer);
994 
995     void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
996                                         const int layerNdx);
997 
998     de::MovePtr<Image> m_image;
999     de::MovePtr<BufferWithMemory> m_constantsBuffer;
1000     const VkDeviceSize m_constantsBufferChunkSizeBytes;
1001     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1002     Move<VkDescriptorPool> m_descriptorPool;
1003     std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
1004     std::vector<SharedVkImageView> m_allImageViews;
1005 };
1006 
ImageStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkImageTiling tiling,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool storeConstantValue)1007 ImageStoreTestInstance::ImageStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
1008                                                const VkImageTiling tiling, const bool declareImageFormatInShader,
1009                                                const bool singleLayerBind, const bool minalign,
1010                                                const bool storeConstantValue)
1011     : StoreTestInstance(context, texture, format, declareImageFormatInShader, singleLayerBind, minalign,
1012                         storeConstantValue)
1013     , m_constantsBufferChunkSizeBytes(getOptimalUniformBufferChunkSize(context.getInstanceInterface(),
1014                                                                        context.getPhysicalDevice(), sizeof(uint32_t)))
1015     , m_allDescriptorSets(texture.numLayers())
1016     , m_allImageViews(texture.numLayers())
1017 {
1018     const DeviceInterface &vk = m_context.getDeviceInterface();
1019     const VkDevice device     = m_context.getDevice();
1020     Allocator &allocator      = m_context.getDefaultAllocator();
1021 
1022     m_image = de::MovePtr<Image>(
1023         new Image(vk, device, allocator,
1024                   makeImageCreateInfo(m_texture, m_format,
1025                                       (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), 0u, tiling),
1026                   MemoryRequirement::Any));
1027 
1028     // This buffer will be used to pass constants to the shader
1029 
1030     const int numLayers                         = m_texture.numLayers();
1031     const VkDeviceSize constantsBufferSizeBytes = numLayers * m_constantsBufferChunkSizeBytes;
1032     m_constantsBuffer                           = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
1033         vk, device, allocator, makeBufferCreateInfo(constantsBufferSizeBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
1034         MemoryRequirement::HostVisible));
1035 
1036     {
1037         const Allocation &alloc = m_constantsBuffer->getAllocation();
1038         uint8_t *const basePtr  = static_cast<uint8_t *>(alloc.getHostPtr());
1039 
1040         deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(constantsBufferSizeBytes));
1041 
1042         for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1043         {
1044             uint32_t *valuePtr = reinterpret_cast<uint32_t *>(basePtr + layerNdx * m_constantsBufferChunkSizeBytes);
1045             *valuePtr          = static_cast<uint32_t>(layerNdx);
1046         }
1047 
1048         flushAlloc(vk, device, alloc);
1049     }
1050 }
1051 
prepareDescriptors(void)1052 VkDescriptorSetLayout ImageStoreTestInstance::prepareDescriptors(void)
1053 {
1054     const DeviceInterface &vk = m_context.getDeviceInterface();
1055     const VkDevice device     = m_context.getDevice();
1056 
1057     const int numLayers   = m_texture.numLayers();
1058     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1059                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1060                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1061                                 .build(vk, device);
1062 
1063     m_descriptorPool = DescriptorPoolBuilder()
1064                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1065                            .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, numLayers)
1066                            .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
1067 
1068     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1069 
1070     if (m_singleLayerBind)
1071     {
1072         for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1073         {
1074             m_allDescriptorSets[layerNdx] =
1075                 makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1076             m_allImageViews[layerNdx] = makeVkSharedPtr(makeImageView(
1077                 vk, device, m_image->get(), mapImageViewType(getImageTypeForSingleLayer(m_texture.type())), m_format,
1078                 makeImageSubresourceRange(aspectMask, 0u, 1u, layerNdx, 1u)));
1079         }
1080     }
1081     else // bind all layers at once
1082     {
1083         m_allDescriptorSets[0] =
1084             makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1085         m_allImageViews[0] =
1086             makeVkSharedPtr(makeImageView(vk, device, m_image->get(), mapImageViewType(m_texture.type()), m_format,
1087                                           makeImageSubresourceRange(aspectMask, 0u, 1u, 0u, numLayers)));
1088     }
1089 
1090     return *m_descriptorSetLayout; // not passing the ownership
1091 }
1092 
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1093 void ImageStoreTestInstance::commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,
1094                                                             const VkPipelineLayout pipelineLayout, const int layerNdx)
1095 {
1096     const DeviceInterface &vk = m_context.getDeviceInterface();
1097     const VkDevice device     = m_context.getDevice();
1098 
1099     const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
1100     const VkImageView imageView         = **m_allImageViews[layerNdx];
1101 
1102     const VkDescriptorImageInfo descriptorImageInfo =
1103         makeDescriptorImageInfo(VK_NULL_HANDLE, imageView, VK_IMAGE_LAYOUT_GENERAL);
1104 
1105     // Set the next chunk of the constants buffer. Each chunk begins with layer index that we've set before.
1106     const VkDescriptorBufferInfo descriptorConstantsBufferInfo = makeDescriptorBufferInfo(
1107         m_constantsBuffer->get(), layerNdx * m_constantsBufferChunkSizeBytes, m_constantsBufferChunkSizeBytes);
1108 
1109     DescriptorSetUpdateBuilder()
1110         .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
1111                      &descriptorImageInfo)
1112         .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
1113                      VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
1114         .update(vk, device);
1115     vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u,
1116                              nullptr);
1117 }
1118 
commandBeforeCompute(const VkCommandBuffer cmdBuffer)1119 void ImageStoreTestInstance::commandBeforeCompute(const VkCommandBuffer cmdBuffer)
1120 {
1121     const DeviceInterface &vk            = m_context.getDeviceInterface();
1122     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1123 
1124     const VkImageSubresourceRange fullImageSubresourceRange =
1125         makeImageSubresourceRange(aspectMask, 0u, 1u, 0u, m_texture.numLayers());
1126     const VkImageMemoryBarrier setImageLayoutBarrier =
1127         makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1128                                m_image->get(), fullImageSubresourceRange);
1129 
1130     const VkDeviceSize constantsBufferSize            = m_texture.numLayers() * m_constantsBufferChunkSizeBytes;
1131     const VkBufferMemoryBarrier writeConstantsBarrier = makeBufferMemoryBarrier(
1132         VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, m_constantsBuffer->get(), 0ull, constantsBufferSize);
1133 
1134     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
1135                           (VkDependencyFlags)0, 0, nullptr, 1, &writeConstantsBarrier, 1, &setImageLayoutBarrier);
1136 }
1137 
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)1138 void ImageStoreTestInstance::commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)
1139 {
1140     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1141     commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_image->get(), m_texture, aspectMask);
1142 }
1143 
commandAfterCompute(const VkCommandBuffer cmdBuffer)1144 void ImageStoreTestInstance::commandAfterCompute(const VkCommandBuffer cmdBuffer)
1145 {
1146     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1147     commandCopyImageToBuffer(m_context, cmdBuffer, m_image->get(), m_imageBuffer->get(), m_imageSizeBytes, m_texture,
1148                              aspectMask);
1149 }
1150 
1151 //! Store test for buffers
1152 class BufferStoreTestInstance : public StoreTestInstance
1153 {
1154 public:
1155     BufferStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
1156                             const bool declareImageFormatInShader, const bool minalign, const bool storeConstantValue);
1157 
1158 protected:
1159     VkDescriptorSetLayout prepareDescriptors(void);
1160     void commandAfterCompute(const VkCommandBuffer cmdBuffer);
1161 
1162     void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
1163                                         const int layerNdx);
1164 
1165     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1166     Move<VkDescriptorPool> m_descriptorPool;
1167     Move<VkDescriptorSet> m_descriptorSet;
1168     Move<VkBufferView> m_bufferView;
1169 };
1170 
BufferStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool declareImageFormatInShader,const bool minalign,const bool storeConstantValue)1171 BufferStoreTestInstance::BufferStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
1172                                                  const bool declareImageFormatInShader, const bool minalign,
1173                                                  const bool storeConstantValue)
1174     : StoreTestInstance(context, texture, format, declareImageFormatInShader, false, minalign, storeConstantValue)
1175 {
1176 }
1177 
prepareDescriptors(void)1178 VkDescriptorSetLayout BufferStoreTestInstance::prepareDescriptors(void)
1179 {
1180     const DeviceInterface &vk = m_context.getDeviceInterface();
1181     const VkDevice device     = m_context.getDevice();
1182 
1183     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1184                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1185                                 .build(vk, device);
1186 
1187     m_descriptorPool = DescriptorPoolBuilder()
1188                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
1189                            .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1190 
1191     m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1192     m_bufferView    = makeBufferView(vk, device, m_imageBuffer->get(), m_format, m_dstViewOffset, m_imageSizeBytes);
1193 
1194     return *m_descriptorSetLayout; // not passing the ownership
1195 }
1196 
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1197 void BufferStoreTestInstance::commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,
1198                                                              const VkPipelineLayout pipelineLayout, const int layerNdx)
1199 {
1200     DE_ASSERT(layerNdx == 0);
1201     DE_UNREF(layerNdx);
1202 
1203     const VkDevice device     = m_context.getDevice();
1204     const DeviceInterface &vk = m_context.getDeviceInterface();
1205 
1206     DescriptorSetUpdateBuilder()
1207         .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1208                      VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
1209         .update(vk, device);
1210     vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &m_descriptorSet.get(),
1211                              0u, nullptr);
1212 }
1213 
commandAfterCompute(const VkCommandBuffer cmdBuffer)1214 void BufferStoreTestInstance::commandAfterCompute(const VkCommandBuffer cmdBuffer)
1215 {
1216     commandBufferWriteBarrierBeforeHostRead(m_context, cmdBuffer, m_imageBuffer->get(),
1217                                             m_imageSizeBytes + m_dstViewOffset);
1218 }
1219 
1220 class LoadStoreTest : public TestCase
1221 {
1222 public:
1223     enum TestFlags
1224     {
1225         FLAG_SINGLE_LAYER_BIND = (1 << 0), //!< Run the shader multiple times, each time binding a different layer.
1226         FLAG_RESTRICT_IMAGES   = (1 << 1), //!< If given, images in the shader will be qualified with "restrict".
1227         FLAG_DECLARE_FORMAT_IN_SHADER_READS  = (1 << 2), //!< Declare the format of images being read in the shader code
1228         FLAG_DECLARE_FORMAT_IN_SHADER_WRITES = (1 << 3), //!< Declare the format of images being read in the shader code
1229         FLAG_MINALIGN             = (1 << 4), //!< Use bufferview offset that matches the advertised minimum alignment
1230         FLAG_UNIFORM_TEXEL_BUFFER = (1 << 5), //!< Load from a uniform texel buffer rather than a storage texel buffer
1231     };
1232 
1233     LoadStoreTest(tcu::TestContext &testCtx, const std::string &name, const Texture &texture, const VkFormat format,
1234                   const VkFormat imageFormat, const VkImageTiling tiling,
1235                   const uint32_t flags = (FLAG_DECLARE_FORMAT_IN_SHADER_READS | FLAG_DECLARE_FORMAT_IN_SHADER_WRITES),
1236                   const bool imageLoadStoreLodAMD = false);
1237 
1238     virtual void checkSupport(Context &context) const;
1239     void makePrograms(SourceCollections &programCollection, const DeviceScopeType deviceScopeType = DEVICESCOPE_NONE,
1240                       const bool draw = false, const uint32_t verticesCount = 0u) const;
1241     virtual void initPrograms(SourceCollections &programCollection) const;
1242     TestInstance *createInstance(Context &context) const;
1243 
1244 protected:
1245     const Texture m_texture;
1246     const VkFormat m_format;      //!< Format as accessed in the shader
1247     const VkFormat m_imageFormat; //!< Storage format
1248     const VkImageTiling m_tiling; //!< Image Tiling
1249     const bool
1250         m_declareFormatInShaderReads; //!< Whether the shader will specify the format layout qualifier of images being read from.
1251     const bool
1252         m_declareFormatInShaderWrites; //!< Whether the shader will specify the format layout qualifier of images being written to.
1253     const bool m_singleLayerBind;
1254     const bool m_restrictImages;
1255     const bool m_minalign;
1256     bool m_bufferLoadUniform;
1257     const bool m_imageLoadStoreLodAMD;
1258 };
1259 
LoadStoreTest(tcu::TestContext & testCtx,const std::string & name,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const VkImageTiling tiling,const uint32_t flags,const bool imageLoadStoreLodAMD)1260 LoadStoreTest::LoadStoreTest(tcu::TestContext &testCtx, const std::string &name, const Texture &texture,
1261                              const VkFormat format, const VkFormat imageFormat, const VkImageTiling tiling,
1262                              const uint32_t flags, const bool imageLoadStoreLodAMD)
1263     : TestCase(testCtx, name)
1264     , m_texture(texture)
1265     , m_format(format)
1266     , m_imageFormat(imageFormat)
1267     , m_tiling(tiling)
1268     , m_declareFormatInShaderReads((flags & FLAG_DECLARE_FORMAT_IN_SHADER_READS) != 0)
1269     , m_declareFormatInShaderWrites((flags & FLAG_DECLARE_FORMAT_IN_SHADER_WRITES) != 0)
1270     , m_singleLayerBind((flags & FLAG_SINGLE_LAYER_BIND) != 0)
1271     , m_restrictImages((flags & FLAG_RESTRICT_IMAGES) != 0)
1272     , m_minalign((flags & FLAG_MINALIGN) != 0)
1273     , m_bufferLoadUniform((flags & FLAG_UNIFORM_TEXEL_BUFFER) != 0)
1274     , m_imageLoadStoreLodAMD(imageLoadStoreLodAMD)
1275 {
1276     if (m_singleLayerBind)
1277         DE_ASSERT(m_texture.numLayers() > 1);
1278 
1279     DE_ASSERT(formatsAreCompatible(m_format, m_imageFormat));
1280 }
1281 
checkSupport(Context & context) const1282 void LoadStoreTest::checkSupport(Context &context) const
1283 {
1284 #ifndef CTS_USES_VULKANSC
1285     if (m_format == VK_FORMAT_A8_UNORM_KHR || m_format == VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR)
1286         context.requireDeviceFunctionality("VK_KHR_maintenance5");
1287 
1288     const VkFormatProperties3 formatProperties(context.getFormatProperties(m_format));
1289     const VkFormatProperties3 imageFormatProperties(context.getFormatProperties(m_imageFormat));
1290 
1291     const auto &tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures :
1292                                                                              formatProperties.linearTilingFeatures;
1293     const auto &imageTilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ?
1294                                           imageFormatProperties.optimalTilingFeatures :
1295                                           imageFormatProperties.linearTilingFeatures;
1296 
1297     if (m_imageLoadStoreLodAMD)
1298         context.requireDeviceFunctionality("VK_AMD_shader_image_load_store_lod");
1299 
1300     if (!m_bufferLoadUniform && !m_declareFormatInShaderReads &&
1301         !(tilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT))
1302         TCU_THROW(NotSupportedError, "Format not supported for unformatted loads via storage images");
1303 
1304     if (m_texture.type() == IMAGE_TYPE_BUFFER && !m_declareFormatInShaderReads &&
1305         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT))
1306         TCU_THROW(NotSupportedError, "Format not supported for unformatted loads via buffers");
1307 
1308     if (!m_declareFormatInShaderWrites && !(tilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT))
1309         TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via storage images");
1310 
1311     if (m_texture.type() == IMAGE_TYPE_BUFFER && !m_declareFormatInShaderWrites &&
1312         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT))
1313         TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via buffers");
1314 
1315     if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
1316         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
1317 
1318     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1319         TCU_THROW(NotSupportedError, "Format not supported for storage images");
1320 
1321     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1322         TCU_THROW(NotSupportedError, "Format not supported for storage images");
1323 
1324     if (m_texture.type() == IMAGE_TYPE_BUFFER &&
1325         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1326         TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1327 
1328     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures))
1329         TCU_THROW(NotSupportedError, "Underlying format not supported at all for images");
1330 
1331     if ((m_texture.type() == IMAGE_TYPE_BUFFER) && !(imageFormatProperties.bufferFeatures))
1332         TCU_THROW(NotSupportedError, "Underlying format not supported at all for buffers");
1333 
1334     if (formatHasThreeComponents(m_format))
1335     {
1336         // When the source buffer is three-component, the destination buffer is single-component.
1337         VkFormat dstFormat = getSingleComponentFormat(m_format);
1338         const VkFormatProperties3 dstFormatProperties(context.getFormatProperties(dstFormat));
1339 
1340         if (m_texture.type() == IMAGE_TYPE_BUFFER &&
1341             !(dstFormatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1342             TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1343     }
1344     else if (m_texture.type() == IMAGE_TYPE_BUFFER &&
1345              !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1346         TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1347 
1348     if (m_bufferLoadUniform && m_texture.type() == IMAGE_TYPE_BUFFER &&
1349         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT))
1350         TCU_THROW(NotSupportedError, "Format not supported for uniform texel buffers");
1351 #else
1352     const vk::VkFormatProperties formatProperties(
1353         vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), m_format));
1354     const vk::VkFormatProperties imageFormatProperties(vk::getPhysicalDeviceFormatProperties(
1355         context.getInstanceInterface(), context.getPhysicalDevice(), m_imageFormat));
1356 
1357     const auto tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures :
1358                                                                             formatProperties.linearTilingFeatures;
1359     const auto imageTilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ?
1360                                          imageFormatProperties.optimalTilingFeatures :
1361                                          imageFormatProperties.linearTilingFeatures;
1362 
1363     if (m_imageLoadStoreLodAMD)
1364         context.requireDeviceFunctionality("VK_AMD_shader_image_load_store_lod");
1365 
1366     if (!m_bufferLoadUniform && !m_declareFormatInShaderReads)
1367         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_READ_WITHOUT_FORMAT);
1368 
1369     if (!m_declareFormatInShaderWrites)
1370         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT);
1371 
1372     if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
1373         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
1374 
1375     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1376         TCU_THROW(NotSupportedError, "Format not supported for storage images");
1377 
1378     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1379         TCU_THROW(NotSupportedError, "Format not supported for storage images");
1380 
1381     if (m_texture.type() == IMAGE_TYPE_BUFFER &&
1382         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1383         TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1384 
1385     if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures))
1386         TCU_THROW(NotSupportedError, "Underlying format not supported at all for images");
1387 
1388     if ((m_texture.type() == IMAGE_TYPE_BUFFER) && !(imageFormatProperties.bufferFeatures))
1389         TCU_THROW(NotSupportedError, "Underlying format not supported at all for buffers");
1390 
1391     if (formatHasThreeComponents(m_format))
1392     {
1393         // When the source buffer is three-component, the destination buffer is single-component.
1394         VkFormat dstFormat = getSingleComponentFormat(m_format);
1395         const vk::VkFormatProperties dstFormatProperties(vk::getPhysicalDeviceFormatProperties(
1396             context.getInstanceInterface(), context.getPhysicalDevice(), dstFormat));
1397 
1398         if (m_texture.type() == IMAGE_TYPE_BUFFER &&
1399             !(dstFormatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1400             TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1401     }
1402     else if (m_texture.type() == IMAGE_TYPE_BUFFER &&
1403              !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1404         TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1405 
1406     if (m_bufferLoadUniform && m_texture.type() == IMAGE_TYPE_BUFFER &&
1407         !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT))
1408         TCU_THROW(NotSupportedError, "Format not supported for uniform texel buffers");
1409 #endif // CTS_USES_VULKANSC
1410 
1411     const auto &vki           = context.getInstanceInterface();
1412     const auto physicalDevice = context.getPhysicalDevice();
1413 
1414     VkImageFormatProperties vkImageFormatProperties;
1415     const auto result = vki.getPhysicalDeviceImageFormatProperties(
1416         physicalDevice, m_imageFormat, mapImageType(m_texture.type()), m_tiling,
1417         VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, &vkImageFormatProperties);
1418 
1419     if (result != VK_SUCCESS)
1420     {
1421         if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
1422             TCU_THROW(NotSupportedError, "Format unsupported for tiling");
1423         else
1424             TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned unexpected error");
1425     }
1426 
1427     if (vkImageFormatProperties.maxArrayLayers < (uint32_t)m_texture.numLayers())
1428     {
1429         TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of aray layers");
1430     }
1431 
1432     if (vkImageFormatProperties.maxMipLevels < (uint32_t)m_texture.numMipmapLevels())
1433     {
1434         TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of miplevels");
1435     }
1436 }
1437 
makePrograms(SourceCollections & programCollection,const DeviceScopeType deviceScopeType,const bool draw,const uint32_t verticesCount) const1438 void LoadStoreTest::makePrograms(SourceCollections &programCollection, const DeviceScopeType deviceScopeType,
1439                                  const bool draw, const uint32_t verticesCount) const
1440 {
1441     const tcu::TextureFormat texFormat = mapVkFormat(m_format);
1442     const int dimension                = (m_singleLayerBind ? m_texture.layerDimension() : m_texture.dimension());
1443     const ImageType usedImageType =
1444         (m_singleLayerBind ? getImageTypeForSingleLayer(m_texture.type()) : m_texture.type());
1445     const bool noFormats                    = (!m_declareFormatInShaderReads && !m_declareFormatInShaderWrites);
1446     const std::string formatQualifierStr    = (noFormats ? "" : getShaderImageFormatQualifierStr(m_format));
1447     const std::string uniformTypeStr        = getFormatPrefix(texFormat) + "textureBuffer";
1448     const std::string imageTypeStr          = getShaderImageType(texFormat, usedImageType);
1449     const std::string maybeRestrictStr      = (m_restrictImages ? "restrict " : "");
1450     const std::string xMax                  = de::toString(m_texture.size().x() - 1);
1451     const std::string xMaxSub               = (deviceScopeType == DEVICESCOPE_LOAD) ? "" : (xMax + "-");
1452     const std::string maybeFmtQualStrReads  = m_declareFormatInShaderReads ? ", " + formatQualifierStr : "";
1453     const std::string maybeFmtQualStrWrites = m_declareFormatInShaderWrites ? ", " + formatQualifierStr : "";
1454 
1455     // For device scope tests, the output of first shader will become the input for the second shader
1456     const std::string inputBinding  = (deviceScopeType == DEVICESCOPE_LOAD) ? "1" : "0";
1457     const std::string outputBinding = (deviceScopeType == DEVICESCOPE_LOAD) ? "0" : "1";
1458 
1459     const std::string deviceScopeCommonHeader("#pragma use_vulkan_memory_model\n"
1460                                               "#extension GL_KHR_memory_scope_semantics : enable\n");
1461     if (!draw)
1462     {
1463         std::string shaderName = "comp";
1464 
1465         std::ostringstream src;
1466         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1467             << "\n";
1468 
1469         if (deviceScopeType != DEVICESCOPE_NONE)
1470         {
1471             src << deviceScopeCommonHeader;
1472         }
1473 
1474         if (!m_declareFormatInShaderReads || !m_declareFormatInShaderWrites)
1475         {
1476             src << "#extension GL_EXT_shader_image_load_formatted : require\n";
1477         }
1478 
1479         if (m_imageLoadStoreLodAMD)
1480         {
1481             src << "#extension GL_AMD_shader_image_load_store_lod : require\n";
1482         }
1483 
1484         src << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
1485 
1486         if (m_bufferLoadUniform)
1487             src << "layout (binding = " << inputBinding << ") uniform " << uniformTypeStr << " u_image0;\n";
1488         else
1489             src << "layout (binding = " << inputBinding << maybeFmtQualStrReads << ") " << maybeRestrictStr
1490                 << "readonly uniform " << imageTypeStr << " u_image0;\n";
1491 
1492         // For three-component formats, the dst buffer is single-component and the shader expands the store into 3 component-wise stores.
1493         // We always use the format qualifier for the dst buffer, except when splitting it up.
1494         if (formatHasThreeComponents(m_format))
1495             src << "layout (binding = " << outputBinding << ") " << maybeRestrictStr << "writeonly uniform "
1496                 << imageTypeStr << " u_image1;\n";
1497         else
1498             src << "layout (binding = " << outputBinding << maybeFmtQualStrWrites << ") " << maybeRestrictStr
1499                 << "writeonly uniform " << imageTypeStr << " u_image1;\n";
1500 
1501         src << "\n"
1502             << "void main (void)\n"
1503             << "{\n";
1504 
1505         if (deviceScopeType == DEVICESCOPE_LOAD)
1506         {
1507             src << "    memoryBarrier(gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsAcquireRelease | "
1508                    "gl_SemanticsMakeVisible);\n";
1509         }
1510 
1511         switch (dimension)
1512         {
1513         default:
1514             DE_ASSERT(0); // fallthrough
1515         case 1:
1516             if (m_bufferLoadUniform)
1517             {
1518                 // Expand the store into 3 component-wise stores.
1519                 std::string type = getFormatPrefix(texFormat) + "vec4";
1520                 src << "    int pos = int(gl_GlobalInvocationID.x);\n"
1521                        "    "
1522                     << type << " t = texelFetch(u_image0, " + xMax + "-pos);\n";
1523                 if (formatHasThreeComponents(m_format))
1524                 {
1525                     src << "    imageStore(u_image1, 3*pos+0, " << type << "(t.x));\n";
1526                     src << "    imageStore(u_image1, 3*pos+1, " << type << "(t.y));\n";
1527                     src << "    imageStore(u_image1, 3*pos+2, " << type << "(t.z));\n";
1528                 }
1529                 else
1530                     src << "    imageStore(u_image1, pos, t);\n";
1531             }
1532             else if (m_imageLoadStoreLodAMD)
1533             {
1534                 src << "    int pos = int(gl_GlobalInvocationID.x);\n";
1535 
1536                 for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1537                 {
1538                     std::string xMaxSize = de::toString(deMax32(((m_texture.layerSize().x() >> levelNdx) - 1), 1u));
1539                     src << "    imageStoreLodAMD(u_image1, pos, " + de::toString(levelNdx) +
1540                                ", imageLoadLodAMD(u_image0, " + xMaxSize + "-pos, " + de::toString(levelNdx) + "));\n";
1541                 }
1542             }
1543             else
1544             {
1545                 src << "    int pos = int(gl_GlobalInvocationID.x);\n"
1546                        "    imageStore(u_image1, pos, imageLoad(u_image0, " +
1547                            xMaxSub + "pos));\n";
1548             }
1549             break;
1550         case 2:
1551             if (m_imageLoadStoreLodAMD)
1552             {
1553                 src << "    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n";
1554 
1555                 for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1556                 {
1557                     std::string xMaxSize = de::toString(deMax32(((m_texture.layerSize().x() >> levelNdx) - 1), 1u));
1558                     src << "    imageStoreLodAMD(u_image1, pos, " + de::toString(levelNdx) +
1559                                ", imageLoadLodAMD(u_image0, ivec2(" + xMaxSize + "-pos.x, pos.y), " +
1560                                de::toString(levelNdx) + "));\n";
1561                 }
1562             }
1563             else
1564             {
1565                 src << "    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
1566                        "    imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" +
1567                            xMaxSub + "pos.x, pos.y)));\n";
1568             }
1569             break;
1570         case 3:
1571             if (m_imageLoadStoreLodAMD)
1572             {
1573                 src << "    ivec3 pos = ivec3(gl_GlobalInvocationID);\n";
1574 
1575                 for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1576                 {
1577                     std::string xMaxSize = de::toString(deMax32(((m_texture.layerSize().x() >> levelNdx) - 1), 1u));
1578                     src << "    imageStoreLodAMD(u_image1, pos, " + de::toString(levelNdx) +
1579                                ", imageLoadLodAMD(u_image0, ivec3(" + xMaxSize + "-pos.x, pos.y, pos.z), " +
1580                                de::toString(levelNdx) + "));\n";
1581                 }
1582             }
1583             else
1584             {
1585                 src << "    ivec3 pos = ivec3(gl_GlobalInvocationID);\n"
1586                        "    imageStore(u_image1, pos, imageLoad(u_image0, ivec3(" +
1587                            xMaxSub + "pos.x, pos.y, pos.z)));\n";
1588             }
1589             break;
1590         }
1591 
1592         if (deviceScopeType == DEVICESCOPE_STORE)
1593         {
1594             src << "    memoryBarrier(gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsAcquireRelease | "
1595                    "gl_SemanticsMakeAvailable);\n";
1596         }
1597 
1598         src << "}\n";
1599 
1600         if (deviceScopeType == DEVICESCOPE_STORE)
1601             shaderName += "_store";
1602         else if (deviceScopeType == DEVICESCOPE_LOAD)
1603             shaderName += "_load";
1604 
1605         programCollection.glslSources.add(shaderName) << glu::ComputeSource(src.str());
1606     }
1607     else
1608     {
1609         std::ostringstream srcVert;
1610 
1611         srcVert << glu::getGLSLVersionDeclaration(glu::GLSLVersion::GLSL_VERSION_450) << "\n";
1612 
1613         srcVert << "vec4 positions[" << verticesCount << "] = vec4[](\n"
1614                 << "    vec4(-1.0f, -1.0f, 1.0f, 1.0f),\n"
1615                 << "    vec4( 1.0f, -1.0f, 1.0f, 1.0f),\n"
1616                 << "    vec4(-1.0f,  1.0f, 1.0f, 1.0f),\n"
1617                 << "    vec4(-1.0f,  1.0f, 1.0f, 1.0f),\n"
1618                 << "    vec4( 1.0f, -1.0f, 1.0f, 1.0f),\n"
1619                 << "    vec4( 1.0f,  1.0f, 1.0f, 1.0f)\n"
1620                 << ");\n"
1621                 << "\n"
1622                 << "void main() {\n"
1623                 << "    gl_Position = positions[gl_VertexIndex];\n"
1624                 << "}\n";
1625 
1626         programCollection.glslSources.add("vert") << glu::VertexSource(srcVert.str());
1627 
1628         std::ostringstream srcFrag;
1629 
1630         srcFrag << glu::getGLSLVersionDeclaration(glu::GLSLVersion::GLSL_VERSION_450) << "\n";
1631         srcFrag << deviceScopeCommonHeader;
1632 
1633         srcFrag << "layout (binding = " << inputBinding << maybeFmtQualStrReads << ") " << maybeRestrictStr
1634                 << "readonly uniform " << imageTypeStr << " u_image0;\n";
1635 
1636         const std::string signednessPrefix = isUintFormat(m_format) ? "u" : isIntFormat(m_format) ? "i" : "";
1637         const std::string colorType        = signednessPrefix + "vec4";
1638 
1639         srcFrag << "layout (location=0) out " << colorType << " outcolor;\n";
1640         srcFrag << "\n"
1641                 << "void main (void)\n"
1642                 << "{\n";
1643 
1644         if (deviceScopeType == DEVICESCOPE_LOAD)
1645         {
1646             srcFrag << "    memoryBarrier(gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsAcquireRelease | "
1647                        "gl_SemanticsMakeVisible);\n";
1648         }
1649 
1650         switch (dimension)
1651         {
1652         default:
1653             DE_ASSERT(0); // fallthrough
1654         case 1:
1655         {
1656             srcFrag << "    int pos = int(gl_FragCoord.x);\n"
1657                        "    outcolor = imageLoad(u_image0, pos);\n";
1658         }
1659         break;
1660         case 2:
1661         {
1662             srcFrag << "    ivec2 pos = ivec2(gl_FragCoord.xy);\n"
1663                        "    outcolor = imageLoad(u_image0, ivec2(pos.x, pos.y));\n";
1664         }
1665         break;
1666         case 3:
1667         {
1668             srcFrag << "    ivec3 pos = ivec3(gl_FragCoord.xyz);\n"
1669                        "    outcolor = imageLoad(u_image0, ivec3(pos.x, pos.y, pos.z));\n";
1670         }
1671         break;
1672         }
1673         srcFrag << "}\n";
1674 
1675         programCollection.glslSources.add("frag") << glu::FragmentSource(srcFrag.str());
1676     }
1677 }
1678 
initPrograms(SourceCollections & programCollection) const1679 void LoadStoreTest::initPrograms(SourceCollections &programCollection) const
1680 {
1681     makePrograms(programCollection);
1682 }
1683 
1684 //! Load/store test base implementation
1685 class LoadStoreTestInstance : public BaseTestInstance
1686 {
1687 public:
1688     LoadStoreTestInstance(Context &context, const Texture &texture, const VkFormat format, const VkFormat imageFormat,
1689                           const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign,
1690                           const bool bufferLoadUniform);
1691 
1692 protected:
1693     virtual BufferWithMemory *getResultBuffer(void) const = 0; //!< Get the buffer that contains the result image
1694 
1695     tcu::TestStatus verifyResult(void);
1696 
1697     // Add empty implementations for functions that might be not needed
commandBeforeCompute(const VkCommandBuffer)1698     void commandBeforeCompute(const VkCommandBuffer)
1699     {
1700     }
commandBetweenShaderInvocations(const VkCommandBuffer)1701     void commandBetweenShaderInvocations(const VkCommandBuffer)
1702     {
1703     }
commandAfterCompute(const VkCommandBuffer)1704     void commandAfterCompute(const VkCommandBuffer)
1705     {
1706     }
1707 
1708     de::MovePtr<BufferWithMemory> m_imageBuffer; //!< Source data and helper buffer
1709     const VkDeviceSize m_imageSizeBytes;
1710     const VkFormat m_imageFormat;       //!< Image format (for storage, may be different than texture format)
1711     tcu::TextureLevel m_referenceImage; //!< Used as input data and later to verify result image
1712 
1713     bool m_bufferLoadUniform;
1714     VkDescriptorType m_bufferLoadDescriptorType;
1715     VkBufferUsageFlagBits m_bufferLoadUsageBit;
1716 };
1717 
LoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)1718 LoadStoreTestInstance::LoadStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
1719                                              const VkFormat imageFormat, const bool declareImageFormatInShader,
1720                                              const bool singleLayerBind, const bool minalign,
1721                                              const bool bufferLoadUniform)
1722     : BaseTestInstance(context, texture, format, declareImageFormatInShader, singleLayerBind, minalign,
1723                        bufferLoadUniform)
1724     , m_imageSizeBytes(getImageSizeBytes(texture.size(), format))
1725     , m_imageFormat(imageFormat)
1726     , m_referenceImage(generateReferenceImage(texture.size(), imageFormat, format))
1727     , m_bufferLoadUniform(bufferLoadUniform)
1728 {
1729     const DeviceInterface &vk = m_context.getDeviceInterface();
1730     const VkDevice device     = m_context.getDevice();
1731     Allocator &allocator      = m_context.getDefaultAllocator();
1732 
1733     m_bufferLoadDescriptorType =
1734         m_bufferLoadUniform ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1735     m_bufferLoadUsageBit =
1736         m_bufferLoadUniform ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
1737 
1738     // A helper buffer with enough space to hold the whole image.
1739 
1740     m_imageBuffer = de::MovePtr<BufferWithMemory>(
1741         new BufferWithMemory(vk, device, allocator,
1742                              makeBufferCreateInfo(m_imageSizeBytes + m_srcViewOffset,
1743                                                   m_bufferLoadUsageBit | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
1744                                                       VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
1745                              MemoryRequirement::HostVisible));
1746 
1747     // Copy reference data to buffer for subsequent upload to image.
1748 
1749     const Allocation &alloc = m_imageBuffer->getAllocation();
1750     deMemcpy((char *)alloc.getHostPtr() + m_srcViewOffset, m_referenceImage.getAccess().getDataPtr(),
1751              static_cast<size_t>(m_imageSizeBytes));
1752     flushAlloc(vk, device, alloc);
1753 }
1754 
verifyResult(void)1755 tcu::TestStatus LoadStoreTestInstance::verifyResult(void)
1756 {
1757     const DeviceInterface &vk = m_context.getDeviceInterface();
1758     const VkDevice device     = m_context.getDevice();
1759 
1760     // Apply the same transformation as done in the shader
1761     const tcu::PixelBufferAccess reference = m_referenceImage.getAccess();
1762     flipHorizontally(reference);
1763 
1764     const Allocation &alloc = getResultBuffer()->getAllocation();
1765     invalidateAlloc(vk, device, alloc);
1766     const tcu::ConstPixelBufferAccess result(mapVkFormat(m_imageFormat), m_texture.size(),
1767                                              (const char *)alloc.getHostPtr() + m_dstViewOffset);
1768 
1769     if (comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_imageFormat, reference, result))
1770         return tcu::TestStatus::pass("Passed");
1771     else
1772         return tcu::TestStatus::fail("Image comparison failed");
1773 }
1774 
1775 //! Load/store test for images
1776 class ImageLoadStoreTestInstance : public LoadStoreTestInstance
1777 {
1778 public:
1779     ImageLoadStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
1780                                const VkFormat imageFormat, const VkImageTiling tiling,
1781                                const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign,
1782                                const bool bufferLoadUniform);
1783 
1784 protected:
1785     VkDescriptorSetLayout commonPrepareDescriptors(const VkShaderStageFlags stageFlags);
1786     VkDescriptorSetLayout prepareDescriptors(void);
1787     void commandBeforeCompute(const VkCommandBuffer cmdBuffer);
1788     void commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer);
1789     void commandAfterCompute(const VkCommandBuffer cmdBuffer);
1790 
1791     void commonBindDescriptors(const VkCommandBuffer cmdBuffer, const VkPipelineBindPoint pipelineBinding,
1792                                const VkPipelineLayout pipelineLayout, const int layerNdx);
1793     void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
1794                                         const int layerNdx);
1795 
getResultBuffer(void) const1796     BufferWithMemory *getResultBuffer(void) const
1797     {
1798         return m_imageBuffer.get();
1799     }
1800 
1801     de::MovePtr<Image> m_imageSrc;
1802     de::MovePtr<Image> m_imageDst;
1803     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1804     Move<VkDescriptorPool> m_descriptorPool;
1805     std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
1806     std::vector<SharedVkImageView> m_allSrcImageViews;
1807     std::vector<SharedVkImageView> m_allDstImageViews;
1808 };
1809 
ImageLoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const VkImageTiling tiling,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)1810 ImageLoadStoreTestInstance::ImageLoadStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
1811                                                        const VkFormat imageFormat, const VkImageTiling tiling,
1812                                                        const bool declareImageFormatInShader,
1813                                                        const bool singleLayerBind, const bool minalign,
1814                                                        const bool bufferLoadUniform)
1815     : LoadStoreTestInstance(context, texture, format, imageFormat, declareImageFormatInShader, singleLayerBind,
1816                             minalign, bufferLoadUniform)
1817     , m_allDescriptorSets(texture.numLayers())
1818     , m_allSrcImageViews(texture.numLayers())
1819     , m_allDstImageViews(texture.numLayers())
1820 {
1821     const DeviceInterface &vk = m_context.getDeviceInterface();
1822     const VkDevice device     = m_context.getDevice();
1823     Allocator &allocator      = m_context.getDefaultAllocator();
1824     const VkImageCreateFlags imageFlags =
1825         (m_format == m_imageFormat ? 0u : (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT);
1826 
1827     m_imageSrc =
1828         de::MovePtr<Image>(new Image(vk, device, allocator,
1829                                      makeImageCreateInfo(m_texture, m_imageFormat,
1830                                                          VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1831                                                              VK_IMAGE_USAGE_TRANSFER_DST_BIT,
1832                                                          imageFlags, tiling),
1833                                      MemoryRequirement::Any));
1834 
1835     m_imageDst =
1836         de::MovePtr<Image>(new Image(vk, device, allocator,
1837                                      makeImageCreateInfo(m_texture, m_imageFormat,
1838                                                          VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1839                                                              VK_IMAGE_USAGE_TRANSFER_DST_BIT,
1840                                                          imageFlags, tiling),
1841                                      MemoryRequirement::Any));
1842 }
1843 
commonPrepareDescriptors(const VkShaderStageFlags stageFlags)1844 VkDescriptorSetLayout ImageLoadStoreTestInstance::commonPrepareDescriptors(const VkShaderStageFlags stageFlags)
1845 {
1846     const VkDevice device     = m_context.getDevice();
1847     const DeviceInterface &vk = m_context.getDeviceInterface();
1848 
1849     const int numLayers   = m_texture.numLayers();
1850     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1851                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stageFlags)
1852                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stageFlags)
1853                                 .build(vk, device);
1854 
1855     m_descriptorPool = DescriptorPoolBuilder()
1856                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1857                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1858                            .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
1859 
1860     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1861 
1862     if (m_singleLayerBind)
1863     {
1864         for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1865         {
1866             const VkImageViewType viewType = mapImageViewType(getImageTypeForSingleLayer(m_texture.type()));
1867             const VkImageSubresourceRange subresourceRange =
1868                 makeImageSubresourceRange(aspectMask, 0u, 1u, layerNdx, 1u);
1869 
1870             m_allDescriptorSets[layerNdx] =
1871                 makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1872             m_allSrcImageViews[layerNdx] =
1873                 makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1874             m_allDstImageViews[layerNdx] =
1875                 makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1876         }
1877     }
1878     else // bind all layers at once
1879     {
1880         const VkImageViewType viewType                 = mapImageViewType(m_texture.type());
1881         const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(aspectMask, 0u, 1u, 0u, numLayers);
1882 
1883         m_allDescriptorSets[0] =
1884             makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1885         m_allSrcImageViews[0] =
1886             makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1887         m_allDstImageViews[0] =
1888             makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1889     }
1890 
1891     return *m_descriptorSetLayout; // not passing the ownership
1892 }
1893 
prepareDescriptors(void)1894 VkDescriptorSetLayout ImageLoadStoreTestInstance::prepareDescriptors(void)
1895 {
1896     return commonPrepareDescriptors(VK_SHADER_STAGE_COMPUTE_BIT);
1897 }
1898 
commonBindDescriptors(const VkCommandBuffer cmdBuffer,const VkPipelineBindPoint pipelineBinding,const VkPipelineLayout pipelineLayout,const int layerNdx)1899 void ImageLoadStoreTestInstance::commonBindDescriptors(const VkCommandBuffer cmdBuffer,
1900                                                        const VkPipelineBindPoint pipelineBinding,
1901                                                        const VkPipelineLayout pipelineLayout, const int layerNdx)
1902 {
1903     const VkDevice device     = m_context.getDevice();
1904     const DeviceInterface &vk = m_context.getDeviceInterface();
1905 
1906     const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
1907     const VkImageView srcImageView      = **m_allSrcImageViews[layerNdx];
1908     const VkImageView dstImageView      = **m_allDstImageViews[layerNdx];
1909 
1910     const VkDescriptorImageInfo descriptorSrcImageInfo =
1911         makeDescriptorImageInfo(VK_NULL_HANDLE, srcImageView, VK_IMAGE_LAYOUT_GENERAL);
1912     const VkDescriptorImageInfo descriptorDstImageInfo =
1913         makeDescriptorImageInfo(VK_NULL_HANDLE, dstImageView, VK_IMAGE_LAYOUT_GENERAL);
1914 
1915     DescriptorSetUpdateBuilder()
1916         .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
1917                      &descriptorSrcImageInfo)
1918         .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
1919                      &descriptorDstImageInfo)
1920         .update(vk, device);
1921     vk.cmdBindDescriptorSets(cmdBuffer, pipelineBinding, pipelineLayout, 0u, 1u, &descriptorSet, 0u, nullptr);
1922 }
1923 
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1924 void ImageLoadStoreTestInstance::commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,
1925                                                                 const VkPipelineLayout pipelineLayout,
1926                                                                 const int layerNdx)
1927 {
1928     commonBindDescriptors(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, layerNdx);
1929 }
1930 
commandBeforeCompute(const VkCommandBuffer cmdBuffer)1931 void ImageLoadStoreTestInstance::commandBeforeCompute(const VkCommandBuffer cmdBuffer)
1932 {
1933     const DeviceInterface &vk            = m_context.getDeviceInterface();
1934     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1935 
1936     const VkImageSubresourceRange fullImageSubresourceRange =
1937         makeImageSubresourceRange(aspectMask, 0u, 1u, 0u, m_texture.numLayers());
1938     {
1939         const VkImageMemoryBarrier preCopyImageBarriers[] = {
1940             makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1941                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_imageSrc->get(), fullImageSubresourceRange),
1942             makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1943                                    m_imageDst->get(), fullImageSubresourceRange)};
1944 
1945         const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy =
1946             makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_imageBuffer->get(), 0ull,
1947                                     m_imageSizeBytes + m_srcViewOffset);
1948 
1949         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT,
1950                               VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
1951                               (VkDependencyFlags)0, 0, nullptr, 1, &barrierFlushHostWriteBeforeCopy,
1952                               DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
1953     }
1954     {
1955         const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
1956             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1957             VK_IMAGE_LAYOUT_GENERAL, m_imageSrc->get(), fullImageSubresourceRange);
1958 
1959         const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_texture, aspectMask);
1960 
1961         vk.cmdCopyBufferToImage(cmdBuffer, m_imageBuffer->get(), m_imageSrc->get(),
1962                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copyRegion);
1963         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
1964                               (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &barrierAfterCopy);
1965     }
1966 }
1967 
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)1968 void ImageLoadStoreTestInstance::commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)
1969 {
1970     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1971     commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture, aspectMask);
1972 }
1973 
commandAfterCompute(const VkCommandBuffer cmdBuffer)1974 void ImageLoadStoreTestInstance::commandAfterCompute(const VkCommandBuffer cmdBuffer)
1975 {
1976     const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
1977     commandCopyImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_imageBuffer->get(), m_imageSizeBytes, m_texture,
1978                              aspectMask);
1979 }
1980 
1981 //! Load/store Lod AMD test for images
1982 class ImageLoadStoreLodAMDTestInstance : public BaseTestInstance
1983 {
1984 public:
1985     ImageLoadStoreLodAMDTestInstance(Context &context, const Texture &texture, const VkFormat format,
1986                                      const VkFormat imageFormat, const bool declareImageFormatInShader,
1987                                      const bool singleLayerBind, const bool minalign, const bool bufferLoadUniform);
1988 
1989 protected:
1990     VkDescriptorSetLayout prepareDescriptors(void);
1991     void commandBeforeCompute(const VkCommandBuffer cmdBuffer);
1992     void commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer);
1993     void commandAfterCompute(const VkCommandBuffer cmdBuffer);
1994 
1995     void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
1996                                         const int layerNdx);
1997 
getResultBuffer(void) const1998     BufferWithMemory *getResultBuffer(void) const
1999     {
2000         return m_imageBuffer.get();
2001     }
2002     tcu::TestStatus verifyResult(void);
2003 
2004     de::MovePtr<BufferWithMemory> m_imageBuffer; //!< Source data and helper buffer
2005     const VkDeviceSize m_imageSizeBytes;
2006     const VkFormat m_imageFormat; //!< Image format (for storage, may be different than texture format)
2007     std::vector<tcu::TextureLevel> m_referenceImages; //!< Used as input data and later to verify result image
2008 
2009     bool m_bufferLoadUniform;
2010     VkDescriptorType m_bufferLoadDescriptorType;
2011     VkBufferUsageFlagBits m_bufferLoadUsageBit;
2012 
2013     de::MovePtr<Image> m_imageSrc;
2014     de::MovePtr<Image> m_imageDst;
2015     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
2016     Move<VkDescriptorPool> m_descriptorPool;
2017     std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
2018     std::vector<SharedVkImageView> m_allSrcImageViews;
2019     std::vector<SharedVkImageView> m_allDstImageViews;
2020 };
2021 
ImageLoadStoreLodAMDTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)2022 ImageLoadStoreLodAMDTestInstance::ImageLoadStoreLodAMDTestInstance(Context &context, const Texture &texture,
2023                                                                    const VkFormat format, const VkFormat imageFormat,
2024                                                                    const bool declareImageFormatInShader,
2025                                                                    const bool singleLayerBind, const bool minalign,
2026                                                                    const bool bufferLoadUniform)
2027     : BaseTestInstance(context, texture, format, declareImageFormatInShader, singleLayerBind, minalign,
2028                        bufferLoadUniform)
2029     , m_imageSizeBytes(getMipmapImageTotalSizeBytes(texture, format))
2030     , m_imageFormat(imageFormat)
2031     , m_bufferLoadUniform(bufferLoadUniform)
2032     , m_allDescriptorSets(texture.numLayers())
2033     , m_allSrcImageViews(texture.numLayers())
2034     , m_allDstImageViews(texture.numLayers())
2035 {
2036     const DeviceInterface &vk = m_context.getDeviceInterface();
2037     const VkDevice device     = m_context.getDevice();
2038     Allocator &allocator      = m_context.getDefaultAllocator();
2039     const VkImageCreateFlags imageFlags =
2040         (m_format == m_imageFormat ? 0u : (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT);
2041 
2042     const VkSampleCountFlagBits samples = static_cast<VkSampleCountFlagBits>(
2043         m_texture.numSamples()); // integer and bit mask are aligned, so we can cast like this
2044 
2045     for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
2046     {
2047         tcu::TextureLevel referenceImage = generateReferenceImage(texture.size(levelNdx), imageFormat, format);
2048         m_referenceImages.push_back(referenceImage);
2049     }
2050 
2051     m_bufferLoadDescriptorType =
2052         m_bufferLoadUniform ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2053     m_bufferLoadUsageBit =
2054         m_bufferLoadUniform ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
2055 
2056     // A helper buffer with enough space to hold the whole image.
2057     m_imageBuffer = de::MovePtr<BufferWithMemory>(
2058         new BufferWithMemory(vk, device, allocator,
2059                              makeBufferCreateInfo(m_imageSizeBytes + m_srcViewOffset,
2060                                                   m_bufferLoadUsageBit | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
2061                                                       VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
2062                              MemoryRequirement::HostVisible));
2063 
2064     // Copy reference data to buffer for subsequent upload to image.
2065     {
2066         const Allocation &alloc   = m_imageBuffer->getAllocation();
2067         VkDeviceSize bufferOffset = 0u;
2068         for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
2069         {
2070             deMemcpy((char *)alloc.getHostPtr() + m_srcViewOffset + bufferOffset,
2071                      m_referenceImages[levelNdx].getAccess().getDataPtr(),
2072                      static_cast<size_t>(getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx)));
2073             bufferOffset += getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx);
2074         }
2075         flushAlloc(vk, device, alloc);
2076     }
2077 
2078     {
2079         const VkImageCreateInfo imageParamsSrc = {
2080             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
2081             nullptr,                             // const void* pNext;
2082             (isCube(m_texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u) |
2083                 imageFlags,                                               // VkImageCreateFlags flags;
2084             mapImageType(m_texture.type()),                               // VkImageType imageType;
2085             m_imageFormat,                                                // VkFormat format;
2086             makeExtent3D(m_texture.layerSize()),                          // VkExtent3D extent;
2087             (uint32_t)m_texture.numMipmapLevels(),                        // uint32_t mipLevels;
2088             (uint32_t)m_texture.numLayers(),                              // uint32_t arrayLayers;
2089             samples,                                                      // VkSampleCountFlagBits samples;
2090             VK_IMAGE_TILING_OPTIMAL,                                      // VkImageTiling tiling;
2091             VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
2092             VK_SHARING_MODE_EXCLUSIVE,                                    // VkSharingMode sharingMode;
2093             0u,                                                           // uint32_t queueFamilyIndexCount;
2094             nullptr,                                                      // const uint32_t* pQueueFamilyIndices;
2095             VK_IMAGE_LAYOUT_UNDEFINED,                                    // VkImageLayout initialLayout;
2096         };
2097 
2098         m_imageSrc = de::MovePtr<Image>(new Image(vk, device, allocator, imageParamsSrc, MemoryRequirement::Any));
2099     }
2100 
2101     {
2102         const VkImageCreateInfo imageParamsDst = {
2103             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
2104             nullptr,                             // const void* pNext;
2105             (isCube(m_texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u) |
2106                 imageFlags,                                               // VkImageCreateFlags flags;
2107             mapImageType(m_texture.type()),                               // VkImageType imageType;
2108             m_imageFormat,                                                // VkFormat format;
2109             makeExtent3D(m_texture.layerSize()),                          // VkExtent3D extent;
2110             (uint32_t)m_texture.numMipmapLevels(),                        // uint32_t mipLevels;
2111             (uint32_t)m_texture.numLayers(),                              // uint32_t arrayLayers;
2112             samples,                                                      // VkSampleCountFlagBits samples;
2113             VK_IMAGE_TILING_OPTIMAL,                                      // VkImageTiling tiling;
2114             VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
2115             VK_SHARING_MODE_EXCLUSIVE,                                    // VkSharingMode sharingMode;
2116             0u,                                                           // uint32_t queueFamilyIndexCount;
2117             nullptr,                                                      // const uint32_t* pQueueFamilyIndices;
2118             VK_IMAGE_LAYOUT_UNDEFINED,                                    // VkImageLayout initialLayout;
2119         };
2120 
2121         m_imageDst = de::MovePtr<Image>(new Image(vk, device, allocator, imageParamsDst, MemoryRequirement::Any));
2122     }
2123 }
2124 
verifyResult(void)2125 tcu::TestStatus ImageLoadStoreLodAMDTestInstance::verifyResult(void)
2126 {
2127     const DeviceInterface &vk = m_context.getDeviceInterface();
2128     const VkDevice device     = m_context.getDevice();
2129 
2130     const Allocation &alloc = getResultBuffer()->getAllocation();
2131     invalidateAlloc(vk, device, alloc);
2132 
2133     VkDeviceSize bufferOffset = 0;
2134     for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
2135     {
2136         // Apply the same transformation as done in the shader
2137         const tcu::PixelBufferAccess reference = m_referenceImages[levelNdx].getAccess();
2138         flipHorizontally(reference);
2139 
2140         const tcu::ConstPixelBufferAccess result(mapVkFormat(m_imageFormat), m_texture.size(levelNdx),
2141                                                  (const char *)alloc.getHostPtr() + m_dstViewOffset + bufferOffset);
2142 
2143         if (!comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_imageFormat, reference, result,
2144                                  levelNdx))
2145         {
2146             std::ostringstream errorMessage;
2147             errorMessage << "Image Level " << levelNdx << " comparison failed";
2148             return tcu::TestStatus::fail(errorMessage.str());
2149         }
2150         bufferOffset += getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx);
2151     }
2152 
2153     return tcu::TestStatus::pass("Passed");
2154 }
2155 
prepareDescriptors(void)2156 VkDescriptorSetLayout ImageLoadStoreLodAMDTestInstance::prepareDescriptors(void)
2157 {
2158     const VkDevice device     = m_context.getDevice();
2159     const DeviceInterface &vk = m_context.getDeviceInterface();
2160 
2161     const int numLayers   = m_texture.numLayers();
2162     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
2163                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
2164                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
2165                                 .build(vk, device);
2166 
2167     m_descriptorPool = DescriptorPoolBuilder()
2168                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
2169                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
2170                            .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
2171 
2172     if (m_singleLayerBind)
2173     {
2174         for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
2175         {
2176             const VkImageViewType viewType = mapImageViewType(getImageTypeForSingleLayer(m_texture.type()));
2177             const VkImageSubresourceRange subresourceRange =
2178                 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, m_texture.numMipmapLevels(), layerNdx, 1u);
2179 
2180             m_allDescriptorSets[layerNdx] =
2181                 makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
2182             m_allSrcImageViews[layerNdx] =
2183                 makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
2184             m_allDstImageViews[layerNdx] =
2185                 makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
2186         }
2187     }
2188     else // bind all layers at once
2189     {
2190         const VkImageViewType viewType = mapImageViewType(m_texture.type());
2191         const VkImageSubresourceRange subresourceRange =
2192             makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, m_texture.numMipmapLevels(), 0u, numLayers);
2193 
2194         m_allDescriptorSets[0] =
2195             makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
2196         m_allSrcImageViews[0] =
2197             makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
2198         m_allDstImageViews[0] =
2199             makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
2200     }
2201 
2202     return *m_descriptorSetLayout; // not passing the ownership
2203 }
2204 
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)2205 void ImageLoadStoreLodAMDTestInstance::commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,
2206                                                                       const VkPipelineLayout pipelineLayout,
2207                                                                       const int layerNdx)
2208 {
2209     const VkDevice device     = m_context.getDevice();
2210     const DeviceInterface &vk = m_context.getDeviceInterface();
2211 
2212     const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
2213     const VkImageView srcImageView      = **m_allSrcImageViews[layerNdx];
2214     const VkImageView dstImageView      = **m_allDstImageViews[layerNdx];
2215 
2216     const VkDescriptorImageInfo descriptorSrcImageInfo =
2217         makeDescriptorImageInfo(VK_NULL_HANDLE, srcImageView, VK_IMAGE_LAYOUT_GENERAL);
2218     const VkDescriptorImageInfo descriptorDstImageInfo =
2219         makeDescriptorImageInfo(VK_NULL_HANDLE, dstImageView, VK_IMAGE_LAYOUT_GENERAL);
2220 
2221     DescriptorSetUpdateBuilder()
2222         .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
2223                      &descriptorSrcImageInfo)
2224         .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
2225                      &descriptorDstImageInfo)
2226         .update(vk, device);
2227     vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u,
2228                              nullptr);
2229 }
2230 
commandBeforeCompute(const VkCommandBuffer cmdBuffer)2231 void ImageLoadStoreLodAMDTestInstance::commandBeforeCompute(const VkCommandBuffer cmdBuffer)
2232 {
2233     const DeviceInterface &vk                               = m_context.getDeviceInterface();
2234     const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(
2235         VK_IMAGE_ASPECT_COLOR_BIT, 0u, m_texture.numMipmapLevels(), 0u, m_texture.numLayers());
2236     {
2237         const VkImageMemoryBarrier preCopyImageBarriers[] = {
2238             makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
2239                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_imageSrc->get(), fullImageSubresourceRange),
2240             makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
2241                                    m_imageDst->get(), fullImageSubresourceRange)};
2242 
2243         const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy =
2244             makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_imageBuffer->get(), 0ull,
2245                                     m_imageSizeBytes + m_srcViewOffset);
2246 
2247         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT,
2248                               VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
2249                               (VkDependencyFlags)0, 0, nullptr, 1, &barrierFlushHostWriteBeforeCopy,
2250                               DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
2251     }
2252     {
2253         const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
2254             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2255             VK_IMAGE_LAYOUT_GENERAL, m_imageSrc->get(), fullImageSubresourceRange);
2256 
2257         std::vector<VkBufferImageCopy> copyRegions;
2258         VkDeviceSize bufferOffset = 0u;
2259         for (int32_t levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
2260         {
2261             const VkBufferImageCopy copyParams = {
2262                 bufferOffset, // VkDeviceSize bufferOffset;
2263                 0u,           // uint32_t bufferRowLength;
2264                 0u,           // uint32_t bufferImageHeight;
2265                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, levelNdx, 0u,
2266                                            m_texture.numLayers()), // VkImageSubresourceLayers imageSubresource;
2267                 makeOffset3D(0, 0, 0),                             // VkOffset3D imageOffset;
2268                 makeExtent3D(m_texture.layerSize(levelNdx)),       // VkExtent3D imageExtent;
2269             };
2270             copyRegions.push_back(copyParams);
2271             bufferOffset += getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx);
2272         }
2273 
2274         vk.cmdCopyBufferToImage(cmdBuffer, m_imageBuffer->get(), m_imageSrc->get(),
2275                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)copyRegions.size(), copyRegions.data());
2276         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
2277                               (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &barrierAfterCopy);
2278     }
2279 }
2280 
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)2281 void ImageLoadStoreLodAMDTestInstance::commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)
2282 {
2283     commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture);
2284 }
2285 
commandAfterCompute(const VkCommandBuffer cmdBuffer)2286 void ImageLoadStoreLodAMDTestInstance::commandAfterCompute(const VkCommandBuffer cmdBuffer)
2287 {
2288     commandCopyMipmapImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_imageFormat, m_imageBuffer->get(),
2289                                    m_imageSizeBytes, m_texture);
2290 }
2291 
2292 //! Load/store test for buffers
2293 class BufferLoadStoreTestInstance : public LoadStoreTestInstance
2294 {
2295 public:
2296     BufferLoadStoreTestInstance(Context &context, const Texture &texture, const VkFormat format,
2297                                 const VkFormat imageFormat, const bool declareImageFormatInShader, const bool minalign,
2298                                 const bool bufferLoadUniform);
2299 
2300 protected:
2301     VkDescriptorSetLayout prepareDescriptors(void);
2302     void commandAfterCompute(const VkCommandBuffer cmdBuffer);
2303 
2304     void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
2305                                         const int layerNdx);
2306 
getResultBuffer(void) const2307     BufferWithMemory *getResultBuffer(void) const
2308     {
2309         return m_imageBufferDst.get();
2310     }
2311 
2312     de::MovePtr<BufferWithMemory> m_imageBufferDst;
2313     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
2314     Move<VkDescriptorPool> m_descriptorPool;
2315     Move<VkDescriptorSet> m_descriptorSet;
2316     Move<VkBufferView> m_bufferViewSrc;
2317     Move<VkBufferView> m_bufferViewDst;
2318 };
2319 
BufferLoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool declareImageFormatInShader,const bool minalign,const bool bufferLoadUniform)2320 BufferLoadStoreTestInstance::BufferLoadStoreTestInstance(Context &context, const Texture &texture,
2321                                                          const VkFormat format, const VkFormat imageFormat,
2322                                                          const bool declareImageFormatInShader, const bool minalign,
2323                                                          const bool bufferLoadUniform)
2324     : LoadStoreTestInstance(context, texture, format, imageFormat, declareImageFormatInShader, false, minalign,
2325                             bufferLoadUniform)
2326 {
2327     const DeviceInterface &vk = m_context.getDeviceInterface();
2328     const VkDevice device     = m_context.getDevice();
2329     Allocator &allocator      = m_context.getDefaultAllocator();
2330 
2331     // Create a destination buffer.
2332 
2333     m_imageBufferDst = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
2334         vk, device, allocator,
2335         makeBufferCreateInfo(m_imageSizeBytes + m_dstViewOffset, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
2336         MemoryRequirement::HostVisible));
2337 }
2338 
prepareDescriptors(void)2339 VkDescriptorSetLayout BufferLoadStoreTestInstance::prepareDescriptors(void)
2340 {
2341     const DeviceInterface &vk = m_context.getDeviceInterface();
2342     const VkDevice device     = m_context.getDevice();
2343 
2344     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
2345                                 .addSingleBinding(m_bufferLoadDescriptorType, VK_SHADER_STAGE_COMPUTE_BIT)
2346                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
2347                                 .build(vk, device);
2348 
2349     m_descriptorPool = DescriptorPoolBuilder()
2350                            .addType(m_bufferLoadDescriptorType)
2351                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
2352                            .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
2353 
2354     VkFormat dstFormat = formatHasThreeComponents(m_format) ? getSingleComponentFormat(m_format) : m_format;
2355 
2356     m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
2357     m_bufferViewSrc = makeBufferView(vk, device, m_imageBuffer->get(), m_format, m_srcViewOffset, m_imageSizeBytes);
2358     m_bufferViewDst = makeBufferView(vk, device, m_imageBufferDst->get(), dstFormat, m_dstViewOffset, m_imageSizeBytes);
2359 
2360     return *m_descriptorSetLayout; // not passing the ownership
2361 }
2362 
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)2363 void BufferLoadStoreTestInstance::commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,
2364                                                                  const VkPipelineLayout pipelineLayout,
2365                                                                  const int layerNdx)
2366 {
2367     DE_ASSERT(layerNdx == 0);
2368     DE_UNREF(layerNdx);
2369 
2370     const VkDevice device     = m_context.getDevice();
2371     const DeviceInterface &vk = m_context.getDeviceInterface();
2372 
2373     DescriptorSetUpdateBuilder()
2374         .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), m_bufferLoadDescriptorType,
2375                      &m_bufferViewSrc.get())
2376         .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
2377                      VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferViewDst.get())
2378         .update(vk, device);
2379     vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &m_descriptorSet.get(),
2380                              0u, nullptr);
2381 }
2382 
commandAfterCompute(const VkCommandBuffer cmdBuffer)2383 void BufferLoadStoreTestInstance::commandAfterCompute(const VkCommandBuffer cmdBuffer)
2384 {
2385     commandBufferWriteBarrierBeforeHostRead(m_context, cmdBuffer, m_imageBufferDst->get(),
2386                                             m_imageSizeBytes + m_dstViewOffset);
2387 }
2388 
createInstance(Context & context) const2389 TestInstance *StoreTest::createInstance(Context &context) const
2390 {
2391     if (m_texture.type() == IMAGE_TYPE_BUFFER)
2392         return new BufferStoreTestInstance(context, m_texture, m_format, m_declareImageFormatInShader, m_minalign,
2393                                            m_storeConstantValue);
2394     else
2395         return new ImageStoreTestInstance(context, m_texture, m_format, m_tiling, m_declareImageFormatInShader,
2396                                           m_singleLayerBind, m_minalign, m_storeConstantValue);
2397 }
2398 
createInstance(Context & context) const2399 TestInstance *LoadStoreTest::createInstance(Context &context) const
2400 {
2401     if (m_imageLoadStoreLodAMD)
2402         return new ImageLoadStoreLodAMDTestInstance(context, m_texture, m_format, m_imageFormat,
2403                                                     m_declareFormatInShaderReads, m_singleLayerBind, m_minalign,
2404                                                     m_bufferLoadUniform);
2405 
2406     if (m_texture.type() == IMAGE_TYPE_BUFFER)
2407         return new BufferLoadStoreTestInstance(context, m_texture, m_format, m_imageFormat,
2408                                                m_declareFormatInShaderReads, m_minalign, m_bufferLoadUniform);
2409     else
2410         return new ImageLoadStoreTestInstance(context, m_texture, m_format, m_imageFormat, m_tiling,
2411                                               m_declareFormatInShaderReads, m_singleLayerBind, m_minalign,
2412                                               m_bufferLoadUniform);
2413 }
2414 
2415 class ImageExtendOperandTestInstance : public BaseTestInstance
2416 {
2417 public:
2418     ImageExtendOperandTestInstance(Context &context, const Texture &texture, const VkFormat readFormat,
2419                                    const VkFormat writeFormat, bool relaxedPrecision);
2420 
~ImageExtendOperandTestInstance(void)2421     virtual ~ImageExtendOperandTestInstance(void)
2422     {
2423     }
2424 
2425 protected:
2426     VkDescriptorSetLayout prepareDescriptors(void);
2427     void commandBeforeCompute(const VkCommandBuffer cmdBuffer);
2428     void commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer);
2429     void commandAfterCompute(const VkCommandBuffer cmdBuffer);
2430 
2431     void commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout,
2432                                         const int layerNdx);
2433 
2434     tcu::TestStatus verifyResult(void);
2435 
2436 protected:
2437     bool m_isSigned;
2438     tcu::TextureLevel m_inputImageData;
2439 
2440     de::MovePtr<Image> m_imageSrc; // source image
2441     SharedVkImageView m_imageSrcView;
2442     VkDeviceSize m_imageSrcSize;
2443 
2444     de::MovePtr<Image> m_imageDst; // dest image
2445     SharedVkImageView m_imageDstView;
2446     VkFormat m_imageDstFormat;
2447     VkDeviceSize m_imageDstSize;
2448 
2449     de::MovePtr<BufferWithMemory> m_buffer; // result buffer
2450 
2451     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
2452     Move<VkDescriptorPool> m_descriptorPool;
2453     SharedVkDescriptorSet m_descriptorSet;
2454 
2455     bool m_relaxedPrecision;
2456 };
2457 
ImageExtendOperandTestInstance(Context & context,const Texture & texture,const VkFormat readFormat,const VkFormat writeFormat,bool relaxedPrecision)2458 ImageExtendOperandTestInstance::ImageExtendOperandTestInstance(Context &context, const Texture &texture,
2459                                                                const VkFormat readFormat, const VkFormat writeFormat,
2460                                                                bool relaxedPrecision)
2461     : BaseTestInstance(context, texture, readFormat, true, true, false, false)
2462     , m_imageDstFormat(writeFormat)
2463     , m_relaxedPrecision(relaxedPrecision)
2464 {
2465     const DeviceInterface &vk              = m_context.getDeviceInterface();
2466     const VkDevice device                  = m_context.getDevice();
2467     Allocator &allocator                   = m_context.getDefaultAllocator();
2468     const int32_t width                    = texture.size().x();
2469     const int32_t height                   = texture.size().y();
2470     const tcu::TextureFormat textureFormat = mapVkFormat(m_format);
2471 
2472     // Generate reference image
2473     m_isSigned = (getTextureChannelClass(textureFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
2474     m_inputImageData.setStorage(textureFormat, width, height, 1);
2475 
2476     const tcu::PixelBufferAccess access = m_inputImageData.getAccess();
2477     const int valueStart                = (m_isSigned ? (-width / 2) : 0);
2478 
2479     for (int x = 0; x < width; ++x)
2480         for (int y = 0; y < height; ++y)
2481         {
2482             const tcu::IVec4 color(valueStart + x, valueStart + y, valueStart, valueStart);
2483             access.setPixel(color, x, y);
2484         }
2485 
2486     // Create source image
2487     m_imageSrc = de::MovePtr<Image>(new Image(
2488         vk, device, allocator,
2489         makeImageCreateInfo(m_texture, m_format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0u),
2490         MemoryRequirement::Any));
2491 
2492     // Create destination image
2493     m_imageDst = de::MovePtr<Image>(
2494         new Image(vk, device, allocator,
2495                   makeImageCreateInfo(m_texture, m_imageDstFormat,
2496                                       VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u),
2497                   MemoryRequirement::Any));
2498 
2499     // Compute image and buffer sizes
2500     m_imageSrcSize               = width * height * tcu::getPixelSize(textureFormat);
2501     m_imageDstSize               = width * height * tcu::getPixelSize(mapVkFormat(m_imageDstFormat));
2502     VkDeviceSize bufferSizeBytes = de::max(m_imageSrcSize, m_imageDstSize);
2503 
2504     // Create helper buffer able to store input data and image write result
2505     m_buffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
2506         vk, device, allocator,
2507         makeBufferCreateInfo(bufferSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
2508                                                   VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
2509         MemoryRequirement::HostVisible));
2510 
2511     const Allocation &alloc = m_buffer->getAllocation();
2512     deMemcpy(alloc.getHostPtr(), m_inputImageData.getAccess().getDataPtr(), static_cast<size_t>(m_imageSrcSize));
2513     flushAlloc(vk, device, alloc);
2514 }
2515 
prepareDescriptors(void)2516 VkDescriptorSetLayout ImageExtendOperandTestInstance::prepareDescriptors(void)
2517 {
2518     const DeviceInterface &vk = m_context.getDeviceInterface();
2519     const VkDevice device     = m_context.getDevice();
2520 
2521     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
2522                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
2523                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
2524                                 .build(vk, device);
2525 
2526     m_descriptorPool = DescriptorPoolBuilder()
2527                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1)
2528                            .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1)
2529                            .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
2530 
2531     const VkImageViewType viewType = mapImageViewType(m_texture.type());
2532     const VkImageSubresourceRange subresourceRange =
2533         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2534 
2535     m_descriptorSet = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
2536     m_imageSrcView =
2537         makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
2538     m_imageDstView =
2539         makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_imageDstFormat, subresourceRange));
2540 
2541     return *m_descriptorSetLayout; // not passing the ownership
2542 }
2543 
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)2544 void ImageExtendOperandTestInstance::commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,
2545                                                                     const VkPipelineLayout pipelineLayout,
2546                                                                     const int layerNdx)
2547 {
2548     DE_UNREF(layerNdx);
2549 
2550     const DeviceInterface &vk           = m_context.getDeviceInterface();
2551     const VkDevice device               = m_context.getDevice();
2552     const VkDescriptorSet descriptorSet = **m_descriptorSet;
2553 
2554     const VkDescriptorImageInfo descriptorSrcImageInfo =
2555         makeDescriptorImageInfo(VK_NULL_HANDLE, **m_imageSrcView, VK_IMAGE_LAYOUT_GENERAL);
2556     const VkDescriptorImageInfo descriptorDstImageInfo =
2557         makeDescriptorImageInfo(VK_NULL_HANDLE, **m_imageDstView, VK_IMAGE_LAYOUT_GENERAL);
2558 
2559     typedef DescriptorSetUpdateBuilder::Location DSUBL;
2560     DescriptorSetUpdateBuilder()
2561         .writeSingle(descriptorSet, DSUBL::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorSrcImageInfo)
2562         .writeSingle(descriptorSet, DSUBL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorDstImageInfo)
2563         .update(vk, device);
2564     vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u,
2565                              nullptr);
2566 }
2567 
commandBeforeCompute(const VkCommandBuffer cmdBuffer)2568 void ImageExtendOperandTestInstance::commandBeforeCompute(const VkCommandBuffer cmdBuffer)
2569 {
2570     const DeviceInterface &vk = m_context.getDeviceInterface();
2571 
2572     const VkImageSubresourceRange fullImageSubresourceRange =
2573         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
2574     {
2575         const VkImageMemoryBarrier preCopyImageBarriers[] = {
2576             makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
2577                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_imageSrc->get(), fullImageSubresourceRange),
2578             makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
2579                                    m_imageDst->get(), fullImageSubresourceRange)};
2580 
2581         const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy = makeBufferMemoryBarrier(
2582             VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_buffer->get(), 0ull, m_imageSrcSize);
2583 
2584         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT,
2585                               VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
2586                               (VkDependencyFlags)0, 0, nullptr, 1, &barrierFlushHostWriteBeforeCopy,
2587                               DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
2588     }
2589     {
2590         const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
2591             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2592             VK_IMAGE_LAYOUT_GENERAL, m_imageSrc->get(), fullImageSubresourceRange);
2593 
2594         const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_texture);
2595 
2596         vk.cmdCopyBufferToImage(cmdBuffer, m_buffer->get(), m_imageSrc->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
2597                                 &copyRegion);
2598         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
2599                               (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &barrierAfterCopy);
2600     }
2601 }
2602 
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)2603 void ImageExtendOperandTestInstance::commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)
2604 {
2605     commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture);
2606 }
2607 
commandAfterCompute(const VkCommandBuffer cmdBuffer)2608 void ImageExtendOperandTestInstance::commandAfterCompute(const VkCommandBuffer cmdBuffer)
2609 {
2610     commandCopyImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_buffer->get(), m_imageDstSize, m_texture);
2611 }
2612 
2613 // Clears the high bits of every pixel in the pixel buffer, leaving only the lowest 16 bits of each component.
clearHighBits(const tcu::PixelBufferAccess & pixels,int width,int height)2614 void clearHighBits(const tcu::PixelBufferAccess &pixels, int width, int height)
2615 {
2616     for (int y = 0; y < height; ++y)
2617         for (int x = 0; x < width; ++x)
2618         {
2619             auto color = pixels.getPixelUint(x, y);
2620             for (int c = 0; c < decltype(color)::SIZE; ++c)
2621                 color[c] &= 0xFFFFull;
2622             pixels.setPixel(color, x, y);
2623         }
2624 }
2625 
verifyResult(void)2626 tcu::TestStatus ImageExtendOperandTestInstance::verifyResult(void)
2627 {
2628     const DeviceInterface &vk                = m_context.getDeviceInterface();
2629     const VkDevice device                    = m_context.getDevice();
2630     const tcu::IVec3 imageSize               = m_texture.size();
2631     const tcu::PixelBufferAccess inputAccess = m_inputImageData.getAccess();
2632     const int32_t width                      = inputAccess.getWidth();
2633     const int32_t height                     = inputAccess.getHeight();
2634     tcu::TextureLevel refImage(mapVkFormat(m_imageDstFormat), width, height);
2635     tcu::PixelBufferAccess refAccess = refImage.getAccess();
2636 
2637     for (int x = 0; x < width; ++x)
2638         for (int y = 0; y < height; ++y)
2639         {
2640             tcu::IVec4 color = inputAccess.getPixelInt(x, y);
2641             refAccess.setPixel(color, x, y);
2642         }
2643 
2644     const Allocation &alloc = m_buffer->getAllocation();
2645     invalidateAlloc(vk, device, alloc);
2646     const tcu::PixelBufferAccess result(mapVkFormat(m_imageDstFormat), imageSize, alloc.getHostPtr());
2647 
2648     if (m_relaxedPrecision)
2649     {
2650         // Preserve the lowest 16 bits of the reference and result pixels only.
2651         clearHighBits(refAccess, width, height);
2652         clearHighBits(result, width, height);
2653     }
2654 
2655     if (tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Comparison", "Comparison", refAccess, result,
2656                                  tcu::UVec4(0), tcu::COMPARE_LOG_RESULT, true /*use64Bits*/))
2657         return tcu::TestStatus::pass("Passed");
2658     else
2659         return tcu::TestStatus::fail("Image comparison failed");
2660 }
2661 
2662 enum class ExtendTestType
2663 {
2664     READ = 0,
2665     WRITE,
2666     WRITE_NONTEMPORAL,
2667 };
2668 
2669 enum class ExtendOperand
2670 {
2671     SIGN_EXTEND = 0,
2672     ZERO_EXTEND = 1
2673 };
2674 
2675 class ImageExtendOperandTest : public TestCase
2676 {
2677 public:
2678     ImageExtendOperandTest(tcu::TestContext &testCtx, const std::string &name, const Texture texture,
2679                            const VkFormat readFormat, const VkFormat writeFormat, const bool signedInt,
2680                            const bool relaxedPrecision, ExtendTestType extendTestType);
2681 
2682     void checkSupport(Context &context) const;
2683     void initPrograms(SourceCollections &programCollection) const;
2684     TestInstance *createInstance(Context &context) const;
2685 
2686 private:
isWriteTest() const2687     bool isWriteTest() const
2688     {
2689         return (m_extendTestType == ExtendTestType::WRITE) || (m_extendTestType == ExtendTestType::WRITE_NONTEMPORAL);
2690     }
2691 
2692     const Texture m_texture;
2693     VkFormat m_readFormat;
2694     VkFormat m_writeFormat;
2695     bool m_operandForce; // Use an operand that doesn't match SampledType?
2696     bool m_relaxedPrecision;
2697     ExtendTestType m_extendTestType;
2698 };
2699 
ImageExtendOperandTest(tcu::TestContext & testCtx,const std::string & name,const Texture texture,const VkFormat readFormat,const VkFormat writeFormat,const bool operandForce,const bool relaxedPrecision,ExtendTestType extendTestType)2700 ImageExtendOperandTest::ImageExtendOperandTest(tcu::TestContext &testCtx, const std::string &name,
2701                                                const Texture texture, const VkFormat readFormat,
2702                                                const VkFormat writeFormat, const bool operandForce,
2703                                                const bool relaxedPrecision, ExtendTestType extendTestType)
2704     : TestCase(testCtx, name)
2705     , m_texture(texture)
2706     , m_readFormat(readFormat)
2707     , m_writeFormat(writeFormat)
2708     , m_operandForce(operandForce)
2709     , m_relaxedPrecision(relaxedPrecision)
2710     , m_extendTestType(extendTestType)
2711 {
2712 }
2713 
checkFormatProperties(const Context & context,VkFormat format)2714 void checkFormatProperties(const Context &context, VkFormat format)
2715 {
2716 #ifndef CTS_USES_VULKANSC
2717     const VkFormatProperties3 formatProperties(context.getFormatProperties(format));
2718 
2719     if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
2720         TCU_THROW(NotSupportedError, "Format not supported for storage images");
2721 #else
2722     const VkFormatProperties formatProperties(
2723         getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), format));
2724 
2725     if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
2726         TCU_THROW(NotSupportedError, "Format not supported for storage images");
2727 #endif // CTS_USES_VULKANSC
2728 }
2729 
check64BitSupportIfNeeded(Context & context,VkFormat readFormat,VkFormat writeFormat)2730 void check64BitSupportIfNeeded(Context &context, VkFormat readFormat, VkFormat writeFormat)
2731 {
2732     if (is64BitIntegerFormat(readFormat) || is64BitIntegerFormat(writeFormat))
2733     {
2734         const auto &features = context.getDeviceFeatures();
2735         if (!features.shaderInt64)
2736             TCU_THROW(NotSupportedError, "64-bit integers not supported in shaders");
2737     }
2738 }
2739 
checkSupport(Context & context) const2740 void ImageExtendOperandTest::checkSupport(Context &context) const
2741 {
2742     if (!context.requireDeviceFunctionality("VK_KHR_spirv_1_4"))
2743         TCU_THROW(NotSupportedError, "VK_KHR_spirv_1_4 not supported");
2744 
2745 #ifndef CTS_USES_VULKANSC
2746     DE_ASSERT(m_readFormat != VK_FORMAT_A8_UNORM_KHR && m_writeFormat != VK_FORMAT_A8_UNORM_KHR);
2747     DE_ASSERT(m_readFormat != VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR &&
2748               m_writeFormat != VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR);
2749 
2750     if ((m_extendTestType == ExtendTestType::WRITE_NONTEMPORAL) && (context.getUsedApiVersion() < VK_API_VERSION_1_3))
2751         TCU_THROW(NotSupportedError, "Vulkan 1.3 or higher is required for this test to run");
2752 #endif // CTS_USES_VULKANSC
2753 
2754     check64BitSupportIfNeeded(context, m_readFormat, m_writeFormat);
2755 
2756     checkFormatProperties(context, m_readFormat);
2757     checkFormatProperties(context, m_writeFormat);
2758 }
2759 
initPrograms(SourceCollections & programCollection) const2760 void ImageExtendOperandTest::initPrograms(SourceCollections &programCollection) const
2761 {
2762     tcu::StringTemplate shaderTemplate(
2763         "OpCapability Shader\n"
2764         "OpCapability StorageImageExtendedFormats\n"
2765 
2766         "${capability}"
2767         "${extension}"
2768 
2769         "%std450 = OpExtInstImport \"GLSL.std.450\"\n"
2770         "OpMemoryModel Logical GLSL450\n"
2771         "OpEntryPoint GLCompute %main \"main\" %id %src_image_ptr %dst_image_ptr\n"
2772         "OpExecutionMode %main LocalSize 1 1 1\n"
2773 
2774         // decorations
2775         "OpDecorate %id BuiltIn GlobalInvocationId\n"
2776 
2777         "OpDecorate %src_image_ptr DescriptorSet 0\n"
2778         "OpDecorate %src_image_ptr Binding 0\n"
2779         "OpDecorate %src_image_ptr NonWritable\n"
2780 
2781         "${relaxed_precision}"
2782 
2783         "OpDecorate %dst_image_ptr DescriptorSet 0\n"
2784         "OpDecorate %dst_image_ptr Binding 1\n"
2785         "OpDecorate %dst_image_ptr NonReadable\n"
2786 
2787         // types
2788         "%type_void                          = OpTypeVoid\n"
2789         "%type_i32                           = OpTypeInt 32 1\n"
2790         "%type_u32                           = OpTypeInt 32 0\n"
2791         "%type_vec2_i32                      = OpTypeVector %type_i32 2\n"
2792         "%type_vec2_u32                      = OpTypeVector %type_u32 2\n"
2793         "%type_vec3_i32                      = OpTypeVector %type_i32 3\n"
2794         "%type_vec3_u32                      = OpTypeVector %type_u32 3\n"
2795         "%type_vec4_i32                      = OpTypeVector %type_i32 4\n"
2796         "%type_vec4_u32                      = OpTypeVector %type_u32 4\n"
2797         "${extra_types}"
2798 
2799         "%type_fun_void                      = OpTypeFunction %type_void\n"
2800 
2801         "${image_types}"
2802 
2803         "%type_ptr_in_vec3_u32               = OpTypePointer Input %type_vec3_u32\n"
2804         "%type_ptr_in_u32                    = OpTypePointer Input %type_u32\n"
2805 
2806         "${image_uniforms}"
2807 
2808         // variables
2809         "%id                                 = OpVariable %type_ptr_in_vec3_u32 Input\n"
2810 
2811         "${image_variables}"
2812 
2813         // main function
2814         "%main                               = OpFunction %type_void None %type_fun_void\n"
2815         "%label                              = OpLabel\n"
2816 
2817         "${image_load}"
2818 
2819         "%idvec                              = OpLoad %type_vec3_u32 %id\n"
2820         "%id_xy                              = OpVectorShuffle %type_vec2_u32 %idvec %idvec 0 1\n"
2821         "%coord                              = OpBitcast %type_vec2_i32 %id_xy\n"
2822         "%value                              = OpImageRead ${sampled_type_vec4} %src_image %coord "
2823         "${read_extend_operand}\n"
2824         "                                      OpImageWrite %dst_image %coord %value ${write_extend_operand}\n"
2825         "                                      OpReturn\n"
2826         "                                      OpFunctionEnd\n");
2827 
2828     const auto testedFormat = mapVkFormat(isWriteTest() ? m_writeFormat : m_readFormat);
2829     const bool isSigned     = (getTextureChannelClass(testedFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
2830 
2831     const auto isRead64  = is64BitIntegerFormat(m_readFormat);
2832     const auto isWrite64 = is64BitIntegerFormat(m_writeFormat);
2833     DE_ASSERT(isRead64 == isWrite64);
2834 
2835     const bool using64Bits = (isRead64 || isWrite64);
2836 
2837     // Additional capabilities when needed.
2838     std::string capability;
2839     std::string extension;
2840     std::string extraTypes;
2841 
2842     if (using64Bits)
2843     {
2844         extension += "OpExtension \"SPV_EXT_shader_image_int64\"\n";
2845         capability += "OpCapability Int64\n"
2846                       "OpCapability Int64ImageEXT\n";
2847         extraTypes += "%type_i64                           = OpTypeInt 64 1\n"
2848                       "%type_u64                           = OpTypeInt 64 0\n"
2849                       "%type_vec3_i64                      = OpTypeVector %type_i64 3\n"
2850                       "%type_vec3_u64                      = OpTypeVector %type_u64 3\n"
2851                       "%type_vec4_i64                      = OpTypeVector %type_i64 4\n"
2852                       "%type_vec4_u64                      = OpTypeVector %type_u64 4\n";
2853     }
2854 
2855     std::string relaxed = "";
2856     if (m_relaxedPrecision)
2857         relaxed += "OpDecorate %src_image_ptr RelaxedPrecision\n";
2858 
2859     // Sampled type depends on the format sign and mismatch force flag.
2860     const bool signedSampleType          = ((isSigned && !m_operandForce) || (!isSigned && m_operandForce));
2861     const std::string bits               = (using64Bits ? "64" : "32");
2862     const std::string sampledTypePostfix = (signedSampleType ? "i" : "u") + bits;
2863     const std::string extendOperandStr   = (isSigned ? "SignExtend" : "ZeroExtend");
2864 
2865     std::map<std::string, std::string> specializations{
2866         {"image_type_id", "%type_image"},
2867         {"image_uni_ptr_type_id", "%type_ptr_uniform_const_image"},
2868         {"image_var_id", "%src_image_ptr"},
2869         {"image_id", "%src_image"},
2870         {"capability", capability},
2871         {"extension", extension},
2872         {"extra_types", extraTypes},
2873         {"relaxed_precision", relaxed},
2874         {"image_format", getSpirvFormat(m_readFormat)},
2875         {"sampled_type", (std::string("%type_") + sampledTypePostfix)},
2876         {"sampled_type_vec4", (std::string("%type_vec4_") + sampledTypePostfix)},
2877         {"read_extend_operand", (!isWriteTest() ? extendOperandStr : "")},
2878         {"write_extend_operand", (isWriteTest() ? extendOperandStr : "")},
2879     };
2880 
2881     SpirvVersion spirvVersion = SPIRV_VERSION_1_4;
2882     bool allowSpirv14         = true;
2883     if (m_extendTestType == ExtendTestType::WRITE_NONTEMPORAL)
2884     {
2885         spirvVersion                            = SPIRV_VERSION_1_6;
2886         allowSpirv14                            = false;
2887         specializations["write_extend_operand"] = "Nontemporal";
2888     }
2889 
2890     // Addidtional parametrization is needed for a case when source and destination textures have same format
2891     tcu::StringTemplate imageTypeTemplate(
2892         "${image_type_id}                     = OpTypeImage ${sampled_type} 2D 0 0 0 2 ${image_format}\n");
2893     tcu::StringTemplate imageUniformTypeTemplate(
2894         "${image_uni_ptr_type_id}   = OpTypePointer UniformConstant ${image_type_id}\n");
2895     tcu::StringTemplate imageVariablesTemplate(
2896         "${image_var_id}                      = OpVariable ${image_uni_ptr_type_id} UniformConstant\n");
2897     tcu::StringTemplate imageLoadTemplate(
2898         "${image_id}                          = OpLoad ${image_type_id} ${image_var_id}\n");
2899 
2900     std::string imageTypes;
2901     std::string imageUniformTypes;
2902     std::string imageVariables;
2903     std::string imageLoad;
2904 
2905     // If input image format is the same as output there is less spir-v definitions
2906     if (m_readFormat == m_writeFormat)
2907     {
2908         imageTypes        = imageTypeTemplate.specialize(specializations);
2909         imageUniformTypes = imageUniformTypeTemplate.specialize(specializations);
2910         imageVariables    = imageVariablesTemplate.specialize(specializations);
2911         imageLoad         = imageLoadTemplate.specialize(specializations);
2912 
2913         specializations["image_var_id"] = "%dst_image_ptr";
2914         specializations["image_id"]     = "%dst_image";
2915         imageVariables += imageVariablesTemplate.specialize(specializations);
2916         imageLoad += imageLoadTemplate.specialize(specializations);
2917     }
2918     else
2919     {
2920         specializations["image_type_id"]         = "%type_src_image";
2921         specializations["image_uni_ptr_type_id"] = "%type_ptr_uniform_const_src_image";
2922         imageTypes                               = imageTypeTemplate.specialize(specializations);
2923         imageUniformTypes                        = imageUniformTypeTemplate.specialize(specializations);
2924         imageVariables                           = imageVariablesTemplate.specialize(specializations);
2925         imageLoad                                = imageLoadTemplate.specialize(specializations);
2926 
2927         specializations["image_format"]          = getSpirvFormat(m_writeFormat);
2928         specializations["image_type_id"]         = "%type_dst_image";
2929         specializations["image_uni_ptr_type_id"] = "%type_ptr_uniform_const_dst_image";
2930         specializations["image_var_id"]          = "%dst_image_ptr";
2931         specializations["image_id"]              = "%dst_image";
2932         imageTypes += imageTypeTemplate.specialize(specializations);
2933         imageUniformTypes += imageUniformTypeTemplate.specialize(specializations);
2934         imageVariables += imageVariablesTemplate.specialize(specializations);
2935         imageLoad += imageLoadTemplate.specialize(specializations);
2936     }
2937 
2938     specializations["image_types"]     = imageTypes;
2939     specializations["image_uniforms"]  = imageUniformTypes;
2940     specializations["image_variables"] = imageVariables;
2941     specializations["image_load"]      = imageLoad;
2942 
2943     // Specialize whole shader and add it to program collection
2944     programCollection.spirvAsmSources.add("comp")
2945         << shaderTemplate.specialize(specializations)
2946         << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, spirvVersion, allowSpirv14);
2947 }
2948 
createInstance(Context & context) const2949 TestInstance *ImageExtendOperandTest::createInstance(Context &context) const
2950 {
2951     return new ImageExtendOperandTestInstance(context, m_texture, m_readFormat, m_writeFormat, m_relaxedPrecision);
2952 }
2953 
2954 static const Texture s_textures[] = {
2955     Texture(IMAGE_TYPE_1D, tcu::IVec3(64, 1, 1), 1),
2956     Texture(IMAGE_TYPE_1D_ARRAY, tcu::IVec3(64, 1, 1), 8),
2957     Texture(IMAGE_TYPE_2D, tcu::IVec3(64, 64, 1), 1),
2958     Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(64, 64, 1), 8),
2959     Texture(IMAGE_TYPE_3D, tcu::IVec3(64, 64, 8), 1),
2960     Texture(IMAGE_TYPE_CUBE, tcu::IVec3(64, 64, 1), 6),
2961     Texture(IMAGE_TYPE_CUBE_ARRAY, tcu::IVec3(64, 64, 1), 2 * 6),
2962     Texture(IMAGE_TYPE_BUFFER, tcu::IVec3(64, 1, 1), 1),
2963 };
2964 
getTestTexture(const ImageType imageType)2965 const Texture &getTestTexture(const ImageType imageType)
2966 {
2967     for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
2968         if (s_textures[textureNdx].type() == imageType)
2969             return s_textures[textureNdx];
2970 
2971     DE_FATAL("Internal error");
2972     return s_textures[0];
2973 }
2974 
2975 static const VkFormat s_formats[] = {VK_FORMAT_R32G32B32A32_SFLOAT,
2976                                      VK_FORMAT_R16G16B16A16_SFLOAT,
2977                                      VK_FORMAT_R32_SFLOAT,
2978 
2979                                      VK_FORMAT_R32G32B32A32_UINT,
2980                                      VK_FORMAT_R16G16B16A16_UINT,
2981                                      VK_FORMAT_R8G8B8A8_UINT,
2982                                      VK_FORMAT_R32_UINT,
2983 
2984                                      VK_FORMAT_R32G32B32A32_SINT,
2985                                      VK_FORMAT_R16G16B16A16_SINT,
2986                                      VK_FORMAT_R8G8B8A8_SINT,
2987                                      VK_FORMAT_R32_SINT,
2988 
2989                                      VK_FORMAT_R8G8B8A8_UNORM,
2990 
2991                                      VK_FORMAT_B8G8R8A8_UNORM,
2992                                      VK_FORMAT_B8G8R8A8_UINT,
2993 
2994                                      VK_FORMAT_R8G8B8A8_SNORM,
2995 
2996                                      VK_FORMAT_B10G11R11_UFLOAT_PACK32,
2997 
2998                                      VK_FORMAT_R32G32_SFLOAT,
2999                                      VK_FORMAT_R16G16_SFLOAT,
3000                                      VK_FORMAT_R16_SFLOAT,
3001 
3002                                      VK_FORMAT_A2B10G10R10_UINT_PACK32,
3003                                      VK_FORMAT_R32G32_UINT,
3004                                      VK_FORMAT_R16G16_UINT,
3005                                      VK_FORMAT_R16_UINT,
3006                                      VK_FORMAT_R8G8_UINT,
3007                                      VK_FORMAT_R8_UINT,
3008 
3009                                      VK_FORMAT_R32G32_SINT,
3010                                      VK_FORMAT_R16G16_SINT,
3011                                      VK_FORMAT_R16_SINT,
3012                                      VK_FORMAT_R8G8_SINT,
3013                                      VK_FORMAT_R8_SINT,
3014 
3015                                      VK_FORMAT_A2B10G10R10_UNORM_PACK32,
3016                                      VK_FORMAT_R16G16B16A16_UNORM,
3017                                      VK_FORMAT_R16G16B16A16_SNORM,
3018                                      VK_FORMAT_R16G16_UNORM,
3019                                      VK_FORMAT_R16_UNORM,
3020                                      VK_FORMAT_R8G8_UNORM,
3021                                      VK_FORMAT_R8_UNORM,
3022 #ifndef CTS_USES_VULKANSC
3023                                      VK_FORMAT_A8_UNORM_KHR,
3024 #endif // CTS_USES_VULKANSC
3025 
3026                                      VK_FORMAT_R16G16_SNORM,
3027                                      VK_FORMAT_R16_SNORM,
3028                                      VK_FORMAT_R8G8_SNORM,
3029                                      VK_FORMAT_R8_SNORM,
3030 
3031                                      VK_FORMAT_R10X6_UNORM_PACK16,
3032                                      VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
3033                                      VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
3034 
3035                                      VK_FORMAT_R4G4_UNORM_PACK8,
3036                                      VK_FORMAT_R4G4B4A4_UNORM_PACK16,
3037                                      VK_FORMAT_B4G4R4A4_UNORM_PACK16,
3038                                      VK_FORMAT_R5G6B5_UNORM_PACK16,
3039                                      VK_FORMAT_B5G6R5_UNORM_PACK16,
3040                                      VK_FORMAT_R5G5B5A1_UNORM_PACK16,
3041                                      VK_FORMAT_B5G5R5A1_UNORM_PACK16,
3042                                      VK_FORMAT_A1R5G5B5_UNORM_PACK16,
3043 #ifndef CTS_USES_VULKANSC
3044                                      VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR,
3045 #endif // CTS_USES_VULKANSC
3046 
3047                                      VK_FORMAT_B8G8R8A8_SNORM,
3048                                      VK_FORMAT_B8G8R8A8_SINT,
3049                                      VK_FORMAT_A8B8G8R8_UNORM_PACK32,
3050                                      VK_FORMAT_A8B8G8R8_SNORM_PACK32,
3051                                      VK_FORMAT_A8B8G8R8_UINT_PACK32,
3052                                      VK_FORMAT_A8B8G8R8_SINT_PACK32,
3053                                      VK_FORMAT_A2R10G10B10_UNORM_PACK32,
3054                                      VK_FORMAT_A2R10G10B10_SNORM_PACK32,
3055                                      VK_FORMAT_A2R10G10B10_UINT_PACK32,
3056                                      VK_FORMAT_A2R10G10B10_SINT_PACK32,
3057                                      VK_FORMAT_A2B10G10R10_SNORM_PACK32,
3058                                      VK_FORMAT_A2B10G10R10_SINT_PACK32,
3059                                      VK_FORMAT_R32G32B32_UINT,
3060                                      VK_FORMAT_R32G32B32_SINT,
3061                                      VK_FORMAT_R32G32B32_SFLOAT,
3062                                      VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
3063 
3064                                      VK_FORMAT_R8G8_SRGB,
3065                                      VK_FORMAT_R8G8B8_SRGB,
3066                                      VK_FORMAT_B8G8R8_SRGB,
3067                                      VK_FORMAT_R8G8B8A8_SRGB,
3068                                      VK_FORMAT_B8G8R8A8_SRGB,
3069                                      VK_FORMAT_A8B8G8R8_SRGB_PACK32};
3070 
3071 static const VkFormat s_formatsThreeComponent[] = {
3072     VK_FORMAT_R8G8B8_UINT,      VK_FORMAT_R8G8B8_SINT,    VK_FORMAT_R8G8B8_UNORM,    VK_FORMAT_R8G8B8_SNORM,
3073     VK_FORMAT_R16G16B16_UINT,   VK_FORMAT_R16G16B16_SINT, VK_FORMAT_R16G16B16_UNORM, VK_FORMAT_R16G16B16_SNORM,
3074     VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R32G32B32_UINT, VK_FORMAT_R32G32B32_SINT,  VK_FORMAT_R32G32B32_SFLOAT,
3075 };
3076 
3077 static const VkFormat d_formats[] = {VK_FORMAT_D16_UNORM, VK_FORMAT_D32_SFLOAT};
3078 
3079 static const VkImageTiling s_tilings[] = {
3080     VK_IMAGE_TILING_OPTIMAL,
3081     VK_IMAGE_TILING_LINEAR,
3082 };
3083 
tilingSuffix(VkImageTiling tiling)3084 const char *tilingSuffix(VkImageTiling tiling)
3085 {
3086     switch (tiling)
3087     {
3088     case VK_IMAGE_TILING_OPTIMAL:
3089         return "";
3090     case VK_IMAGE_TILING_LINEAR:
3091         return "_linear";
3092     default:
3093         return "unknown";
3094     }
3095 }
3096 
isAllowedDepthFormat(const Texture & texture,VkFormat format,const VkImageTiling tiling)3097 bool isAllowedDepthFormat(const Texture &texture, VkFormat format, const VkImageTiling tiling)
3098 {
3099     if (isDepthStencilFormat(format) && (tiling == VK_IMAGE_TILING_OPTIMAL) &&
3100         ((texture.type() == IMAGE_TYPE_2D) || (texture.type() == IMAGE_TYPE_2D_ARRAY)))
3101     {
3102         return true;
3103     }
3104     return false;
3105 }
3106 
3107 // m_testType == TC_COMP_COMP
3108 // First compute shader executes that will flip the input image, image0, horizontally in output image, image1.
3109 // First compute shader makes image1 available in the shader domain with device scope barrier.
3110 // Pipeline barrier executes that adds execution dependency: second shader will only execute after the first has completed.
3111 // Then second compute shader executes making image1 visible in the shader domain and copies image1 back to image0 without any change.
3112 // image0 is compared to the reference output that should be flipped horizontally.
3113 //
3114 // m_testType == TC_COMP_DRAW
3115 // First compute shader executes that will flip the input image, image0, horizontally in output image, image1.
3116 // First compute shader makes image1 available in the shader domain with device scope barrier.
3117 // Pipeline barrier executes that adds execution dependency: second shader will only execute after first has completed.
3118 // Then vertex shader executes and it does not change the image.
3119 // Fragment compute shader executes making image1 visible in the shader domain and copies image1 to a color attachment without any change.
3120 // color attachment is compared to the reference output that should be flipped horizontally.
3121 class ImageDeviceScopeAccessTest : public LoadStoreTest
3122 {
3123 public:
3124     ImageDeviceScopeAccessTest(tcu::TestContext &testCtx, const TestConfigurationType testType, const std::string &name,
3125                                const Texture &texture, const VkFormat format, const VkImageTiling tiling);
3126     void checkSupport(Context &context) const;
3127     void initPrograms(SourceCollections &sourceCollections) const;
3128     TestInstance *createInstance(Context &context) const;
3129 
3130 private:
3131     const TestConfigurationType m_testType;
3132     const uint32_t m_verticesCount;
3133 };
3134 
3135 class ImageDeviceScopeAccessTestInstance : public ImageLoadStoreTestInstance
3136 {
3137 public:
3138     ImageDeviceScopeAccessTestInstance(Context &context, const TestConfigurationType testType, const Texture &texture,
3139                                        const VkFormat format, const VkImageTiling tiling, const uint32_t verticesCount);
3140 
3141     tcu::TestStatus iterate(void);
3142 
3143 private:
3144     const TestConfigurationType m_testType;
3145     const VkImageTiling m_tiling;
3146     const uint32_t m_verticesCount;
3147 };
3148 
ImageDeviceScopeAccessTest(tcu::TestContext & testCtx,const TestConfigurationType testType,const std::string & name,const Texture & texture,const VkFormat format,const VkImageTiling tiling)3149 ImageDeviceScopeAccessTest::ImageDeviceScopeAccessTest(tcu::TestContext &testCtx, const TestConfigurationType testType,
3150                                                        const std::string &name, const Texture &texture,
3151                                                        const VkFormat format, const VkImageTiling tiling)
3152     : LoadStoreTest(testCtx, name, texture, format, format, tiling)
3153     , m_testType(testType)
3154     , m_verticesCount(6u)
3155 {
3156     DE_ASSERT(texture.numLayers() == 1u);
3157     DE_ASSERT(m_singleLayerBind == false);
3158     DE_ASSERT(m_restrictImages == false);
3159     DE_ASSERT(m_minalign == false);
3160     DE_ASSERT(m_bufferLoadUniform == false);
3161     DE_ASSERT(m_imageLoadStoreLodAMD == false);
3162 }
3163 
initPrograms(SourceCollections & sourceCollections) const3164 void ImageDeviceScopeAccessTest::initPrograms(SourceCollections &sourceCollections) const
3165 {
3166     makePrograms(sourceCollections, DEVICESCOPE_STORE);
3167     makePrograms(sourceCollections, DEVICESCOPE_LOAD, (m_testType == TC_COMP_DRAW), m_verticesCount);
3168 }
3169 
checkSupport(Context & context) const3170 void ImageDeviceScopeAccessTest::checkSupport(Context &context) const
3171 {
3172     if (!context.contextSupports(vk::ApiVersion(0, 1, 1, 0)))
3173         TCU_THROW(NotSupportedError, "Vulkan 1.1 not supported");
3174 
3175     VkPhysicalDeviceVulkanMemoryModelFeatures vkMemModelFeatures = context.getVulkanMemoryModelFeatures();
3176     if (!vkMemModelFeatures.vulkanMemoryModel)
3177         TCU_THROW(NotSupportedError, "vulkanMemoryModel not supported");
3178 
3179     if (!vkMemModelFeatures.vulkanMemoryModelDeviceScope)
3180         TCU_THROW(NotSupportedError, "vulkanMemoryModelDeviceScope not supported");
3181 
3182     if (context.getUsedApiVersion() < SPIRV_VERSION_1_5)
3183         TCU_THROW(NotSupportedError,
3184                   std::string("Vulkan higher than or equal to spirv 1.5 is required for this test to run").c_str());
3185 
3186     if ((m_testType == TC_COMP_DRAW) && context.getTestContext().getCommandLine().isComputeOnly())
3187         THROW_NOT_SUPPORTED_COMPUTE_ONLY();
3188 
3189     LoadStoreTest::checkSupport(context);
3190 
3191     if (m_testType == TC_COMP_DRAW)
3192     {
3193         const auto &vki           = context.getInstanceInterface();
3194         const auto physicalDevice = context.getPhysicalDevice();
3195 
3196         VkImageFormatProperties vkImageFormatProperties;
3197         const auto result = vki.getPhysicalDeviceImageFormatProperties(
3198             physicalDevice, m_format, mapImageType(m_texture.type()), m_tiling,
3199             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, &vkImageFormatProperties);
3200 
3201         if (result != VK_SUCCESS)
3202         {
3203             if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
3204                 TCU_THROW(NotSupportedError, "Format unsupported for tiling");
3205             else
3206                 TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned unexpected error");
3207         }
3208     }
3209 }
3210 
createInstance(Context & context) const3211 TestInstance *ImageDeviceScopeAccessTest::createInstance(Context &context) const
3212 {
3213     return new ImageDeviceScopeAccessTestInstance(context, m_testType, m_texture, m_format, m_tiling, m_verticesCount);
3214 }
3215 
ImageDeviceScopeAccessTestInstance(Context & context,const TestConfigurationType testType,const Texture & texture,const VkFormat format,const VkImageTiling tiling,const uint32_t verticesCount)3216 ImageDeviceScopeAccessTestInstance::ImageDeviceScopeAccessTestInstance(Context &context,
3217                                                                        const TestConfigurationType testType,
3218                                                                        const Texture &texture, const VkFormat format,
3219                                                                        const VkImageTiling tiling,
3220                                                                        const uint32_t verticesCount)
3221     : ImageLoadStoreTestInstance(context, texture, format, format, tiling, true, false, false, false)
3222     , m_testType(testType)
3223     , m_tiling(tiling)
3224     , m_verticesCount(verticesCount)
3225 {
3226 }
3227 
iterate(void)3228 tcu::TestStatus ImageDeviceScopeAccessTestInstance::iterate(void)
3229 {
3230     const DeviceInterface &vk       = m_context.getDeviceInterface();
3231     const VkDevice device           = m_context.getDevice();
3232     const VkQueue queue             = m_context.getUniversalQueue();
3233     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
3234     Allocator &allocator            = m_context.getDefaultAllocator();
3235     const tcu::IVec3 workSize       = m_texture.size();
3236 
3237     Move<VkShaderModule> shaderModuleLoad;
3238     Move<VkPipeline> pipelineLoad;
3239 
3240     // Variables for draw call
3241     Move<VkShaderModule> shaderModuleVert;
3242     Move<VkRenderPass> renderPass;
3243     de::MovePtr<Image> colorAttachmentImage;
3244     Move<VkImageView> colorAttachment;
3245     Move<VkFramebuffer> framebuffer;
3246 
3247     const Unique<VkShaderModule> shaderModuleStore(
3248         createShaderModule(vk, device, m_context.getBinaryCollection().get("comp_store")));
3249 
3250     VkShaderStageFlags descriptorStageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
3251     if (m_testType == TC_COMP_DRAW)
3252         descriptorStageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT;
3253     const VkDescriptorSetLayout descriptorSetLayout = commonPrepareDescriptors(descriptorStageFlags);
3254     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
3255     const Unique<VkPipeline> pipelineStore(makeComputePipeline(vk, device, *pipelineLayout, *shaderModuleStore));
3256 
3257     const Unique<VkCommandPool> cmdPool(
3258         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex));
3259     const Unique<VkCommandBuffer> cmdBuffer(
3260         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3261 
3262     beginCommandBuffer(vk, *cmdBuffer);
3263 
3264     // First compute shader that loads reference image and copies to another image
3265     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineStore);
3266 
3267     commandBeforeCompute(*cmdBuffer);
3268 
3269     commandBindDescriptorsForLayer(*cmdBuffer, *pipelineLayout, 0u);
3270 
3271     vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
3272 
3273     // Barrier between shaders/pipelines
3274     const VkImageSubresourceRange subresourceRange =
3275         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
3276     const VkImageMemoryBarrier imageBarrierBetweenShaders =
3277         makeImageMemoryBarrier(VK_ACCESS_2_NONE, VK_ACCESS_2_NONE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
3278                                m_imageSrc->get(), subresourceRange);
3279     const VkPipelineStageFlags dstStageMask =
3280         (m_testType == TC_COMP_DRAW) ? (VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
3281                                        VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3282     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dstStageMask, (VkDependencyFlags)0, 0,
3283                           nullptr, 0, nullptr, 1, &imageBarrierBetweenShaders);
3284 
3285     // Switch to the second shader program
3286 
3287     if (m_testType == TC_COMP_DRAW)
3288     {
3289         shaderModuleVert = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"));
3290         shaderModuleLoad = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"));
3291 
3292         renderPass = makeRenderPass(vk, device, m_format);
3293 
3294         const uint32_t colorAttachmentCount = 1u;
3295 
3296         colorAttachmentImage = de::MovePtr<Image>(new Image(
3297             vk, device, allocator,
3298             makeImageCreateInfo(m_texture, m_format,
3299                                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u, m_tiling),
3300             MemoryRequirement::Any));
3301 
3302         colorAttachment =
3303             makeImageView(vk, device, colorAttachmentImage->get(), mapImageViewType(m_texture.type()), m_format,
3304                           makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers()));
3305 
3306         const VkExtent2D extent = makeExtent2D(m_texture.size().x(), m_texture.size().y());
3307 
3308         const VkFramebufferCreateInfo fbCreateInfo = {
3309             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType                sType
3310             nullptr,                                   // const void*                    pNext
3311             (VkFramebufferCreateFlags)0,               // VkFramebufferCreateFlags flags;
3312             *renderPass,                               // VkRenderPass                    renderPass
3313             colorAttachmentCount,                      // uint32_t                        attachmentCount
3314             &*colorAttachment,                         // const VkImageView*            pAttachments
3315             extent.width,                              // uint32_t                        width
3316             extent.height,                             // uint32_t                        height
3317             1u                                         // uint32_t                        layers
3318         };
3319         framebuffer = createFramebuffer(vk, device, &fbCreateInfo);
3320 
3321         const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
3322             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType
3323             nullptr,                                  // const void*                                 pNext
3324             (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags       flags
3325             0u,      // uint32_t                                    vertexBindingDescriptionCount
3326             nullptr, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
3327             0u,      // uint32_t                                    vertexAttributeDescriptionCount
3328             nullptr  // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
3329         };
3330 
3331         const VkViewport viewport = makeViewport(extent.width, extent.height);
3332         const VkRect2D scissor    = makeRect2D(extent.width, extent.height);
3333 
3334         const VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
3335             VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType                             sType
3336             nullptr,                                               // const void*                                 pNext
3337             (VkPipelineViewportStateCreateFlags)0,                 // VkPipelineViewportStateCreateFlags          flags
3338             1u,        // uint32_t                                    viewportCount
3339             &viewport, // const VkViewport*                           pViewports
3340             1u,        // uint32_t                                    scissorCount
3341             &scissor   // const VkRect2D*                             pScissors
3342         };
3343         pipelineLoad =
3344             vk::makeGraphicsPipeline(vk, device, *pipelineLayout, *shaderModuleVert, VK_NULL_HANDLE, VK_NULL_HANDLE,
3345                                      VK_NULL_HANDLE, *shaderModuleLoad, *renderPass, 0u, &vertexInputStateCreateInfo,
3346                                      nullptr, nullptr, &viewportStateCreateInfo);
3347 
3348         const tcu::Vec4 clearColor(0.0f, 1.0f, 0.0f, 1.0f);
3349         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, extent.width, extent.height),
3350                         clearColor);
3351 
3352         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLoad);
3353 
3354         const uint32_t layerNdx             = 0u;
3355         const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
3356         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet,
3357                                  0u, nullptr);
3358 
3359         vk.cmdDraw(*cmdBuffer, m_verticesCount, 1u, 0u, 0u);
3360 
3361         endRenderPass(vk, *cmdBuffer);
3362 
3363         copyImageToBuffer(vk, *cmdBuffer, colorAttachmentImage->get(), m_imageBuffer->get(),
3364                           tcu::IVec2(extent.width, extent.height));
3365     }
3366     else
3367     {
3368         shaderModuleLoad = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp_load"));
3369 
3370         pipelineLoad = makeComputePipeline(vk, device, *pipelineLayout, *shaderModuleLoad);
3371 
3372         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLoad);
3373 
3374         // descriptors already bound to command buffer on first dispatch
3375         vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
3376 
3377         const VkImageAspectFlags &aspectMask = getImageAspect(m_format);
3378         commandCopyImageToBuffer(m_context, *cmdBuffer, m_imageSrc->get(), m_imageBuffer->get(), m_imageSizeBytes,
3379                                  m_texture, aspectMask);
3380     }
3381 
3382     endCommandBuffer(vk, *cmdBuffer);
3383     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
3384 
3385     return verifyResult();
3386 }
3387 } // namespace
3388 
createImageStoreTests(tcu::TestContext & testCtx)3389 tcu::TestCaseGroup *createImageStoreTests(tcu::TestContext &testCtx)
3390 {
3391     // Plain imageStore() cases
3392     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "store"));
3393     // Declare a format layout qualifier for write images
3394     de::MovePtr<tcu::TestCaseGroup> testGroupWithFormat(new tcu::TestCaseGroup(testCtx, "with_format"));
3395     de::MovePtr<tcu::TestCaseGroup> testGroupWithoutFormat(new tcu::TestCaseGroup(testCtx, "without_format"));
3396 
3397     for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
3398     {
3399         const Texture &texture = s_textures[textureNdx];
3400         de::MovePtr<tcu::TestCaseGroup> groupWithFormatByImageViewType(
3401             new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3402         de::MovePtr<tcu::TestCaseGroup> groupWithoutFormatByImageViewType(
3403             new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3404         const bool isLayered = (texture.numLayers() > 1);
3405 
3406         for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3407         {
3408             for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
3409             {
3410                 const bool hasSpirvFmt = hasSpirvFormat(s_formats[formatNdx]);
3411                 const char *suffix     = tilingSuffix(s_tilings[tilingNdx]);
3412 
3413                 if (hasSpirvFmt)
3414                 {
3415                     groupWithFormatByImageViewType->addChild(
3416                         new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + suffix, texture,
3417                                       s_formats[formatNdx], s_tilings[tilingNdx]));
3418                     // Additional tests where the shader uses constant data for imageStore.
3419                     groupWithFormatByImageViewType->addChild(new StoreTest(
3420                         testCtx, getFormatShortString(s_formats[formatNdx]) + "_constant" + suffix, texture,
3421                         s_formats[formatNdx], s_tilings[tilingNdx],
3422                         StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER | StoreTest::FLAG_STORE_CONSTANT_VALUE));
3423                 }
3424                 groupWithoutFormatByImageViewType->addChild(
3425                     new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + suffix, texture,
3426                                   s_formats[formatNdx], s_tilings[tilingNdx], 0));
3427 
3428                 if (isLayered && hasSpirvFmt)
3429                     groupWithFormatByImageViewType->addChild(new StoreTest(
3430                         testCtx, getFormatShortString(s_formats[formatNdx]) + "_single_layer" + suffix, texture,
3431                         s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL,
3432                         StoreTest::FLAG_SINGLE_LAYER_BIND | StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER));
3433 
3434                 if (texture.type() == IMAGE_TYPE_BUFFER)
3435                 {
3436                     if (hasSpirvFmt)
3437                         groupWithFormatByImageViewType->addChild(
3438                             new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_minalign" + suffix,
3439                                           texture, s_formats[formatNdx], s_tilings[tilingNdx],
3440                                           StoreTest::FLAG_MINALIGN | StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER));
3441                     groupWithoutFormatByImageViewType->addChild(
3442                         new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_minalign" + suffix,
3443                                       texture, s_formats[formatNdx], s_tilings[tilingNdx], StoreTest::FLAG_MINALIGN));
3444                 }
3445             }
3446         }
3447 
3448         {
3449             // Test depth formats with storage image
3450 
3451             // Depth formats for storage images are only allowed with optimal tiling
3452             const auto testTilingType = VK_IMAGE_TILING_OPTIMAL;
3453 
3454             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(d_formats); ++formatNdx)
3455             {
3456                 const char *suffix           = tilingSuffix(testTilingType);
3457                 const auto testFormat        = d_formats[formatNdx];
3458                 const auto formatShortString = getFormatShortString(testFormat);
3459 
3460                 if (!isAllowedDepthFormat(texture, testFormat, testTilingType))
3461                     continue;
3462 
3463                 groupWithoutFormatByImageViewType->addChild(
3464                     new StoreTest(testCtx, formatShortString + suffix, texture, testFormat, testTilingType, 0));
3465 
3466 #if 0
3467                 /* 'with_format' tests require format declaration in shader.
3468                    Since depth format has no spirv equivalent, r16 can be used for d16 and r32f can be used for d32_sfloat.
3469                    The validation layers do not complain and it works on some implementations */
3470 
3471                 groupWithFormatByImageViewType->addChild(new StoreTest(testCtx, formatShortString + suffix, texture, testFormat, testTilingType));
3472                 // Additional tests where the shader uses constant data for imageStore.
3473                 groupWithFormatByImageViewType->addChild(new StoreTest(testCtx, formatShortString + "_constant" + suffix, texture, testFormat, testTilingType, StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER | StoreTest::FLAG_STORE_CONSTANT_VALUE));
3474 
3475                 if (isLayered)
3476                     groupWithFormatByImageViewType->addChild(new StoreTest(testCtx, formatShortString + "_single_layer" + suffix,
3477                                                                             texture, testFormat, testTilingType,
3478                                                                             StoreTest::FLAG_SINGLE_LAYER_BIND | StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER));
3479 #endif
3480             }
3481         }
3482 
3483         testGroupWithFormat->addChild(groupWithFormatByImageViewType.release());
3484         testGroupWithoutFormat->addChild(groupWithoutFormatByImageViewType.release());
3485     }
3486 
3487     testGroup->addChild(testGroupWithFormat.release());
3488     testGroup->addChild(testGroupWithoutFormat.release());
3489 
3490     return testGroup.release();
3491 }
3492 
createImageLoadStoreTests(tcu::TestContext & testCtx)3493 tcu::TestCaseGroup *createImageLoadStoreTests(tcu::TestContext &testCtx)
3494 {
3495     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store"));
3496     de::MovePtr<tcu::TestCaseGroup> testGroupWithFormat(new tcu::TestCaseGroup(testCtx, "with_format"));
3497     de::MovePtr<tcu::TestCaseGroup> testGroupWithoutFormat(new tcu::TestCaseGroup(testCtx, "without_format"));
3498     de::MovePtr<tcu::TestCaseGroup> testGroupWithoutAnyFormat(new tcu::TestCaseGroup(testCtx, "without_any_format"));
3499 
3500     for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
3501     {
3502         const Texture &texture   = s_textures[textureNdx];
3503         const auto imageTypeName = getImageTypeName(texture.type());
3504         const bool isLayered     = (texture.numLayers() > 1);
3505 
3506         de::MovePtr<tcu::TestCaseGroup> groupWithFormatByImageViewType(
3507             new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
3508         de::MovePtr<tcu::TestCaseGroup> groupWithoutFormatByImageViewType(
3509             new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
3510         de::MovePtr<tcu::TestCaseGroup> groupWithoutAnyFormatByImageViewType(
3511             new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
3512 
3513         for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3514         {
3515             const auto formatShortString = getFormatShortString(s_formats[formatNdx]);
3516             const auto hasSpvFormat      = hasSpirvFormat(s_formats[formatNdx]);
3517 
3518             for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
3519             {
3520                 const char *suffix = tilingSuffix(s_tilings[tilingNdx]);
3521 
3522                 if (hasSpvFormat)
3523                 {
3524                     groupWithFormatByImageViewType->addChild(
3525                         new LoadStoreTest(testCtx, formatShortString + suffix, texture, s_formats[formatNdx],
3526                                           s_formats[formatNdx], s_tilings[tilingNdx]));
3527                     groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(
3528                         testCtx, formatShortString + suffix, texture, s_formats[formatNdx], s_formats[formatNdx],
3529                         s_tilings[tilingNdx], LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3530                 }
3531 
3532                 groupWithoutAnyFormatByImageViewType->addChild(
3533                     new LoadStoreTest(testCtx, formatShortString + suffix, texture, s_formats[formatNdx],
3534                                       s_formats[formatNdx], s_tilings[tilingNdx], 0u));
3535 
3536                 if (isLayered && hasSpvFormat)
3537                     groupWithFormatByImageViewType->addChild(new LoadStoreTest(
3538                         testCtx, formatShortString + "_single_layer" + suffix, texture, s_formats[formatNdx],
3539                         s_formats[formatNdx], s_tilings[tilingNdx],
3540                         LoadStoreTest::FLAG_SINGLE_LAYER_BIND | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS |
3541                             LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3542 
3543                 if (texture.type() == IMAGE_TYPE_BUFFER)
3544                 {
3545                     if (hasSpvFormat)
3546                     {
3547                         groupWithFormatByImageViewType->addChild(new LoadStoreTest(
3548                             testCtx, formatShortString + "_minalign" + suffix, texture, s_formats[formatNdx],
3549                             s_formats[formatNdx], s_tilings[tilingNdx],
3550                             LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS |
3551                                 LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3552                         groupWithFormatByImageViewType->addChild(new LoadStoreTest(
3553                             testCtx, formatShortString + "_minalign_uniform" + suffix, texture, s_formats[formatNdx],
3554                             s_formats[formatNdx], s_tilings[tilingNdx],
3555                             LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS |
3556                                 LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES |
3557                                 LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER));
3558                         groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(
3559                             testCtx, formatShortString + "_minalign" + suffix, texture, s_formats[formatNdx],
3560                             s_formats[formatNdx], s_tilings[tilingNdx],
3561                             LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3562                         groupWithoutFormatByImageViewType->addChild(
3563                             new LoadStoreTest(testCtx, formatShortString + "_minalign_uniform" + suffix, texture,
3564                                               s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx],
3565                                               LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER |
3566                                                   LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3567                     }
3568                     groupWithoutAnyFormatByImageViewType->addChild(new LoadStoreTest(
3569                         testCtx, formatShortString + "_minalign" + suffix, texture, s_formats[formatNdx],
3570                         s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN));
3571                     groupWithoutAnyFormatByImageViewType->addChild(
3572                         new LoadStoreTest(testCtx, formatShortString + "_minalign_uniform" + suffix, texture,
3573                                           s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx],
3574                                           LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER));
3575                 }
3576             }
3577         }
3578 
3579         if (texture.type() == IMAGE_TYPE_BUFFER)
3580         {
3581             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formatsThreeComponent); ++formatNdx)
3582             {
3583                 const auto formatShortString = getFormatShortString(s_formatsThreeComponent[formatNdx]);
3584 
3585                 for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
3586                 {
3587                     const char *suffix = tilingSuffix(s_tilings[tilingNdx]);
3588 
3589                     groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(
3590                         testCtx, formatShortString + "_uniform" + suffix, texture, s_formatsThreeComponent[formatNdx],
3591                         s_formatsThreeComponent[formatNdx], s_tilings[tilingNdx],
3592                         LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER |
3593                             LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3594                     groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(
3595                         testCtx, formatShortString + "_minalign_uniform" + suffix, texture,
3596                         s_formatsThreeComponent[formatNdx], s_formatsThreeComponent[formatNdx], s_tilings[tilingNdx],
3597                         LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER |
3598                             LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3599                 }
3600             }
3601         }
3602 
3603         {
3604             // Test depth formats with storage image
3605 
3606             // Depth formats for storage images are only allowed with optimal tiling
3607             const auto testTilingType = VK_IMAGE_TILING_OPTIMAL;
3608 
3609             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(d_formats); ++formatNdx)
3610             {
3611                 const char *suffix           = tilingSuffix(testTilingType);
3612                 const auto testFormat        = d_formats[formatNdx];
3613                 const auto formatShortString = getFormatShortString(testFormat);
3614 
3615                 if (!isAllowedDepthFormat(texture, testFormat, testTilingType))
3616                     continue;
3617 
3618                 groupWithoutAnyFormatByImageViewType->addChild(new LoadStoreTest(
3619                     testCtx, formatShortString + suffix, texture, testFormat, testFormat, testTilingType, 0u));
3620 #if 0
3621                 /* 'with_format' tests and tests that have FLAG_DECLARE_FORMAT_IN_SHADER_* flags require format declaration in shader.
3622                    Since depth format has no spirv equivalent, r16 can be used for d16 and r32f can be used for d32_sfloat.
3623                    The validation layers do not complain and it works on some implementations */
3624 
3625                 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + suffix, texture, testFormat, testFormat, testTilingType));
3626                 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + suffix, texture, testFormat, testFormat, testTilingType, LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3627 
3628                 if (isLayered)
3629                     groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_single_layer" + suffix,
3630                                                              texture, s_formats[formatNdx], s_formats[formatNdx], testTilingType,
3631                                                              LoadStoreTest::FLAG_SINGLE_LAYER_BIND | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3632 #endif
3633             }
3634         }
3635 
3636         testGroupWithFormat->addChild(groupWithFormatByImageViewType.release());
3637         testGroupWithoutFormat->addChild(groupWithoutFormatByImageViewType.release());
3638         testGroupWithoutAnyFormat->addChild(groupWithoutAnyFormatByImageViewType.release());
3639     }
3640 
3641     testGroup->addChild(testGroupWithFormat.release());
3642     testGroup->addChild(testGroupWithoutFormat.release());
3643     testGroup->addChild(testGroupWithoutAnyFormat.release());
3644 
3645     return testGroup.release();
3646 }
3647 
createImageLoadStoreLodAMDTests(tcu::TestContext & testCtx)3648 tcu::TestCaseGroup *createImageLoadStoreLodAMDTests(tcu::TestContext &testCtx)
3649 {
3650     static const Texture textures[] = {
3651         Texture(IMAGE_TYPE_1D_ARRAY, tcu::IVec3(64, 1, 1), 8, 1, 6),
3652         Texture(IMAGE_TYPE_1D, tcu::IVec3(64, 1, 1), 1, 1, 6),
3653         Texture(IMAGE_TYPE_2D, tcu::IVec3(64, 64, 1), 1, 1, 6),
3654         Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(64, 64, 1), 8, 1, 6),
3655         Texture(IMAGE_TYPE_3D, tcu::IVec3(64, 64, 8), 1, 1, 6),
3656         Texture(IMAGE_TYPE_CUBE, tcu::IVec3(64, 64, 1), 6, 1, 6),
3657         Texture(IMAGE_TYPE_CUBE_ARRAY, tcu::IVec3(64, 64, 1), 2 * 6, 1, 6),
3658     };
3659 
3660     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store_lod"));
3661     de::MovePtr<tcu::TestCaseGroup> testGroupWithFormat(new tcu::TestCaseGroup(testCtx, "with_format"));
3662     de::MovePtr<tcu::TestCaseGroup> testGroupWithoutFormat(new tcu::TestCaseGroup(testCtx, "without_format"));
3663 
3664     for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(textures); ++textureNdx)
3665     {
3666         const Texture &texture = textures[textureNdx];
3667         de::MovePtr<tcu::TestCaseGroup> groupWithFormatByImageViewType(
3668             new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3669         de::MovePtr<tcu::TestCaseGroup> groupWithoutFormatByImageViewType(
3670             new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3671         const bool isLayered = (texture.numLayers() > 1);
3672 
3673         if (texture.type() == IMAGE_TYPE_BUFFER)
3674             continue;
3675 
3676         for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3677         {
3678             // These tests always require a SPIR-V format for the write image, even if the read
3679             // image is being used without a format.
3680             if (!hasSpirvFormat(s_formats[formatNdx]))
3681                 continue;
3682 
3683             groupWithFormatByImageViewType->addChild(
3684                 new LoadStoreTest(testCtx, getFormatShortString(s_formats[formatNdx]), texture, s_formats[formatNdx],
3685                                   s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL,
3686                                   (LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS |
3687                                    LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES),
3688                                   true));
3689             groupWithoutFormatByImageViewType->addChild(
3690                 new LoadStoreTest(testCtx, getFormatShortString(s_formats[formatNdx]), texture, s_formats[formatNdx],
3691                                   s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL,
3692                                   LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES, true));
3693 
3694             if (isLayered)
3695                 groupWithFormatByImageViewType->addChild(new LoadStoreTest(
3696                     testCtx, getFormatShortString(s_formats[formatNdx]) + "_single_layer", texture,
3697                     s_formats[formatNdx], s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL,
3698                     LoadStoreTest::FLAG_SINGLE_LAYER_BIND | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS |
3699                         LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES,
3700                     true));
3701         }
3702 
3703         testGroupWithFormat->addChild(groupWithFormatByImageViewType.release());
3704         testGroupWithoutFormat->addChild(groupWithoutFormatByImageViewType.release());
3705     }
3706 
3707     testGroup->addChild(testGroupWithFormat.release());
3708     testGroup->addChild(testGroupWithoutFormat.release());
3709 
3710     return testGroup.release();
3711 }
3712 
createImageFormatReinterpretTests(tcu::TestContext & testCtx)3713 tcu::TestCaseGroup *createImageFormatReinterpretTests(tcu::TestContext &testCtx)
3714 {
3715     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "format_reinterpret"));
3716 
3717     for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
3718     {
3719         const Texture &texture = s_textures[textureNdx];
3720         de::MovePtr<tcu::TestCaseGroup> groupByImageViewType(
3721             new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3722 
3723         for (int imageFormatNdx = 0; imageFormatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++imageFormatNdx)
3724             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3725             {
3726                 if (!hasSpirvFormat(s_formats[formatNdx]))
3727                     continue;
3728 
3729                 const std::string caseName =
3730                     getFormatShortString(s_formats[imageFormatNdx]) + "_" + getFormatShortString(s_formats[formatNdx]);
3731                 if (imageFormatNdx != formatNdx &&
3732                     formatsAreCompatible(s_formats[imageFormatNdx], s_formats[formatNdx]))
3733                     groupByImageViewType->addChild(new LoadStoreTest(testCtx, caseName, texture, s_formats[formatNdx],
3734                                                                      s_formats[imageFormatNdx],
3735                                                                      VK_IMAGE_TILING_OPTIMAL));
3736             }
3737         testGroup->addChild(groupByImageViewType.release());
3738     }
3739 
3740     return testGroup.release();
3741 }
3742 
createImageQualifierRestrictCase(tcu::TestContext & testCtx,const ImageType imageType,const std::string & name)3743 de::MovePtr<TestCase> createImageQualifierRestrictCase(tcu::TestContext &testCtx, const ImageType imageType,
3744                                                        const std::string &name)
3745 {
3746     const VkFormat format  = VK_FORMAT_R32G32B32A32_UINT;
3747     const Texture &texture = getTestTexture(imageType);
3748     return de::MovePtr<TestCase>(new LoadStoreTest(testCtx, name, texture, format, format, VK_IMAGE_TILING_OPTIMAL,
3749                                                    LoadStoreTest::FLAG_RESTRICT_IMAGES |
3750                                                        LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS |
3751                                                        LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3752 }
3753 
3754 namespace
3755 {
3756 
relaxedOK(VkFormat format)3757 bool relaxedOK(VkFormat format)
3758 {
3759     tcu::IVec4 bitDepth = tcu::getTextureFormatBitDepth(mapVkFormat(format));
3760     int maxBitDepth     = deMax32(deMax32(bitDepth[0], bitDepth[1]), deMax32(bitDepth[2], bitDepth[3]));
3761     return maxBitDepth <= 16;
3762 }
3763 
3764 // Get a format used for reading or writing in extension operand tests. These formats allow representing the shader sampled type to
3765 // verify results from read or write operations.
getShaderExtensionOperandFormat(bool isSigned,bool is64Bit)3766 VkFormat getShaderExtensionOperandFormat(bool isSigned, bool is64Bit)
3767 {
3768     const VkFormat formats[] = {
3769         VK_FORMAT_R32G32B32A32_UINT,
3770         VK_FORMAT_R32G32B32A32_SINT,
3771         VK_FORMAT_R64_UINT,
3772         VK_FORMAT_R64_SINT,
3773     };
3774     return formats[2u * (is64Bit ? 1u : 0u) + (isSigned ? 1u : 0u)];
3775 }
3776 
3777 // INT or UINT format?
isIntegralFormat(VkFormat format)3778 bool isIntegralFormat(VkFormat format)
3779 {
3780     return (isIntFormat(format) || isUintFormat(format));
3781 }
3782 
3783 // Return the list of formats used for the extension operand tests (SignExten/ZeroExtend).
getExtensionOperandFormatList(void)3784 std::vector<VkFormat> getExtensionOperandFormatList(void)
3785 {
3786     std::vector<VkFormat> formatList;
3787 
3788     for (auto format : s_formats)
3789     {
3790         if (isIntegralFormat(format))
3791             formatList.push_back(format);
3792     }
3793 
3794     formatList.push_back(VK_FORMAT_R64_SINT);
3795     formatList.push_back(VK_FORMAT_R64_UINT);
3796 
3797     return formatList;
3798 }
3799 
3800 } // namespace
3801 
createImageExtendOperandsTests(tcu::TestContext & testCtx)3802 tcu::TestCaseGroup *createImageExtendOperandsTests(tcu::TestContext &testCtx)
3803 {
3804     using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
3805 
3806     GroupPtr testGroup(new tcu::TestCaseGroup(testCtx, "extend_operands_spirv1p4"));
3807 
3808     const struct
3809     {
3810         ExtendTestType testType;
3811         const char *name;
3812     } testTypes[] = {
3813         {ExtendTestType::READ, "read"},
3814         {ExtendTestType::WRITE, "write"},
3815     };
3816 
3817     const auto texture    = Texture(IMAGE_TYPE_2D, tcu::IVec3(8, 8, 1), 1);
3818     const auto formatList = getExtensionOperandFormatList();
3819 
3820     for (const auto format : formatList)
3821     {
3822         const auto isInt     = isIntFormat(format);
3823         const auto isUint    = isUintFormat(format);
3824         const auto use64Bits = is64BitIntegerFormat(format);
3825 
3826         DE_ASSERT(isInt || isUint);
3827 
3828         GroupPtr formatGroup(new tcu::TestCaseGroup(testCtx, getFormatShortString(format).c_str()));
3829 
3830         for (const auto &testType : testTypes)
3831         {
3832             GroupPtr testTypeGroup(new tcu::TestCaseGroup(testCtx, testType.name));
3833 
3834             for (int match = 0; match < 2; ++match)
3835             {
3836                 const bool mismatched      = (match == 1);
3837                 const char *matchGroupName = (mismatched ? "mismatched_sign" : "matched_sign");
3838 
3839                 // SPIR-V does not allow this kind of sampled type override.
3840                 if (mismatched && isUint)
3841                     continue;
3842 
3843                 GroupPtr matchGroup(new tcu::TestCaseGroup(testCtx, matchGroupName));
3844 
3845                 for (int prec = 0; prec < 2; prec++)
3846                 {
3847                     const bool relaxedPrecision = (prec != 0);
3848 
3849                     const char *precisionName = (relaxedPrecision ? "relaxed_precision" : "normal_precision");
3850                     const auto signedOther    = ((isInt && !mismatched) || (isUint && mismatched));
3851                     const auto otherFormat    = getShaderExtensionOperandFormat(signedOther, use64Bits);
3852                     const auto readFormat     = (testType.testType == ExtendTestType::READ ? format : otherFormat);
3853                     const auto writeFormat    = (testType.testType == ExtendTestType::WRITE ? format : otherFormat);
3854 
3855                     if (relaxedPrecision && !relaxedOK(readFormat))
3856                         continue;
3857 
3858                     if (!hasSpirvFormat(readFormat) || !hasSpirvFormat(writeFormat))
3859                         continue;
3860 
3861                     matchGroup->addChild(new ImageExtendOperandTest(testCtx, precisionName, texture, readFormat,
3862                                                                     writeFormat, mismatched, relaxedPrecision,
3863                                                                     testType.testType));
3864                 }
3865 
3866                 testTypeGroup->addChild(matchGroup.release());
3867             }
3868 
3869             formatGroup->addChild(testTypeGroup.release());
3870         }
3871 
3872         testGroup->addChild(formatGroup.release());
3873     }
3874 
3875     return testGroup.release();
3876 }
3877 
createImageNontemporalOperandTests(tcu::TestContext & testCtx)3878 tcu::TestCaseGroup *createImageNontemporalOperandTests(tcu::TestContext &testCtx)
3879 {
3880     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "nontemporal_operand"));
3881 
3882     const auto texture = Texture(IMAGE_TYPE_2D, tcu::IVec3(8, 8, 1), 1);
3883 
3884     // using just integer formats for tests so that ImageExtendOperandTest could be reused
3885     const auto formatList = getExtensionOperandFormatList();
3886 
3887     for (const auto format : formatList)
3888     {
3889         const std::string caseName = getFormatShortString(format);
3890         const auto readFormat      = format;
3891         const auto writeFormat     = getShaderExtensionOperandFormat(isIntFormat(format), is64BitIntegerFormat(format));
3892 
3893         if (!hasSpirvFormat(readFormat) || !hasSpirvFormat(writeFormat))
3894             continue;
3895 
3896         // note: just testing OpImageWrite as OpImageRead is tested with addComputeImageSamplerTest
3897         testGroup->addChild(new ImageExtendOperandTest(testCtx, caseName, texture, readFormat, writeFormat, false,
3898                                                        false, ExtendTestType::WRITE_NONTEMPORAL));
3899     }
3900 
3901     return testGroup.release();
3902 }
3903 
createImageDeviceScopeAccessTests(tcu::TestContext & testCtx)3904 tcu::TestCaseGroup *createImageDeviceScopeAccessTests(tcu::TestContext &testCtx)
3905 {
3906     const Texture testTextures[] = {
3907         Texture(IMAGE_TYPE_1D, tcu::IVec3(64, 1, 1), 1),
3908         Texture(IMAGE_TYPE_2D, tcu::IVec3(64, 64, 1), 1),
3909         Texture(IMAGE_TYPE_3D, tcu::IVec3(64, 64, 8), 1, 1, 1),
3910     };
3911 
3912     const struct TestConfiguration
3913     {
3914         TestConfigurationType type;
3915         const std::string typeName;
3916 
3917     } testConfigurations[] = {{TC_COMP_COMP, "comp_comp"}, {TC_COMP_DRAW, "comp_draw"}};
3918 
3919     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "device_scope_access"));
3920 
3921     for (const auto &testConfig : testConfigurations)
3922     {
3923         de::MovePtr<tcu::TestCaseGroup> groupTestType(new tcu::TestCaseGroup(testCtx, testConfig.typeName.c_str()));
3924 
3925         for (uint32_t textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(testTextures); ++textureNdx)
3926         {
3927             const Texture &texture   = testTextures[textureNdx];
3928             const auto imageTypeName = getImageTypeName(texture.type());
3929 
3930             if ((testConfig.type == TC_COMP_DRAW) && (testTextures[textureNdx].type() == IMAGE_TYPE_3D))
3931                 continue;
3932 
3933             de::MovePtr<tcu::TestCaseGroup> groupImageType(new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
3934 
3935             for (uint32_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3936             {
3937                 const auto formatShortString = getFormatShortString(s_formats[formatNdx]);
3938                 const auto hasSpvFormat      = hasSpirvFormat(s_formats[formatNdx]);
3939 
3940                 for (uint32_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
3941                 {
3942                     const char *suffix = tilingSuffix(s_tilings[tilingNdx]);
3943 
3944                     if (hasSpvFormat)
3945                     {
3946                         groupImageType->addChild(
3947                             new ImageDeviceScopeAccessTest(testCtx, testConfig.type, formatShortString + suffix,
3948                                                            texture, s_formats[formatNdx], s_tilings[tilingNdx]));
3949                     }
3950                 }
3951             }
3952 
3953             groupTestType->addChild(groupImageType.release());
3954         }
3955         testGroup->addChild(groupTestType.release());
3956     }
3957 
3958     return testGroup.release();
3959 }
3960 
3961 } // namespace image
3962 } // namespace vkt
3963