1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2023 LunarG, Inc.
7  * Copyright (c) 2023 Nintendo
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*
22 * \file vktPipelineMultisampleBaseResolve.cpp
23 * \brief Base class for tests that check results of multisample resolve
24 *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineMultisampleBaseResolve.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkBarrierUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "tcuTestLog.hpp"
36 #include <vector>
37 
38 namespace vkt
39 {
40 namespace pipeline
41 {
42 namespace multisample
43 {
44 
45 using namespace vk;
46 
iterate(void)47 tcu::TestStatus MSInstanceBaseResolve::iterate(void)
48 {
49     // cases creating this tests are defined using templates and we do not have easy access
50     // to image type - to do this check in checkSupport bigger reffactoring would be needed
51 #ifndef CTS_USES_VULKANSC
52     if (m_context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
53         !m_context.getPortabilitySubsetFeatures().multisampleArrayImage && (m_imageType == IMAGE_TYPE_2D_ARRAY) &&
54         (m_imageMSParams.numSamples != VK_SAMPLE_COUNT_1_BIT) && (m_imageMSParams.imageSize.z() != 1))
55     {
56         TCU_THROW(
57             NotSupportedError,
58             "VK_KHR_portability_subset: Implementation does not support image array with multiple samples per texel");
59     }
60 #endif // CTS_USES_VULKANSC
61 
62     const InstanceInterface &instance        = m_context.getInstanceInterface();
63     const DeviceInterface &deviceInterface   = m_context.getDeviceInterface();
64     const VkDevice device                    = m_context.getDevice();
65     const VkPhysicalDevice physicalDevice    = m_context.getPhysicalDevice();
66     const VkPhysicalDeviceFeatures &features = m_context.getDeviceFeatures();
67     Allocator &allocator                     = m_context.getDefaultAllocator();
68     const VkQueue queue                      = m_context.getUniversalQueue();
69     const uint32_t queueFamilyIndex          = m_context.getUniversalQueueFamilyIndex();
70     const bool usePushConstants              = (m_imageMSParams.componentData.source == ComponentSource::PUSH_CONSTANT);
71     const uint32_t pushConstantSize = static_cast<uint32_t>(sizeof(decltype(m_imageMSParams.componentData.index)));
72 
73     VkImageCreateInfo imageMSInfo;
74     VkImageCreateInfo imageRSInfo;
75 
76     // Check if image size does not exceed device limits
77     validateImageSize(instance, physicalDevice, m_imageType, m_imageMSParams.imageSize);
78 
79     // Check if device supports image format as color attachment
80     validateImageFeatureFlags(instance, physicalDevice, mapTextureFormat(m_imageFormat),
81                               VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
82 
83     imageMSInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
84     imageMSInfo.pNext                 = DE_NULL;
85     imageMSInfo.flags                 = 0u;
86     imageMSInfo.imageType             = mapImageType(m_imageType);
87     imageMSInfo.format                = mapTextureFormat(m_imageFormat);
88     imageMSInfo.extent                = makeExtent3D(getLayerSize(m_imageType, m_imageMSParams.imageSize));
89     imageMSInfo.arrayLayers           = getNumLayers(m_imageType, m_imageMSParams.imageSize);
90     imageMSInfo.mipLevels             = 1u;
91     imageMSInfo.samples               = m_imageMSParams.numSamples;
92     imageMSInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
93     imageMSInfo.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
94     imageMSInfo.usage                 = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
95     imageMSInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
96     imageMSInfo.queueFamilyIndexCount = 0u;
97     imageMSInfo.pQueueFamilyIndices   = DE_NULL;
98 
99     if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
100     {
101         imageMSInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
102     }
103 
104     validateImageInfo(instance, physicalDevice, imageMSInfo);
105 
106     const de::UniquePtr<ImageWithMemory> imageMS(
107         new ImageWithMemory(deviceInterface, device, allocator, imageMSInfo, MemoryRequirement::Any));
108 
109     imageRSInfo         = imageMSInfo;
110     imageRSInfo.samples = VK_SAMPLE_COUNT_1_BIT;
111 
112     validateImageInfo(instance, physicalDevice, imageRSInfo);
113 
114     const de::UniquePtr<ImageWithMemory> imageRS(
115         new ImageWithMemory(deviceInterface, device, allocator, imageRSInfo, MemoryRequirement::Any));
116 
117     // Create render pass
118     const VkAttachmentDescription attachmentMSDesc = {
119         (VkAttachmentDescriptionFlags)0u,         // VkAttachmentDescriptionFlags flags;
120         imageMSInfo.format,                       // VkFormat format;
121         imageMSInfo.samples,                      // VkSampleCountFlagBits samples;
122         VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
123         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
124         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
125         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
126         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
127         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL  // VkImageLayout finalLayout;
128     };
129 
130     const VkAttachmentDescription attachmentRSDesc = {
131         (VkAttachmentDescriptionFlags)0u,         // VkAttachmentDescriptionFlags flags;
132         imageRSInfo.format,                       // VkFormat format;
133         imageRSInfo.samples,                      // VkSampleCountFlagBits samples;
134         VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
135         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
136         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
137         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
138         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
139         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL  // VkImageLayout finalLayout;
140     };
141 
142     const VkAttachmentDescription attachments[] = {attachmentMSDesc, attachmentRSDesc};
143 
144     const VkAttachmentReference attachmentMSRef = {
145         0u,                                      // uint32_t attachment;
146         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
147     };
148 
149     const VkAttachmentReference attachmentRSRef = {
150         1u,                                      // uint32_t attachment;
151         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
152     };
153 
154     const VkAttachmentReference *resolveAttachment =
155         m_imageMSParams.numSamples == VK_SAMPLE_COUNT_1_BIT ? DE_NULL : &attachmentRSRef;
156 
157     const VkSubpassDescription subpassDescription = {
158         (VkSubpassDescriptionFlags)0u,   // VkSubpassDescriptionFlags flags;
159         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
160         0u,                              // uint32_t inputAttachmentCount;
161         DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
162         1u,                              // uint32_t colorAttachmentCount;
163         &attachmentMSRef,                // const VkAttachmentReference* pColorAttachments;
164         resolveAttachment,               // const VkAttachmentReference* pResolveAttachments;
165         DE_NULL,                         // const VkAttachmentReference* pDepthStencilAttachment;
166         0u,                              // uint32_t preserveAttachmentCount;
167         DE_NULL                          // const uint32_t* pPreserveAttachments;
168     };
169 
170     const VkRenderPassCreateInfo renderPassInfo = {
171         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
172         DE_NULL,                                   // const void* pNext;
173         (VkRenderPassCreateFlags)0u,               // VkRenderPassCreateFlags flags;
174         2u,                                        // uint32_t attachmentCount;
175         attachments,                               // const VkAttachmentDescription* pAttachments;
176         1u,                                        // uint32_t subpassCount;
177         &subpassDescription,                       // const VkSubpassDescription* pSubpasses;
178         0u,                                        // uint32_t dependencyCount;
179         DE_NULL                                    // const VkSubpassDependency* pDependencies;
180     };
181 
182     RenderPassWrapper renderPass(m_imageMSParams.pipelineConstructionType, deviceInterface, device, &renderPassInfo);
183 
184     const VkImageSubresourceRange fullImageRange =
185         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageMSInfo.mipLevels, 0u, imageMSInfo.arrayLayers);
186 
187     // Create color attachments image views
188     const Unique<VkImageView> imageMSView(makeImageView(
189         deviceInterface, device, **imageMS, mapImageViewType(m_imageType), imageMSInfo.format, fullImageRange));
190     const Unique<VkImageView> imageRSView(makeImageView(
191         deviceInterface, device, **imageRS, mapImageViewType(m_imageType), imageMSInfo.format, fullImageRange));
192 
193     std::vector<VkImage> images          = {**imageMS, **imageRS};
194     const VkImageView attachmentsViews[] = {*imageMSView, *imageRSView};
195 
196     // Create framebuffer
197     const VkFramebufferCreateInfo framebufferInfo = {
198         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType                             sType;
199         DE_NULL,                                   // const void*                                 pNext;
200         (VkFramebufferCreateFlags)0u,              // VkFramebufferCreateFlags                    flags;
201         *renderPass,                               // VkRenderPass                                renderPass;
202         2u,                                        // uint32_t                                    attachmentCount;
203         attachmentsViews,                          // const VkImageView*                          pAttachments;
204         imageMSInfo.extent.width,                  // uint32_t                                    width;
205         imageMSInfo.extent.height,                 // uint32_t                                    height;
206         imageMSInfo.arrayLayers,                   // uint32_t                                    layers;
207     };
208 
209     renderPass.createFramebuffer(deviceInterface, device, &framebufferInfo, images);
210 
211     std::vector<vk::VkPushConstantRange> pushConstantRanges;
212 
213     if (usePushConstants)
214     {
215         const vk::VkPushConstantRange pushConstantRange = {
216             vk::VK_SHADER_STAGE_ALL, // VkShaderStageFlags stageFlags;
217             0u,                      // uint32_t offset;
218             pushConstantSize,        // uint32_t size;
219         };
220         pushConstantRanges.push_back(pushConstantRange);
221     }
222 
223     // Create pipeline layout
224     const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
225         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,    // VkStructureType sType;
226         DE_NULL,                                          // const void* pNext;
227         (VkPipelineLayoutCreateFlags)0u,                  // VkPipelineLayoutCreateFlags flags;
228         0u,                                               // uint32_t setLayoutCount;
229         DE_NULL,                                          // const VkDescriptorSetLayout* pSetLayouts;
230         static_cast<uint32_t>(pushConstantRanges.size()), // uint32_t pushConstantRangeCount;
231         (pushConstantRanges.empty() ? nullptr :
232                                       pushConstantRanges.data()), // const VkPushConstantRange* pPushConstantRanges;
233     };
234 
235     const PipelineLayoutWrapper pipelineLayout(m_imageMSParams.pipelineConstructionType, deviceInterface, device,
236                                                &pipelineLayoutParams);
237 
238     // Create vertex attributes data
239     const VertexDataDesc vertexDataDesc = getVertexDataDescripton();
240 
241     de::SharedPtr<BufferWithMemory> vertexBuffer = de::SharedPtr<BufferWithMemory>(
242         new BufferWithMemory(deviceInterface, device, allocator,
243                              makeBufferCreateInfo(vertexDataDesc.dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
244                              MemoryRequirement::HostVisible));
245     const Allocation &vertexBufferAllocation = vertexBuffer->getAllocation();
246 
247     uploadVertexData(vertexBufferAllocation, vertexDataDesc);
248 
249     flushAlloc(deviceInterface, device, vertexBufferAllocation);
250 
251     const VkVertexInputBindingDescription vertexBinding = {
252         0u,                         // uint32_t binding;
253         vertexDataDesc.dataStride,  // uint32_t stride;
254         VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
255     };
256 
257     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
258         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType;
259         DE_NULL,                                                   // const void*                                 pNext;
260         (VkPipelineVertexInputStateCreateFlags)0u,                 // VkPipelineVertexInputStateCreateFlags       flags;
261         1u,             // uint32_t                                    vertexBindingDescriptionCount;
262         &vertexBinding, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
263         static_cast<uint32_t>(
264             vertexDataDesc.vertexAttribDescVec
265                 .size()), // uint32_t                                    vertexAttributeDescriptionCount;
266         dataPointer(
267             vertexDataDesc
268                 .vertexAttribDescVec), // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
269     };
270 
271     const std::vector<VkViewport> viewports{makeViewport(imageMSInfo.extent)};
272     const std::vector<VkRect2D> scissors{makeRect2D(imageMSInfo.extent)};
273 
274     const VkPipelineMultisampleStateCreateInfo multisampleStateInfo{
275         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
276         DE_NULL,                                                  // const void* pNext;
277         (VkPipelineMultisampleStateCreateFlags)0u,                // VkPipelineMultisampleStateCreateFlags flags;
278         imageMSInfo.samples,                                      // VkSampleCountFlagBits rasterizationSamples;
279         features.sampleRateShading,                               // VkBool32 sampleShadingEnable;
280         1.0f,                                                     // float minSampleShading;
281         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
282         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
283         VK_FALSE,                                                 // VkBool32 alphaToOneEnable;
284     };
285 
286     const ShaderWrapper vsModule(ShaderWrapper(
287         deviceInterface, device, m_context.getBinaryCollection().get("vertex_shader"), (VkShaderModuleCreateFlags)0));
288     const ShaderWrapper fsModule(ShaderWrapper(
289         deviceInterface, device, m_context.getBinaryCollection().get("fragment_shader"), (VkShaderModuleCreateFlags)0));
290 
291     // Create graphics pipeline
292     GraphicsPipelineWrapper graphicsPipeline(instance, deviceInterface, physicalDevice, device,
293                                              m_context.getDeviceExtensions(), m_imageMSParams.pipelineConstructionType);
294     graphicsPipeline.setDefaultRasterizationState()
295         .setDefaultColorBlendState()
296         .setDefaultDepthStencilState()
297         .setDefaultTopology(vertexDataDesc.primitiveTopology)
298         .setupVertexInputState(&vertexInputStateInfo)
299         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u, vsModule)
300         .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fsModule, DE_NULL, &multisampleStateInfo)
301         .setupFragmentOutputState(*renderPass, 0, DE_NULL, &multisampleStateInfo)
302         .setMonolithicPipelineLayout(pipelineLayout)
303         .buildPipeline();
304 
305     // Create command buffer for compute and transfer oparations
306     const Unique<VkCommandPool> commandPool(
307         createCommandPool(deviceInterface, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
308     const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, device, *commandPool));
309 
310     // Start recording commands
311     beginCommandBuffer(deviceInterface, *commandBuffer);
312 
313     {
314         VkImageMemoryBarrier imageOutputAttachmentBarriers[2];
315 
316         imageOutputAttachmentBarriers[0] =
317             makeImageMemoryBarrier(0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
318                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, **imageMS, fullImageRange);
319 
320         imageOutputAttachmentBarriers[1] =
321             makeImageMemoryBarrier(0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
322                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, **imageRS, fullImageRange);
323 
324         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
325                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
326                                            2u, imageOutputAttachmentBarriers);
327     }
328 
329     {
330         const VkDeviceSize vertexStartOffset = 0u;
331 
332         std::vector<VkClearValue> clearValues;
333         clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
334         clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
335 
336         renderPass.begin(deviceInterface, *commandBuffer,
337                          makeRect2D(0, 0, imageMSInfo.extent.width, imageMSInfo.extent.height),
338                          (uint32_t)clearValues.size(), &clearValues[0]);
339 
340         // Bind graphics pipeline
341         graphicsPipeline.bind(*commandBuffer);
342 
343         // Bind vertex buffer
344         deviceInterface.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer->get(), &vertexStartOffset);
345 
346         // Push constants.
347         if (usePushConstants)
348             deviceInterface.cmdPushConstants(*commandBuffer, *pipelineLayout, vk::VK_SHADER_STAGE_ALL, 0u,
349                                              pushConstantSize, &m_imageMSParams.componentData.index);
350 
351         // Draw full screen quad
352         deviceInterface.cmdDraw(*commandBuffer, vertexDataDesc.verticesCount, 1u, 0u, 0u);
353 
354         // End render pass
355         renderPass.end(deviceInterface, *commandBuffer);
356     }
357 
358     const VkImage sourceImage = m_imageMSParams.numSamples == VK_SAMPLE_COUNT_1_BIT ? **imageMS : **imageRS;
359 
360     {
361         const VkImageMemoryBarrier imageTransferSrcBarrier = makeImageMemoryBarrier(
362             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
363             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, sourceImage, fullImageRange);
364 
365         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
366                                            VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
367                                            &imageTransferSrcBarrier);
368     }
369 
370     // Copy data from resolve image to buffer
371     const uint32_t imageRSSizeInBytes =
372         getImageSizeInBytes(imageRSInfo.extent, imageRSInfo.arrayLayers, m_imageFormat, imageRSInfo.mipLevels);
373 
374     const VkBufferCreateInfo bufferRSInfo = makeBufferCreateInfo(imageRSSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
375     const de::UniquePtr<BufferWithMemory> bufferRS(
376         new BufferWithMemory(deviceInterface, device, allocator, bufferRSInfo, MemoryRequirement::HostVisible));
377 
378     {
379         const VkBufferImageCopy bufferImageCopy = {
380             0u, // VkDeviceSize bufferOffset;
381             0u, // uint32_t bufferRowLength;
382             0u, // uint32_t bufferImageHeight;
383             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
384                                        imageRSInfo.arrayLayers), // VkImageSubresourceLayers imageSubresource;
385             makeOffset3D(0, 0, 0),                               // VkOffset3D imageOffset;
386             imageRSInfo.extent,                                  // VkExtent3D imageExtent;
387         };
388 
389         deviceInterface.cmdCopyImageToBuffer(*commandBuffer, sourceImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
390                                              bufferRS->get(), 1u, &bufferImageCopy);
391     }
392 
393     {
394         const VkBufferMemoryBarrier bufferRSHostReadBarrier = makeBufferMemoryBarrier(
395             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, bufferRS->get(), 0u, imageRSSizeInBytes);
396 
397         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
398                                            0u, 0u, DE_NULL, 1u, &bufferRSHostReadBarrier, 0u, DE_NULL);
399     }
400 
401     // End recording commands
402     endCommandBuffer(deviceInterface, *commandBuffer);
403 
404     // Submit commands for execution and wait for completion
405     submitCommandsAndWait(deviceInterface, device, queue, *commandBuffer);
406 
407     // Retrieve data from buffer to host memory
408     const Allocation &bufferRSAllocation = bufferRS->getAllocation();
409 
410     invalidateAlloc(deviceInterface, device, bufferRSAllocation);
411 
412     const tcu::ConstPixelBufferAccess bufferRSData(m_imageFormat, imageRSInfo.extent.width, imageRSInfo.extent.height,
413                                                    imageRSInfo.extent.depth * imageRSInfo.arrayLayers,
414                                                    bufferRSAllocation.getHostPtr());
415 
416     std::stringstream imageName;
417     imageName << getImageTypeName(m_imageType) << "_" << bufferRSData.getWidth() << "_" << bufferRSData.getHeight()
418               << "_" << bufferRSData.getDepth() << std::endl;
419 
420     m_context.getTestContext().getLog() << tcu::TestLog::Section(imageName.str(), imageName.str())
421                                         << tcu::LogImage("image", "", bufferRSData) << tcu::TestLog::EndSection;
422 
423     return verifyImageData(imageRSInfo, bufferRSData);
424 }
425 
426 } // namespace multisample
427 } // namespace pipeline
428 } // namespace vkt
429