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