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 // Check for three-component (non-packed) format, i.e. pixel size is a multiple of 3.
formatHasThreeComponents(VkFormat format)72 bool formatHasThreeComponents(VkFormat format)
73 {
74 const tcu::TextureFormat texFormat = mapVkFormat(format);
75 return (getPixelSize(texFormat) % 3) == 0;
76 }
77
getSingleComponentFormat(VkFormat format)78 VkFormat getSingleComponentFormat(VkFormat format)
79 {
80 tcu::TextureFormat texFormat = mapVkFormat(format);
81 texFormat = tcu::TextureFormat(tcu::TextureFormat::R, texFormat.type);
82 return mapTextureFormat(texFormat);
83 }
84
makeBufferImageCopy(const Texture & texture)85 inline VkBufferImageCopy makeBufferImageCopy (const Texture& texture)
86 {
87 return image::makeBufferImageCopy(makeExtent3D(texture.layerSize()), texture.numLayers());
88 }
89
getLayerOrSlice(const Texture & texture,const tcu::ConstPixelBufferAccess access,const int layer)90 tcu::ConstPixelBufferAccess getLayerOrSlice (const Texture& texture, const tcu::ConstPixelBufferAccess access, const int layer)
91 {
92 switch (texture.type())
93 {
94 case IMAGE_TYPE_1D:
95 case IMAGE_TYPE_2D:
96 case IMAGE_TYPE_BUFFER:
97 // Not layered
98 DE_ASSERT(layer == 0);
99 return access;
100
101 case IMAGE_TYPE_1D_ARRAY:
102 return tcu::getSubregion(access, 0, layer, access.getWidth(), 1);
103
104 case IMAGE_TYPE_2D_ARRAY:
105 case IMAGE_TYPE_CUBE:
106 case IMAGE_TYPE_CUBE_ARRAY:
107 case IMAGE_TYPE_3D: // 3d texture is treated as if depth was the layers
108 return tcu::getSubregion(access, 0, 0, layer, access.getWidth(), access.getHeight(), 1);
109
110 default:
111 DE_FATAL("Internal test error");
112 return tcu::ConstPixelBufferAccess();
113 }
114 }
115
116 //! \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 deUint32 mipmapLevel)117 vk::VkDeviceSize getMipmapLevelImageSizeBytes (const Texture& texture, const vk::VkFormat format, const deUint32 mipmapLevel)
118 {
119 tcu::IVec3 size = texture.size(mipmapLevel);
120 return tcu::getPixelSize(vk::mapVkFormat(format)) * size.x() * size.y() * size.z();
121 }
122
123 //! \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)124 vk::VkDeviceSize getMipmapImageTotalSizeBytes (const Texture& texture, const vk::VkFormat format)
125 {
126 vk::VkDeviceSize size = 0u;
127 deInt32 levelCount = 0u;
128
129 do
130 {
131 size += getMipmapLevelImageSizeBytes(texture, format, levelCount);
132 levelCount++;
133 } while (levelCount < texture.numMipmapLevels());
134 return size;
135 }
136
137 //! \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 deUint32 mipmapLevel=0u)138 bool comparePixelBuffers (tcu::TestLog& log,
139 const Texture& texture,
140 const VkFormat format,
141 const tcu::ConstPixelBufferAccess reference,
142 const tcu::ConstPixelBufferAccess result,
143 const deUint32 mipmapLevel = 0u)
144 {
145 DE_ASSERT(reference.getFormat() == result.getFormat());
146 DE_ASSERT(reference.getSize() == result.getSize());
147
148 const bool is3d = (texture.type() == IMAGE_TYPE_3D);
149 const int numLayersOrSlices = (is3d ? texture.size(mipmapLevel).z() : texture.numLayers());
150 const int numCubeFaces = 6;
151
152 int passedLayers = 0;
153 for (int layerNdx = 0; layerNdx < numLayersOrSlices; ++layerNdx)
154 {
155 const std::string comparisonName = "Comparison" + de::toString(layerNdx);
156 const std::string comparisonDesc = "Image Comparison, " +
157 (isCube(texture) ? "face " + de::toString(layerNdx % numCubeFaces) + ", cube " + de::toString(layerNdx / numCubeFaces) :
158 is3d ? "slice " + de::toString(layerNdx) : "layer " + de::toString(layerNdx) + " , level " + de::toString(mipmapLevel));
159
160 const tcu::ConstPixelBufferAccess refLayer = getLayerOrSlice(texture, reference, layerNdx);
161 const tcu::ConstPixelBufferAccess resultLayer = getLayerOrSlice(texture, result, layerNdx);
162
163 bool ok = false;
164
165 switch (tcu::getTextureChannelClass(mapVkFormat(format).type))
166 {
167 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
168 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
169 {
170 ok = tcu::intThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
171 break;
172 }
173
174 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
175 {
176 // Allow error of minimum representable difference
177 tcu::Vec4 threshold(1.0f / ((tcu::UVec4(1u) << tcu::getTextureFormatMantissaBitDepth(mapVkFormat(format)).cast<deUint32>()) - 1u).cast<float>());
178
179 // Add 1 ULP of fp32 imprecision to account for image comparison fp32 math with unorm->float conversions.
180 threshold += tcu::Vec4(std::numeric_limits<float>::epsilon());
181
182 ok = tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, threshold, tcu::COMPARE_LOG_RESULT);
183 break;
184 }
185
186 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
187 {
188 const tcu::UVec4 bitDepth = tcu::getTextureFormatMantissaBitDepth(mapVkFormat(format)).cast<deUint32>() - 1u;
189 // To avoid bit-shifting with negative value, which is undefined behaviour.
190 const tcu::UVec4 fixedBitDepth = tcu::select(bitDepth, tcu::UVec4(0u, 0u, 0u, 0u), tcu::greaterThanEqual(bitDepth.cast<deInt32>(), tcu::IVec4(0, 0, 0, 0)));
191
192 // Allow error of minimum representable difference
193 const tcu::Vec4 threshold (1.0f / ((tcu::UVec4(1u) << fixedBitDepth) - 1u).cast<float>());
194
195 ok = tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, threshold, tcu::COMPARE_LOG_RESULT);
196 break;
197 }
198
199 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
200 {
201 // Convert target format ulps to float ulps and allow 1 ulp difference
202 const tcu::UVec4 threshold (tcu::UVec4(1u) << (tcu::UVec4(23) - tcu::getTextureFormatMantissaBitDepth(mapVkFormat(format)).cast<deUint32>()));
203
204 ok = tcu::floatUlpThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, threshold, tcu::COMPARE_LOG_RESULT);
205 break;
206 }
207
208 default:
209 DE_FATAL("Unknown channel class");
210 }
211
212 if (ok)
213 ++passedLayers;
214 }
215
216 return passedLayers == numLayersOrSlices;
217 }
218
219 //!< Zero out invalid pixels in the image (denormalized, infinite, NaN values)
replaceBadFloatReinterpretValues(const tcu::PixelBufferAccess access)220 void replaceBadFloatReinterpretValues (const tcu::PixelBufferAccess access)
221 {
222 DE_ASSERT(tcu::getTextureChannelClass(access.getFormat().type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
223
224 for (int z = 0; z < access.getDepth(); ++z)
225 for (int y = 0; y < access.getHeight(); ++y)
226 for (int x = 0; x < access.getWidth(); ++x)
227 {
228 const tcu::Vec4 color(access.getPixel(x, y, z));
229 tcu::Vec4 newColor = color;
230
231 for (int i = 0; i < 4; ++i)
232 {
233 if (access.getFormat().type == tcu::TextureFormat::HALF_FLOAT)
234 {
235 const tcu::Float16 f(color[i]);
236 if (f.isDenorm() || f.isInf() || f.isNaN())
237 newColor[i] = 0.0f;
238 }
239 else
240 {
241 const tcu::Float32 f(color[i]);
242 if (f.isDenorm() || f.isInf() || f.isNaN())
243 newColor[i] = 0.0f;
244 }
245 }
246
247 if (newColor != color)
248 access.setPixel(newColor, x, y, z);
249 }
250 }
251
252 //!< replace invalid pixels in the image (-128)
replaceSnormReinterpretValues(const tcu::PixelBufferAccess access)253 void replaceSnormReinterpretValues (const tcu::PixelBufferAccess access)
254 {
255 DE_ASSERT(tcu::getTextureChannelClass(access.getFormat().type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT);
256
257 for (int z = 0; z < access.getDepth(); ++z)
258 for (int y = 0; y < access.getHeight(); ++y)
259 for (int x = 0; x < access.getWidth(); ++x)
260 {
261 const tcu::IVec4 color(access.getPixelInt(x, y, z));
262 tcu::IVec4 newColor = color;
263
264 for (int i = 0; i < 4; ++i)
265 {
266 const deInt32 oldColor(color[i]);
267 if (oldColor == -128) newColor[i] = -127;
268 }
269
270 if (newColor != color)
271 access.setPixel(newColor, x, y, z);
272 }
273 }
274
getMiddleValue(VkFormat imageFormat)275 tcu::Vec4 getMiddleValue(VkFormat imageFormat)
276 {
277 tcu::TextureFormat format = mapVkFormat(imageFormat);
278 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(format);
279 tcu::Vec4 val = (fmtInfo.valueMax - fmtInfo.valueMin) * tcu::Vec4(0.5f);
280
281 if (isIntegerFormat(imageFormat))
282 val = floor(val);
283
284 return val;
285 }
286
generateReferenceImage(const tcu::IVec3 & imageSize,const VkFormat imageFormat,const VkFormat readFormat,bool constantValue=false)287 tcu::TextureLevel generateReferenceImage (const tcu::IVec3& imageSize, const VkFormat imageFormat, const VkFormat readFormat, bool constantValue = false)
288 {
289 // Generate a reference image data using the storage format
290
291 tcu::TextureLevel reference(mapVkFormat(imageFormat), imageSize.x(), imageSize.y(), imageSize.z());
292 const tcu::PixelBufferAccess access = reference.getAccess();
293
294 const float storeColorScale = computeStoreColorScale(imageFormat, imageSize);
295 const float storeColorBias = computeStoreColorBias(imageFormat);
296
297 const bool srgbFormat = isSrgbFormat(imageFormat);
298 const bool intFormat = isIntegerFormat(imageFormat);
299 const bool storeNegativeValues = isSignedFormat(imageFormat) && (storeColorBias == 0);
300 const int xMax = imageSize.x() - 1;
301 const int yMax = imageSize.y() - 1;
302
303 for (int z = 0; z < imageSize.z(); ++z)
304 for (int y = 0; y < imageSize.y(); ++y)
305 for (int x = 0; x < imageSize.x(); ++x)
306 {
307 if (constantValue)
308 {
309 access.setPixel(getMiddleValue(imageFormat), x, y, z);
310 }
311 else
312 {
313 tcu::IVec4 color = tcu::IVec4(x ^ y ^ z, (xMax - x) ^ y ^ z, x ^ (yMax - y) ^ z, (xMax - x) ^ (yMax - y) ^ z);
314
315 if (storeNegativeValues)
316 color -= tcu::IVec4(deRoundFloatToInt32((float)de::max(xMax, yMax) / 2.0f));
317
318 if (intFormat)
319 access.setPixel(color, x, y, z);
320 else
321 {
322 if (srgbFormat)
323 access.setPixel(tcu::linearToSRGB(color.asFloat() * storeColorScale + storeColorBias), x, y, z);
324 else
325 access.setPixel(color.asFloat() * storeColorScale + storeColorBias, x, y, z);
326 }
327 }
328 }
329
330 // If the image is to be accessed as a float texture, get rid of invalid values
331
332 if (isFloatFormat(readFormat) && imageFormat != readFormat)
333 replaceBadFloatReinterpretValues(tcu::PixelBufferAccess(mapVkFormat(readFormat), imageSize, access.getDataPtr()));
334 if (isSnormFormat(readFormat) && imageFormat != readFormat)
335 replaceSnormReinterpretValues(tcu::PixelBufferAccess(mapVkFormat(readFormat), imageSize, access.getDataPtr()));
336
337 return reference;
338 }
339
generateReferenceImage(const tcu::IVec3 & imageSize,const VkFormat imageFormat,bool constantValue=false)340 inline tcu::TextureLevel generateReferenceImage (const tcu::IVec3& imageSize, const VkFormat imageFormat, bool constantValue = false)
341 {
342 return generateReferenceImage(imageSize, imageFormat, imageFormat, constantValue);
343 }
344
flipHorizontally(const tcu::PixelBufferAccess access)345 void flipHorizontally (const tcu::PixelBufferAccess access)
346 {
347 const int xMax = access.getWidth() - 1;
348 const int halfWidth = access.getWidth() / 2;
349
350 if (isIntegerFormat(mapTextureFormat(access.getFormat())))
351 for (int z = 0; z < access.getDepth(); z++)
352 for (int y = 0; y < access.getHeight(); y++)
353 for (int x = 0; x < halfWidth; x++)
354 {
355 const tcu::UVec4 temp = access.getPixelUint(xMax - x, y, z);
356 access.setPixel(access.getPixelUint(x, y, z), xMax - x, y, z);
357 access.setPixel(temp, x, y, z);
358 }
359 else
360 for (int z = 0; z < access.getDepth(); z++)
361 for (int y = 0; y < access.getHeight(); y++)
362 for (int x = 0; x < halfWidth; x++)
363 {
364 const tcu::Vec4 temp = access.getPixel(xMax - x, y, z);
365 access.setPixel(access.getPixel(x, y, z), xMax - x, y, z);
366 access.setPixel(temp, x, y, z);
367 }
368 }
369
formatsAreCompatible(const VkFormat format0,const VkFormat format1)370 inline bool formatsAreCompatible (const VkFormat format0, const VkFormat format1)
371 {
372 const bool isAlphaOnly = (isAlphaOnlyFormat(format0) || isAlphaOnlyFormat(format1));
373 return format0 == format1 || (mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize() && !isAlphaOnly);
374 }
375
commandImageWriteBarrierBetweenShaderInvocations(Context & context,const VkCommandBuffer cmdBuffer,const VkImage image,const Texture & texture)376 void commandImageWriteBarrierBetweenShaderInvocations (Context& context, const VkCommandBuffer cmdBuffer, const VkImage image, const Texture& texture)
377 {
378 const DeviceInterface& vk = context.getDeviceInterface();
379
380 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, texture.numMipmapLevels(), 0u, texture.numLayers());
381 const VkImageMemoryBarrier shaderWriteBarrier = makeImageMemoryBarrier(
382 VK_ACCESS_SHADER_WRITE_BIT, 0u,
383 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
384 image, fullImageSubresourceRange);
385
386 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &shaderWriteBarrier);
387 }
388
commandBufferWriteBarrierBeforeHostRead(Context & context,const VkCommandBuffer cmdBuffer,const VkBuffer buffer,const VkDeviceSize bufferSizeBytes)389 void commandBufferWriteBarrierBeforeHostRead (Context& context, const VkCommandBuffer cmdBuffer, const VkBuffer buffer, const VkDeviceSize bufferSizeBytes)
390 {
391 const DeviceInterface& vk = context.getDeviceInterface();
392
393 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
394 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
395 buffer, 0ull, bufferSizeBytes);
396
397 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &shaderWriteBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
398 }
399
400 //! 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)401 void commandCopyImageToBuffer (Context& context,
402 const VkCommandBuffer cmdBuffer,
403 const VkImage image,
404 const VkBuffer buffer,
405 const VkDeviceSize bufferSizeBytes,
406 const Texture& texture)
407 {
408 const DeviceInterface& vk = context.getDeviceInterface();
409
410 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, texture.numLayers());
411 const VkImageMemoryBarrier prepareForTransferBarrier = makeImageMemoryBarrier(
412 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
413 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
414 image, fullImageSubresourceRange);
415
416 const VkBufferImageCopy copyRegion = makeBufferImageCopy(texture);
417
418 const VkBufferMemoryBarrier copyBarrier = makeBufferMemoryBarrier(
419 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
420 buffer, 0ull, bufferSizeBytes);
421
422 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &prepareForTransferBarrier);
423 vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ©Region);
424 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, ©Barrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
425 }
426
427 //! 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)428 void commandCopyMipmapImageToBuffer (Context& context,
429 const VkCommandBuffer cmdBuffer,
430 const VkImage image,
431 const VkFormat imageFormat,
432 const VkBuffer buffer,
433 const VkDeviceSize bufferSizeBytes,
434 const Texture& texture)
435 {
436 const DeviceInterface& vk = context.getDeviceInterface();
437
438 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, texture.numMipmapLevels(), 0u, texture.numLayers());
439 const VkImageMemoryBarrier prepareForTransferBarrier = makeImageMemoryBarrier(
440 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
441 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
442 image, fullImageSubresourceRange);
443
444 std::vector<VkBufferImageCopy> copyRegions;
445 VkDeviceSize bufferOffset = 0u;
446 for (deInt32 levelNdx = 0; levelNdx < texture.numMipmapLevels(); levelNdx++)
447 {
448 const VkBufferImageCopy copyParams =
449 {
450 bufferOffset, // VkDeviceSize bufferOffset;
451 0u, // deUint32 bufferRowLength;
452 0u, // deUint32 bufferImageHeight;
453 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, levelNdx, 0u, texture.numLayers()), // VkImageSubresourceLayers imageSubresource;
454 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
455 makeExtent3D(texture.layerSize(levelNdx)), // VkExtent3D imageExtent;
456 };
457 copyRegions.push_back(copyParams);
458 bufferOffset += getMipmapLevelImageSizeBytes(texture, imageFormat, levelNdx);
459 }
460
461 const VkBufferMemoryBarrier copyBarrier = makeBufferMemoryBarrier(
462 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
463 buffer, 0ull, bufferSizeBytes);
464
465 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &prepareForTransferBarrier);
466 vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, (deUint32) copyRegions.size(), copyRegions.data());
467 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, ©Barrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
468 }
469
470 class StoreTest : public TestCase
471 {
472 public:
473 enum TestFlags
474 {
475 FLAG_SINGLE_LAYER_BIND = 0x1, //!< Run the shader multiple times, each time binding a different layer.
476 FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER = 0x2, //!< Declare the format of the images in the shader code
477 FLAG_MINALIGN = 0x4, //!< Use bufferview offset that matches the advertised minimum alignment
478 FLAG_STORE_CONSTANT_VALUE = 0x8, //!< Store constant value
479 };
480
481 StoreTest (tcu::TestContext& testCtx,
482 const std::string& name,
483 const Texture& texture,
484 const VkFormat format,
485 const VkImageTiling tiling,
486 const deUint32 flags = FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER);
487
488 virtual void checkSupport (Context& context) const;
489 void initPrograms (SourceCollections& programCollection) const;
490 TestInstance* createInstance (Context& context) const;
491
492 private:
493 const Texture m_texture;
494 const VkFormat m_format;
495 const VkImageTiling m_tiling;
496 const bool m_declareImageFormatInShader;
497 const bool m_singleLayerBind;
498 const bool m_minalign;
499 const bool m_storeConstantValue;
500 };
501
StoreTest(tcu::TestContext & testCtx,const std::string & name,const Texture & texture,const VkFormat format,const VkImageTiling tiling,const deUint32 flags)502 StoreTest::StoreTest (tcu::TestContext& testCtx,
503 const std::string& name,
504 const Texture& texture,
505 const VkFormat format,
506 const VkImageTiling tiling,
507 const deUint32 flags)
508 : TestCase (testCtx, name)
509 , m_texture (texture)
510 , m_format (format)
511 , m_tiling (tiling)
512 , m_declareImageFormatInShader ((flags & FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER) != 0)
513 , m_singleLayerBind ((flags & FLAG_SINGLE_LAYER_BIND) != 0)
514 , m_minalign ((flags & FLAG_MINALIGN) != 0)
515 , m_storeConstantValue ((flags & FLAG_STORE_CONSTANT_VALUE) != 0)
516 {
517 if (m_singleLayerBind)
518 DE_ASSERT(m_texture.numLayers() > 1);
519 }
520
checkSupport(Context & context) const521 void StoreTest::checkSupport (Context& context) const
522 {
523 #ifndef CTS_USES_VULKANSC
524 if (m_format == VK_FORMAT_A8_UNORM_KHR || m_format == VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR)
525 context.requireDeviceFunctionality("VK_KHR_maintenance5");
526
527 const VkFormatProperties3 formatProperties (context.getFormatProperties(m_format));
528
529 const auto& tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures : formatProperties.linearTilingFeatures;
530
531 if ((m_texture.type() == IMAGE_TYPE_BUFFER) && !m_declareImageFormatInShader && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR))
532 TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via storage buffer");
533
534 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !m_declareImageFormatInShader && !(tilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR))
535 TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via storage images");
536
537 if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
538 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
539
540 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
541 TCU_THROW(NotSupportedError, "Format not supported for storage images");
542
543 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
544 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
545 #else
546 const VkFormatProperties formatProperties(getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), m_format));
547 const auto tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures : formatProperties.linearTilingFeatures;
548
549 if (!m_declareImageFormatInShader)
550 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT);
551
552 if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
553 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
554
555 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
556 TCU_THROW(NotSupportedError, "Format not supported for storage images");
557
558 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
559 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
560 #endif // CTS_USES_VULKANSC
561
562 const auto& vki = context.getInstanceInterface();
563 const auto physicalDevice = context.getPhysicalDevice();
564
565 VkImageFormatProperties imageFormatProperties;
566 const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_format, mapImageType(m_texture.type()), m_tiling, (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), 0, &imageFormatProperties);
567
568 if (result != VK_SUCCESS)
569 {
570 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
571 TCU_THROW(NotSupportedError, "Format unsupported for tiling");
572 else
573 TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned unexpected error");
574 }
575
576 if (imageFormatProperties.maxArrayLayers < (uint32_t)m_texture.numLayers()) {
577 TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of aray layers");
578 }
579
580 if (imageFormatProperties.maxMipLevels < (uint32_t)m_texture.numMipmapLevels()) {
581 TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of miplevels");
582 }
583 }
584
initPrograms(SourceCollections & programCollection) const585 void StoreTest::initPrograms (SourceCollections& programCollection) const
586 {
587 const float storeColorScale = computeStoreColorScale(m_format, m_texture.size());
588 const float storeColorBias = computeStoreColorBias(m_format);
589 DE_ASSERT(colorScaleAndBiasAreValid(m_format, storeColorScale, storeColorBias));
590
591 const deUint32 xMax = m_texture.size().x() - 1;
592 const deUint32 yMax = m_texture.size().y() - 1;
593 const std::string signednessPrefix = isUintFormat(m_format) ? "u" : isIntFormat(m_format) ? "i" : "";
594 const bool storeNegativeValues = isSignedFormat(m_format) && (storeColorBias == 0);
595 bool useClamp = false;
596 const std::string colorType = signednessPrefix + "vec4";
597 std::string colorBaseExpr = colorType + "(";
598
599 std::string colorExpr;
600
601 if (m_storeConstantValue)
602 {
603 tcu::Vec4 val = getMiddleValue(m_format);
604
605 if (isIntegerFormat(m_format))
606 {
607 colorExpr = colorBaseExpr
608 + de::toString(static_cast<deInt64>(val.x())) + ", "
609 + de::toString(static_cast<deInt64>(val.y())) + ", "
610 + de::toString(static_cast<deInt64>(val.z())) + ", "
611 + de::toString(static_cast<deInt64>(val.w())) + ")";
612 }
613 else
614 {
615 colorExpr = colorBaseExpr
616 + de::toString(val.x()) + ", "
617 + de::toString(val.y()) + ", "
618 + de::toString(val.z()) + ", "
619 + de::toString(val.w()) + ")";
620 }
621 }
622 else
623 {
624 colorBaseExpr = colorBaseExpr
625 + "gx^gy^gz, "
626 + "(" + de::toString(xMax) + "-gx)^gy^gz, "
627 + "gx^(" + de::toString(yMax) + "-gy)^gz, "
628 + "(" + de::toString(xMax) + "-gx)^(" + de::toString(yMax) + "-gy)^gz)";
629
630 // Large integer values may not be represented with formats with low bit depths
631 if (isIntegerFormat(m_format))
632 {
633 const deInt64 minStoreValue = storeNegativeValues ? 0 - deRoundFloatToInt64((float)de::max(xMax, yMax) / 2.0f) : 0;
634 const deInt64 maxStoreValue = storeNegativeValues ? deRoundFloatToInt64((float)de::max(xMax, yMax) / 2.0f) : de::max(xMax, yMax);
635
636 useClamp = !isRepresentableIntegerValue(tcu::Vector<deInt64, 4>(minStoreValue), mapVkFormat(m_format)) ||
637 !isRepresentableIntegerValue(tcu::Vector<deInt64, 4>(maxStoreValue), mapVkFormat(m_format));
638 }
639
640 // Clamp if integer value cannot be represented with the current format
641 if (useClamp)
642 {
643 const tcu::IVec4 bitDepths = tcu::getTextureFormatBitDepth(mapVkFormat(m_format));
644 tcu::IVec4 minRepresentableValue;
645 tcu::IVec4 maxRepresentableValue;
646
647 switch (tcu::getTextureChannelClass(mapVkFormat(m_format).type))
648 {
649 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
650 {
651 minRepresentableValue = tcu::IVec4(0);
652 maxRepresentableValue = (tcu::IVec4(1) << bitDepths) - tcu::IVec4(1);
653 break;
654 }
655
656 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
657 {
658 minRepresentableValue = -(tcu::IVec4(1) << bitDepths - tcu::IVec4(1));
659 maxRepresentableValue = (tcu::IVec4(1) << (bitDepths - tcu::IVec4(1))) - tcu::IVec4(1);
660 break;
661 }
662
663 default:
664 DE_ASSERT(isIntegerFormat(m_format));
665 }
666
667 colorBaseExpr = "clamp(" + colorBaseExpr + ", "
668 + signednessPrefix + "vec4" + de::toString(minRepresentableValue) + ", "
669 + signednessPrefix + "vec4" + de::toString(maxRepresentableValue) + ")";
670 }
671
672 colorExpr = colorBaseExpr + (storeColorScale == 1.0f ? "" : "*" + de::toString(storeColorScale))
673 + (storeColorBias == 0.0f ? "" : " + float(" + de::toString(storeColorBias) + ")");
674
675 if (storeNegativeValues)
676 colorExpr += "-" + de::toString(deRoundFloatToInt32((float)deMax32(xMax, yMax) / 2.0f));
677 }
678
679 const int dimension = (m_singleLayerBind ? m_texture.layerDimension() : m_texture.dimension());
680 const std::string texelCoordStr = (dimension == 1 ? "gx" : dimension == 2 ? "ivec2(gx, gy)" : dimension == 3 ? "ivec3(gx, gy, gz)" : "");
681
682 const ImageType usedImageType = (m_singleLayerBind ? getImageTypeForSingleLayer(m_texture.type()) : m_texture.type());
683 const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), usedImageType);
684
685 std::string maybeFmtQualStr = m_declareImageFormatInShader ? ", " + getShaderImageFormatQualifier(mapVkFormat(m_format)) : "";
686
687 std::ostringstream src;
688 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
689 << "\n"
690 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
691 << "layout (binding = 0" << maybeFmtQualStr << ") writeonly uniform " << imageTypeStr << " u_image;\n";
692
693 if (m_singleLayerBind)
694 src << "layout (binding = 1) readonly uniform Constants {\n"
695 << " int u_layerNdx;\n"
696 << "};\n";
697
698 src << "\n"
699 << "void main (void)\n"
700 << "{\n"
701 << " int gx = int(gl_GlobalInvocationID.x);\n"
702 << " int gy = int(gl_GlobalInvocationID.y);\n"
703 << " int gz = " << (m_singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
704 << " " << colorType << " storedColor = " << colorExpr << ";\n"
705 << " imageStore(u_image, " << texelCoordStr << ", storedColor);\n"
706 << "}\n";
707
708 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
709 }
710
711 //! Generic test iteration algorithm for image tests
712 class BaseTestInstance : public TestInstance
713 {
714 public:
715 BaseTestInstance (Context& context,
716 const Texture& texture,
717 const VkFormat format,
718 const bool declareImageFormatInShader,
719 const bool singleLayerBind,
720 const bool minalign,
721 const bool bufferLoadUniform);
722
723 tcu::TestStatus iterate (void);
724
~BaseTestInstance(void)725 virtual ~BaseTestInstance (void) {}
726
727 protected:
728 virtual VkDescriptorSetLayout prepareDescriptors (void) = 0;
729 virtual tcu::TestStatus verifyResult (void) = 0;
730
731 virtual void commandBeforeCompute (const VkCommandBuffer cmdBuffer) = 0;
732 virtual void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer) = 0;
733 virtual void commandAfterCompute (const VkCommandBuffer cmdBuffer) = 0;
734
735 virtual void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
736 const VkPipelineLayout pipelineLayout,
737 const int layerNdx) = 0;
738 virtual deUint32 getViewOffset (Context& context,
739 const VkFormat format,
740 bool uniform);
741
742 const Texture m_texture;
743 const VkFormat m_format;
744 const bool m_declareImageFormatInShader;
745 const bool m_singleLayerBind;
746 const bool m_minalign;
747 const bool m_bufferLoadUniform;
748 const deUint32 m_srcViewOffset;
749 const deUint32 m_dstViewOffset;
750 };
751
BaseTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)752 BaseTestInstance::BaseTestInstance (Context& context, const Texture& texture, const VkFormat format, const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign, const bool bufferLoadUniform)
753 : TestInstance (context)
754 , m_texture (texture)
755 , m_format (format)
756 , m_declareImageFormatInShader (declareImageFormatInShader)
757 , m_singleLayerBind (singleLayerBind)
758 , m_minalign (minalign)
759 , m_bufferLoadUniform (bufferLoadUniform)
760 , m_srcViewOffset (getViewOffset(context, format, m_bufferLoadUniform))
761 , m_dstViewOffset (getViewOffset(context, formatHasThreeComponents(format) ? getSingleComponentFormat(format) : format, false))
762 {
763 }
764
iterate(void)765 tcu::TestStatus BaseTestInstance::iterate (void)
766 {
767 const DeviceInterface& vk = m_context.getDeviceInterface();
768 const VkDevice device = m_context.getDevice();
769 const VkQueue queue = m_context.getUniversalQueue();
770 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
771
772 const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
773
774 const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
775 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
776 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
777
778 const Unique<VkCommandPool> cmdPool(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex));
779 const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
780
781 beginCommandBuffer(vk, *cmdBuffer);
782
783 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
784 commandBeforeCompute(*cmdBuffer);
785
786 const tcu::IVec3 workSize = (m_singleLayerBind ? m_texture.layerSize() : m_texture.size());
787 const int loopNumLayers = (m_singleLayerBind ? m_texture.numLayers() : 1);
788 for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
789 {
790 commandBindDescriptorsForLayer(*cmdBuffer, *pipelineLayout, layerNdx);
791
792 if (layerNdx > 0)
793 commandBetweenShaderInvocations(*cmdBuffer);
794
795 vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
796 }
797
798 commandAfterCompute(*cmdBuffer);
799
800 endCommandBuffer(vk, *cmdBuffer);
801
802 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
803
804 return verifyResult();
805 }
806
807 //! Base store test implementation
808 class StoreTestInstance : public BaseTestInstance
809 {
810 public:
811 StoreTestInstance (Context& context,
812 const Texture& texture,
813 const VkFormat format,
814 const bool declareImageFormatInShader,
815 const bool singleLayerBind,
816 const bool minalign,
817 const bool storeConstantValue);
818
819 protected:
820 virtual tcu::TestStatus verifyResult (void);
821
822 // Add empty implementations for functions that might be not needed
commandBeforeCompute(const VkCommandBuffer)823 void commandBeforeCompute (const VkCommandBuffer) {}
commandBetweenShaderInvocations(const VkCommandBuffer)824 void commandBetweenShaderInvocations (const VkCommandBuffer) {}
commandAfterCompute(const VkCommandBuffer)825 void commandAfterCompute (const VkCommandBuffer) {}
826
827 de::MovePtr<BufferWithMemory> m_imageBuffer;
828 const VkDeviceSize m_imageSizeBytes;
829 bool m_storeConstantValue;
830 };
831
getViewOffset(Context & context,const VkFormat format,bool uniform)832 deUint32 BaseTestInstance::getViewOffset(Context& context,
833 const VkFormat format,
834 bool uniform)
835 {
836 if (m_minalign)
837 {
838 if (!context.getTexelBufferAlignmentFeaturesEXT().texelBufferAlignment)
839 return (deUint32)context.getDeviceProperties().limits.minTexelBufferOffsetAlignment;
840
841 VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT alignmentProperties;
842 deMemset(&alignmentProperties, 0, sizeof(alignmentProperties));
843 alignmentProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT;
844
845 VkPhysicalDeviceProperties2 properties2;
846 deMemset(&properties2, 0, sizeof(properties2));
847 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
848 properties2.pNext = &alignmentProperties;
849
850 context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties2);
851
852 VkBool32 singleTexelAlignment = uniform ? alignmentProperties.uniformTexelBufferOffsetSingleTexelAlignment :
853 alignmentProperties.storageTexelBufferOffsetSingleTexelAlignment;
854 VkDeviceSize align = uniform ? alignmentProperties.uniformTexelBufferOffsetAlignmentBytes :
855 alignmentProperties.storageTexelBufferOffsetAlignmentBytes;
856
857 VkDeviceSize texelSize = formatHasThreeComponents(format) ? tcu::getChannelSize(vk::mapVkFormat(format).type) : tcu::getPixelSize(vk::mapVkFormat(format));
858
859 if (singleTexelAlignment)
860 align = de::min(align, texelSize);
861
862 return (deUint32)align;
863 }
864
865 return 0;
866 }
867
StoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool storeConstantValue)868 StoreTestInstance::StoreTestInstance (Context& context, const Texture& texture, const VkFormat format, const bool declareImageFormatInShader, const bool singleLayerBind, const bool minalign, const bool storeConstantValue)
869 : BaseTestInstance (context, texture, format, declareImageFormatInShader, singleLayerBind, minalign, false)
870 , m_imageSizeBytes (getImageSizeBytes(texture.size(), format))
871 , m_storeConstantValue (storeConstantValue)
872 {
873 const DeviceInterface& vk = m_context.getDeviceInterface();
874 const VkDevice device = m_context.getDevice();
875 Allocator& allocator = m_context.getDefaultAllocator();
876
877 // A helper buffer with enough space to hold the whole image. Usage flags accommodate all derived test instances.
878
879 m_imageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
880 vk, device, allocator,
881 makeBufferCreateInfo(m_imageSizeBytes + m_dstViewOffset, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
882 MemoryRequirement::HostVisible));
883 }
884
verifyResult(void)885 tcu::TestStatus StoreTestInstance::verifyResult (void)
886 {
887 const DeviceInterface& vk = m_context.getDeviceInterface();
888 const VkDevice device = m_context.getDevice();
889
890 const tcu::IVec3 imageSize = m_texture.size();
891 const tcu::TextureLevel reference = generateReferenceImage(imageSize, m_format, m_storeConstantValue);
892
893 const Allocation& alloc = m_imageBuffer->getAllocation();
894 invalidateAlloc(vk, device, alloc);
895 const tcu::ConstPixelBufferAccess result(mapVkFormat(m_format), imageSize, (const char *)alloc.getHostPtr() + m_dstViewOffset);
896
897 if (comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_format, reference.getAccess(), result))
898 return tcu::TestStatus::pass("Passed");
899 else
900 return tcu::TestStatus::fail("Image comparison failed");
901 }
902
903 //! Store test for images
904 class ImageStoreTestInstance : public StoreTestInstance
905 {
906 public:
907 ImageStoreTestInstance (Context& context,
908 const Texture& texture,
909 const VkFormat format,
910 const VkImageTiling tiling,
911 const bool declareImageFormatInShader,
912 const bool singleLayerBind,
913 const bool minalign,
914 const bool storeConstantValue);
915
916 protected:
917 VkDescriptorSetLayout prepareDescriptors (void);
918 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
919 void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer);
920 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
921
922 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
923 const VkPipelineLayout pipelineLayout,
924 const int layerNdx);
925
926 de::MovePtr<Image> m_image;
927 de::MovePtr<BufferWithMemory> m_constantsBuffer;
928 const VkDeviceSize m_constantsBufferChunkSizeBytes;
929 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
930 Move<VkDescriptorPool> m_descriptorPool;
931 std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
932 std::vector<SharedVkImageView> m_allImageViews;
933 };
934
ImageStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkImageTiling tiling,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool storeConstantValue)935 ImageStoreTestInstance::ImageStoreTestInstance (Context& context,
936 const Texture& texture,
937 const VkFormat format,
938 const VkImageTiling tiling,
939 const bool declareImageFormatInShader,
940 const bool singleLayerBind,
941 const bool minalign,
942 const bool storeConstantValue)
943 : StoreTestInstance (context, texture, format, declareImageFormatInShader, singleLayerBind, minalign, storeConstantValue)
944 , m_constantsBufferChunkSizeBytes (getOptimalUniformBufferChunkSize(context.getInstanceInterface(), context.getPhysicalDevice(), sizeof(deUint32)))
945 , m_allDescriptorSets (texture.numLayers())
946 , m_allImageViews (texture.numLayers())
947 {
948 const DeviceInterface& vk = m_context.getDeviceInterface();
949 const VkDevice device = m_context.getDevice();
950 Allocator& allocator = m_context.getDefaultAllocator();
951
952 m_image = de::MovePtr<Image>(new Image(
953 vk, device, allocator,
954 makeImageCreateInfo(m_texture, m_format, (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), 0u, tiling),
955 MemoryRequirement::Any));
956
957 // This buffer will be used to pass constants to the shader
958
959 const int numLayers = m_texture.numLayers();
960 const VkDeviceSize constantsBufferSizeBytes = numLayers * m_constantsBufferChunkSizeBytes;
961 m_constantsBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
962 vk, device, allocator,
963 makeBufferCreateInfo(constantsBufferSizeBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
964 MemoryRequirement::HostVisible));
965
966 {
967 const Allocation& alloc = m_constantsBuffer->getAllocation();
968 deUint8* const basePtr = static_cast<deUint8*>(alloc.getHostPtr());
969
970 deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(constantsBufferSizeBytes));
971
972 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
973 {
974 deUint32* valuePtr = reinterpret_cast<deUint32*>(basePtr + layerNdx * m_constantsBufferChunkSizeBytes);
975 *valuePtr = static_cast<deUint32>(layerNdx);
976 }
977
978 flushAlloc(vk, device, alloc);
979 }
980 }
981
prepareDescriptors(void)982 VkDescriptorSetLayout ImageStoreTestInstance::prepareDescriptors (void)
983 {
984 const DeviceInterface& vk = m_context.getDeviceInterface();
985 const VkDevice device = m_context.getDevice();
986
987 const int numLayers = m_texture.numLayers();
988 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
989 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
990 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
991 .build(vk, device);
992
993 m_descriptorPool = DescriptorPoolBuilder()
994 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
995 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, numLayers)
996 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
997
998 if (m_singleLayerBind)
999 {
1000 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1001 {
1002 m_allDescriptorSets[layerNdx] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1003 m_allImageViews[layerNdx] = makeVkSharedPtr(makeImageView(
1004 vk, device, m_image->get(), mapImageViewType(getImageTypeForSingleLayer(m_texture.type())), m_format,
1005 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u)));
1006 }
1007 }
1008 else // bind all layers at once
1009 {
1010 m_allDescriptorSets[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1011 m_allImageViews[0] = makeVkSharedPtr(makeImageView(
1012 vk, device, m_image->get(), mapImageViewType(m_texture.type()), m_format,
1013 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers)));
1014 }
1015
1016 return *m_descriptorSetLayout; // not passing the ownership
1017 }
1018
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1019 void ImageStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
1020 {
1021 const DeviceInterface& vk = m_context.getDeviceInterface();
1022 const VkDevice device = m_context.getDevice();
1023
1024 const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
1025 const VkImageView imageView = **m_allImageViews[layerNdx];
1026
1027 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, imageView, VK_IMAGE_LAYOUT_GENERAL);
1028
1029 // Set the next chunk of the constants buffer. Each chunk begins with layer index that we've set before.
1030 const VkDescriptorBufferInfo descriptorConstantsBufferInfo = makeDescriptorBufferInfo(
1031 m_constantsBuffer->get(), layerNdx*m_constantsBufferChunkSizeBytes, m_constantsBufferChunkSizeBytes);
1032
1033 DescriptorSetUpdateBuilder()
1034 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1035 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
1036 .update(vk, device);
1037 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
1038 }
1039
commandBeforeCompute(const VkCommandBuffer cmdBuffer)1040 void ImageStoreTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
1041 {
1042 const DeviceInterface& vk = m_context.getDeviceInterface();
1043
1044 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
1045 const VkImageMemoryBarrier setImageLayoutBarrier = makeImageMemoryBarrier(
1046 0u, VK_ACCESS_SHADER_WRITE_BIT,
1047 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1048 m_image->get(), fullImageSubresourceRange);
1049
1050 const VkDeviceSize constantsBufferSize = m_texture.numLayers() * m_constantsBufferChunkSizeBytes;
1051 const VkBufferMemoryBarrier writeConstantsBarrier = makeBufferMemoryBarrier(
1052 VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
1053 m_constantsBuffer->get(), 0ull, constantsBufferSize);
1054
1055 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &writeConstantsBarrier, 1, &setImageLayoutBarrier);
1056 }
1057
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)1058 void ImageStoreTestInstance::commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer)
1059 {
1060 commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_image->get(), m_texture);
1061 }
1062
commandAfterCompute(const VkCommandBuffer cmdBuffer)1063 void ImageStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
1064 {
1065 commandCopyImageToBuffer(m_context, cmdBuffer, m_image->get(), m_imageBuffer->get(), m_imageSizeBytes, m_texture);
1066 }
1067
1068 //! Store test for buffers
1069 class BufferStoreTestInstance : public StoreTestInstance
1070 {
1071 public:
1072 BufferStoreTestInstance (Context& context,
1073 const Texture& texture,
1074 const VkFormat format,
1075 const bool declareImageFormatInShader,
1076 const bool minalign,
1077 const bool storeConstantValue);
1078
1079 protected:
1080 VkDescriptorSetLayout prepareDescriptors (void);
1081 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
1082
1083 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
1084 const VkPipelineLayout pipelineLayout,
1085 const int layerNdx);
1086
1087 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1088 Move<VkDescriptorPool> m_descriptorPool;
1089 Move<VkDescriptorSet> m_descriptorSet;
1090 Move<VkBufferView> m_bufferView;
1091 };
1092
BufferStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool declareImageFormatInShader,const bool minalign,const bool storeConstantValue)1093 BufferStoreTestInstance::BufferStoreTestInstance (Context& context,
1094 const Texture& texture,
1095 const VkFormat format,
1096 const bool declareImageFormatInShader,
1097 const bool minalign,
1098 const bool storeConstantValue)
1099 : StoreTestInstance(context, texture, format, declareImageFormatInShader, false, minalign, storeConstantValue)
1100 {
1101 }
1102
prepareDescriptors(void)1103 VkDescriptorSetLayout BufferStoreTestInstance::prepareDescriptors (void)
1104 {
1105 const DeviceInterface& vk = m_context.getDeviceInterface();
1106 const VkDevice device = m_context.getDevice();
1107
1108 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1109 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1110 .build(vk, device);
1111
1112 m_descriptorPool = DescriptorPoolBuilder()
1113 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
1114 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1115
1116 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1117 m_bufferView = makeBufferView(vk, device, m_imageBuffer->get(), m_format, m_dstViewOffset, m_imageSizeBytes);
1118
1119 return *m_descriptorSetLayout; // not passing the ownership
1120 }
1121
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1122 void BufferStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
1123 {
1124 DE_ASSERT(layerNdx == 0);
1125 DE_UNREF(layerNdx);
1126
1127 const VkDevice device = m_context.getDevice();
1128 const DeviceInterface& vk = m_context.getDeviceInterface();
1129
1130 DescriptorSetUpdateBuilder()
1131 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
1132 .update(vk, device);
1133 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
1134 }
1135
commandAfterCompute(const VkCommandBuffer cmdBuffer)1136 void BufferStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
1137 {
1138 commandBufferWriteBarrierBeforeHostRead(m_context, cmdBuffer, m_imageBuffer->get(), m_imageSizeBytes + m_dstViewOffset);
1139 }
1140
1141 class LoadStoreTest : public TestCase
1142 {
1143 public:
1144 enum TestFlags
1145 {
1146 FLAG_SINGLE_LAYER_BIND = (1 << 0), //!< Run the shader multiple times, each time binding a different layer.
1147 FLAG_RESTRICT_IMAGES = (1 << 1), //!< If given, images in the shader will be qualified with "restrict".
1148 FLAG_DECLARE_FORMAT_IN_SHADER_READS = (1 << 2), //!< Declare the format of images being read in the shader code
1149 FLAG_DECLARE_FORMAT_IN_SHADER_WRITES = (1 << 3), //!< Declare the format of images being read in the shader code
1150 FLAG_MINALIGN = (1 << 4), //!< Use bufferview offset that matches the advertised minimum alignment
1151 FLAG_UNIFORM_TEXEL_BUFFER = (1 << 5), //!< Load from a uniform texel buffer rather than a storage texel buffer
1152 };
1153
1154 LoadStoreTest (tcu::TestContext& testCtx,
1155 const std::string& name,
1156 const Texture& texture,
1157 const VkFormat format,
1158 const VkFormat imageFormat,
1159 const VkImageTiling tiling,
1160 const deUint32 flags = (FLAG_DECLARE_FORMAT_IN_SHADER_READS | FLAG_DECLARE_FORMAT_IN_SHADER_WRITES),
1161 const deBool imageLoadStoreLodAMD = DE_FALSE);
1162
1163 virtual void checkSupport (Context& context) const;
1164 void initPrograms (SourceCollections& programCollection) const;
1165 TestInstance* createInstance (Context& context) const;
1166
1167 private:
1168 const Texture m_texture;
1169 const VkFormat m_format; //!< Format as accessed in the shader
1170 const VkFormat m_imageFormat; //!< Storage format
1171 const VkImageTiling m_tiling; //!< Image Tiling
1172 const bool m_declareFormatInShaderReads; //!< Whether the shader will specify the format layout qualifier of images being read from.
1173 const bool m_declareFormatInShaderWrites; //!< Whether the shader will specify the format layout qualifier of images being written to.
1174 const bool m_singleLayerBind;
1175 const bool m_restrictImages;
1176 const bool m_minalign;
1177 bool m_bufferLoadUniform;
1178 const deBool m_imageLoadStoreLodAMD;
1179 };
1180
LoadStoreTest(tcu::TestContext & testCtx,const std::string & name,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const VkImageTiling tiling,const deUint32 flags,const deBool imageLoadStoreLodAMD)1181 LoadStoreTest::LoadStoreTest (tcu::TestContext& testCtx,
1182 const std::string& name,
1183 const Texture& texture,
1184 const VkFormat format,
1185 const VkFormat imageFormat,
1186 const VkImageTiling tiling,
1187 const deUint32 flags,
1188 const deBool imageLoadStoreLodAMD)
1189 : TestCase (testCtx, name)
1190 , m_texture (texture)
1191 , m_format (format)
1192 , m_imageFormat (imageFormat)
1193 , m_tiling (tiling)
1194 , m_declareFormatInShaderReads ((flags & FLAG_DECLARE_FORMAT_IN_SHADER_READS) != 0)
1195 , m_declareFormatInShaderWrites ((flags & FLAG_DECLARE_FORMAT_IN_SHADER_WRITES) != 0)
1196 , m_singleLayerBind ((flags & FLAG_SINGLE_LAYER_BIND) != 0)
1197 , m_restrictImages ((flags & FLAG_RESTRICT_IMAGES) != 0)
1198 , m_minalign ((flags & FLAG_MINALIGN) != 0)
1199 , m_bufferLoadUniform ((flags & FLAG_UNIFORM_TEXEL_BUFFER) != 0)
1200 , m_imageLoadStoreLodAMD (imageLoadStoreLodAMD)
1201 {
1202 if (m_singleLayerBind)
1203 DE_ASSERT(m_texture.numLayers() > 1);
1204
1205 DE_ASSERT(formatsAreCompatible(m_format, m_imageFormat));
1206 }
1207
checkSupport(Context & context) const1208 void LoadStoreTest::checkSupport (Context& context) const
1209 {
1210 #ifndef CTS_USES_VULKANSC
1211 if (m_format == VK_FORMAT_A8_UNORM_KHR || m_format == VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR)
1212 context.requireDeviceFunctionality("VK_KHR_maintenance5");
1213
1214 const VkFormatProperties3 formatProperties (context.getFormatProperties(m_format));
1215 const VkFormatProperties3 imageFormatProperties (context.getFormatProperties(m_imageFormat));
1216
1217 const auto& tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures : formatProperties.linearTilingFeatures;
1218 const auto& imageTilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? imageFormatProperties.optimalTilingFeatures : imageFormatProperties.linearTilingFeatures;
1219
1220 if (m_imageLoadStoreLodAMD)
1221 context.requireDeviceFunctionality("VK_AMD_shader_image_load_store_lod");
1222
1223 if (!m_bufferLoadUniform && !m_declareFormatInShaderReads && !(tilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT))
1224 TCU_THROW(NotSupportedError, "Format not supported for unformatted loads via storage images");
1225
1226 if (m_texture.type() == IMAGE_TYPE_BUFFER && !m_declareFormatInShaderReads && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT))
1227 TCU_THROW(NotSupportedError, "Format not supported for unformatted loads via buffers");
1228
1229 if (!m_declareFormatInShaderWrites && !(tilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT))
1230 TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via storage images");
1231
1232 if (m_texture.type() == IMAGE_TYPE_BUFFER && !m_declareFormatInShaderWrites && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT))
1233 TCU_THROW(NotSupportedError, "Format not supported for unformatted stores via buffers");
1234
1235 if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
1236 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
1237
1238 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1239 TCU_THROW(NotSupportedError, "Format not supported for storage images");
1240
1241 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1242 TCU_THROW(NotSupportedError, "Format not supported for storage images");
1243
1244 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1245 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1246
1247 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures))
1248 TCU_THROW(NotSupportedError, "Underlying format not supported at all for images");
1249
1250 if ((m_texture.type() == IMAGE_TYPE_BUFFER) && !(imageFormatProperties.bufferFeatures))
1251 TCU_THROW(NotSupportedError, "Underlying format not supported at all for buffers");
1252
1253 if (formatHasThreeComponents(m_format))
1254 {
1255 // When the source buffer is three-component, the destination buffer is single-component.
1256 VkFormat dstFormat = getSingleComponentFormat(m_format);
1257 const VkFormatProperties3 dstFormatProperties (context.getFormatProperties(dstFormat));
1258
1259 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(dstFormatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1260 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1261 }
1262 else
1263 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1264 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1265
1266 if (m_bufferLoadUniform && m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT))
1267 TCU_THROW(NotSupportedError, "Format not supported for uniform texel buffers");
1268 #else
1269 const vk::VkFormatProperties formatProperties (vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
1270 context.getPhysicalDevice(),
1271 m_format));
1272 const vk::VkFormatProperties imageFormatProperties (vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
1273 context.getPhysicalDevice(),
1274 m_imageFormat));
1275
1276 const auto tilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? formatProperties.optimalTilingFeatures : formatProperties.linearTilingFeatures;
1277 const auto imageTilingFeatures = (m_tiling == vk::VK_IMAGE_TILING_OPTIMAL) ? imageFormatProperties.optimalTilingFeatures : imageFormatProperties.linearTilingFeatures;
1278
1279 if (m_imageLoadStoreLodAMD)
1280 context.requireDeviceFunctionality("VK_AMD_shader_image_load_store_lod");
1281
1282 if (!m_bufferLoadUniform && !m_declareFormatInShaderReads)
1283 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_READ_WITHOUT_FORMAT);
1284
1285 if (!m_declareFormatInShaderWrites)
1286 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT);
1287
1288 if (m_texture.type() == IMAGE_TYPE_CUBE_ARRAY)
1289 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
1290
1291 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(tilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1292 TCU_THROW(NotSupportedError, "Format not supported for storage images");
1293
1294 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
1295 TCU_THROW(NotSupportedError, "Format not supported for storage images");
1296
1297 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1298 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1299
1300 if ((m_texture.type() != IMAGE_TYPE_BUFFER) && !(imageTilingFeatures))
1301 TCU_THROW(NotSupportedError, "Underlying format not supported at all for images");
1302
1303 if ((m_texture.type() == IMAGE_TYPE_BUFFER) && !(imageFormatProperties.bufferFeatures))
1304 TCU_THROW(NotSupportedError, "Underlying format not supported at all for buffers");
1305
1306 if (formatHasThreeComponents(m_format))
1307 {
1308 // When the source buffer is three-component, the destination buffer is single-component.
1309 VkFormat dstFormat = getSingleComponentFormat(m_format);
1310 const vk::VkFormatProperties dstFormatProperties (vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
1311 context.getPhysicalDevice(),
1312 dstFormat));
1313
1314 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(dstFormatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1315 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1316 }
1317 else
1318 if (m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
1319 TCU_THROW(NotSupportedError, "Format not supported for storage texel buffers");
1320
1321 if (m_bufferLoadUniform && m_texture.type() == IMAGE_TYPE_BUFFER && !(formatProperties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT))
1322 TCU_THROW(NotSupportedError, "Format not supported for uniform texel buffers");
1323 #endif // CTS_USES_VULKANSC
1324
1325 const auto& vki = context.getInstanceInterface();
1326 const auto physicalDevice = context.getPhysicalDevice();
1327
1328 VkImageFormatProperties vkImageFormatProperties;
1329 const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_imageFormat, mapImageType(m_texture.type()), m_tiling, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, &vkImageFormatProperties);
1330
1331 if (result != VK_SUCCESS)
1332 {
1333 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
1334 TCU_THROW(NotSupportedError, "Format unsupported for tiling");
1335 else
1336 TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned unexpected error");
1337 }
1338
1339 if (vkImageFormatProperties.maxArrayLayers < (uint32_t)m_texture.numLayers()) {
1340 TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of aray layers");
1341 }
1342
1343 if (vkImageFormatProperties.maxMipLevels < (uint32_t)m_texture.numMipmapLevels()) {
1344 TCU_THROW(NotSupportedError, "This format and tiling combination does not support this number of miplevels");
1345 }
1346 }
1347
initPrograms(SourceCollections & programCollection) const1348 void LoadStoreTest::initPrograms (SourceCollections& programCollection) const
1349 {
1350 const tcu::TextureFormat texFormat = mapVkFormat(m_format);
1351 const int dimension = (m_singleLayerBind ? m_texture.layerDimension() : m_texture.dimension());
1352 const ImageType usedImageType = (m_singleLayerBind ? getImageTypeForSingleLayer(m_texture.type()) : m_texture.type());
1353 const bool noFormats = (!m_declareFormatInShaderReads && !m_declareFormatInShaderWrites);
1354 const std::string formatQualifierStr = (noFormats ? "" : getShaderImageFormatQualifier(texFormat));
1355 const std::string uniformTypeStr = getFormatPrefix(texFormat) + "textureBuffer";
1356 const std::string imageTypeStr = getShaderImageType(texFormat, usedImageType);
1357 const std::string maybeRestrictStr = (m_restrictImages ? "restrict " : "");
1358 const std::string xMax = de::toString(m_texture.size().x() - 1);
1359
1360 std::ostringstream src;
1361 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1362 << "\n";
1363
1364 if (!m_declareFormatInShaderReads || !m_declareFormatInShaderWrites)
1365 {
1366 src << "#extension GL_EXT_shader_image_load_formatted : require\n";
1367 }
1368
1369 if (m_imageLoadStoreLodAMD)
1370 {
1371 src << "#extension GL_AMD_shader_image_load_store_lod : require\n";
1372 }
1373
1374 const std::string maybeFmtQualStrReads = m_declareFormatInShaderReads ? ", " + formatQualifierStr : "";
1375 const std::string maybeFmtQualStrWrites = m_declareFormatInShaderWrites ? ", " + formatQualifierStr : "";
1376
1377 src << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
1378
1379 if (m_bufferLoadUniform)
1380 src << "layout (binding = 0) uniform " << uniformTypeStr << " u_image0;\n";
1381 else
1382 src << "layout (binding = 0" << maybeFmtQualStrReads << ") " << maybeRestrictStr << "readonly uniform " << imageTypeStr << " u_image0;\n";
1383
1384 // For three-component formats, the dst buffer is single-component and the shader expands the store into 3 component-wise stores.
1385 // We always use the format qualifier for the dst buffer, except when splitting it up.
1386 if (formatHasThreeComponents(m_format))
1387 src << "layout (binding = 1) " << maybeRestrictStr << "writeonly uniform " << imageTypeStr << " u_image1;\n";
1388 else
1389 src << "layout (binding = 1" << maybeFmtQualStrWrites << ") " << maybeRestrictStr << "writeonly uniform " << imageTypeStr << " u_image1;\n";
1390
1391 src << "\n"
1392 << "void main (void)\n"
1393 << "{\n";
1394
1395 switch (dimension)
1396 {
1397 default: DE_ASSERT(0); // fallthrough
1398 case 1:
1399 if (m_bufferLoadUniform)
1400 {
1401 // Expand the store into 3 component-wise stores.
1402 std::string type = getFormatPrefix(texFormat) + "vec4";
1403 src << " int pos = int(gl_GlobalInvocationID.x);\n"
1404 " " << type << " t = texelFetch(u_image0, " + xMax + "-pos);\n";
1405 if (formatHasThreeComponents(m_format))
1406 {
1407 src << " imageStore(u_image1, 3*pos+0, " << type << "(t.x));\n";
1408 src << " imageStore(u_image1, 3*pos+1, " << type << "(t.y));\n";
1409 src << " imageStore(u_image1, 3*pos+2, " << type << "(t.z));\n";
1410 }
1411 else
1412 src << " imageStore(u_image1, pos, t);\n";
1413 }
1414 else if (m_imageLoadStoreLodAMD)
1415 {
1416 src <<
1417 " int pos = int(gl_GlobalInvocationID.x);\n";
1418
1419 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1420 {
1421 std::string xMaxSize = de::toString(deMax32(((m_texture.layerSize().x() >> levelNdx) - 1), 1u));
1422 src << " imageStoreLodAMD(u_image1, pos, " + de::toString(levelNdx) + ", imageLoadLodAMD(u_image0, " + xMaxSize + "-pos, " + de::toString(levelNdx) + "));\n";
1423 }
1424 }
1425 else
1426 {
1427 src <<
1428 " int pos = int(gl_GlobalInvocationID.x);\n"
1429 " imageStore(u_image1, pos, imageLoad(u_image0, " + xMax + "-pos));\n";
1430 }
1431 break;
1432 case 2:
1433 if (m_imageLoadStoreLodAMD)
1434 {
1435 src << " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n";
1436
1437 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1438 {
1439 std::string xMaxSize = de::toString(deMax32(((m_texture.layerSize().x() >> levelNdx) - 1), 1u));
1440 src << " imageStoreLodAMD(u_image1, pos, " + de::toString(levelNdx) + ", imageLoadLodAMD(u_image0, ivec2(" + xMaxSize + "-pos.x, pos.y), " + de::toString(levelNdx) + "));\n";
1441 }
1442
1443 }
1444 else
1445 {
1446 src <<
1447 " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
1448 " imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" + xMax + "-pos.x, pos.y)));\n";
1449 }
1450 break;
1451 case 3:
1452 if (m_imageLoadStoreLodAMD)
1453 {
1454 src << " ivec3 pos = ivec3(gl_GlobalInvocationID);\n";
1455
1456 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1457 {
1458 std::string xMaxSize = de::toString(deMax32(((m_texture.layerSize().x() >> levelNdx) - 1), 1u));
1459 src << " imageStoreLodAMD(u_image1, pos, " + de::toString(levelNdx) + ", imageLoadLodAMD(u_image0, ivec3(" + xMaxSize + "-pos.x, pos.y, pos.z), " + de::toString(levelNdx) + "));\n";
1460 }
1461 }
1462 else
1463 {
1464 src <<
1465 " ivec3 pos = ivec3(gl_GlobalInvocationID);\n"
1466 " imageStore(u_image1, pos, imageLoad(u_image0, ivec3(" + xMax + "-pos.x, pos.y, pos.z)));\n";
1467 }
1468 break;
1469 }
1470 src << "}\n";
1471
1472 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
1473 }
1474
1475 //! Load/store test base implementation
1476 class LoadStoreTestInstance : public BaseTestInstance
1477 {
1478 public:
1479 LoadStoreTestInstance (Context& context,
1480 const Texture& texture,
1481 const VkFormat format,
1482 const VkFormat imageFormat,
1483 const bool declareImageFormatInShader,
1484 const bool singleLayerBind,
1485 const bool minalign,
1486 const bool bufferLoadUniform);
1487
1488 protected:
1489 virtual BufferWithMemory* getResultBuffer (void) const = 0; //!< Get the buffer that contains the result image
1490
1491 tcu::TestStatus verifyResult (void);
1492
1493 // Add empty implementations for functions that might be not needed
commandBeforeCompute(const VkCommandBuffer)1494 void commandBeforeCompute (const VkCommandBuffer) {}
commandBetweenShaderInvocations(const VkCommandBuffer)1495 void commandBetweenShaderInvocations (const VkCommandBuffer) {}
commandAfterCompute(const VkCommandBuffer)1496 void commandAfterCompute (const VkCommandBuffer) {}
1497
1498 de::MovePtr<BufferWithMemory> m_imageBuffer; //!< Source data and helper buffer
1499 const VkDeviceSize m_imageSizeBytes;
1500 const VkFormat m_imageFormat; //!< Image format (for storage, may be different than texture format)
1501 tcu::TextureLevel m_referenceImage; //!< Used as input data and later to verify result image
1502
1503 bool m_bufferLoadUniform;
1504 VkDescriptorType m_bufferLoadDescriptorType;
1505 VkBufferUsageFlagBits m_bufferLoadUsageBit;
1506 };
1507
LoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)1508 LoadStoreTestInstance::LoadStoreTestInstance (Context& context,
1509 const Texture& texture,
1510 const VkFormat format,
1511 const VkFormat imageFormat,
1512 const bool declareImageFormatInShader,
1513 const bool singleLayerBind,
1514 const bool minalign,
1515 const bool bufferLoadUniform)
1516 : BaseTestInstance (context, texture, format, declareImageFormatInShader, singleLayerBind, minalign, bufferLoadUniform)
1517 , m_imageSizeBytes (getImageSizeBytes(texture.size(), format))
1518 , m_imageFormat (imageFormat)
1519 , m_referenceImage (generateReferenceImage(texture.size(), imageFormat, format))
1520 , m_bufferLoadUniform (bufferLoadUniform)
1521 {
1522 const DeviceInterface& vk = m_context.getDeviceInterface();
1523 const VkDevice device = m_context.getDevice();
1524 Allocator& allocator = m_context.getDefaultAllocator();
1525
1526 m_bufferLoadDescriptorType = m_bufferLoadUniform ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1527 m_bufferLoadUsageBit = m_bufferLoadUniform ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
1528
1529 // A helper buffer with enough space to hold the whole image.
1530
1531 m_imageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
1532 vk, device, allocator,
1533 makeBufferCreateInfo(m_imageSizeBytes + m_srcViewOffset, m_bufferLoadUsageBit | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
1534 MemoryRequirement::HostVisible));
1535
1536 // Copy reference data to buffer for subsequent upload to image.
1537
1538 const Allocation& alloc = m_imageBuffer->getAllocation();
1539 deMemcpy((char *)alloc.getHostPtr() + m_srcViewOffset, m_referenceImage.getAccess().getDataPtr(), static_cast<size_t>(m_imageSizeBytes));
1540 flushAlloc(vk, device, alloc);
1541 }
1542
verifyResult(void)1543 tcu::TestStatus LoadStoreTestInstance::verifyResult (void)
1544 {
1545 const DeviceInterface& vk = m_context.getDeviceInterface();
1546 const VkDevice device = m_context.getDevice();
1547
1548 // Apply the same transformation as done in the shader
1549 const tcu::PixelBufferAccess reference = m_referenceImage.getAccess();
1550 flipHorizontally(reference);
1551
1552 const Allocation& alloc = getResultBuffer()->getAllocation();
1553 invalidateAlloc(vk, device, alloc);
1554 const tcu::ConstPixelBufferAccess result(mapVkFormat(m_imageFormat), m_texture.size(), (const char *)alloc.getHostPtr() + m_dstViewOffset);
1555
1556 if (comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_imageFormat, reference, result))
1557 return tcu::TestStatus::pass("Passed");
1558 else
1559 return tcu::TestStatus::fail("Image comparison failed");
1560 }
1561
1562 //! Load/store test for images
1563 class ImageLoadStoreTestInstance : public LoadStoreTestInstance
1564 {
1565 public:
1566 ImageLoadStoreTestInstance (Context& context,
1567 const Texture& texture,
1568 const VkFormat format,
1569 const VkFormat imageFormat,
1570 const VkImageTiling tiling,
1571 const bool declareImageFormatInShader,
1572 const bool singleLayerBind,
1573 const bool minalign,
1574 const bool bufferLoadUniform);
1575
1576 protected:
1577 VkDescriptorSetLayout prepareDescriptors (void);
1578 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
1579 void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer);
1580 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
1581
1582 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
1583 const VkPipelineLayout pipelineLayout,
1584 const int layerNdx);
1585
getResultBuffer(void) const1586 BufferWithMemory* getResultBuffer (void) const { return m_imageBuffer.get(); }
1587
1588 de::MovePtr<Image> m_imageSrc;
1589 de::MovePtr<Image> m_imageDst;
1590 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1591 Move<VkDescriptorPool> m_descriptorPool;
1592 std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
1593 std::vector<SharedVkImageView> m_allSrcImageViews;
1594 std::vector<SharedVkImageView> m_allDstImageViews;
1595 };
1596
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)1597 ImageLoadStoreTestInstance::ImageLoadStoreTestInstance (Context& context,
1598 const Texture& texture,
1599 const VkFormat format,
1600 const VkFormat imageFormat,
1601 const VkImageTiling tiling,
1602 const bool declareImageFormatInShader,
1603 const bool singleLayerBind,
1604 const bool minalign,
1605 const bool bufferLoadUniform)
1606 : LoadStoreTestInstance (context, texture, format, imageFormat, declareImageFormatInShader, singleLayerBind, minalign, bufferLoadUniform)
1607 , m_allDescriptorSets (texture.numLayers())
1608 , m_allSrcImageViews (texture.numLayers())
1609 , m_allDstImageViews (texture.numLayers())
1610 {
1611 const DeviceInterface& vk = m_context.getDeviceInterface();
1612 const VkDevice device = m_context.getDevice();
1613 Allocator& allocator = m_context.getDefaultAllocator();
1614 const VkImageCreateFlags imageFlags = (m_format == m_imageFormat ? 0u : (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT);
1615
1616 m_imageSrc = de::MovePtr<Image>(new Image(
1617 vk, device, allocator,
1618 makeImageCreateInfo(m_texture, m_imageFormat, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, imageFlags, tiling),
1619 MemoryRequirement::Any));
1620
1621 m_imageDst = de::MovePtr<Image>(new Image(
1622 vk, device, allocator,
1623 makeImageCreateInfo(m_texture, m_imageFormat, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, imageFlags, tiling),
1624 MemoryRequirement::Any));
1625 }
1626
prepareDescriptors(void)1627 VkDescriptorSetLayout ImageLoadStoreTestInstance::prepareDescriptors (void)
1628 {
1629 const VkDevice device = m_context.getDevice();
1630 const DeviceInterface& vk = m_context.getDeviceInterface();
1631
1632 const int numLayers = m_texture.numLayers();
1633 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1634 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1635 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1636 .build(vk, device);
1637
1638 m_descriptorPool = DescriptorPoolBuilder()
1639 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1640 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1641 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
1642
1643 if (m_singleLayerBind)
1644 {
1645 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1646 {
1647 const VkImageViewType viewType = mapImageViewType(getImageTypeForSingleLayer(m_texture.type()));
1648 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u);
1649
1650 m_allDescriptorSets[layerNdx] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1651 m_allSrcImageViews[layerNdx] = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1652 m_allDstImageViews[layerNdx] = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1653 }
1654 }
1655 else // bind all layers at once
1656 {
1657 const VkImageViewType viewType = mapImageViewType(m_texture.type());
1658 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers);
1659
1660 m_allDescriptorSets[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1661 m_allSrcImageViews[0] = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1662 m_allDstImageViews[0] = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1663 }
1664
1665 return *m_descriptorSetLayout; // not passing the ownership
1666 }
1667
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1668 void ImageLoadStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
1669 {
1670 const VkDevice device = m_context.getDevice();
1671 const DeviceInterface& vk = m_context.getDeviceInterface();
1672
1673 const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
1674 const VkImageView srcImageView = **m_allSrcImageViews[layerNdx];
1675 const VkImageView dstImageView = **m_allDstImageViews[layerNdx];
1676
1677 const VkDescriptorImageInfo descriptorSrcImageInfo = makeDescriptorImageInfo(DE_NULL, srcImageView, VK_IMAGE_LAYOUT_GENERAL);
1678 const VkDescriptorImageInfo descriptorDstImageInfo = makeDescriptorImageInfo(DE_NULL, dstImageView, VK_IMAGE_LAYOUT_GENERAL);
1679
1680 DescriptorSetUpdateBuilder()
1681 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorSrcImageInfo)
1682 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorDstImageInfo)
1683 .update(vk, device);
1684 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
1685 }
1686
commandBeforeCompute(const VkCommandBuffer cmdBuffer)1687 void ImageLoadStoreTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
1688 {
1689 const DeviceInterface& vk = m_context.getDeviceInterface();
1690
1691 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
1692 {
1693 const VkImageMemoryBarrier preCopyImageBarriers[] =
1694 {
1695 makeImageMemoryBarrier(
1696 0u, VK_ACCESS_TRANSFER_WRITE_BIT,
1697 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1698 m_imageSrc->get(), fullImageSubresourceRange),
1699 makeImageMemoryBarrier(
1700 0u, VK_ACCESS_SHADER_WRITE_BIT,
1701 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1702 m_imageDst->get(), fullImageSubresourceRange)
1703 };
1704
1705 const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy = makeBufferMemoryBarrier(
1706 VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1707 m_imageBuffer->get(), 0ull, m_imageSizeBytes + m_srcViewOffset);
1708
1709 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
1710 (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &barrierFlushHostWriteBeforeCopy, DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
1711 }
1712 {
1713 const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
1714 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
1715 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
1716 m_imageSrc->get(), fullImageSubresourceRange);
1717
1718 const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_texture);
1719
1720 vk.cmdCopyBufferToImage(cmdBuffer, m_imageBuffer->get(), m_imageSrc->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region);
1721 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &barrierAfterCopy);
1722 }
1723 }
1724
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)1725 void ImageLoadStoreTestInstance::commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer)
1726 {
1727 commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture);
1728 }
1729
commandAfterCompute(const VkCommandBuffer cmdBuffer)1730 void ImageLoadStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
1731 {
1732 commandCopyImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_imageBuffer->get(), m_imageSizeBytes, m_texture);
1733 }
1734
1735 //! Load/store Lod AMD test for images
1736 class ImageLoadStoreLodAMDTestInstance : public BaseTestInstance
1737 {
1738 public:
1739 ImageLoadStoreLodAMDTestInstance (Context& context,
1740 const Texture& texture,
1741 const VkFormat format,
1742 const VkFormat imageFormat,
1743 const bool declareImageFormatInShader,
1744 const bool singleLayerBind,
1745 const bool minalign,
1746 const bool bufferLoadUniform);
1747
1748 protected:
1749 VkDescriptorSetLayout prepareDescriptors (void);
1750 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
1751 void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer);
1752 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
1753
1754 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
1755 const VkPipelineLayout pipelineLayout,
1756 const int layerNdx);
1757
getResultBuffer(void) const1758 BufferWithMemory* getResultBuffer (void) const { return m_imageBuffer.get(); }
1759 tcu::TestStatus verifyResult (void);
1760
1761 de::MovePtr<BufferWithMemory> m_imageBuffer; //!< Source data and helper buffer
1762 const VkDeviceSize m_imageSizeBytes;
1763 const VkFormat m_imageFormat; //!< Image format (for storage, may be different than texture format)
1764 std::vector<tcu::TextureLevel> m_referenceImages; //!< Used as input data and later to verify result image
1765
1766 bool m_bufferLoadUniform;
1767 VkDescriptorType m_bufferLoadDescriptorType;
1768 VkBufferUsageFlagBits m_bufferLoadUsageBit;
1769
1770 de::MovePtr<Image> m_imageSrc;
1771 de::MovePtr<Image> m_imageDst;
1772 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1773 Move<VkDescriptorPool> m_descriptorPool;
1774 std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
1775 std::vector<SharedVkImageView> m_allSrcImageViews;
1776 std::vector<SharedVkImageView> m_allDstImageViews;
1777
1778 };
1779
ImageLoadStoreLodAMDTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool declareImageFormatInShader,const bool singleLayerBind,const bool minalign,const bool bufferLoadUniform)1780 ImageLoadStoreLodAMDTestInstance::ImageLoadStoreLodAMDTestInstance (Context& context,
1781 const Texture& texture,
1782 const VkFormat format,
1783 const VkFormat imageFormat,
1784 const bool declareImageFormatInShader,
1785 const bool singleLayerBind,
1786 const bool minalign,
1787 const bool bufferLoadUniform)
1788 : BaseTestInstance (context, texture, format, declareImageFormatInShader, singleLayerBind, minalign, bufferLoadUniform)
1789 , m_imageSizeBytes (getMipmapImageTotalSizeBytes(texture, format))
1790 , m_imageFormat (imageFormat)
1791 , m_bufferLoadUniform (bufferLoadUniform)
1792 , m_allDescriptorSets (texture.numLayers())
1793 , m_allSrcImageViews (texture.numLayers())
1794 , m_allDstImageViews (texture.numLayers())
1795 {
1796 const DeviceInterface& vk = m_context.getDeviceInterface();
1797 const VkDevice device = m_context.getDevice();
1798 Allocator& allocator = m_context.getDefaultAllocator();
1799 const VkImageCreateFlags imageFlags = (m_format == m_imageFormat ? 0u : (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT);
1800
1801 const VkSampleCountFlagBits samples = static_cast<VkSampleCountFlagBits>(m_texture.numSamples()); // integer and bit mask are aligned, so we can cast like this
1802
1803 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1804 {
1805 tcu::TextureLevel referenceImage = generateReferenceImage(texture.size(levelNdx), imageFormat, format);
1806 m_referenceImages.push_back(referenceImage);
1807 }
1808
1809 m_bufferLoadDescriptorType = m_bufferLoadUniform ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1810 m_bufferLoadUsageBit = m_bufferLoadUniform ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
1811
1812 // A helper buffer with enough space to hold the whole image.
1813 m_imageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
1814 vk, device, allocator,
1815 makeBufferCreateInfo(m_imageSizeBytes + m_srcViewOffset, m_bufferLoadUsageBit | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
1816 MemoryRequirement::HostVisible));
1817
1818 // Copy reference data to buffer for subsequent upload to image.
1819 {
1820 const Allocation& alloc = m_imageBuffer->getAllocation();
1821 VkDeviceSize bufferOffset = 0u;
1822 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1823 {
1824 deMemcpy((char *)alloc.getHostPtr() + m_srcViewOffset + bufferOffset, m_referenceImages[levelNdx].getAccess().getDataPtr(), static_cast<size_t>(getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx)));
1825 bufferOffset += getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx);
1826 }
1827 flushAlloc(vk, device, alloc);
1828 }
1829
1830 {
1831 const VkImageCreateInfo imageParamsSrc =
1832 {
1833 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1834 DE_NULL, // const void* pNext;
1835 (isCube(m_texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u) | imageFlags, // VkImageCreateFlags flags;
1836 mapImageType(m_texture.type()), // VkImageType imageType;
1837 m_imageFormat, // VkFormat format;
1838 makeExtent3D(m_texture.layerSize()), // VkExtent3D extent;
1839 (deUint32)m_texture.numMipmapLevels(), // deUint32 mipLevels;
1840 (deUint32)m_texture.numLayers(), // deUint32 arrayLayers;
1841 samples, // VkSampleCountFlagBits samples;
1842 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1843 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
1844 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1845 0u, // deUint32 queueFamilyIndexCount;
1846 DE_NULL, // const deUint32* pQueueFamilyIndices;
1847 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1848 };
1849
1850 m_imageSrc = de::MovePtr<Image>(new Image(
1851 vk, device, allocator,
1852 imageParamsSrc,
1853 MemoryRequirement::Any));
1854 }
1855
1856 {
1857 const VkImageCreateInfo imageParamsDst =
1858 {
1859 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1860 DE_NULL, // const void* pNext;
1861 (isCube(m_texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u) | imageFlags, // VkImageCreateFlags flags;
1862 mapImageType(m_texture.type()), // VkImageType imageType;
1863 m_imageFormat, // VkFormat format;
1864 makeExtent3D(m_texture.layerSize()), // VkExtent3D extent;
1865 (deUint32)m_texture.numMipmapLevels(), // deUint32 mipLevels;
1866 (deUint32)m_texture.numLayers(), // deUint32 arrayLayers;
1867 samples, // VkSampleCountFlagBits samples;
1868 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1869 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
1870 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1871 0u, // deUint32 queueFamilyIndexCount;
1872 DE_NULL, // const deUint32* pQueueFamilyIndices;
1873 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1874 };
1875
1876 m_imageDst = de::MovePtr<Image>(new Image(
1877 vk, device, allocator,
1878 imageParamsDst,
1879 MemoryRequirement::Any));
1880 }
1881 }
1882
verifyResult(void)1883 tcu::TestStatus ImageLoadStoreLodAMDTestInstance::verifyResult (void)
1884 {
1885 const DeviceInterface& vk = m_context.getDeviceInterface();
1886 const VkDevice device = m_context.getDevice();
1887
1888 const Allocation& alloc = getResultBuffer()->getAllocation();
1889 invalidateAlloc(vk, device, alloc);
1890
1891 VkDeviceSize bufferOffset = 0;
1892 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
1893 {
1894 // Apply the same transformation as done in the shader
1895 const tcu::PixelBufferAccess reference = m_referenceImages[levelNdx].getAccess();
1896 flipHorizontally(reference);
1897
1898 const tcu::ConstPixelBufferAccess result(mapVkFormat(m_imageFormat), m_texture.size(levelNdx), (const char *)alloc.getHostPtr() + m_dstViewOffset + bufferOffset);
1899
1900 if (!comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_imageFormat, reference, result, levelNdx))
1901 {
1902 std::ostringstream errorMessage;
1903 errorMessage << "Image Level " << levelNdx << " comparison failed";
1904 return tcu::TestStatus::fail(errorMessage.str());
1905 }
1906 bufferOffset += getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx);
1907 }
1908
1909 return tcu::TestStatus::pass("Passed");
1910 }
1911
prepareDescriptors(void)1912 VkDescriptorSetLayout ImageLoadStoreLodAMDTestInstance::prepareDescriptors (void)
1913 {
1914 const VkDevice device = m_context.getDevice();
1915 const DeviceInterface& vk = m_context.getDeviceInterface();
1916
1917 const int numLayers = m_texture.numLayers();
1918 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1919 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1920 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1921 .build(vk, device);
1922
1923 m_descriptorPool = DescriptorPoolBuilder()
1924 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1925 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1926 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
1927
1928 if (m_singleLayerBind)
1929 {
1930 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1931 {
1932 const VkImageViewType viewType = mapImageViewType(getImageTypeForSingleLayer(m_texture.type()));
1933 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, m_texture.numMipmapLevels(), layerNdx, 1u);
1934
1935 m_allDescriptorSets[layerNdx] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1936 m_allSrcImageViews[layerNdx] = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1937 m_allDstImageViews[layerNdx] = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1938 }
1939 }
1940 else // bind all layers at once
1941 {
1942 const VkImageViewType viewType = mapImageViewType(m_texture.type());
1943 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, m_texture.numMipmapLevels(), 0u, numLayers);
1944
1945 m_allDescriptorSets[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1946 m_allSrcImageViews[0] = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1947 m_allDstImageViews[0] = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1948 }
1949
1950 return *m_descriptorSetLayout; // not passing the ownership
1951 }
1952
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1953 void ImageLoadStoreLodAMDTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
1954 {
1955 const VkDevice device = m_context.getDevice();
1956 const DeviceInterface& vk = m_context.getDeviceInterface();
1957
1958 const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
1959 const VkImageView srcImageView = **m_allSrcImageViews[layerNdx];
1960 const VkImageView dstImageView = **m_allDstImageViews[layerNdx];
1961
1962 const VkDescriptorImageInfo descriptorSrcImageInfo = makeDescriptorImageInfo(DE_NULL, srcImageView, VK_IMAGE_LAYOUT_GENERAL);
1963 const VkDescriptorImageInfo descriptorDstImageInfo = makeDescriptorImageInfo(DE_NULL, dstImageView, VK_IMAGE_LAYOUT_GENERAL);
1964
1965 DescriptorSetUpdateBuilder()
1966 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorSrcImageInfo)
1967 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorDstImageInfo)
1968 .update(vk, device);
1969 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
1970 }
1971
commandBeforeCompute(const VkCommandBuffer cmdBuffer)1972 void ImageLoadStoreLodAMDTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
1973 {
1974 const DeviceInterface& vk = m_context.getDeviceInterface();
1975 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, m_texture.numMipmapLevels(), 0u, m_texture.numLayers());
1976 {
1977 const VkImageMemoryBarrier preCopyImageBarriers[] =
1978 {
1979 makeImageMemoryBarrier(
1980 0u, VK_ACCESS_TRANSFER_WRITE_BIT,
1981 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1982 m_imageSrc->get(), fullImageSubresourceRange),
1983 makeImageMemoryBarrier(
1984 0u, VK_ACCESS_SHADER_WRITE_BIT,
1985 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1986 m_imageDst->get(), fullImageSubresourceRange)
1987 };
1988
1989 const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy = makeBufferMemoryBarrier(
1990 VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1991 m_imageBuffer->get(), 0ull, m_imageSizeBytes + m_srcViewOffset);
1992
1993 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
1994 (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &barrierFlushHostWriteBeforeCopy, DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
1995 }
1996 {
1997 const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
1998 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
1999 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
2000 m_imageSrc->get(), fullImageSubresourceRange);
2001
2002 std::vector<VkBufferImageCopy> copyRegions;
2003 VkDeviceSize bufferOffset = 0u;
2004 for (deInt32 levelNdx = 0; levelNdx < m_texture.numMipmapLevels(); levelNdx++)
2005 {
2006 const VkBufferImageCopy copyParams =
2007 {
2008 bufferOffset, // VkDeviceSize bufferOffset;
2009 0u, // deUint32 bufferRowLength;
2010 0u, // deUint32 bufferImageHeight;
2011 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, levelNdx, 0u, m_texture.numLayers()), // VkImageSubresourceLayers imageSubresource;
2012 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
2013 makeExtent3D(m_texture.layerSize(levelNdx)), // VkExtent3D imageExtent;
2014 };
2015 copyRegions.push_back(copyParams);
2016 bufferOffset += getMipmapLevelImageSizeBytes(m_texture, m_imageFormat, levelNdx);
2017 }
2018
2019 vk.cmdCopyBufferToImage(cmdBuffer, m_imageBuffer->get(), m_imageSrc->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32) copyRegions.size(), copyRegions.data());
2020 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &barrierAfterCopy);
2021 }
2022 }
2023
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)2024 void ImageLoadStoreLodAMDTestInstance::commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer)
2025 {
2026 commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture);
2027 }
2028
commandAfterCompute(const VkCommandBuffer cmdBuffer)2029 void ImageLoadStoreLodAMDTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
2030 {
2031 commandCopyMipmapImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_imageFormat, m_imageBuffer->get(), m_imageSizeBytes, m_texture);
2032 }
2033
2034 //! Load/store test for buffers
2035 class BufferLoadStoreTestInstance : public LoadStoreTestInstance
2036 {
2037 public:
2038 BufferLoadStoreTestInstance (Context& context,
2039 const Texture& texture,
2040 const VkFormat format,
2041 const VkFormat imageFormat,
2042 const bool declareImageFormatInShader,
2043 const bool minalign,
2044 const bool bufferLoadUniform);
2045
2046 protected:
2047 VkDescriptorSetLayout prepareDescriptors (void);
2048 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
2049
2050 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
2051 const VkPipelineLayout pipelineLayout,
2052 const int layerNdx);
2053
getResultBuffer(void) const2054 BufferWithMemory* getResultBuffer (void) const { return m_imageBufferDst.get(); }
2055
2056 de::MovePtr<BufferWithMemory> m_imageBufferDst;
2057 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
2058 Move<VkDescriptorPool> m_descriptorPool;
2059 Move<VkDescriptorSet> m_descriptorSet;
2060 Move<VkBufferView> m_bufferViewSrc;
2061 Move<VkBufferView> m_bufferViewDst;
2062 };
2063
BufferLoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool declareImageFormatInShader,const bool minalign,const bool bufferLoadUniform)2064 BufferLoadStoreTestInstance::BufferLoadStoreTestInstance (Context& context,
2065 const Texture& texture,
2066 const VkFormat format,
2067 const VkFormat imageFormat,
2068 const bool declareImageFormatInShader,
2069 const bool minalign,
2070 const bool bufferLoadUniform)
2071 : LoadStoreTestInstance(context, texture, format, imageFormat, declareImageFormatInShader, false, minalign, bufferLoadUniform)
2072 {
2073 const DeviceInterface& vk = m_context.getDeviceInterface();
2074 const VkDevice device = m_context.getDevice();
2075 Allocator& allocator = m_context.getDefaultAllocator();
2076
2077 // Create a destination buffer.
2078
2079 m_imageBufferDst = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
2080 vk, device, allocator,
2081 makeBufferCreateInfo(m_imageSizeBytes + m_dstViewOffset, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
2082 MemoryRequirement::HostVisible));
2083 }
2084
prepareDescriptors(void)2085 VkDescriptorSetLayout BufferLoadStoreTestInstance::prepareDescriptors (void)
2086 {
2087 const DeviceInterface& vk = m_context.getDeviceInterface();
2088 const VkDevice device = m_context.getDevice();
2089
2090 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
2091 .addSingleBinding(m_bufferLoadDescriptorType, VK_SHADER_STAGE_COMPUTE_BIT)
2092 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
2093 .build(vk, device);
2094
2095 m_descriptorPool = DescriptorPoolBuilder()
2096 .addType(m_bufferLoadDescriptorType)
2097 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
2098 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
2099
2100 VkFormat dstFormat = formatHasThreeComponents(m_format) ? getSingleComponentFormat(m_format) : m_format;
2101
2102 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
2103 m_bufferViewSrc = makeBufferView(vk, device, m_imageBuffer->get(), m_format, m_srcViewOffset, m_imageSizeBytes);
2104 m_bufferViewDst = makeBufferView(vk, device, m_imageBufferDst->get(), dstFormat, m_dstViewOffset, m_imageSizeBytes);
2105
2106 return *m_descriptorSetLayout; // not passing the ownership
2107 }
2108
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)2109 void BufferLoadStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
2110 {
2111 DE_ASSERT(layerNdx == 0);
2112 DE_UNREF(layerNdx);
2113
2114 const VkDevice device = m_context.getDevice();
2115 const DeviceInterface& vk = m_context.getDeviceInterface();
2116
2117 DescriptorSetUpdateBuilder()
2118 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), m_bufferLoadDescriptorType, &m_bufferViewSrc.get())
2119 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferViewDst.get())
2120 .update(vk, device);
2121 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
2122 }
2123
commandAfterCompute(const VkCommandBuffer cmdBuffer)2124 void BufferLoadStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
2125 {
2126 commandBufferWriteBarrierBeforeHostRead(m_context, cmdBuffer, m_imageBufferDst->get(), m_imageSizeBytes + m_dstViewOffset);
2127 }
2128
createInstance(Context & context) const2129 TestInstance* StoreTest::createInstance (Context& context) const
2130 {
2131 if (m_texture.type() == IMAGE_TYPE_BUFFER)
2132 return new BufferStoreTestInstance(context, m_texture, m_format, m_declareImageFormatInShader, m_minalign, m_storeConstantValue);
2133 else
2134 return new ImageStoreTestInstance(context, m_texture, m_format, m_tiling, m_declareImageFormatInShader, m_singleLayerBind, m_minalign, m_storeConstantValue);
2135 }
2136
createInstance(Context & context) const2137 TestInstance* LoadStoreTest::createInstance (Context& context) const
2138 {
2139 if (m_imageLoadStoreLodAMD)
2140 return new ImageLoadStoreLodAMDTestInstance(context, m_texture, m_format, m_imageFormat, m_declareFormatInShaderReads, m_singleLayerBind, m_minalign, m_bufferLoadUniform);
2141
2142 if (m_texture.type() == IMAGE_TYPE_BUFFER)
2143 return new BufferLoadStoreTestInstance(context, m_texture, m_format, m_imageFormat, m_declareFormatInShaderReads, m_minalign, m_bufferLoadUniform);
2144 else
2145 return new ImageLoadStoreTestInstance(context, m_texture, m_format, m_imageFormat, m_tiling, m_declareFormatInShaderReads, m_singleLayerBind, m_minalign, m_bufferLoadUniform);
2146 }
2147
2148 class ImageExtendOperandTestInstance : public BaseTestInstance
2149 {
2150 public:
2151 ImageExtendOperandTestInstance (Context& context,
2152 const Texture& texture,
2153 const VkFormat readFormat,
2154 const VkFormat writeFormat,
2155 bool relaxedPrecision);
2156
~ImageExtendOperandTestInstance(void)2157 virtual ~ImageExtendOperandTestInstance (void) {}
2158
2159 protected:
2160
2161 VkDescriptorSetLayout prepareDescriptors (void);
2162 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
2163 void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer);
2164 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
2165
2166 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
2167 const VkPipelineLayout pipelineLayout,
2168 const int layerNdx);
2169
2170 tcu::TestStatus verifyResult (void);
2171
2172 protected:
2173
2174 bool m_isSigned;
2175 tcu::TextureLevel m_inputImageData;
2176
2177 de::MovePtr<Image> m_imageSrc; // source image
2178 SharedVkImageView m_imageSrcView;
2179 VkDeviceSize m_imageSrcSize;
2180
2181 de::MovePtr<Image> m_imageDst; // dest image
2182 SharedVkImageView m_imageDstView;
2183 VkFormat m_imageDstFormat;
2184 VkDeviceSize m_imageDstSize;
2185
2186 de::MovePtr<BufferWithMemory> m_buffer; // result buffer
2187
2188 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
2189 Move<VkDescriptorPool> m_descriptorPool;
2190 SharedVkDescriptorSet m_descriptorSet;
2191
2192 bool m_relaxedPrecision;
2193 };
2194
ImageExtendOperandTestInstance(Context & context,const Texture & texture,const VkFormat readFormat,const VkFormat writeFormat,bool relaxedPrecision)2195 ImageExtendOperandTestInstance::ImageExtendOperandTestInstance (Context& context,
2196 const Texture& texture,
2197 const VkFormat readFormat,
2198 const VkFormat writeFormat,
2199 bool relaxedPrecision)
2200 : BaseTestInstance (context, texture, readFormat, true, true, false, false)
2201 , m_imageDstFormat (writeFormat)
2202 , m_relaxedPrecision (relaxedPrecision)
2203 {
2204 const DeviceInterface& vk = m_context.getDeviceInterface();
2205 const VkDevice device = m_context.getDevice();
2206 Allocator& allocator = m_context.getDefaultAllocator();
2207 const deInt32 width = texture.size().x();
2208 const deInt32 height = texture.size().y();
2209 const tcu::TextureFormat textureFormat = mapVkFormat(m_format);
2210
2211 // Generate reference image
2212 m_isSigned = (getTextureChannelClass(textureFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
2213 m_inputImageData.setStorage(textureFormat, width, height, 1);
2214
2215 const tcu::PixelBufferAccess access = m_inputImageData.getAccess();
2216 const int valueStart = (m_isSigned ? (-width / 2) : 0);
2217
2218 for (int x = 0; x < width; ++x)
2219 for (int y = 0; y < height; ++y)
2220 {
2221 const tcu::IVec4 color(valueStart + x, valueStart + y, valueStart, valueStart);
2222 access.setPixel(color, x, y);
2223 }
2224
2225 // Create source image
2226 m_imageSrc = de::MovePtr<Image>(new Image(
2227 vk, device, allocator,
2228 makeImageCreateInfo(m_texture, m_format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0u),
2229 MemoryRequirement::Any));
2230
2231 // Create destination image
2232 m_imageDst = de::MovePtr<Image>(new Image(
2233 vk, device, allocator,
2234 makeImageCreateInfo(m_texture, m_imageDstFormat, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u),
2235 MemoryRequirement::Any));
2236
2237 // Compute image and buffer sizes
2238 m_imageSrcSize = width * height * tcu::getPixelSize(textureFormat);
2239 m_imageDstSize = width * height * tcu::getPixelSize(mapVkFormat(m_imageDstFormat));
2240 VkDeviceSize bufferSizeBytes = de::max(m_imageSrcSize, m_imageDstSize);
2241
2242 // Create helper buffer able to store input data and image write result
2243 m_buffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
2244 vk, device, allocator,
2245 makeBufferCreateInfo(bufferSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
2246 MemoryRequirement::HostVisible));
2247
2248 const Allocation& alloc = m_buffer->getAllocation();
2249 deMemcpy(alloc.getHostPtr(), m_inputImageData.getAccess().getDataPtr(), static_cast<size_t>(m_imageSrcSize));
2250 flushAlloc(vk, device, alloc);
2251 }
2252
prepareDescriptors(void)2253 VkDescriptorSetLayout ImageExtendOperandTestInstance::prepareDescriptors (void)
2254 {
2255 const DeviceInterface& vk = m_context.getDeviceInterface();
2256 const VkDevice device = m_context.getDevice();
2257
2258 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
2259 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
2260 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
2261 .build(vk, device);
2262
2263 m_descriptorPool = DescriptorPoolBuilder()
2264 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1)
2265 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1)
2266 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
2267
2268 const VkImageViewType viewType = mapImageViewType(m_texture.type());
2269 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2270
2271 m_descriptorSet = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
2272 m_imageSrcView = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
2273 m_imageDstView = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_imageDstFormat, subresourceRange));
2274
2275 return *m_descriptorSetLayout; // not passing the ownership
2276 }
2277
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)2278 void ImageExtendOperandTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
2279 {
2280 DE_UNREF(layerNdx);
2281
2282 const DeviceInterface& vk = m_context.getDeviceInterface();
2283 const VkDevice device = m_context.getDevice();
2284 const VkDescriptorSet descriptorSet = **m_descriptorSet;
2285
2286 const VkDescriptorImageInfo descriptorSrcImageInfo = makeDescriptorImageInfo(DE_NULL, **m_imageSrcView, VK_IMAGE_LAYOUT_GENERAL);
2287 const VkDescriptorImageInfo descriptorDstImageInfo = makeDescriptorImageInfo(DE_NULL, **m_imageDstView, VK_IMAGE_LAYOUT_GENERAL);
2288
2289 typedef DescriptorSetUpdateBuilder::Location DSUBL;
2290 DescriptorSetUpdateBuilder()
2291 .writeSingle(descriptorSet, DSUBL::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorSrcImageInfo)
2292 .writeSingle(descriptorSet, DSUBL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorDstImageInfo)
2293 .update(vk, device);
2294 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
2295 }
2296
commandBeforeCompute(const VkCommandBuffer cmdBuffer)2297 void ImageExtendOperandTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
2298 {
2299 const DeviceInterface& vk = m_context.getDeviceInterface();
2300
2301 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
2302 {
2303 const VkImageMemoryBarrier preCopyImageBarriers[] =
2304 {
2305 makeImageMemoryBarrier(
2306 0u, VK_ACCESS_TRANSFER_WRITE_BIT,
2307 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2308 m_imageSrc->get(), fullImageSubresourceRange),
2309 makeImageMemoryBarrier(
2310 0u, VK_ACCESS_SHADER_WRITE_BIT,
2311 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
2312 m_imageDst->get(), fullImageSubresourceRange)
2313 };
2314
2315 const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy = makeBufferMemoryBarrier(
2316 VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
2317 m_buffer->get(), 0ull, m_imageSrcSize);
2318
2319 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
2320 (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &barrierFlushHostWriteBeforeCopy, DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
2321 }
2322 {
2323 const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
2324 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
2325 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
2326 m_imageSrc->get(), fullImageSubresourceRange);
2327
2328 const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_texture);
2329
2330 vk.cmdCopyBufferToImage(cmdBuffer, m_buffer->get(), m_imageSrc->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region);
2331 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &barrierAfterCopy);
2332 }
2333 }
2334
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)2335 void ImageExtendOperandTestInstance::commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer)
2336 {
2337 commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture);
2338 }
2339
commandAfterCompute(const VkCommandBuffer cmdBuffer)2340 void ImageExtendOperandTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
2341 {
2342 commandCopyImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_buffer->get(), m_imageDstSize, m_texture);
2343 }
2344
2345 // 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)2346 void clearHighBits (const tcu::PixelBufferAccess& pixels, int width, int height)
2347 {
2348 for (int y = 0; y < height; ++y)
2349 for (int x = 0; x < width; ++x)
2350 {
2351 auto color = pixels.getPixelUint(x, y);
2352 for (int c = 0; c < decltype(color)::SIZE; ++c)
2353 color[c] &= 0xFFFFull;
2354 pixels.setPixel(color, x, y);
2355 }
2356 }
2357
verifyResult(void)2358 tcu::TestStatus ImageExtendOperandTestInstance::verifyResult (void)
2359 {
2360 const DeviceInterface& vk = m_context.getDeviceInterface();
2361 const VkDevice device = m_context.getDevice();
2362 const tcu::IVec3 imageSize = m_texture.size();
2363 const tcu::PixelBufferAccess inputAccess = m_inputImageData.getAccess();
2364 const deInt32 width = inputAccess.getWidth();
2365 const deInt32 height = inputAccess.getHeight();
2366 tcu::TextureLevel refImage (mapVkFormat(m_imageDstFormat), width, height);
2367 tcu::PixelBufferAccess refAccess = refImage.getAccess();
2368
2369 for (int x = 0; x < width; ++x)
2370 for (int y = 0; y < height; ++y)
2371 {
2372 tcu::IVec4 color = inputAccess.getPixelInt(x, y);
2373 refAccess.setPixel(color, x, y);
2374 }
2375
2376 const Allocation& alloc = m_buffer->getAllocation();
2377 invalidateAlloc(vk, device, alloc);
2378 const tcu::PixelBufferAccess result(mapVkFormat(m_imageDstFormat), imageSize, alloc.getHostPtr());
2379
2380 if (m_relaxedPrecision)
2381 {
2382 // Preserve the lowest 16 bits of the reference and result pixels only.
2383 clearHighBits(refAccess, width, height);
2384 clearHighBits(result, width, height);
2385 }
2386
2387 if (tcu::intThresholdCompare (m_context.getTestContext().getLog(), "Comparison", "Comparison", refAccess, result, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT, true/*use64Bits*/))
2388 return tcu::TestStatus::pass("Passed");
2389 else
2390 return tcu::TestStatus::fail("Image comparison failed");
2391 }
2392
2393 enum class ExtendTestType
2394 {
2395 READ = 0,
2396 WRITE,
2397 WRITE_NONTEMPORAL,
2398 };
2399
2400 enum class ExtendOperand
2401 {
2402 SIGN_EXTEND = 0,
2403 ZERO_EXTEND = 1
2404 };
2405
2406 class ImageExtendOperandTest : public TestCase
2407 {
2408 public:
2409 ImageExtendOperandTest (tcu::TestContext& testCtx,
2410 const std::string& name,
2411 const Texture texture,
2412 const VkFormat readFormat,
2413 const VkFormat writeFormat,
2414 const bool signedInt,
2415 const bool relaxedPrecision,
2416 ExtendTestType extendTestType);
2417
2418 void checkSupport (Context& context) const;
2419 void initPrograms (SourceCollections& programCollection) const;
2420 TestInstance* createInstance (Context& context) const;
2421
2422 private:
isWriteTest() const2423 bool isWriteTest () const { return (m_extendTestType == ExtendTestType::WRITE) ||
2424 (m_extendTestType == ExtendTestType::WRITE_NONTEMPORAL); }
2425
2426 const Texture m_texture;
2427 VkFormat m_readFormat;
2428 VkFormat m_writeFormat;
2429 bool m_operandForce; // Use an operand that doesn't match SampledType?
2430 bool m_relaxedPrecision;
2431 ExtendTestType m_extendTestType;
2432 };
2433
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)2434 ImageExtendOperandTest::ImageExtendOperandTest (tcu::TestContext& testCtx,
2435 const std::string& name,
2436 const Texture texture,
2437 const VkFormat readFormat,
2438 const VkFormat writeFormat,
2439 const bool operandForce,
2440 const bool relaxedPrecision,
2441 ExtendTestType extendTestType)
2442 : TestCase (testCtx, name)
2443 , m_texture (texture)
2444 , m_readFormat (readFormat)
2445 , m_writeFormat (writeFormat)
2446 , m_operandForce (operandForce)
2447 , m_relaxedPrecision (relaxedPrecision)
2448 , m_extendTestType (extendTestType)
2449 {
2450 }
2451
checkFormatProperties(const Context & context,VkFormat format)2452 void checkFormatProperties (const Context& context, VkFormat format)
2453 {
2454 #ifndef CTS_USES_VULKANSC
2455 const VkFormatProperties3 formatProperties (context.getFormatProperties(format));
2456
2457 if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
2458 TCU_THROW(NotSupportedError, "Format not supported for storage images");
2459 #else
2460 const VkFormatProperties formatProperties(getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), format));
2461
2462 if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
2463 TCU_THROW(NotSupportedError, "Format not supported for storage images");
2464 #endif // CTS_USES_VULKANSC
2465 }
2466
check64BitSupportIfNeeded(Context & context,VkFormat readFormat,VkFormat writeFormat)2467 void check64BitSupportIfNeeded (Context& context, VkFormat readFormat, VkFormat writeFormat)
2468 {
2469 if (is64BitIntegerFormat(readFormat) || is64BitIntegerFormat(writeFormat))
2470 {
2471 const auto& features = context.getDeviceFeatures();
2472 if (!features.shaderInt64)
2473 TCU_THROW(NotSupportedError, "64-bit integers not supported in shaders");
2474 }
2475 }
2476
checkSupport(Context & context) const2477 void ImageExtendOperandTest::checkSupport (Context& context) const
2478 {
2479 if (!context.requireDeviceFunctionality("VK_KHR_spirv_1_4"))
2480 TCU_THROW(NotSupportedError, "VK_KHR_spirv_1_4 not supported");
2481
2482 #ifndef CTS_USES_VULKANSC
2483 DE_ASSERT(m_readFormat != VK_FORMAT_A8_UNORM_KHR && m_writeFormat != VK_FORMAT_A8_UNORM_KHR);
2484 DE_ASSERT(m_readFormat != VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR && m_writeFormat != VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR);
2485
2486 if ((m_extendTestType == ExtendTestType::WRITE_NONTEMPORAL) &&
2487 (context.getUsedApiVersion() < VK_API_VERSION_1_3))
2488 TCU_THROW(NotSupportedError, "Vulkan 1.3 or higher is required for this test to run");
2489 #endif // CTS_USES_VULKANSC
2490
2491 check64BitSupportIfNeeded(context, m_readFormat, m_writeFormat);
2492
2493 checkFormatProperties(context, m_readFormat);
2494 checkFormatProperties(context, m_writeFormat);
2495 }
2496
initPrograms(SourceCollections & programCollection) const2497 void ImageExtendOperandTest::initPrograms (SourceCollections& programCollection) const
2498 {
2499 tcu::StringTemplate shaderTemplate(
2500 "OpCapability Shader\n"
2501 "OpCapability StorageImageExtendedFormats\n"
2502
2503 "${capability}"
2504 "${extension}"
2505
2506 "%std450 = OpExtInstImport \"GLSL.std.450\"\n"
2507 "OpMemoryModel Logical GLSL450\n"
2508 "OpEntryPoint GLCompute %main \"main\" %id %src_image_ptr %dst_image_ptr\n"
2509 "OpExecutionMode %main LocalSize 1 1 1\n"
2510
2511 // decorations
2512 "OpDecorate %id BuiltIn GlobalInvocationId\n"
2513
2514 "OpDecorate %src_image_ptr DescriptorSet 0\n"
2515 "OpDecorate %src_image_ptr Binding 0\n"
2516 "OpDecorate %src_image_ptr NonWritable\n"
2517
2518 "${relaxed_precision}"
2519
2520 "OpDecorate %dst_image_ptr DescriptorSet 0\n"
2521 "OpDecorate %dst_image_ptr Binding 1\n"
2522 "OpDecorate %dst_image_ptr NonReadable\n"
2523
2524 // types
2525 "%type_void = OpTypeVoid\n"
2526 "%type_i32 = OpTypeInt 32 1\n"
2527 "%type_u32 = OpTypeInt 32 0\n"
2528 "%type_vec2_i32 = OpTypeVector %type_i32 2\n"
2529 "%type_vec2_u32 = OpTypeVector %type_u32 2\n"
2530 "%type_vec3_i32 = OpTypeVector %type_i32 3\n"
2531 "%type_vec3_u32 = OpTypeVector %type_u32 3\n"
2532 "%type_vec4_i32 = OpTypeVector %type_i32 4\n"
2533 "%type_vec4_u32 = OpTypeVector %type_u32 4\n"
2534 "${extra_types}"
2535
2536 "%type_fun_void = OpTypeFunction %type_void\n"
2537
2538 "${image_types}"
2539
2540 "%type_ptr_in_vec3_u32 = OpTypePointer Input %type_vec3_u32\n"
2541 "%type_ptr_in_u32 = OpTypePointer Input %type_u32\n"
2542
2543 "${image_uniforms}"
2544
2545 // variables
2546 "%id = OpVariable %type_ptr_in_vec3_u32 Input\n"
2547
2548 "${image_variables}"
2549
2550 // main function
2551 "%main = OpFunction %type_void None %type_fun_void\n"
2552 "%label = OpLabel\n"
2553
2554 "${image_load}"
2555
2556 "%idvec = OpLoad %type_vec3_u32 %id\n"
2557 "%id_xy = OpVectorShuffle %type_vec2_u32 %idvec %idvec 0 1\n"
2558 "%coord = OpBitcast %type_vec2_i32 %id_xy\n"
2559 "%value = OpImageRead ${sampled_type_vec4} %src_image %coord ${read_extend_operand}\n"
2560 " OpImageWrite %dst_image %coord %value ${write_extend_operand}\n"
2561 " OpReturn\n"
2562 " OpFunctionEnd\n");
2563
2564 const auto testedFormat = mapVkFormat(isWriteTest() ? m_writeFormat : m_readFormat);
2565 const bool isSigned = (getTextureChannelClass(testedFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
2566
2567 const auto isRead64 = is64BitIntegerFormat(m_readFormat);
2568 const auto isWrite64 = is64BitIntegerFormat(m_writeFormat);
2569 DE_ASSERT(isRead64 == isWrite64);
2570
2571 const bool using64Bits = (isRead64 || isWrite64);
2572
2573 // Additional capabilities when needed.
2574 std::string capability;
2575 std::string extension;
2576 std::string extraTypes;
2577
2578 if (using64Bits)
2579 {
2580 extension += "OpExtension \"SPV_EXT_shader_image_int64\"\n";
2581 capability +=
2582 "OpCapability Int64\n"
2583 "OpCapability Int64ImageEXT\n"
2584 ;
2585 extraTypes +=
2586 "%type_i64 = OpTypeInt 64 1\n"
2587 "%type_u64 = OpTypeInt 64 0\n"
2588 "%type_vec3_i64 = OpTypeVector %type_i64 3\n"
2589 "%type_vec3_u64 = OpTypeVector %type_u64 3\n"
2590 "%type_vec4_i64 = OpTypeVector %type_i64 4\n"
2591 "%type_vec4_u64 = OpTypeVector %type_u64 4\n"
2592 ;
2593 }
2594
2595 std::string relaxed = "";
2596 if (m_relaxedPrecision)
2597 relaxed += "OpDecorate %src_image_ptr RelaxedPrecision\n";
2598
2599 // Sampled type depends on the format sign and mismatch force flag.
2600 const bool signedSampleType = ((isSigned && !m_operandForce) || (!isSigned && m_operandForce));
2601 const std::string bits = (using64Bits ? "64" : "32");
2602 const std::string sampledTypePostfix = (signedSampleType ? "i" : "u") + bits;
2603 const std::string extendOperandStr = (isSigned ? "SignExtend" : "ZeroExtend");
2604
2605 std::map<std::string, std::string> specializations
2606 {
2607 { "image_type_id", "%type_image" },
2608 { "image_uni_ptr_type_id", "%type_ptr_uniform_const_image" },
2609 { "image_var_id", "%src_image_ptr" },
2610 { "image_id", "%src_image" },
2611 { "capability", capability },
2612 { "extension", extension },
2613 { "extra_types", extraTypes },
2614 { "relaxed_precision", relaxed },
2615 { "image_format", getSpirvFormat(m_readFormat) },
2616 { "sampled_type", (std::string("%type_") + sampledTypePostfix) },
2617 { "sampled_type_vec4", (std::string("%type_vec4_") + sampledTypePostfix) },
2618 { "read_extend_operand", (!isWriteTest() ? extendOperandStr : "") },
2619 { "write_extend_operand", (isWriteTest() ? extendOperandStr : "") },
2620 };
2621
2622 SpirvVersion spirvVersion = SPIRV_VERSION_1_4;
2623 bool allowSpirv14 = true;
2624 if (m_extendTestType == ExtendTestType::WRITE_NONTEMPORAL)
2625 {
2626 spirvVersion = SPIRV_VERSION_1_6;
2627 allowSpirv14 = false;
2628 specializations["write_extend_operand"] = "Nontemporal";
2629 }
2630
2631 // Addidtional parametrization is needed for a case when source and destination textures have same format
2632 tcu::StringTemplate imageTypeTemplate(
2633 "${image_type_id} = OpTypeImage ${sampled_type} 2D 0 0 0 2 ${image_format}\n");
2634 tcu::StringTemplate imageUniformTypeTemplate(
2635 "${image_uni_ptr_type_id} = OpTypePointer UniformConstant ${image_type_id}\n");
2636 tcu::StringTemplate imageVariablesTemplate(
2637 "${image_var_id} = OpVariable ${image_uni_ptr_type_id} UniformConstant\n");
2638 tcu::StringTemplate imageLoadTemplate(
2639 "${image_id} = OpLoad ${image_type_id} ${image_var_id}\n");
2640
2641 std::string imageTypes;
2642 std::string imageUniformTypes;
2643 std::string imageVariables;
2644 std::string imageLoad;
2645
2646 // If input image format is the same as output there is less spir-v definitions
2647 if (m_readFormat == m_writeFormat)
2648 {
2649 imageTypes = imageTypeTemplate.specialize(specializations);
2650 imageUniformTypes = imageUniformTypeTemplate.specialize(specializations);
2651 imageVariables = imageVariablesTemplate.specialize(specializations);
2652 imageLoad = imageLoadTemplate.specialize(specializations);
2653
2654 specializations["image_var_id"] = "%dst_image_ptr";
2655 specializations["image_id"] = "%dst_image";
2656 imageVariables += imageVariablesTemplate.specialize(specializations);
2657 imageLoad += imageLoadTemplate.specialize(specializations);
2658 }
2659 else
2660 {
2661 specializations["image_type_id"] = "%type_src_image";
2662 specializations["image_uni_ptr_type_id"] = "%type_ptr_uniform_const_src_image";
2663 imageTypes = imageTypeTemplate.specialize(specializations);
2664 imageUniformTypes = imageUniformTypeTemplate.specialize(specializations);
2665 imageVariables = imageVariablesTemplate.specialize(specializations);
2666 imageLoad = imageLoadTemplate.specialize(specializations);
2667
2668 specializations["image_format"] = getSpirvFormat(m_writeFormat);
2669 specializations["image_type_id"] = "%type_dst_image";
2670 specializations["image_uni_ptr_type_id"] = "%type_ptr_uniform_const_dst_image";
2671 specializations["image_var_id"] = "%dst_image_ptr";
2672 specializations["image_id"] = "%dst_image";
2673 imageTypes += imageTypeTemplate.specialize(specializations);
2674 imageUniformTypes += imageUniformTypeTemplate.specialize(specializations);
2675 imageVariables += imageVariablesTemplate.specialize(specializations);
2676 imageLoad += imageLoadTemplate.specialize(specializations);
2677 }
2678
2679 specializations["image_types"] = imageTypes;
2680 specializations["image_uniforms"] = imageUniformTypes;
2681 specializations["image_variables"] = imageVariables;
2682 specializations["image_load"] = imageLoad;
2683
2684 // Specialize whole shader and add it to program collection
2685 programCollection.spirvAsmSources.add("comp") << shaderTemplate.specialize(specializations)
2686 << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, spirvVersion, allowSpirv14);
2687 }
2688
createInstance(Context & context) const2689 TestInstance* ImageExtendOperandTest::createInstance(Context& context) const
2690 {
2691 return new ImageExtendOperandTestInstance(context, m_texture, m_readFormat, m_writeFormat, m_relaxedPrecision);
2692 }
2693
2694 static const Texture s_textures[] =
2695 {
2696 Texture(IMAGE_TYPE_1D, tcu::IVec3(64, 1, 1), 1),
2697 Texture(IMAGE_TYPE_1D_ARRAY, tcu::IVec3(64, 1, 1), 8),
2698 Texture(IMAGE_TYPE_2D, tcu::IVec3(64, 64, 1), 1),
2699 Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(64, 64, 1), 8),
2700 Texture(IMAGE_TYPE_3D, tcu::IVec3(64, 64, 8), 1),
2701 Texture(IMAGE_TYPE_CUBE, tcu::IVec3(64, 64, 1), 6),
2702 Texture(IMAGE_TYPE_CUBE_ARRAY, tcu::IVec3(64, 64, 1), 2*6),
2703 Texture(IMAGE_TYPE_BUFFER, tcu::IVec3(64, 1, 1), 1),
2704 };
2705
getTestTexture(const ImageType imageType)2706 const Texture& getTestTexture (const ImageType imageType)
2707 {
2708 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
2709 if (s_textures[textureNdx].type() == imageType)
2710 return s_textures[textureNdx];
2711
2712 DE_FATAL("Internal error");
2713 return s_textures[0];
2714 }
2715
2716 static const VkFormat s_formats[] =
2717 {
2718 VK_FORMAT_R32G32B32A32_SFLOAT,
2719 VK_FORMAT_R16G16B16A16_SFLOAT,
2720 VK_FORMAT_R32_SFLOAT,
2721
2722 VK_FORMAT_R32G32B32A32_UINT,
2723 VK_FORMAT_R16G16B16A16_UINT,
2724 VK_FORMAT_R8G8B8A8_UINT,
2725 VK_FORMAT_R32_UINT,
2726
2727 VK_FORMAT_R32G32B32A32_SINT,
2728 VK_FORMAT_R16G16B16A16_SINT,
2729 VK_FORMAT_R8G8B8A8_SINT,
2730 VK_FORMAT_R32_SINT,
2731
2732 VK_FORMAT_R8G8B8A8_UNORM,
2733
2734 VK_FORMAT_B8G8R8A8_UNORM,
2735 VK_FORMAT_B8G8R8A8_UINT,
2736
2737 VK_FORMAT_R8G8B8A8_SNORM,
2738
2739 VK_FORMAT_B10G11R11_UFLOAT_PACK32,
2740
2741 VK_FORMAT_R32G32_SFLOAT,
2742 VK_FORMAT_R16G16_SFLOAT,
2743 VK_FORMAT_R16_SFLOAT,
2744
2745 VK_FORMAT_A2B10G10R10_UINT_PACK32,
2746 VK_FORMAT_R32G32_UINT,
2747 VK_FORMAT_R16G16_UINT,
2748 VK_FORMAT_R16_UINT,
2749 VK_FORMAT_R8G8_UINT,
2750 VK_FORMAT_R8_UINT,
2751
2752 VK_FORMAT_R32G32_SINT,
2753 VK_FORMAT_R16G16_SINT,
2754 VK_FORMAT_R16_SINT,
2755 VK_FORMAT_R8G8_SINT,
2756 VK_FORMAT_R8_SINT,
2757
2758 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
2759 VK_FORMAT_R16G16B16A16_UNORM,
2760 VK_FORMAT_R16G16B16A16_SNORM,
2761 VK_FORMAT_R16G16_UNORM,
2762 VK_FORMAT_R16_UNORM,
2763 VK_FORMAT_R8G8_UNORM,
2764 VK_FORMAT_R8_UNORM,
2765 #ifndef CTS_USES_VULKANSC
2766 VK_FORMAT_A8_UNORM_KHR,
2767 #endif // CTS_USES_VULKANSC
2768
2769 VK_FORMAT_R16G16_SNORM,
2770 VK_FORMAT_R16_SNORM,
2771 VK_FORMAT_R8G8_SNORM,
2772 VK_FORMAT_R8_SNORM,
2773
2774 VK_FORMAT_R10X6_UNORM_PACK16,
2775 VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
2776 VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
2777
2778 VK_FORMAT_R4G4_UNORM_PACK8,
2779 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
2780 VK_FORMAT_B4G4R4A4_UNORM_PACK16,
2781 VK_FORMAT_R5G6B5_UNORM_PACK16,
2782 VK_FORMAT_B5G6R5_UNORM_PACK16,
2783 VK_FORMAT_R5G5B5A1_UNORM_PACK16,
2784 VK_FORMAT_B5G5R5A1_UNORM_PACK16,
2785 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
2786 #ifndef CTS_USES_VULKANSC
2787 VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR,
2788 #endif // CTS_USES_VULKANSC
2789
2790 VK_FORMAT_B8G8R8A8_SNORM,
2791 VK_FORMAT_B8G8R8A8_SINT,
2792 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
2793 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
2794 VK_FORMAT_A8B8G8R8_UINT_PACK32,
2795 VK_FORMAT_A8B8G8R8_SINT_PACK32,
2796 VK_FORMAT_A2R10G10B10_UNORM_PACK32,
2797 VK_FORMAT_A2R10G10B10_SNORM_PACK32,
2798 VK_FORMAT_A2R10G10B10_UINT_PACK32,
2799 VK_FORMAT_A2R10G10B10_SINT_PACK32,
2800 VK_FORMAT_A2B10G10R10_SNORM_PACK32,
2801 VK_FORMAT_A2B10G10R10_SINT_PACK32,
2802 VK_FORMAT_R32G32B32_UINT,
2803 VK_FORMAT_R32G32B32_SINT,
2804 VK_FORMAT_R32G32B32_SFLOAT,
2805 VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
2806
2807 VK_FORMAT_R8G8_SRGB,
2808 VK_FORMAT_R8G8B8_SRGB,
2809 VK_FORMAT_B8G8R8_SRGB,
2810 VK_FORMAT_R8G8B8A8_SRGB,
2811 VK_FORMAT_B8G8R8A8_SRGB,
2812 VK_FORMAT_A8B8G8R8_SRGB_PACK32
2813 };
2814
2815 static const VkFormat s_formatsThreeComponent[] =
2816 {
2817 VK_FORMAT_R8G8B8_UINT,
2818 VK_FORMAT_R8G8B8_SINT,
2819 VK_FORMAT_R8G8B8_UNORM,
2820 VK_FORMAT_R8G8B8_SNORM,
2821 VK_FORMAT_R16G16B16_UINT,
2822 VK_FORMAT_R16G16B16_SINT,
2823 VK_FORMAT_R16G16B16_UNORM,
2824 VK_FORMAT_R16G16B16_SNORM,
2825 VK_FORMAT_R16G16B16_SFLOAT,
2826 VK_FORMAT_R32G32B32_UINT,
2827 VK_FORMAT_R32G32B32_SINT,
2828 VK_FORMAT_R32G32B32_SFLOAT,
2829 };
2830
2831 static const VkImageTiling s_tilings[] = {
2832 VK_IMAGE_TILING_OPTIMAL,
2833 VK_IMAGE_TILING_LINEAR,
2834 };
2835
tilingSuffix(VkImageTiling tiling)2836 const char* tilingSuffix(VkImageTiling tiling) {
2837 switch (tiling) {
2838 case VK_IMAGE_TILING_OPTIMAL:
2839 return "";
2840 case VK_IMAGE_TILING_LINEAR:
2841 return "_linear";
2842 default:
2843 return "unknown";
2844 }
2845 }
2846
2847 } // anonymous ns
2848
createImageStoreTests(tcu::TestContext & testCtx)2849 tcu::TestCaseGroup* createImageStoreTests (tcu::TestContext& testCtx)
2850 {
2851 // Plain imageStore() cases
2852 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "store"));
2853 de::MovePtr<tcu::TestCaseGroup> testGroupWithFormat(new tcu::TestCaseGroup(testCtx, "with_format", "Declare a format layout qualifier for write images"));
2854 de::MovePtr<tcu::TestCaseGroup> testGroupWithoutFormat(new tcu::TestCaseGroup(testCtx, "without_format", "Do not declare a format layout qualifier for write images"));
2855
2856 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
2857 {
2858 const Texture& texture = s_textures[textureNdx];
2859 de::MovePtr<tcu::TestCaseGroup> groupWithFormatByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
2860 de::MovePtr<tcu::TestCaseGroup> groupWithoutFormatByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
2861 const bool isLayered = (texture.numLayers() > 1);
2862
2863 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
2864 {
2865 for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
2866 {
2867 const bool hasSpirvFmt = hasSpirvFormat(s_formats[formatNdx]);
2868 const char* suffix = tilingSuffix(s_tilings[tilingNdx]);
2869
2870 if (hasSpirvFmt)
2871 {
2872 groupWithFormatByImageViewType->addChild( new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + suffix, texture, s_formats[formatNdx], s_tilings[tilingNdx]));
2873 // Additional tests where the shader uses constant data for imageStore.
2874 groupWithFormatByImageViewType->addChild(new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_constant" + suffix, texture, s_formats[formatNdx], s_tilings[tilingNdx], StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER | StoreTest::FLAG_STORE_CONSTANT_VALUE));
2875 }
2876 groupWithoutFormatByImageViewType->addChild(new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + suffix, texture, s_formats[formatNdx], s_tilings[tilingNdx], 0));
2877
2878 if (isLayered && hasSpirvFmt)
2879 groupWithFormatByImageViewType->addChild(new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_single_layer" + suffix,
2880 texture, s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL,
2881 StoreTest::FLAG_SINGLE_LAYER_BIND | StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER));
2882
2883 if (texture.type() == IMAGE_TYPE_BUFFER)
2884 {
2885 if (hasSpirvFmt)
2886 groupWithFormatByImageViewType->addChild(new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_minalign" + suffix, texture, s_formats[formatNdx], s_tilings[tilingNdx], StoreTest::FLAG_MINALIGN | StoreTest::FLAG_DECLARE_IMAGE_FORMAT_IN_SHADER));
2887 groupWithoutFormatByImageViewType->addChild(new StoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_minalign" + suffix, texture, s_formats[formatNdx], s_tilings[tilingNdx], StoreTest::FLAG_MINALIGN));
2888 }
2889 }
2890 }
2891
2892 testGroupWithFormat->addChild(groupWithFormatByImageViewType.release());
2893 testGroupWithoutFormat->addChild(groupWithoutFormatByImageViewType.release());
2894 }
2895
2896 testGroup->addChild(testGroupWithFormat.release());
2897 testGroup->addChild(testGroupWithoutFormat.release());
2898
2899 return testGroup.release();
2900 }
2901
createImageLoadStoreTests(tcu::TestContext & testCtx)2902 tcu::TestCaseGroup* createImageLoadStoreTests (tcu::TestContext& testCtx)
2903 {
2904 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store", "Cases with imageLoad() followed by imageStore()"));
2905 de::MovePtr<tcu::TestCaseGroup> testGroupWithFormat(new tcu::TestCaseGroup(testCtx, "with_format", "Declare a format layout qualifier for read images"));
2906 de::MovePtr<tcu::TestCaseGroup> testGroupWithoutFormat(new tcu::TestCaseGroup(testCtx, "without_format", "Do not declare a format layout qualifier for read images"));
2907 de::MovePtr<tcu::TestCaseGroup> testGroupWithoutAnyFormat(new tcu::TestCaseGroup(testCtx, "without_any_format", "Do not declare a format layout qualifier for read or write images"));
2908
2909 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
2910 {
2911 const Texture& texture = s_textures[textureNdx];
2912 const auto imageTypeName = getImageTypeName(texture.type());
2913 const bool isLayered = (texture.numLayers() > 1);
2914
2915 de::MovePtr<tcu::TestCaseGroup> groupWithFormatByImageViewType (new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
2916 de::MovePtr<tcu::TestCaseGroup> groupWithoutFormatByImageViewType (new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
2917 de::MovePtr<tcu::TestCaseGroup> groupWithoutAnyFormatByImageViewType (new tcu::TestCaseGroup(testCtx, imageTypeName.c_str()));
2918
2919 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
2920 {
2921 const auto formatShortString = getFormatShortString(s_formats[formatNdx]);
2922 const auto hasSpvFormat = hasSpirvFormat(s_formats[formatNdx]);
2923
2924 for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
2925 {
2926 const char* suffix = tilingSuffix(s_tilings[tilingNdx]);
2927
2928 if (hasSpvFormat)
2929 {
2930 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx]));
2931 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2932 }
2933 groupWithoutAnyFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], 0u));
2934
2935 if (isLayered && hasSpvFormat)
2936 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_single_layer" + suffix,
2937 texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx],
2938 LoadStoreTest::FLAG_SINGLE_LAYER_BIND | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2939
2940 if (texture.type() == IMAGE_TYPE_BUFFER)
2941 {
2942 if (hasSpvFormat)
2943 {
2944 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign" + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2945 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign_uniform" + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER));
2946 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign" + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2947 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign_uniform" + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2948 }
2949 groupWithoutAnyFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign" + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN));
2950 groupWithoutAnyFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign_uniform" + suffix, texture, s_formats[formatNdx], s_formats[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER));
2951 }
2952 }
2953 }
2954
2955 if (texture.type() == IMAGE_TYPE_BUFFER)
2956 {
2957 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formatsThreeComponent); ++formatNdx)
2958 {
2959 const auto formatShortString = getFormatShortString(s_formatsThreeComponent[formatNdx]);
2960
2961 for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(s_tilings); tilingNdx++)
2962 {
2963 const char* suffix = tilingSuffix(s_tilings[tilingNdx]);
2964
2965 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_uniform" + suffix, texture, s_formatsThreeComponent[formatNdx], s_formatsThreeComponent[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2966 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, formatShortString + "_minalign_uniform" + suffix, texture, s_formatsThreeComponent[formatNdx], s_formatsThreeComponent[formatNdx], s_tilings[tilingNdx], LoadStoreTest::FLAG_MINALIGN | LoadStoreTest::FLAG_UNIFORM_TEXEL_BUFFER | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
2967 }
2968 }
2969 }
2970
2971 testGroupWithFormat->addChild(groupWithFormatByImageViewType.release());
2972 testGroupWithoutFormat->addChild(groupWithoutFormatByImageViewType.release());
2973 testGroupWithoutAnyFormat->addChild(groupWithoutAnyFormatByImageViewType.release());
2974 }
2975
2976 testGroup->addChild(testGroupWithFormat.release());
2977 testGroup->addChild(testGroupWithoutFormat.release());
2978 testGroup->addChild(testGroupWithoutAnyFormat.release());
2979
2980 return testGroup.release();
2981 }
2982
createImageLoadStoreLodAMDTests(tcu::TestContext & testCtx)2983 tcu::TestCaseGroup* createImageLoadStoreLodAMDTests (tcu::TestContext& testCtx)
2984 {
2985 static const Texture textures[] =
2986 {
2987 Texture(IMAGE_TYPE_1D_ARRAY, tcu::IVec3(64, 1, 1), 8, 1, 6),
2988 Texture(IMAGE_TYPE_1D, tcu::IVec3(64, 1, 1), 1, 1, 6),
2989 Texture(IMAGE_TYPE_2D, tcu::IVec3(64, 64, 1), 1, 1, 6),
2990 Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(64, 64, 1), 8, 1, 6),
2991 Texture(IMAGE_TYPE_3D, tcu::IVec3(64, 64, 8), 1, 1, 6),
2992 Texture(IMAGE_TYPE_CUBE, tcu::IVec3(64, 64, 1), 6, 1, 6),
2993 Texture(IMAGE_TYPE_CUBE_ARRAY, tcu::IVec3(64, 64, 1), 2*6, 1, 6),
2994 };
2995
2996 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store_lod", "Cases with imageLoad() followed by imageStore()"));
2997 de::MovePtr<tcu::TestCaseGroup> testGroupWithFormat(new tcu::TestCaseGroup(testCtx, "with_format", "Declare a format layout qualifier for read images"));
2998 de::MovePtr<tcu::TestCaseGroup> testGroupWithoutFormat(new tcu::TestCaseGroup(testCtx, "without_format", "Do not declare a format layout qualifier for read images"));
2999
3000 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(textures); ++textureNdx)
3001 {
3002 const Texture& texture = textures[textureNdx];
3003 de::MovePtr<tcu::TestCaseGroup> groupWithFormatByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3004 de::MovePtr<tcu::TestCaseGroup> groupWithoutFormatByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3005 const bool isLayered = (texture.numLayers() > 1);
3006
3007 if (texture.type() == IMAGE_TYPE_BUFFER)
3008 continue;
3009
3010 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3011 {
3012 // These tests always require a SPIR-V format for the write image, even if the read
3013 // image is being used without a format.
3014 if (!hasSpirvFormat(s_formats[formatNdx]))
3015 continue;
3016
3017 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, getFormatShortString(s_formats[formatNdx]), texture, s_formats[formatNdx], s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL, (LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES), DE_TRUE));
3018 groupWithoutFormatByImageViewType->addChild(new LoadStoreTest(testCtx, getFormatShortString(s_formats[formatNdx]), texture, s_formats[formatNdx], s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL, LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES, DE_TRUE));
3019
3020 if (isLayered)
3021 groupWithFormatByImageViewType->addChild(new LoadStoreTest(testCtx, getFormatShortString(s_formats[formatNdx]) + "_single_layer",
3022 texture, s_formats[formatNdx], s_formats[formatNdx], VK_IMAGE_TILING_OPTIMAL,
3023 LoadStoreTest::FLAG_SINGLE_LAYER_BIND | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES, DE_TRUE));
3024 }
3025
3026 testGroupWithFormat->addChild(groupWithFormatByImageViewType.release());
3027 testGroupWithoutFormat->addChild(groupWithoutFormatByImageViewType.release());
3028 }
3029
3030 testGroup->addChild(testGroupWithFormat.release());
3031 testGroup->addChild(testGroupWithoutFormat.release());
3032
3033 return testGroup.release();
3034 }
3035
createImageFormatReinterpretTests(tcu::TestContext & testCtx)3036 tcu::TestCaseGroup* createImageFormatReinterpretTests (tcu::TestContext& testCtx)
3037 {
3038 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "format_reinterpret", "Cases with differing texture and image formats"));
3039
3040 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
3041 {
3042 const Texture& texture = s_textures[textureNdx];
3043 de::MovePtr<tcu::TestCaseGroup> groupByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
3044
3045 for (int imageFormatNdx = 0; imageFormatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++imageFormatNdx)
3046 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
3047 {
3048 if (!hasSpirvFormat(s_formats[formatNdx]))
3049 continue;
3050
3051 const std::string caseName = getFormatShortString(s_formats[imageFormatNdx]) + "_" + getFormatShortString(s_formats[formatNdx]);
3052 if (imageFormatNdx != formatNdx && formatsAreCompatible(s_formats[imageFormatNdx], s_formats[formatNdx]))
3053 groupByImageViewType->addChild(new LoadStoreTest(testCtx, caseName, texture, s_formats[formatNdx], s_formats[imageFormatNdx], VK_IMAGE_TILING_OPTIMAL));
3054 }
3055 testGroup->addChild(groupByImageViewType.release());
3056 }
3057
3058 return testGroup.release();
3059 }
3060
createImageQualifierRestrictCase(tcu::TestContext & testCtx,const ImageType imageType,const std::string & name)3061 de::MovePtr<TestCase> createImageQualifierRestrictCase (tcu::TestContext& testCtx, const ImageType imageType, const std::string& name)
3062 {
3063 const VkFormat format = VK_FORMAT_R32G32B32A32_UINT;
3064 const Texture& texture = getTestTexture(imageType);
3065 return de::MovePtr<TestCase>(new LoadStoreTest(testCtx, name, texture, format, format, VK_IMAGE_TILING_OPTIMAL, LoadStoreTest::FLAG_RESTRICT_IMAGES | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_READS | LoadStoreTest::FLAG_DECLARE_FORMAT_IN_SHADER_WRITES));
3066 }
3067
3068 namespace
3069 {
3070
relaxedOK(VkFormat format)3071 bool relaxedOK(VkFormat format)
3072 {
3073 tcu::IVec4 bitDepth = tcu::getTextureFormatBitDepth(mapVkFormat(format));
3074 int maxBitDepth = deMax32(deMax32(bitDepth[0], bitDepth[1]), deMax32(bitDepth[2], bitDepth[3]));
3075 return maxBitDepth <= 16;
3076 }
3077
3078 // Get a format used for reading or writing in extension operand tests. These formats allow representing the shader sampled type to
3079 // verify results from read or write operations.
getShaderExtensionOperandFormat(bool isSigned,bool is64Bit)3080 VkFormat getShaderExtensionOperandFormat (bool isSigned, bool is64Bit)
3081 {
3082 const VkFormat formats[] =
3083 {
3084 VK_FORMAT_R32G32B32A32_UINT,
3085 VK_FORMAT_R32G32B32A32_SINT,
3086 VK_FORMAT_R64_UINT,
3087 VK_FORMAT_R64_SINT,
3088 };
3089 return formats[2u * (is64Bit ? 1u : 0u) + (isSigned ? 1u : 0u)];
3090 }
3091
3092 // INT or UINT format?
isIntegralFormat(VkFormat format)3093 bool isIntegralFormat (VkFormat format)
3094 {
3095 return (isIntFormat(format) || isUintFormat(format));
3096 }
3097
3098 // Return the list of formats used for the extension operand tests (SignExten/ZeroExtend).
getExtensionOperandFormatList(void)3099 std::vector<VkFormat> getExtensionOperandFormatList (void)
3100 {
3101 std::vector<VkFormat> formatList;
3102
3103 for (auto format : s_formats)
3104 {
3105 if (isIntegralFormat(format))
3106 formatList.push_back(format);
3107 }
3108
3109 formatList.push_back(VK_FORMAT_R64_SINT);
3110 formatList.push_back(VK_FORMAT_R64_UINT);
3111
3112 return formatList;
3113 }
3114
3115 } // anonymous
3116
createImageExtendOperandsTests(tcu::TestContext & testCtx)3117 tcu::TestCaseGroup* createImageExtendOperandsTests(tcu::TestContext& testCtx)
3118 {
3119 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
3120
3121 GroupPtr testGroup(new tcu::TestCaseGroup(testCtx, "extend_operands_spirv1p4", "Cases with SignExtend and ZeroExtend"));
3122
3123 const struct
3124 {
3125 ExtendTestType testType;
3126 const char* name;
3127 } testTypes[] =
3128 {
3129 { ExtendTestType::READ, "read" },
3130 { ExtendTestType::WRITE, "write" },
3131 };
3132
3133 const auto texture = Texture(IMAGE_TYPE_2D, tcu::IVec3(8, 8, 1), 1);
3134 const auto formatList = getExtensionOperandFormatList();
3135
3136 for (const auto format : formatList)
3137 {
3138 const auto isInt = isIntFormat(format);
3139 const auto isUint = isUintFormat(format);
3140 const auto use64Bits = is64BitIntegerFormat(format);
3141
3142 DE_ASSERT(isInt || isUint);
3143
3144 GroupPtr formatGroup (new tcu::TestCaseGroup(testCtx, getFormatShortString(format).c_str()));
3145
3146 for (const auto& testType : testTypes)
3147 {
3148 GroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testType.name));
3149
3150 for (int match = 0; match < 2; ++match)
3151 {
3152 const bool mismatched = (match == 1);
3153 const char* matchGroupName = (mismatched ? "mismatched_sign" : "matched_sign");
3154
3155 // SPIR-V does not allow this kind of sampled type override.
3156 if (mismatched && isUint)
3157 continue;
3158
3159 GroupPtr matchGroup (new tcu::TestCaseGroup(testCtx, matchGroupName));
3160
3161 for (int prec = 0; prec < 2; prec++)
3162 {
3163 const bool relaxedPrecision = (prec != 0);
3164
3165 const char* precisionName = (relaxedPrecision ? "relaxed_precision" : "normal_precision");
3166 const auto signedOther = ((isInt && !mismatched) || (isUint && mismatched));
3167 const auto otherFormat = getShaderExtensionOperandFormat(signedOther, use64Bits);
3168 const auto readFormat = (testType.testType == ExtendTestType::READ ? format : otherFormat);
3169 const auto writeFormat = (testType.testType == ExtendTestType::WRITE ? format : otherFormat);
3170
3171 if (relaxedPrecision && !relaxedOK(readFormat))
3172 continue;
3173
3174 if (!hasSpirvFormat(readFormat) || !hasSpirvFormat(writeFormat))
3175 continue;
3176
3177 matchGroup->addChild(new ImageExtendOperandTest(testCtx, precisionName, texture, readFormat, writeFormat, mismatched, relaxedPrecision, testType.testType));
3178 }
3179
3180 testTypeGroup->addChild(matchGroup.release());
3181 }
3182
3183 formatGroup->addChild(testTypeGroup.release());
3184 }
3185
3186 testGroup->addChild(formatGroup.release());
3187 }
3188
3189 return testGroup.release();
3190 }
3191
createImageNontemporalOperandTests(tcu::TestContext & testCtx)3192 tcu::TestCaseGroup* createImageNontemporalOperandTests(tcu::TestContext& testCtx)
3193 {
3194 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "nontemporal_operand", "Cases with Nontemporal image operand for SPOIR-V 1.6"));
3195
3196 const auto texture = Texture(IMAGE_TYPE_2D, tcu::IVec3(8, 8, 1), 1);
3197
3198 // using just integer formats for tests so that ImageExtendOperandTest could be reused
3199 const auto formatList = getExtensionOperandFormatList();
3200
3201 for (const auto format : formatList)
3202 {
3203 const std::string caseName = getFormatShortString(format);
3204 const auto readFormat = format;
3205 const auto writeFormat = getShaderExtensionOperandFormat(isIntFormat(format), is64BitIntegerFormat(format));
3206
3207 if (!hasSpirvFormat(readFormat) || !hasSpirvFormat(writeFormat))
3208 continue;
3209
3210 // note: just testing OpImageWrite as OpImageRead is tested with addComputeImageSamplerTest
3211 testGroup->addChild(new ImageExtendOperandTest(testCtx, caseName, texture,
3212 readFormat, writeFormat, false, false, ExtendTestType::WRITE_NONTEMPORAL));
3213 }
3214
3215 return testGroup.release();
3216 }
3217
3218 } // image
3219 } // vkt
3220