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