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