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 "vktImageTexture.hpp"
29
30 #include "vkDefs.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkImageUtil.hpp"
39
40 #include "deUniquePtr.hpp"
41 #include "deSharedPtr.hpp"
42 #include "deStringUtil.hpp"
43
44 #include "tcuImageCompare.hpp"
45 #include "tcuTexture.hpp"
46 #include "tcuTextureUtil.hpp"
47 #include "tcuFloat.hpp"
48
49 #include <string>
50 #include <vector>
51
52 using namespace vk;
53
54 namespace vkt
55 {
56 namespace image
57 {
58 namespace
59 {
60
61 typedef de::SharedPtr<Unique<VkDescriptorSet> > SharedVkDescriptorSet;
62 typedef de::SharedPtr<Unique<VkImageView> > SharedVkImageView;
63
64 template<typename T>
makeVkSharedPtr(Move<T> vkMove)65 inline de::SharedPtr<Unique<T> > makeVkSharedPtr (Move<T> vkMove)
66 {
67 return de::SharedPtr<Unique<T> >(new Unique<T>(vkMove));
68 }
69
makeImageCreateInfo(const Texture & texture,const VkFormat format,const VkImageUsageFlags usage,const VkImageCreateFlags flags)70 inline VkImageCreateInfo makeImageCreateInfo (const Texture& texture, const VkFormat format, const VkImageUsageFlags usage, const VkImageCreateFlags flags)
71 {
72 const VkImageCreateInfo imageParams =
73 {
74 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
75 DE_NULL, // const void* pNext;
76 (isCube(texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u) | flags, // VkImageCreateFlags flags;
77 mapImageType(texture.type()), // VkImageType imageType;
78 format, // VkFormat format;
79 makeExtent3D(texture.layerSize()), // VkExtent3D extent;
80 1u, // deUint32 mipLevels;
81 (deUint32)texture.numLayers(), // deUint32 arrayLayers;
82 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
83 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
84 usage, // VkImageUsageFlags usage;
85 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
86 0u, // deUint32 queueFamilyIndexCount;
87 DE_NULL, // const deUint32* pQueueFamilyIndices;
88 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
89 };
90 return imageParams;
91 }
92
makeBufferImageCopy(const Texture & texture)93 inline VkBufferImageCopy makeBufferImageCopy (const Texture& texture)
94 {
95 return image::makeBufferImageCopy(makeExtent3D(texture.layerSize()), texture.numLayers());
96 }
97
getImageTypeForSingleLayer(const ImageType imageType)98 ImageType getImageTypeForSingleLayer (const ImageType imageType)
99 {
100 switch (imageType)
101 {
102 case IMAGE_TYPE_1D:
103 case IMAGE_TYPE_1D_ARRAY:
104 return IMAGE_TYPE_1D;
105
106 case IMAGE_TYPE_2D:
107 case IMAGE_TYPE_2D_ARRAY:
108 case IMAGE_TYPE_CUBE:
109 case IMAGE_TYPE_CUBE_ARRAY:
110 // A single layer for cube is a 2d face
111 return IMAGE_TYPE_2D;
112
113 case IMAGE_TYPE_3D:
114 return IMAGE_TYPE_3D;
115
116 case IMAGE_TYPE_BUFFER:
117 return IMAGE_TYPE_BUFFER;
118
119 default:
120 DE_FATAL("Internal test error");
121 return IMAGE_TYPE_LAST;
122 }
123 }
124
computeStoreColorScale(const VkFormat format,const tcu::IVec3 imageSize)125 float computeStoreColorScale (const VkFormat format, const tcu::IVec3 imageSize)
126 {
127 const int maxImageDimension = de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z()));
128 const float div = static_cast<float>(maxImageDimension - 1);
129
130 if (isUnormFormat(format))
131 return 1.0f / div;
132 else if (isSnormFormat(format))
133 return 2.0f / div;
134 else
135 return 1.0f;
136 }
137
computeStoreColorBias(const VkFormat format)138 inline float computeStoreColorBias (const VkFormat format)
139 {
140 return isSnormFormat(format) ? -1.0f : 0.0f;
141 }
142
isIntegerFormat(const VkFormat format)143 inline bool isIntegerFormat (const VkFormat format)
144 {
145 return isIntFormat(format) || isUintFormat(format);
146 }
147
getLayerOrSlice(const Texture & texture,const tcu::ConstPixelBufferAccess access,const int layer)148 tcu::ConstPixelBufferAccess getLayerOrSlice (const Texture& texture, const tcu::ConstPixelBufferAccess access, const int layer)
149 {
150 switch (texture.type())
151 {
152 case IMAGE_TYPE_1D:
153 case IMAGE_TYPE_2D:
154 case IMAGE_TYPE_BUFFER:
155 // Not layered
156 DE_ASSERT(layer == 0);
157 return access;
158
159 case IMAGE_TYPE_1D_ARRAY:
160 return tcu::getSubregion(access, 0, layer, access.getWidth(), 1);
161
162 case IMAGE_TYPE_2D_ARRAY:
163 case IMAGE_TYPE_CUBE:
164 case IMAGE_TYPE_CUBE_ARRAY:
165 case IMAGE_TYPE_3D: // 3d texture is treated as if depth was the layers
166 return tcu::getSubregion(access, 0, 0, layer, access.getWidth(), access.getHeight(), 1);
167
168 default:
169 DE_FATAL("Internal test error");
170 return tcu::ConstPixelBufferAccess();
171 }
172 }
173
getFormatCaseName(const VkFormat format)174 std::string getFormatCaseName (const VkFormat format)
175 {
176 const std::string fullName = getFormatName(format);
177
178 DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
179
180 return de::toLower(fullName.substr(10));
181 }
182
183 //! \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)184 bool comparePixelBuffers (tcu::TestLog& log,
185 const Texture& texture,
186 const VkFormat format,
187 const tcu::ConstPixelBufferAccess reference,
188 const tcu::ConstPixelBufferAccess result)
189 {
190 DE_ASSERT(reference.getFormat() == result.getFormat());
191 DE_ASSERT(reference.getSize() == result.getSize());
192
193 const bool intFormat = isIntegerFormat(format);
194 const bool is3d = (texture.type() == IMAGE_TYPE_3D);
195 const int numLayersOrSlices = (is3d ? texture.size().z() : texture.numLayers());
196 const int numCubeFaces = 6;
197
198 int passedLayers = 0;
199 for (int layerNdx = 0; layerNdx < numLayersOrSlices; ++layerNdx)
200 {
201 const std::string comparisonName = "Comparison" + de::toString(layerNdx);
202 const std::string comparisonDesc = "Image Comparison, " +
203 (isCube(texture) ? "face " + de::toString(layerNdx % numCubeFaces) + ", cube " + de::toString(layerNdx / numCubeFaces) :
204 is3d ? "slice " + de::toString(layerNdx) : "layer " + de::toString(layerNdx));
205
206 const tcu::ConstPixelBufferAccess refLayer = getLayerOrSlice(texture, reference, layerNdx);
207 const tcu::ConstPixelBufferAccess resultLayer = getLayerOrSlice(texture, result, layerNdx);
208
209 bool ok = false;
210 if (intFormat)
211 ok = tcu::intThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
212 else
213 ok = tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
214
215 if (ok)
216 ++passedLayers;
217 }
218 return passedLayers == numLayersOrSlices;
219 }
220
221 //!< Zero out invalid pixels in the image (denormalized, infinite, NaN values)
replaceBadFloatReinterpretValues(const tcu::PixelBufferAccess access)222 void replaceBadFloatReinterpretValues (const tcu::PixelBufferAccess access)
223 {
224 DE_ASSERT(tcu::getTextureChannelClass(access.getFormat().type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
225
226 for (int z = 0; z < access.getDepth(); ++z)
227 for (int y = 0; y < access.getHeight(); ++y)
228 for (int x = 0; x < access.getWidth(); ++x)
229 {
230 const tcu::Vec4 color(access.getPixel(x, y, z));
231 tcu::Vec4 newColor = color;
232
233 for (int i = 0; i < 4; ++i)
234 {
235 if (access.getFormat().type == tcu::TextureFormat::HALF_FLOAT)
236 {
237 const tcu::Float16 f(color[i]);
238 if (f.isDenorm() || f.isInf() || f.isNaN())
239 newColor[i] = 0.0f;
240 }
241 else
242 {
243 const tcu::Float32 f(color[i]);
244 if (f.isDenorm() || f.isInf() || f.isNaN())
245 newColor[i] = 0.0f;
246 }
247 }
248
249 if (newColor != color)
250 access.setPixel(newColor, x, y, z);
251 }
252 }
253
254 //!< replace invalid pixels in the image (-128)
replaceSnormReinterpretValues(const tcu::PixelBufferAccess access)255 void replaceSnormReinterpretValues (const tcu::PixelBufferAccess access)
256 {
257 DE_ASSERT(tcu::getTextureChannelClass(access.getFormat().type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT);
258
259 for (int z = 0; z < access.getDepth(); ++z)
260 for (int y = 0; y < access.getHeight(); ++y)
261 for (int x = 0; x < access.getWidth(); ++x)
262 {
263 const tcu::IVec4 color(access.getPixelInt(x, y, z));
264 tcu::IVec4 newColor = color;
265
266 for (int i = 0; i < 4; ++i)
267 {
268 const deInt32 oldColor(color[i]);
269 if (oldColor == -128) newColor[i] = -127;
270 }
271
272 if (newColor != color)
273 access.setPixel(newColor, x, y, z);
274 }
275 }
276
generateReferenceImage(const tcu::IVec3 & imageSize,const VkFormat imageFormat,const VkFormat readFormat)277 tcu::TextureLevel generateReferenceImage (const tcu::IVec3& imageSize, const VkFormat imageFormat, const VkFormat readFormat)
278 {
279 // Generate a reference image data using the storage format
280
281 tcu::TextureLevel reference(mapVkFormat(imageFormat), imageSize.x(), imageSize.y(), imageSize.z());
282 const tcu::PixelBufferAccess access = reference.getAccess();
283
284 const float storeColorScale = computeStoreColorScale(imageFormat, imageSize);
285 const float storeColorBias = computeStoreColorBias(imageFormat);
286
287 const bool intFormat = isIntegerFormat(imageFormat);
288 const int xMax = imageSize.x() - 1;
289 const int yMax = imageSize.y() - 1;
290
291 for (int z = 0; z < imageSize.z(); ++z)
292 for (int y = 0; y < imageSize.y(); ++y)
293 for (int x = 0; x < imageSize.x(); ++x)
294 {
295 const tcu::IVec4 color(x^y^z, (xMax - x)^y^z, x^(yMax - y)^z, (xMax - x)^(yMax - y)^z);
296
297 if (intFormat)
298 access.setPixel(color, x, y, z);
299 else
300 access.setPixel(color.asFloat()*storeColorScale + storeColorBias, x, y, z);
301 }
302
303 // If the image is to be accessed as a float texture, get rid of invalid values
304
305 if (isFloatFormat(readFormat) && imageFormat != readFormat)
306 replaceBadFloatReinterpretValues(tcu::PixelBufferAccess(mapVkFormat(readFormat), imageSize, access.getDataPtr()));
307 if (isSnormFormat(readFormat) && imageFormat != readFormat)
308 replaceSnormReinterpretValues(tcu::PixelBufferAccess(mapVkFormat(readFormat), imageSize, access.getDataPtr()));
309
310 return reference;
311 }
312
generateReferenceImage(const tcu::IVec3 & imageSize,const VkFormat imageFormat)313 inline tcu::TextureLevel generateReferenceImage (const tcu::IVec3& imageSize, const VkFormat imageFormat)
314 {
315 return generateReferenceImage(imageSize, imageFormat, imageFormat);
316 }
317
flipHorizontally(const tcu::PixelBufferAccess access)318 void flipHorizontally (const tcu::PixelBufferAccess access)
319 {
320 const int xMax = access.getWidth() - 1;
321 const int halfWidth = access.getWidth() / 2;
322
323 if (isIntegerFormat(mapTextureFormat(access.getFormat())))
324 for (int z = 0; z < access.getDepth(); z++)
325 for (int y = 0; y < access.getHeight(); y++)
326 for (int x = 0; x < halfWidth; x++)
327 {
328 const tcu::UVec4 temp = access.getPixelUint(xMax - x, y, z);
329 access.setPixel(access.getPixelUint(x, y, z), xMax - x, y, z);
330 access.setPixel(temp, x, y, z);
331 }
332 else
333 for (int z = 0; z < access.getDepth(); z++)
334 for (int y = 0; y < access.getHeight(); y++)
335 for (int x = 0; x < halfWidth; x++)
336 {
337 const tcu::Vec4 temp = access.getPixel(xMax - x, y, z);
338 access.setPixel(access.getPixel(x, y, z), xMax - x, y, z);
339 access.setPixel(temp, x, y, z);
340 }
341 }
342
343 #if defined(DE_DEBUG)
colorScaleAndBiasAreValid(const VkFormat format,const float colorScale,const float colorBias)344 inline bool colorScaleAndBiasAreValid (const VkFormat format, const float colorScale, const float colorBias)
345 {
346 // Only normalized (fixed-point) formats may have scale/bias
347 const bool integerOrFloatFormat = isIntFormat(format) || isUintFormat(format) || isFloatFormat(format);
348 return !integerOrFloatFormat || (colorScale == 1.0f && colorBias == 0.0f);
349 }
350 #endif
351
formatsAreCompatible(const VkFormat format0,const VkFormat format1)352 inline bool formatsAreCompatible (const VkFormat format0, const VkFormat format1)
353 {
354 return format0 == format1 || mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize();
355 }
356
commandImageWriteBarrierBetweenShaderInvocations(Context & context,const VkCommandBuffer cmdBuffer,const VkImage image,const Texture & texture)357 void commandImageWriteBarrierBetweenShaderInvocations (Context& context, const VkCommandBuffer cmdBuffer, const VkImage image, const Texture& texture)
358 {
359 const DeviceInterface& vk = context.getDeviceInterface();
360
361 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, texture.numLayers());
362 const VkImageMemoryBarrier shaderWriteBarrier = makeImageMemoryBarrier(
363 VK_ACCESS_SHADER_WRITE_BIT, 0u,
364 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
365 image, fullImageSubresourceRange);
366
367 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);
368 }
369
commandBufferWriteBarrierBeforeHostRead(Context & context,const VkCommandBuffer cmdBuffer,const VkBuffer buffer,const VkDeviceSize bufferSizeBytes)370 void commandBufferWriteBarrierBeforeHostRead (Context& context, const VkCommandBuffer cmdBuffer, const VkBuffer buffer, const VkDeviceSize bufferSizeBytes)
371 {
372 const DeviceInterface& vk = context.getDeviceInterface();
373
374 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
375 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
376 buffer, 0ull, bufferSizeBytes);
377
378 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);
379 }
380
381 //! 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)382 void commandCopyImageToBuffer (Context& context,
383 const VkCommandBuffer cmdBuffer,
384 const VkImage image,
385 const VkBuffer buffer,
386 const VkDeviceSize bufferSizeBytes,
387 const Texture& texture)
388 {
389 const DeviceInterface& vk = context.getDeviceInterface();
390
391 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, texture.numLayers());
392 const VkImageMemoryBarrier prepareForTransferBarrier = makeImageMemoryBarrier(
393 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
394 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
395 image, fullImageSubresourceRange);
396
397 const VkBufferImageCopy copyRegion = makeBufferImageCopy(texture);
398
399 const VkBufferMemoryBarrier copyBarrier = makeBufferMemoryBarrier(
400 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
401 buffer, 0ull, bufferSizeBytes);
402
403 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);
404 vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ©Region);
405 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);
406 }
407
408 //! Minimum chunk size is determined by the offset alignment requirements.
getOptimalUniformBufferChunkSize(Context & context,VkDeviceSize minimumRequiredChunkSizeBytes)409 VkDeviceSize getOptimalUniformBufferChunkSize (Context& context, VkDeviceSize minimumRequiredChunkSizeBytes)
410 {
411 const VkPhysicalDeviceProperties properties = getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice());
412 const VkDeviceSize alignment = properties.limits.minUniformBufferOffsetAlignment;
413
414 if (minimumRequiredChunkSizeBytes > alignment)
415 return alignment + (minimumRequiredChunkSizeBytes / alignment) * alignment;
416 else
417 return alignment;
418 }
419
420 class StoreTest : public TestCase
421 {
422 public:
423 enum TestFlags
424 {
425 FLAG_SINGLE_LAYER_BIND = 0x1, //!< Run the shader multiple times, each time binding a different layer.
426 };
427
428 StoreTest (tcu::TestContext& testCtx,
429 const std::string& name,
430 const std::string& description,
431 const Texture& texture,
432 const VkFormat format,
433 const TestFlags flags = static_cast<TestFlags>(0));
434
435 void initPrograms (SourceCollections& programCollection) const;
436
437 TestInstance* createInstance (Context& context) const;
438
439 private:
440 const Texture m_texture;
441 const VkFormat m_format;
442 const bool m_singleLayerBind;
443 };
444
StoreTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const Texture & texture,const VkFormat format,const TestFlags flags)445 StoreTest::StoreTest (tcu::TestContext& testCtx,
446 const std::string& name,
447 const std::string& description,
448 const Texture& texture,
449 const VkFormat format,
450 const TestFlags flags)
451 : TestCase (testCtx, name, description)
452 , m_texture (texture)
453 , m_format (format)
454 , m_singleLayerBind ((flags & FLAG_SINGLE_LAYER_BIND) != 0)
455 {
456 if (m_singleLayerBind)
457 DE_ASSERT(m_texture.numLayers() > 1);
458 }
459
initPrograms(SourceCollections & programCollection) const460 void StoreTest::initPrograms (SourceCollections& programCollection) const
461 {
462 const float storeColorScale = computeStoreColorScale(m_format, m_texture.size());
463 const float storeColorBias = computeStoreColorBias(m_format);
464 DE_ASSERT(colorScaleAndBiasAreValid(m_format, storeColorScale, storeColorBias));
465
466 const std::string xMax = de::toString(m_texture.size().x() - 1);
467 const std::string yMax = de::toString(m_texture.size().y() - 1);
468 const std::string signednessPrefix = isUintFormat(m_format) ? "u" : isIntFormat(m_format) ? "i" : "";
469 const std::string colorBaseExpr = signednessPrefix + "vec4("
470 + "gx^gy^gz, "
471 + "(" + xMax + "-gx)^gy^gz, "
472 + "gx^(" + yMax + "-gy)^gz, "
473 + "(" + xMax + "-gx)^(" + yMax + "-gy)^gz)";
474
475 const std::string colorExpr = colorBaseExpr + (storeColorScale == 1.0f ? "" : "*" + de::toString(storeColorScale))
476 + (storeColorBias == 0.0f ? "" : " + float(" + de::toString(storeColorBias) + ")");
477
478 const int dimension = (m_singleLayerBind ? m_texture.layerDimension() : m_texture.dimension());
479 const std::string texelCoordStr = (dimension == 1 ? "gx" : dimension == 2 ? "ivec2(gx, gy)" : dimension == 3 ? "ivec3(gx, gy, gz)" : "");
480
481 const ImageType usedImageType = (m_singleLayerBind ? getImageTypeForSingleLayer(m_texture.type()) : m_texture.type());
482 const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
483 const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), usedImageType);
484
485 std::ostringstream src;
486 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
487 << "\n"
488 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
489 << "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n";
490
491 if (m_singleLayerBind)
492 src << "layout (binding = 1) readonly uniform Constants {\n"
493 << " int u_layerNdx;\n"
494 << "};\n";
495
496 src << "\n"
497 << "void main (void)\n"
498 << "{\n"
499 << " int gx = int(gl_GlobalInvocationID.x);\n"
500 << " int gy = int(gl_GlobalInvocationID.y);\n"
501 << " int gz = " << (m_singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
502 << " imageStore(u_image, " << texelCoordStr << ", " << colorExpr << ");\n"
503 << "}\n";
504
505 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
506 }
507
508 //! Generic test iteration algorithm for image tests
509 class BaseTestInstance : public TestInstance
510 {
511 public:
512 BaseTestInstance (Context& context,
513 const Texture& texture,
514 const VkFormat format,
515 const bool singleLayerBind);
516
517 tcu::TestStatus iterate (void);
518
~BaseTestInstance(void)519 virtual ~BaseTestInstance (void) {}
520
521 protected:
522 virtual VkDescriptorSetLayout prepareDescriptors (void) = 0;
523 virtual tcu::TestStatus verifyResult (void) = 0;
524
525 virtual void commandBeforeCompute (const VkCommandBuffer cmdBuffer) = 0;
526 virtual void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer) = 0;
527 virtual void commandAfterCompute (const VkCommandBuffer cmdBuffer) = 0;
528
529 virtual void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
530 const VkPipelineLayout pipelineLayout,
531 const int layerNdx) = 0;
532
533 const Texture m_texture;
534 const VkFormat m_format;
535 const bool m_singleLayerBind;
536 };
537
BaseTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool singleLayerBind)538 BaseTestInstance::BaseTestInstance (Context& context, const Texture& texture, const VkFormat format, const bool singleLayerBind)
539 : TestInstance (context)
540 , m_texture (texture)
541 , m_format (format)
542 , m_singleLayerBind (singleLayerBind)
543 {
544 }
545
iterate(void)546 tcu::TestStatus BaseTestInstance::iterate (void)
547 {
548 const DeviceInterface& vk = m_context.getDeviceInterface();
549 const VkDevice device = m_context.getDevice();
550 const VkQueue queue = m_context.getUniversalQueue();
551 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
552
553 const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
554
555 const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
556 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
557 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
558
559 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
560 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
561
562 beginCommandBuffer(vk, *cmdBuffer);
563
564 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
565 commandBeforeCompute(*cmdBuffer);
566
567 const tcu::IVec3 workSize = (m_singleLayerBind ? m_texture.layerSize() : m_texture.size());
568 const int loopNumLayers = (m_singleLayerBind ? m_texture.numLayers() : 1);
569 for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
570 {
571 commandBindDescriptorsForLayer(*cmdBuffer, *pipelineLayout, layerNdx);
572
573 if (layerNdx > 0)
574 commandBetweenShaderInvocations(*cmdBuffer);
575
576 vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
577 }
578
579 commandAfterCompute(*cmdBuffer);
580
581 endCommandBuffer(vk, *cmdBuffer);
582
583 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
584
585 return verifyResult();
586 }
587
588 //! Base store test implementation
589 class StoreTestInstance : public BaseTestInstance
590 {
591 public:
592 StoreTestInstance (Context& context,
593 const Texture& texture,
594 const VkFormat format,
595 const bool singleLayerBind);
596
597 protected:
598 tcu::TestStatus verifyResult (void);
599
600 // Add empty implementations for functions that might be not needed
commandBeforeCompute(const VkCommandBuffer)601 void commandBeforeCompute (const VkCommandBuffer) {}
commandBetweenShaderInvocations(const VkCommandBuffer)602 void commandBetweenShaderInvocations (const VkCommandBuffer) {}
commandAfterCompute(const VkCommandBuffer)603 void commandAfterCompute (const VkCommandBuffer) {}
604
605 de::MovePtr<Buffer> m_imageBuffer;
606 const VkDeviceSize m_imageSizeBytes;
607 };
608
StoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool singleLayerBind)609 StoreTestInstance::StoreTestInstance (Context& context, const Texture& texture, const VkFormat format, const bool singleLayerBind)
610 : BaseTestInstance (context, texture, format, singleLayerBind)
611 , m_imageSizeBytes (getImageSizeBytes(texture.size(), format))
612 {
613 const DeviceInterface& vk = m_context.getDeviceInterface();
614 const VkDevice device = m_context.getDevice();
615 Allocator& allocator = m_context.getDefaultAllocator();
616
617 // A helper buffer with enough space to hold the whole image. Usage flags accommodate all derived test instances.
618
619 m_imageBuffer = de::MovePtr<Buffer>(new Buffer(
620 vk, device, allocator,
621 makeBufferCreateInfo(m_imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
622 MemoryRequirement::HostVisible));
623 }
624
verifyResult(void)625 tcu::TestStatus StoreTestInstance::verifyResult (void)
626 {
627 const DeviceInterface& vk = m_context.getDeviceInterface();
628 const VkDevice device = m_context.getDevice();
629
630 const tcu::IVec3 imageSize = m_texture.size();
631 const tcu::TextureLevel reference = generateReferenceImage(imageSize, m_format);
632
633 const Allocation& alloc = m_imageBuffer->getAllocation();
634 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), m_imageSizeBytes);
635 const tcu::ConstPixelBufferAccess result(mapVkFormat(m_format), imageSize, alloc.getHostPtr());
636
637 if (comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_format, reference.getAccess(), result))
638 return tcu::TestStatus::pass("Passed");
639 else
640 return tcu::TestStatus::fail("Image comparison failed");
641 }
642
643 //! Store test for images
644 class ImageStoreTestInstance : public StoreTestInstance
645 {
646 public:
647 ImageStoreTestInstance (Context& context,
648 const Texture& texture,
649 const VkFormat format,
650 const bool singleLayerBind);
651
652 protected:
653 VkDescriptorSetLayout prepareDescriptors (void);
654 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
655 void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer);
656 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
657
658 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
659 const VkPipelineLayout pipelineLayout,
660 const int layerNdx);
661
662 de::MovePtr<Image> m_image;
663 de::MovePtr<Buffer> m_constantsBuffer;
664 const VkDeviceSize m_constantsBufferChunkSizeBytes;
665 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
666 Move<VkDescriptorPool> m_descriptorPool;
667 std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
668 std::vector<SharedVkImageView> m_allImageViews;
669 };
670
ImageStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const bool singleLayerBind)671 ImageStoreTestInstance::ImageStoreTestInstance (Context& context,
672 const Texture& texture,
673 const VkFormat format,
674 const bool singleLayerBind)
675 : StoreTestInstance (context, texture, format, singleLayerBind)
676 , m_constantsBufferChunkSizeBytes (getOptimalUniformBufferChunkSize(context, sizeof(deUint32)))
677 , m_allDescriptorSets (texture.numLayers())
678 , m_allImageViews (texture.numLayers())
679 {
680 const DeviceInterface& vk = m_context.getDeviceInterface();
681 const VkDevice device = m_context.getDevice();
682 Allocator& allocator = m_context.getDefaultAllocator();
683
684 m_image = de::MovePtr<Image>(new Image(
685 vk, device, allocator,
686 makeImageCreateInfo(m_texture, m_format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u),
687 MemoryRequirement::Any));
688
689 // This buffer will be used to pass constants to the shader
690
691 const int numLayers = m_texture.numLayers();
692 const VkDeviceSize constantsBufferSizeBytes = numLayers * m_constantsBufferChunkSizeBytes;
693 m_constantsBuffer = de::MovePtr<Buffer>(new Buffer(
694 vk, device, allocator,
695 makeBufferCreateInfo(constantsBufferSizeBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
696 MemoryRequirement::HostVisible));
697
698 {
699 const Allocation& alloc = m_constantsBuffer->getAllocation();
700 deUint8* const basePtr = static_cast<deUint8*>(alloc.getHostPtr());
701
702 deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(constantsBufferSizeBytes));
703
704 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
705 {
706 deUint32* valuePtr = reinterpret_cast<deUint32*>(basePtr + layerNdx * m_constantsBufferChunkSizeBytes);
707 *valuePtr = static_cast<deUint32>(layerNdx);
708 }
709
710 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), constantsBufferSizeBytes);
711 }
712 }
713
prepareDescriptors(void)714 VkDescriptorSetLayout ImageStoreTestInstance::prepareDescriptors (void)
715 {
716 const DeviceInterface& vk = m_context.getDeviceInterface();
717 const VkDevice device = m_context.getDevice();
718
719 const int numLayers = m_texture.numLayers();
720 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
721 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
722 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
723 .build(vk, device);
724
725 m_descriptorPool = DescriptorPoolBuilder()
726 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
727 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, numLayers)
728 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
729
730 if (m_singleLayerBind)
731 {
732 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
733 {
734 m_allDescriptorSets[layerNdx] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
735 m_allImageViews[layerNdx] = makeVkSharedPtr(makeImageView(
736 vk, device, m_image->get(), mapImageViewType(getImageTypeForSingleLayer(m_texture.type())), m_format,
737 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u)));
738 }
739 }
740 else // bind all layers at once
741 {
742 m_allDescriptorSets[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
743 m_allImageViews[0] = makeVkSharedPtr(makeImageView(
744 vk, device, m_image->get(), mapImageViewType(m_texture.type()), m_format,
745 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers)));
746 }
747
748 return *m_descriptorSetLayout; // not passing the ownership
749 }
750
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)751 void ImageStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
752 {
753 const DeviceInterface& vk = m_context.getDeviceInterface();
754 const VkDevice device = m_context.getDevice();
755
756 const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
757 const VkImageView imageView = **m_allImageViews[layerNdx];
758
759 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, imageView, VK_IMAGE_LAYOUT_GENERAL);
760
761 // Set the next chunk of the constants buffer. Each chunk begins with layer index that we've set before.
762 const VkDescriptorBufferInfo descriptorConstantsBufferInfo = makeDescriptorBufferInfo(
763 m_constantsBuffer->get(), layerNdx*m_constantsBufferChunkSizeBytes, m_constantsBufferChunkSizeBytes);
764
765 DescriptorSetUpdateBuilder()
766 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
767 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
768 .update(vk, device);
769 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
770 }
771
commandBeforeCompute(const VkCommandBuffer cmdBuffer)772 void ImageStoreTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
773 {
774 const DeviceInterface& vk = m_context.getDeviceInterface();
775
776 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
777 const VkImageMemoryBarrier setImageLayoutBarrier = makeImageMemoryBarrier(
778 0u, 0u,
779 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
780 m_image->get(), fullImageSubresourceRange);
781
782 const VkDeviceSize constantsBufferSize = m_texture.numLayers() * m_constantsBufferChunkSizeBytes;
783 const VkBufferMemoryBarrier writeConstantsBarrier = makeBufferMemoryBarrier(
784 VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
785 m_constantsBuffer->get(), 0ull, constantsBufferSize);
786
787 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &writeConstantsBarrier, 1, &setImageLayoutBarrier);
788 }
789
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)790 void ImageStoreTestInstance::commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer)
791 {
792 commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_image->get(), m_texture);
793 }
794
commandAfterCompute(const VkCommandBuffer cmdBuffer)795 void ImageStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
796 {
797 commandCopyImageToBuffer(m_context, cmdBuffer, m_image->get(), m_imageBuffer->get(), m_imageSizeBytes, m_texture);
798 }
799
800 //! Store test for buffers
801 class BufferStoreTestInstance : public StoreTestInstance
802 {
803 public:
804 BufferStoreTestInstance (Context& context,
805 const Texture& texture,
806 const VkFormat format);
807
808 protected:
809 VkDescriptorSetLayout prepareDescriptors (void);
810 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
811
812 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
813 const VkPipelineLayout pipelineLayout,
814 const int layerNdx);
815
816 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
817 Move<VkDescriptorPool> m_descriptorPool;
818 Move<VkDescriptorSet> m_descriptorSet;
819 Move<VkBufferView> m_bufferView;
820 };
821
BufferStoreTestInstance(Context & context,const Texture & texture,const VkFormat format)822 BufferStoreTestInstance::BufferStoreTestInstance (Context& context,
823 const Texture& texture,
824 const VkFormat format)
825 : StoreTestInstance(context, texture, format, false)
826 {
827 }
828
prepareDescriptors(void)829 VkDescriptorSetLayout BufferStoreTestInstance::prepareDescriptors (void)
830 {
831 const DeviceInterface& vk = m_context.getDeviceInterface();
832 const VkDevice device = m_context.getDevice();
833
834 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
835 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
836 .build(vk, device);
837
838 m_descriptorPool = DescriptorPoolBuilder()
839 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
840 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
841
842 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
843 m_bufferView = makeBufferView(vk, device, m_imageBuffer->get(), m_format, 0ull, m_imageSizeBytes);
844
845 return *m_descriptorSetLayout; // not passing the ownership
846 }
847
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)848 void BufferStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
849 {
850 DE_ASSERT(layerNdx == 0);
851 DE_UNREF(layerNdx);
852
853 const VkDevice device = m_context.getDevice();
854 const DeviceInterface& vk = m_context.getDeviceInterface();
855
856 DescriptorSetUpdateBuilder()
857 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
858 .update(vk, device);
859 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
860 }
861
commandAfterCompute(const VkCommandBuffer cmdBuffer)862 void BufferStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
863 {
864 commandBufferWriteBarrierBeforeHostRead(m_context, cmdBuffer, m_imageBuffer->get(), m_imageSizeBytes);
865 }
866
867 class LoadStoreTest : public TestCase
868 {
869 public:
870 enum TestFlags
871 {
872 FLAG_SINGLE_LAYER_BIND = 1 << 0, //!< Run the shader multiple times, each time binding a different layer.
873 FLAG_RESTRICT_IMAGES = 1 << 1, //!< If given, images in the shader will be qualified with "restrict".
874 };
875
876 LoadStoreTest (tcu::TestContext& testCtx,
877 const std::string& name,
878 const std::string& description,
879 const Texture& texture,
880 const VkFormat format,
881 const VkFormat imageFormat,
882 const TestFlags flags = static_cast<TestFlags>(0));
883
884 void initPrograms (SourceCollections& programCollection) const;
885 TestInstance* createInstance (Context& context) const;
886
887 private:
888 const Texture m_texture;
889 const VkFormat m_format; //!< Format as accessed in the shader
890 const VkFormat m_imageFormat; //!< Storage format
891 const bool m_singleLayerBind;
892 const bool m_restrictImages;
893 };
894
LoadStoreTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const TestFlags flags)895 LoadStoreTest::LoadStoreTest (tcu::TestContext& testCtx,
896 const std::string& name,
897 const std::string& description,
898 const Texture& texture,
899 const VkFormat format,
900 const VkFormat imageFormat,
901 const TestFlags flags)
902 : TestCase (testCtx, name, description)
903 , m_texture (texture)
904 , m_format (format)
905 , m_imageFormat (imageFormat)
906 , m_singleLayerBind ((flags & FLAG_SINGLE_LAYER_BIND) != 0)
907 , m_restrictImages ((flags & FLAG_RESTRICT_IMAGES) != 0)
908 {
909 if (m_singleLayerBind)
910 DE_ASSERT(m_texture.numLayers() > 1);
911
912 DE_ASSERT(formatsAreCompatible(m_format, m_imageFormat));
913 }
914
initPrograms(SourceCollections & programCollection) const915 void LoadStoreTest::initPrograms (SourceCollections& programCollection) const
916 {
917 const int dimension = (m_singleLayerBind ? m_texture.layerDimension() : m_texture.dimension());
918 const ImageType usedImageType = (m_singleLayerBind ? getImageTypeForSingleLayer(m_texture.type()) : m_texture.type());
919 const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
920 const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), usedImageType);
921 const std::string maybeRestrictStr = (m_restrictImages ? "restrict " : "");
922 const std::string xMax = de::toString(m_texture.size().x() - 1);
923
924 std::ostringstream src;
925 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
926 << "\n"
927 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
928 << "layout (binding = 0, " << formatQualifierStr << ") " << maybeRestrictStr << "readonly uniform highp " << imageTypeStr << " u_image0;\n"
929 << "layout (binding = 1, " << formatQualifierStr << ") " << maybeRestrictStr << "writeonly uniform highp " << imageTypeStr << " u_image1;\n"
930 << "\n"
931 << "void main (void)\n"
932 << "{\n"
933 << (dimension == 1 ?
934 " int pos = int(gl_GlobalInvocationID.x);\n"
935 " imageStore(u_image1, pos, imageLoad(u_image0, " + xMax + "-pos));\n"
936 : dimension == 2 ?
937 " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
938 " imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" + xMax + "-pos.x, pos.y)));\n"
939 : dimension == 3 ?
940 " ivec3 pos = ivec3(gl_GlobalInvocationID);\n"
941 " imageStore(u_image1, pos, imageLoad(u_image0, ivec3(" + xMax + "-pos.x, pos.y, pos.z)));\n"
942 : "")
943 << "}\n";
944
945 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
946 }
947
948 //! Load/store test base implementation
949 class LoadStoreTestInstance : public BaseTestInstance
950 {
951 public:
952 LoadStoreTestInstance (Context& context,
953 const Texture& texture,
954 const VkFormat format,
955 const VkFormat imageFormat,
956 const bool singleLayerBind);
957
958 protected:
959 virtual Buffer* getResultBuffer (void) const = 0; //!< Get the buffer that contains the result image
960
961 tcu::TestStatus verifyResult (void);
962
963 // Add empty implementations for functions that might be not needed
commandBeforeCompute(const VkCommandBuffer)964 void commandBeforeCompute (const VkCommandBuffer) {}
commandBetweenShaderInvocations(const VkCommandBuffer)965 void commandBetweenShaderInvocations (const VkCommandBuffer) {}
commandAfterCompute(const VkCommandBuffer)966 void commandAfterCompute (const VkCommandBuffer) {}
967
968 de::MovePtr<Buffer> m_imageBuffer; //!< Source data and helper buffer
969 const VkDeviceSize m_imageSizeBytes;
970 const VkFormat m_imageFormat; //!< Image format (for storage, may be different than texture format)
971 tcu::TextureLevel m_referenceImage; //!< Used as input data and later to verify result image
972 };
973
LoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool singleLayerBind)974 LoadStoreTestInstance::LoadStoreTestInstance (Context& context,
975 const Texture& texture,
976 const VkFormat format,
977 const VkFormat imageFormat,
978 const bool singleLayerBind)
979 : BaseTestInstance (context, texture, format, singleLayerBind)
980 , m_imageSizeBytes (getImageSizeBytes(texture.size(), format))
981 , m_imageFormat (imageFormat)
982 , m_referenceImage (generateReferenceImage(texture.size(), imageFormat, format))
983 {
984 const DeviceInterface& vk = m_context.getDeviceInterface();
985 const VkDevice device = m_context.getDevice();
986 Allocator& allocator = m_context.getDefaultAllocator();
987
988 // A helper buffer with enough space to hold the whole image.
989
990 m_imageBuffer = de::MovePtr<Buffer>(new Buffer(
991 vk, device, allocator,
992 makeBufferCreateInfo(m_imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
993 MemoryRequirement::HostVisible));
994
995 // Copy reference data to buffer for subsequent upload to image.
996
997 const Allocation& alloc = m_imageBuffer->getAllocation();
998 deMemcpy(alloc.getHostPtr(), m_referenceImage.getAccess().getDataPtr(), static_cast<size_t>(m_imageSizeBytes));
999 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), m_imageSizeBytes);
1000 }
1001
verifyResult(void)1002 tcu::TestStatus LoadStoreTestInstance::verifyResult (void)
1003 {
1004 const DeviceInterface& vk = m_context.getDeviceInterface();
1005 const VkDevice device = m_context.getDevice();
1006
1007 // Apply the same transformation as done in the shader
1008 const tcu::PixelBufferAccess reference = m_referenceImage.getAccess();
1009 flipHorizontally(reference);
1010
1011 const Allocation& alloc = getResultBuffer()->getAllocation();
1012 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), m_imageSizeBytes);
1013 const tcu::ConstPixelBufferAccess result(mapVkFormat(m_imageFormat), m_texture.size(), alloc.getHostPtr());
1014
1015 if (comparePixelBuffers(m_context.getTestContext().getLog(), m_texture, m_imageFormat, reference, result))
1016 return tcu::TestStatus::pass("Passed");
1017 else
1018 return tcu::TestStatus::fail("Image comparison failed");
1019 }
1020
1021 //! Load/store test for images
1022 class ImageLoadStoreTestInstance : public LoadStoreTestInstance
1023 {
1024 public:
1025 ImageLoadStoreTestInstance (Context& context,
1026 const Texture& texture,
1027 const VkFormat format,
1028 const VkFormat imageFormat,
1029 const bool singleLayerBind);
1030
1031 protected:
1032 VkDescriptorSetLayout prepareDescriptors (void);
1033 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
1034 void commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer);
1035 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
1036
1037 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
1038 const VkPipelineLayout pipelineLayout,
1039 const int layerNdx);
1040
getResultBuffer(void) const1041 Buffer* getResultBuffer (void) const { return m_imageBuffer.get(); }
1042
1043 de::MovePtr<Image> m_imageSrc;
1044 de::MovePtr<Image> m_imageDst;
1045 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1046 Move<VkDescriptorPool> m_descriptorPool;
1047 std::vector<SharedVkDescriptorSet> m_allDescriptorSets;
1048 std::vector<SharedVkImageView> m_allSrcImageViews;
1049 std::vector<SharedVkImageView> m_allDstImageViews;
1050 };
1051
ImageLoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat,const bool singleLayerBind)1052 ImageLoadStoreTestInstance::ImageLoadStoreTestInstance (Context& context,
1053 const Texture& texture,
1054 const VkFormat format,
1055 const VkFormat imageFormat,
1056 const bool singleLayerBind)
1057 : LoadStoreTestInstance (context, texture, format, imageFormat, singleLayerBind)
1058 , m_allDescriptorSets (texture.numLayers())
1059 , m_allSrcImageViews (texture.numLayers())
1060 , m_allDstImageViews (texture.numLayers())
1061 {
1062 const DeviceInterface& vk = m_context.getDeviceInterface();
1063 const VkDevice device = m_context.getDevice();
1064 Allocator& allocator = m_context.getDefaultAllocator();
1065 const VkImageCreateFlags imageFlags = (m_format == m_imageFormat ? 0u : (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT);
1066
1067 m_imageSrc = de::MovePtr<Image>(new Image(
1068 vk, device, allocator,
1069 makeImageCreateInfo(m_texture, m_imageFormat, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, imageFlags),
1070 MemoryRequirement::Any));
1071
1072 m_imageDst = de::MovePtr<Image>(new Image(
1073 vk, device, allocator,
1074 makeImageCreateInfo(m_texture, m_imageFormat, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, imageFlags),
1075 MemoryRequirement::Any));
1076 }
1077
prepareDescriptors(void)1078 VkDescriptorSetLayout ImageLoadStoreTestInstance::prepareDescriptors (void)
1079 {
1080 const VkDevice device = m_context.getDevice();
1081 const DeviceInterface& vk = m_context.getDeviceInterface();
1082
1083 const int numLayers = m_texture.numLayers();
1084 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1085 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1086 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1087 .build(vk, device);
1088
1089 m_descriptorPool = DescriptorPoolBuilder()
1090 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1091 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
1092 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers);
1093
1094 if (m_singleLayerBind)
1095 {
1096 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
1097 {
1098 const VkImageViewType viewType = mapImageViewType(getImageTypeForSingleLayer(m_texture.type()));
1099 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u);
1100
1101 m_allDescriptorSets[layerNdx] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1102 m_allSrcImageViews[layerNdx] = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1103 m_allDstImageViews[layerNdx] = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1104 }
1105 }
1106 else // bind all layers at once
1107 {
1108 const VkImageViewType viewType = mapImageViewType(m_texture.type());
1109 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers);
1110
1111 m_allDescriptorSets[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout));
1112 m_allSrcImageViews[0] = makeVkSharedPtr(makeImageView(vk, device, m_imageSrc->get(), viewType, m_format, subresourceRange));
1113 m_allDstImageViews[0] = makeVkSharedPtr(makeImageView(vk, device, m_imageDst->get(), viewType, m_format, subresourceRange));
1114 }
1115
1116 return *m_descriptorSetLayout; // not passing the ownership
1117 }
1118
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1119 void ImageLoadStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
1120 {
1121 const VkDevice device = m_context.getDevice();
1122 const DeviceInterface& vk = m_context.getDeviceInterface();
1123
1124 const VkDescriptorSet descriptorSet = **m_allDescriptorSets[layerNdx];
1125 const VkImageView srcImageView = **m_allSrcImageViews[layerNdx];
1126 const VkImageView dstImageView = **m_allDstImageViews[layerNdx];
1127
1128 const VkDescriptorImageInfo descriptorSrcImageInfo = makeDescriptorImageInfo(DE_NULL, srcImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1129 const VkDescriptorImageInfo descriptorDstImageInfo = makeDescriptorImageInfo(DE_NULL, dstImageView, VK_IMAGE_LAYOUT_GENERAL);
1130
1131 DescriptorSetUpdateBuilder()
1132 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorSrcImageInfo)
1133 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorDstImageInfo)
1134 .update(vk, device);
1135 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
1136 }
1137
commandBeforeCompute(const VkCommandBuffer cmdBuffer)1138 void ImageLoadStoreTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
1139 {
1140 const DeviceInterface& vk = m_context.getDeviceInterface();
1141
1142 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
1143 {
1144 const VkImageMemoryBarrier preCopyImageBarriers[] =
1145 {
1146 makeImageMemoryBarrier(
1147 0u, VK_ACCESS_TRANSFER_WRITE_BIT,
1148 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1149 m_imageSrc->get(), fullImageSubresourceRange),
1150 makeImageMemoryBarrier(
1151 0u, VK_ACCESS_SHADER_WRITE_BIT,
1152 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1153 m_imageDst->get(), fullImageSubresourceRange)
1154 };
1155
1156 const VkBufferMemoryBarrier barrierFlushHostWriteBeforeCopy = makeBufferMemoryBarrier(
1157 VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1158 m_imageBuffer->get(), 0ull, m_imageSizeBytes);
1159
1160 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
1161 (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &barrierFlushHostWriteBeforeCopy, DE_LENGTH_OF_ARRAY(preCopyImageBarriers), preCopyImageBarriers);
1162 }
1163 {
1164 const VkImageMemoryBarrier barrierAfterCopy = makeImageMemoryBarrier(
1165 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
1166 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1167 m_imageSrc->get(), fullImageSubresourceRange);
1168
1169 const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_texture);
1170
1171 vk.cmdCopyBufferToImage(cmdBuffer, m_imageBuffer->get(), m_imageSrc->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region);
1172 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);
1173 }
1174 }
1175
commandBetweenShaderInvocations(const VkCommandBuffer cmdBuffer)1176 void ImageLoadStoreTestInstance::commandBetweenShaderInvocations (const VkCommandBuffer cmdBuffer)
1177 {
1178 commandImageWriteBarrierBetweenShaderInvocations(m_context, cmdBuffer, m_imageDst->get(), m_texture);
1179 }
1180
commandAfterCompute(const VkCommandBuffer cmdBuffer)1181 void ImageLoadStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
1182 {
1183 commandCopyImageToBuffer(m_context, cmdBuffer, m_imageDst->get(), m_imageBuffer->get(), m_imageSizeBytes, m_texture);
1184 }
1185
1186 //! Load/store test for buffers
1187 class BufferLoadStoreTestInstance : public LoadStoreTestInstance
1188 {
1189 public:
1190 BufferLoadStoreTestInstance (Context& context,
1191 const Texture& texture,
1192 const VkFormat format,
1193 const VkFormat imageFormat);
1194
1195 protected:
1196 VkDescriptorSetLayout prepareDescriptors (void);
1197 void commandAfterCompute (const VkCommandBuffer cmdBuffer);
1198
1199 void commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer,
1200 const VkPipelineLayout pipelineLayout,
1201 const int layerNdx);
1202
getResultBuffer(void) const1203 Buffer* getResultBuffer (void) const { return m_imageBufferDst.get(); }
1204
1205 de::MovePtr<Buffer> m_imageBufferDst;
1206 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1207 Move<VkDescriptorPool> m_descriptorPool;
1208 Move<VkDescriptorSet> m_descriptorSet;
1209 Move<VkBufferView> m_bufferViewSrc;
1210 Move<VkBufferView> m_bufferViewDst;
1211 };
1212
BufferLoadStoreTestInstance(Context & context,const Texture & texture,const VkFormat format,const VkFormat imageFormat)1213 BufferLoadStoreTestInstance::BufferLoadStoreTestInstance (Context& context,
1214 const Texture& texture,
1215 const VkFormat format,
1216 const VkFormat imageFormat)
1217 : LoadStoreTestInstance(context, texture, format, imageFormat, false)
1218 {
1219 const DeviceInterface& vk = m_context.getDeviceInterface();
1220 const VkDevice device = m_context.getDevice();
1221 Allocator& allocator = m_context.getDefaultAllocator();
1222
1223 // Create a destination buffer.
1224
1225 m_imageBufferDst = de::MovePtr<Buffer>(new Buffer(
1226 vk, device, allocator,
1227 makeBufferCreateInfo(m_imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
1228 MemoryRequirement::HostVisible));
1229 }
1230
prepareDescriptors(void)1231 VkDescriptorSetLayout BufferLoadStoreTestInstance::prepareDescriptors (void)
1232 {
1233 const DeviceInterface& vk = m_context.getDeviceInterface();
1234 const VkDevice device = m_context.getDevice();
1235
1236 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1237 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1238 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1239 .build(vk, device);
1240
1241 m_descriptorPool = DescriptorPoolBuilder()
1242 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
1243 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
1244 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1245
1246 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1247 m_bufferViewSrc = makeBufferView(vk, device, m_imageBuffer->get(), m_format, 0ull, m_imageSizeBytes);
1248 m_bufferViewDst = makeBufferView(vk, device, m_imageBufferDst->get(), m_format, 0ull, m_imageSizeBytes);
1249
1250 return *m_descriptorSetLayout; // not passing the ownership
1251 }
1252
commandBindDescriptorsForLayer(const VkCommandBuffer cmdBuffer,const VkPipelineLayout pipelineLayout,const int layerNdx)1253 void BufferLoadStoreTestInstance::commandBindDescriptorsForLayer (const VkCommandBuffer cmdBuffer, const VkPipelineLayout pipelineLayout, const int layerNdx)
1254 {
1255 DE_ASSERT(layerNdx == 0);
1256 DE_UNREF(layerNdx);
1257
1258 const VkDevice device = m_context.getDevice();
1259 const DeviceInterface& vk = m_context.getDeviceInterface();
1260
1261 DescriptorSetUpdateBuilder()
1262 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferViewSrc.get())
1263 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferViewDst.get())
1264 .update(vk, device);
1265 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
1266 }
1267
commandAfterCompute(const VkCommandBuffer cmdBuffer)1268 void BufferLoadStoreTestInstance::commandAfterCompute (const VkCommandBuffer cmdBuffer)
1269 {
1270 commandBufferWriteBarrierBeforeHostRead(m_context, cmdBuffer, m_imageBufferDst->get(), m_imageSizeBytes);
1271 }
1272
createInstance(Context & context) const1273 TestInstance* StoreTest::createInstance (Context& context) const
1274 {
1275 if (m_texture.type() == IMAGE_TYPE_BUFFER)
1276 return new BufferStoreTestInstance(context, m_texture, m_format);
1277 else
1278 return new ImageStoreTestInstance(context, m_texture, m_format, m_singleLayerBind);
1279 }
1280
createInstance(Context & context) const1281 TestInstance* LoadStoreTest::createInstance (Context& context) const
1282 {
1283 if (m_texture.type() == IMAGE_TYPE_BUFFER)
1284 return new BufferLoadStoreTestInstance(context, m_texture, m_format, m_imageFormat);
1285 else
1286 return new ImageLoadStoreTestInstance(context, m_texture, m_format, m_imageFormat, m_singleLayerBind);
1287 }
1288
1289 // TODO Which image/format combinations should be supported? Spec says it should be queried with vkGetPhysicalDeviceImageFormatProperties.
1290 // What about buffer/format? (texel storage buffer) (use vkGetPhysicalDeviceFormatProperties ?)
1291
1292 static const Texture s_textures[] =
1293 {
1294 Texture(IMAGE_TYPE_1D, tcu::IVec3(64, 1, 1), 1),
1295 Texture(IMAGE_TYPE_1D_ARRAY, tcu::IVec3(64, 1, 1), 8),
1296 Texture(IMAGE_TYPE_2D, tcu::IVec3(64, 64, 1), 1),
1297 Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(64, 64, 1), 8),
1298 Texture(IMAGE_TYPE_3D, tcu::IVec3(64, 64, 8), 1),
1299 Texture(IMAGE_TYPE_CUBE, tcu::IVec3(64, 64, 1), 6),
1300 Texture(IMAGE_TYPE_CUBE_ARRAY, tcu::IVec3(64, 64, 1), 2*6),
1301 Texture(IMAGE_TYPE_BUFFER, tcu::IVec3(64, 1, 1), 1),
1302 };
1303
getTestTexture(const ImageType imageType)1304 const Texture& getTestTexture (const ImageType imageType)
1305 {
1306 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
1307 if (s_textures[textureNdx].type() == imageType)
1308 return s_textures[textureNdx];
1309
1310 DE_FATAL("Internal error");
1311 return s_textures[0];
1312 }
1313
1314 static const VkFormat s_formats[] =
1315 {
1316 VK_FORMAT_R32G32B32A32_SFLOAT,
1317 VK_FORMAT_R16G16B16A16_SFLOAT,
1318 VK_FORMAT_R32_SFLOAT,
1319
1320 VK_FORMAT_R32G32B32A32_UINT,
1321 VK_FORMAT_R16G16B16A16_UINT,
1322 VK_FORMAT_R8G8B8A8_UINT,
1323 VK_FORMAT_R32_UINT,
1324
1325 VK_FORMAT_R32G32B32A32_SINT,
1326 VK_FORMAT_R16G16B16A16_SINT,
1327 VK_FORMAT_R8G8B8A8_SINT,
1328 VK_FORMAT_R32_SINT,
1329
1330 VK_FORMAT_R8G8B8A8_UNORM,
1331
1332 VK_FORMAT_R8G8B8A8_SNORM,
1333 };
1334
1335 } // anonymous ns
1336
createImageStoreTests(tcu::TestContext & testCtx)1337 tcu::TestCaseGroup* createImageStoreTests (tcu::TestContext& testCtx)
1338 {
1339 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "store", "Plain imageStore() cases"));
1340
1341 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
1342 {
1343 const Texture& texture = s_textures[textureNdx];
1344 de::MovePtr<tcu::TestCaseGroup> groupByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str(), ""));
1345 const bool isLayered = (texture.numLayers() > 1);
1346
1347 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
1348 {
1349 groupByImageViewType->addChild(new StoreTest(testCtx, getFormatCaseName(s_formats[formatNdx]), "", texture, s_formats[formatNdx]));
1350
1351 if (isLayered)
1352 groupByImageViewType->addChild(new StoreTest(testCtx, getFormatCaseName(s_formats[formatNdx]) + "_single_layer", "",
1353 texture, s_formats[formatNdx], StoreTest::FLAG_SINGLE_LAYER_BIND));
1354 }
1355 testGroup->addChild(groupByImageViewType.release());
1356 }
1357
1358 return testGroup.release();
1359 }
1360
createImageLoadStoreTests(tcu::TestContext & testCtx)1361 tcu::TestCaseGroup* createImageLoadStoreTests (tcu::TestContext& testCtx)
1362 {
1363 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store", "Cases with imageLoad() followed by imageStore()"));
1364
1365 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
1366 {
1367 const Texture& texture = s_textures[textureNdx];
1368 de::MovePtr<tcu::TestCaseGroup> groupByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str(), ""));
1369 const bool isLayered = (texture.numLayers() > 1);
1370
1371 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
1372 {
1373 groupByImageViewType->addChild(new LoadStoreTest(testCtx, getFormatCaseName(s_formats[formatNdx]), "",
1374 texture, s_formats[formatNdx], s_formats[formatNdx]));
1375
1376 if (isLayered)
1377 groupByImageViewType->addChild(new LoadStoreTest(testCtx, getFormatCaseName(s_formats[formatNdx]) + "_single_layer", "",
1378 texture, s_formats[formatNdx], s_formats[formatNdx], LoadStoreTest::FLAG_SINGLE_LAYER_BIND));
1379 }
1380 testGroup->addChild(groupByImageViewType.release());
1381 }
1382
1383 return testGroup.release();
1384 }
1385
createImageFormatReinterpretTests(tcu::TestContext & testCtx)1386 tcu::TestCaseGroup* createImageFormatReinterpretTests (tcu::TestContext& testCtx)
1387 {
1388 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "format_reinterpret", "Cases with differing texture and image formats"));
1389
1390 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
1391 {
1392 const Texture& texture = s_textures[textureNdx];
1393 de::MovePtr<tcu::TestCaseGroup> groupByImageViewType (new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str(), ""));
1394
1395 for (int imageFormatNdx = 0; imageFormatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++imageFormatNdx)
1396 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++formatNdx)
1397 {
1398 //TODO Are all conversions valid or do we have to limit (or expand) somehow? Is it stated anywhere in the spec?
1399
1400 const std::string caseName = getFormatCaseName(s_formats[imageFormatNdx]) + "_" + getFormatCaseName(s_formats[formatNdx]);
1401 if (imageFormatNdx != formatNdx && formatsAreCompatible(s_formats[imageFormatNdx], s_formats[formatNdx]))
1402 groupByImageViewType->addChild(new LoadStoreTest(testCtx, caseName, "", texture, s_formats[formatNdx], s_formats[imageFormatNdx]));
1403 }
1404 testGroup->addChild(groupByImageViewType.release());
1405 }
1406
1407 return testGroup.release();
1408 }
1409
createImageQualifierRestrictCase(tcu::TestContext & testCtx,const ImageType imageType,const std::string & name)1410 de::MovePtr<TestCase> createImageQualifierRestrictCase (tcu::TestContext& testCtx, const ImageType imageType, const std::string& name)
1411 {
1412 const VkFormat format = VK_FORMAT_R32G32B32A32_UINT;
1413 const Texture& texture = getTestTexture(imageType);
1414 return de::MovePtr<TestCase>(new LoadStoreTest(testCtx, name, "", texture, format, format, LoadStoreTest::FLAG_RESTRICT_IMAGES));
1415 }
1416
1417 } // image
1418 } // vkt
1419