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