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 Multisampled image load/store Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktImageMultisampleLoadStoreTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageLoadStoreUtil.hpp"
29 #include "vktImageTexture.hpp"
30
31 #include "vkDefs.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkQueryUtil.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 #include "vkBufferWithMemory.hpp"
44
45 #include "deUniquePtr.hpp"
46
47 #include "tcuTextureUtil.hpp"
48 #include "tcuTestLog.hpp"
49
50 #include <string>
51 #include <vector>
52
53 namespace vkt
54 {
55 namespace image
56 {
57 namespace
58 {
59 using namespace vk;
60 using de::MovePtr;
61 using de::UniquePtr;
62 using tcu::IVec3;
63
64 static const VkFormat CHECKSUM_IMAGE_FORMAT = VK_FORMAT_R32_SINT;
65
66 struct CaseDef
67 {
68 Texture texture;
69 VkFormat format;
70 VkSampleCountFlagBits numSamples;
71 bool singleLayerBind;
72 };
73
74 // Multisampled storage image test.
75 //
76 // Pass 1: Write a slightly different color pattern per-sample to the whole image.
77 // Pass 2: Read samples of the same image and check if color values are in the expected range.
78 // Write back results as a checksum image and verify them on the host.
79 // Each checksum image pixel should contain an integer equal to the number of samples.
80
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)81 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
82 {
83 const int dimension = (caseDef.singleLayerBind ? caseDef.texture.layerDimension() : caseDef.texture.dimension());
84 const std::string texelCoordStr = (dimension == 1 ? "gx" :
85 dimension == 2 ? "ivec2(gx, gy)" :
86 dimension == 3 ? "ivec3(gx, gy, gz)" :
87 "");
88
89 const ImageType usedImageType =
90 (caseDef.singleLayerBind ? getImageTypeForSingleLayer(caseDef.texture.type()) : caseDef.texture.type());
91 const bool isAlphaOnly = isAlphaOnlyFormat(caseDef.format);
92 const std::string formatQualifierStr =
93 (isAlphaOnly ? "" : ", " + getShaderImageFormatQualifier(mapVkFormat(caseDef.format)));
94 const std::string msImageTypeStr =
95 getShaderImageType(mapVkFormat(caseDef.format), usedImageType, (caseDef.texture.numSamples() > 1));
96
97 const std::string xMax = de::toString(caseDef.texture.size().x() - 1);
98 const std::string yMax = de::toString(caseDef.texture.size().y() - 1);
99 const std::string signednessPrefix = isUintFormat(caseDef.format) ? "u" : isIntFormat(caseDef.format) ? "i" : "";
100 const std::string gvec4Expr = signednessPrefix + "vec4";
101 const int numColorComponents =
102 (isAlphaOnly ?
103 4 :
104 tcu::getNumUsedChannels(mapVkFormat(caseDef.format).order)); // Force 4 for A8_UNORM as per the spec.
105
106 const float storeColorScale = computeStoreColorScale(caseDef.format, caseDef.texture.size());
107 const float storeColorBias = computeStoreColorBias(caseDef.format);
108 DE_ASSERT(colorScaleAndBiasAreValid(caseDef.format, storeColorScale, storeColorBias));
109
110 const std::string colorScaleExpr = (storeColorScale == 1.0f ? "" : "*" + de::toString(storeColorScale)) +
111 (storeColorBias == 0.0f ? "" : " + float(" + de::toString(storeColorBias) + ")");
112
113 const std::string red =
114 "gx^gy^gz^(sampleNdx >> 5)^(sampleNdx & 31)"; // we "split" sampleNdx to keep this value in [0, 31] range for numSamples = 64 case
115 const std::string green = "(" + xMax + "-gx)^gy^gz";
116 const std::string blue = "gx^(" + yMax + "-gy)^gz";
117 const std::string alpha = "(" + xMax + "-gx)^(" + yMax + "-gy)^gz";
118 const std::string colorExpr =
119 gvec4Expr + "(" + ((isAlphaOnly ? alpha : red) + ", ") // For A8_UNORM we switch the alpha and red values.
120 + (numColorComponents > 1 ? green + ", " : "0, ") + (numColorComponents > 2 ? blue + ", " : "0, ") +
121 (numColorComponents > 3 ? (isAlphaOnly ? red : alpha) : "1") + ")" + colorScaleExpr;
122
123 const std::string expectedColorExpr =
124 gvec4Expr + "(" + ((isAlphaOnly ? "0" : red) + ", ") // A8_UNORM should result in RGB (0, 0, 0).
125 + ((numColorComponents > 1 && !isAlphaOnly) ? green + ", " : "0, ") +
126 ((numColorComponents > 2 && !isAlphaOnly) ? blue + ", " : "0, ") +
127 ((numColorComponents > 3) ? (isAlphaOnly ? red : alpha) : "1") + ")" + colorScaleExpr;
128
129 // Store shader
130 {
131 std::ostringstream src;
132 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
133 << (isAlphaOnly ? "#extension GL_EXT_shader_image_load_formatted : require\n" : "") << "\n"
134 << "layout(local_size_x = 1) in;\n"
135 << "layout(set = 0, binding = 1" << formatQualifierStr << ") writeonly uniform " << msImageTypeStr
136 << " u_msImage;\n";
137
138 if (caseDef.singleLayerBind)
139 src << "layout(set = 0, binding = 0) readonly uniform Constants {\n"
140 << " int u_layerNdx;\n"
141 << "};\n";
142
143 src << "\n"
144 << "void main (void)\n"
145 << "{\n"
146 << " int gx = int(gl_GlobalInvocationID.x);\n"
147 << " int gy = int(gl_GlobalInvocationID.y);\n"
148 << " int gz = " << (caseDef.singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
149 << "\n"
150 << " for (int sampleNdx = 0; sampleNdx < " << caseDef.texture.numSamples() << "; ++sampleNdx) {\n"
151 << " imageStore(u_msImage, " << texelCoordStr << ", sampleNdx, " << colorExpr << ");\n"
152 << " }\n"
153 << "}\n";
154
155 programCollection.glslSources.add("comp_store") << glu::ComputeSource(src.str());
156 }
157
158 // Load shader
159 {
160 const tcu::TextureFormat checksumFormat = mapVkFormat(CHECKSUM_IMAGE_FORMAT);
161 const std::string checksumImageTypeStr = getShaderImageType(checksumFormat, usedImageType);
162 const bool useExactCompare = isIntegerFormat(caseDef.format);
163
164 std::ostringstream src;
165 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
166 << (isAlphaOnly ? "#extension GL_EXT_shader_image_load_formatted : require\n" : "") << "\n"
167 << "layout(local_size_x = 1) in;\n"
168 << "layout(set = 0, binding = 1" << formatQualifierStr << ") readonly uniform " << msImageTypeStr
169 << " u_msImage;\n"
170 << "layout(set = 0, binding = 2, " << getShaderImageFormatQualifier(checksumFormat)
171 << ") writeonly uniform " << checksumImageTypeStr << " u_checksumImage;\n";
172
173 if (caseDef.singleLayerBind)
174 src << "layout(set = 0, binding = 0) readonly uniform Constants {\n"
175 << " int u_layerNdx;\n"
176 << "};\n";
177
178 src << "\n"
179 << "void main (void)\n"
180 << "{\n"
181 << " int gx = int(gl_GlobalInvocationID.x);\n"
182 << " int gy = int(gl_GlobalInvocationID.y);\n"
183 << " int gz = " << (caseDef.singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
184 << "\n"
185 << " int checksum = 0;\n"
186 << " for (int sampleNdx = 0; sampleNdx < " << caseDef.texture.numSamples() << "; ++sampleNdx) {\n"
187 << " " << gvec4Expr << " color = imageLoad(u_msImage, " << texelCoordStr << ", sampleNdx);\n";
188
189 if (useExactCompare)
190 src << " if (color == " << expectedColorExpr << ")\n"
191 << " ++checksum;\n";
192 else
193 src << " " << gvec4Expr << " diff = abs(abs(color) - abs(" << expectedColorExpr << "));\n"
194 << " if (all(lessThan(diff, " << gvec4Expr << "(0.02))))\n"
195 << " ++checksum;\n";
196
197 src << " }\n"
198 << "\n"
199 << " imageStore(u_checksumImage, " << texelCoordStr << ", ivec4(checksum));\n"
200 << "}\n";
201
202 programCollection.glslSources.add("comp_load") << glu::ComputeSource(src.str());
203 }
204 }
205
checkSupport(Context & context,const CaseDef caseDef)206 void checkSupport(Context &context, const CaseDef caseDef)
207 {
208 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_MULTISAMPLE);
209
210 #ifndef CTS_USES_VULKANSC
211 if (caseDef.format == VK_FORMAT_A8_UNORM_KHR)
212 context.requireDeviceFunctionality("VK_KHR_maintenance5");
213 #endif // CTS_USES_VULKANSC
214
215 VkImageFormatProperties imageFormatProperties;
216 const auto &vki = context.getInstanceInterface();
217 const auto physicalDevice = context.getPhysicalDevice();
218 const VkResult imageFormatResult = vki.getPhysicalDeviceImageFormatProperties(
219 physicalDevice, caseDef.format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT,
220 (VkImageCreateFlags)0, &imageFormatProperties);
221
222 if (imageFormatResult == VK_ERROR_FORMAT_NOT_SUPPORTED)
223 TCU_THROW(NotSupportedError, "Format is not supported");
224
225 if ((imageFormatProperties.sampleCounts & caseDef.numSamples) != caseDef.numSamples)
226 TCU_THROW(NotSupportedError, "Requested sample count is not supported");
227
228 #ifndef CTS_USES_VULKANSC
229 if (caseDef.format == VK_FORMAT_A8_UNORM_KHR)
230 {
231 const auto formatProperties = context.getFormatProperties(caseDef.format);
232
233 if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT) == 0u)
234 TCU_THROW(NotSupportedError, "Format does not support storage reads without format");
235
236 if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT) == 0u)
237 TCU_THROW(NotSupportedError, "Format does not support storage writes without format");
238 }
239 #endif // CTS_USES_VULKANSC
240 }
241
242 //! Helper function to deal with per-layer resources.
insertImageViews(const DeviceInterface & vk,const VkDevice device,const CaseDef & caseDef,const VkFormat format,const VkImage image,std::vector<SharedVkImageView> * const pOutImageViews)243 void insertImageViews(const DeviceInterface &vk, const VkDevice device, const CaseDef &caseDef, const VkFormat format,
244 const VkImage image, std::vector<SharedVkImageView> *const pOutImageViews)
245 {
246 if (caseDef.singleLayerBind)
247 {
248 pOutImageViews->clear();
249 pOutImageViews->resize(caseDef.texture.numLayers());
250 for (int layerNdx = 0; layerNdx < caseDef.texture.numLayers(); ++layerNdx)
251 {
252 (*pOutImageViews)[layerNdx] = makeVkSharedPtr(
253 makeImageView(vk, device, image, mapImageViewType(getImageTypeForSingleLayer(caseDef.texture.type())),
254 format, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u)));
255 }
256 }
257 else // bind all layers at once
258 {
259 pOutImageViews->clear();
260 pOutImageViews->resize(1);
261 (*pOutImageViews)[0] = makeVkSharedPtr(makeImageView(
262 vk, device, image, mapImageViewType(caseDef.texture.type()), format,
263 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, caseDef.texture.numLayers())));
264 }
265 }
266
267 //! Helper function to deal with per-layer resources.
insertDescriptorSets(const DeviceInterface & vk,const VkDevice device,const CaseDef & caseDef,const VkDescriptorPool descriptorPool,const VkDescriptorSetLayout descriptorSetLayout,std::vector<SharedVkDescriptorSet> * const pOutDescriptorSets)268 void insertDescriptorSets(const DeviceInterface &vk, const VkDevice device, const CaseDef &caseDef,
269 const VkDescriptorPool descriptorPool, const VkDescriptorSetLayout descriptorSetLayout,
270 std::vector<SharedVkDescriptorSet> *const pOutDescriptorSets)
271 {
272 if (caseDef.singleLayerBind)
273 {
274 pOutDescriptorSets->clear();
275 pOutDescriptorSets->resize(caseDef.texture.numLayers());
276 for (int layerNdx = 0; layerNdx < caseDef.texture.numLayers(); ++layerNdx)
277 (*pOutDescriptorSets)[layerNdx] =
278 makeVkSharedPtr(makeDescriptorSet(vk, device, descriptorPool, descriptorSetLayout));
279 }
280 else // bind all layers at once
281 {
282 pOutDescriptorSets->clear();
283 pOutDescriptorSets->resize(1);
284 (*pOutDescriptorSets)[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, descriptorPool, descriptorSetLayout));
285 }
286 }
287
test(Context & context,const CaseDef caseDef)288 tcu::TestStatus test(Context &context, const CaseDef caseDef)
289 {
290 const InstanceInterface &vki = context.getInstanceInterface();
291 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
292 const DeviceInterface &vk = context.getDeviceInterface();
293 const VkDevice device = context.getDevice();
294 const VkQueue queue = context.getUniversalQueue();
295 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
296 Allocator &allocator = context.getDefaultAllocator();
297
298 // Images
299
300 const UniquePtr<Image> msImage(new Image(
301 vk, device, allocator, makeImageCreateInfo(caseDef.texture, caseDef.format, VK_IMAGE_USAGE_STORAGE_BIT, 0u),
302 MemoryRequirement::Any));
303
304 const UniquePtr<Image> checksumImage(
305 new Image(vk, device, allocator,
306 makeImageCreateInfo(Texture(caseDef.texture, 1), CHECKSUM_IMAGE_FORMAT,
307 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u),
308 MemoryRequirement::Any));
309
310 // Buffer used to pass constants to the shader.
311
312 const int numLayers = caseDef.texture.numLayers();
313 const VkDeviceSize bufferChunkSize = getOptimalUniformBufferChunkSize(vki, physDevice, sizeof(int32_t));
314 const VkDeviceSize constantsBufferSizeBytes = numLayers * bufferChunkSize;
315 UniquePtr<BufferWithMemory> constantsBuffer(new BufferWithMemory(
316 vk, device, allocator, makeBufferCreateInfo(constantsBufferSizeBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
317 MemoryRequirement::HostVisible));
318
319 {
320 const Allocation &alloc = constantsBuffer->getAllocation();
321 uint8_t *const basePtr = static_cast<uint8_t *>(alloc.getHostPtr());
322
323 deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(constantsBufferSizeBytes));
324
325 for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
326 {
327 int32_t *const valuePtr = reinterpret_cast<int32_t *>(basePtr + layerNdx * bufferChunkSize);
328 *valuePtr = layerNdx;
329 }
330
331 flushAlloc(vk, device, alloc);
332 }
333
334 const VkDeviceSize resultBufferSizeBytes = getImageSizeBytes(caseDef.texture.size(), CHECKSUM_IMAGE_FORMAT);
335 UniquePtr<BufferWithMemory> resultBuffer(new BufferWithMemory(
336 vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
337 MemoryRequirement::HostVisible));
338
339 {
340 const Allocation &alloc = resultBuffer->getAllocation();
341 deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(resultBufferSizeBytes));
342 flushAlloc(vk, device, alloc);
343 }
344
345 // Descriptors
346
347 Unique<VkDescriptorSetLayout> descriptorSetLayout(
348 DescriptorSetLayoutBuilder()
349 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
350 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
351 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
352 .build(vk, device));
353
354 Unique<VkDescriptorPool> descriptorPool(
355 DescriptorPoolBuilder()
356 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, numLayers)
357 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
358 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
359 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers));
360
361 std::vector<SharedVkDescriptorSet> allDescriptorSets;
362 std::vector<SharedVkImageView> allMultisampledImageViews;
363 std::vector<SharedVkImageView> allChecksumImageViews;
364
365 insertDescriptorSets(vk, device, caseDef, *descriptorPool, *descriptorSetLayout, &allDescriptorSets);
366 insertImageViews(vk, device, caseDef, caseDef.format, **msImage, &allMultisampledImageViews);
367 insertImageViews(vk, device, caseDef, CHECKSUM_IMAGE_FORMAT, **checksumImage, &allChecksumImageViews);
368
369 // Prepare commands
370
371 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
372 const Unique<VkCommandPool> cmdPool(
373 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
374 const Unique<VkCommandBuffer> cmdBuffer(
375 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
376
377 const tcu::IVec3 workSize = (caseDef.singleLayerBind ? caseDef.texture.layerSize() : caseDef.texture.size());
378 const int loopNumLayers = (caseDef.singleLayerBind ? numLayers : 1);
379 const VkImageSubresourceRange subresourceAllLayers =
380 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, caseDef.texture.numLayers());
381
382 // Pass 1: Write MS image
383 {
384 const Unique<VkShaderModule> shaderModule(
385 createShaderModule(vk, device, context.getBinaryCollection().get("comp_store"), 0));
386 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
387
388 beginCommandBuffer(vk, *cmdBuffer);
389 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
390
391 {
392 const VkImageMemoryBarrier barriers[] = {
393 makeImageMemoryBarrier((VkAccessFlags)0, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
394 VK_IMAGE_LAYOUT_GENERAL, **msImage, subresourceAllLayers),
395 makeImageMemoryBarrier((VkAccessFlags)0, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
396 VK_IMAGE_LAYOUT_GENERAL, **checksumImage, subresourceAllLayers),
397 };
398
399 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
400 (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers),
401 barriers);
402 }
403
404 for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
405 {
406 const VkDescriptorSet descriptorSet = **allDescriptorSets[layerNdx];
407 const VkDescriptorImageInfo descriptorMultiImageInfo =
408 makeDescriptorImageInfo(DE_NULL, **allMultisampledImageViews[layerNdx], VK_IMAGE_LAYOUT_GENERAL);
409 const VkDescriptorBufferInfo descriptorConstantsBufferInfo =
410 makeDescriptorBufferInfo(constantsBuffer->get(), layerNdx * bufferChunkSize, bufferChunkSize);
411
412 DescriptorSetUpdateBuilder()
413 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
414 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
415 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
416 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorMultiImageInfo)
417 .update(vk, device);
418
419 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
420 &descriptorSet, 0u, DE_NULL);
421 vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
422 }
423
424 endCommandBuffer(vk, *cmdBuffer);
425 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
426 context.resetCommandPoolForVKSC(device, *cmdPool);
427 }
428
429 // Pass 2: "Resolve" MS image in compute shader
430 {
431 const Unique<VkShaderModule> shaderModule(
432 createShaderModule(vk, device, context.getBinaryCollection().get("comp_load"), 0));
433 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
434
435 beginCommandBuffer(vk, *cmdBuffer);
436 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
437
438 {
439 const VkImageMemoryBarrier barriers[] = {
440 makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
441 VK_IMAGE_LAYOUT_GENERAL, **msImage, subresourceAllLayers),
442 };
443
444 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
445 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL,
446 DE_LENGTH_OF_ARRAY(barriers), barriers);
447 }
448
449 for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
450 {
451 const VkDescriptorSet descriptorSet = **allDescriptorSets[layerNdx];
452 const VkDescriptorImageInfo descriptorMultiImageInfo =
453 makeDescriptorImageInfo(DE_NULL, **allMultisampledImageViews[layerNdx], VK_IMAGE_LAYOUT_GENERAL);
454 const VkDescriptorImageInfo descriptorChecksumImageInfo =
455 makeDescriptorImageInfo(DE_NULL, **allChecksumImageViews[layerNdx], VK_IMAGE_LAYOUT_GENERAL);
456 const VkDescriptorBufferInfo descriptorConstantsBufferInfo =
457 makeDescriptorBufferInfo(constantsBuffer->get(), layerNdx * bufferChunkSize, bufferChunkSize);
458
459 DescriptorSetUpdateBuilder()
460 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
461 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
462 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
463 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorMultiImageInfo)
464 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u),
465 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorChecksumImageInfo)
466 .update(vk, device);
467
468 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
469 &descriptorSet, 0u, DE_NULL);
470 vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
471 }
472
473 endCommandBuffer(vk, *cmdBuffer);
474 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
475 context.resetCommandPoolForVKSC(device, *cmdPool);
476 }
477
478 // Retrieve result
479 {
480 beginCommandBuffer(vk, *cmdBuffer);
481
482 {
483 const VkImageMemoryBarrier barriers[] = {
484 makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
485 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **checksumImage, subresourceAllLayers),
486 };
487 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
488 (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers),
489 barriers);
490 }
491 {
492 const VkBufferImageCopy copyRegion =
493 makeBufferImageCopy(makeExtent3D(caseDef.texture.layerSize()), caseDef.texture.numLayers());
494 vk.cmdCopyImageToBuffer(*cmdBuffer, **checksumImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer,
495 1u, ©Region);
496 }
497 {
498 const VkBufferMemoryBarrier barriers[] = {
499 makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, **resultBuffer, 0ull,
500 resultBufferSizeBytes),
501 };
502 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
503 (VkDependencyFlags)0, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, 0u,
504 DE_NULL);
505 }
506
507 endCommandBuffer(vk, *cmdBuffer);
508 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
509 }
510
511 // Verify
512 {
513 const Allocation &alloc = resultBuffer->getAllocation();
514 invalidateAlloc(vk, device, alloc);
515
516 const IVec3 imageSize = caseDef.texture.size();
517 const int32_t *pDataPtr = static_cast<int32_t *>(alloc.getHostPtr());
518 const int32_t expectedChecksum = caseDef.texture.numSamples();
519
520 for (int layer = 0; layer < imageSize.z(); ++layer)
521 for (int y = 0; y < imageSize.y(); ++y)
522 for (int x = 0; x < imageSize.x(); ++x)
523 {
524 if (*pDataPtr != expectedChecksum)
525 {
526 context.getTestContext().getLog()
527 << tcu::TestLog::Message << "Some sample colors were incorrect at (x, y, layer) = (" << x
528 << ", " << y << ", " << layer << ")" << tcu::TestLog::EndMessage << tcu::TestLog::Message
529 << "Checksum value is " << *pDataPtr << " but expected " << expectedChecksum
530 << tcu::TestLog::EndMessage;
531
532 return tcu::TestStatus::fail("Some sample colors were incorrect");
533 }
534 ++pDataPtr;
535 }
536
537 return tcu::TestStatus::pass("OK");
538 }
539 }
540
541 } // namespace
542
createImageMultisampleLoadStoreTests(tcu::TestContext & testCtx)543 tcu::TestCaseGroup *createImageMultisampleLoadStoreTests(tcu::TestContext &testCtx)
544 {
545 const Texture textures[] = {
546 // \note Shader code is tweaked to work with image size of 32, take a look if this needs to be modified.
547 Texture(IMAGE_TYPE_2D, tcu::IVec3(32, 32, 1), 1),
548 Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(32, 32, 1), 4),
549 };
550
551 static const VkFormat formats[] = {
552 VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32_SFLOAT,
553
554 VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R32_UINT,
555
556 VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R8G8B8A8_SINT, VK_FORMAT_R32_SINT,
557
558 VK_FORMAT_R8G8B8A8_UNORM,
559
560 VK_FORMAT_R8G8B8A8_SNORM,
561
562 #ifndef CTS_USES_VULKANSC
563 VK_FORMAT_A8_UNORM_KHR,
564 #endif // CTS_USES_VULKANSC
565 };
566
567 static const VkSampleCountFlagBits samples[] = {
568 VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT,
569 VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_64_BIT,
570 };
571
572 MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store_multisample"));
573
574 for (int baseTextureNdx = 0; baseTextureNdx < DE_LENGTH_OF_ARRAY(textures); ++baseTextureNdx)
575 {
576 const Texture &baseTexture = textures[baseTextureNdx];
577 MovePtr<tcu::TestCaseGroup> imageViewGroup(
578 new tcu::TestCaseGroup(testCtx, getImageTypeName(baseTexture.type()).c_str()));
579 const int numLayerBindModes = (baseTexture.numLayers() == 1 ? 1 : 2);
580
581 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
582 for (int layerBindMode = 0; layerBindMode < numLayerBindModes; ++layerBindMode)
583 {
584 const bool singleLayerBind = (layerBindMode != 0);
585 const std::string formatGroupName =
586 getFormatShortString(formats[formatNdx]) + (singleLayerBind ? "_single_layer" : "");
587 MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, formatGroupName.c_str()));
588
589 for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
590 {
591 const std::string samplesCaseName = "samples_" + de::toString(samples[samplesNdx]);
592
593 const CaseDef caseDef = {
594 Texture(baseTexture, samples[samplesNdx]),
595 formats[formatNdx],
596 samples[samplesNdx],
597 singleLayerBind,
598 };
599
600 addFunctionCaseWithPrograms(formatGroup.get(), samplesCaseName, checkSupport, initPrograms, test,
601 caseDef);
602 }
603 imageViewGroup->addChild(formatGroup.release());
604 }
605 testGroup->addChild(imageViewGroup.release());
606 }
607
608 return testGroup.release();
609 }
610
611 } // namespace image
612 } // namespace vkt
613