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