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 vktPipelineMultisampleBaseResolveAndPerSampleFetch.cpp
23 * \brief Base class for tests that check results of multisample resolve
24 * and/or values of individual samples
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineMultisampleBaseResolveAndPerSampleFetch.hpp"
28 #include "vktPipelineMakeUtil.hpp"
29 #include "vkBarrierUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkBufferWithMemory.hpp"
36 #include "vkImageWithMemory.hpp"
37 #include "tcuTestLog.hpp"
38 #include <vector>
39
40 namespace vkt
41 {
42 namespace pipeline
43 {
44 namespace multisample
45 {
46
47 using namespace vk;
48
initPrograms(vk::SourceCollections & programCollection) const49 void MSCaseBaseResolveAndPerSampleFetch::initPrograms(vk::SourceCollections &programCollection) const
50 {
51 // Create vertex shader
52 std::ostringstream vs;
53
54 vs << "#version 440\n"
55 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
56 << "\n"
57 << "out gl_PerVertex {\n"
58 << " vec4 gl_Position;\n"
59 << "};\n"
60 << "void main (void)\n"
61 << "{\n"
62 << " gl_Position = vs_in_position_ndc;\n"
63 << "}\n";
64
65 programCollection.glslSources.add("per_sample_fetch_vs") << glu::VertexSource(vs.str());
66
67 // Create fragment shader
68 std::ostringstream fs;
69
70 fs << "#version 440\n"
71 << "\n"
72 << "layout(location = 0) out vec4 fs_out_color;\n"
73 << "\n"
74 << "layout(set = 0, binding = 0, input_attachment_index = 0) uniform subpassInputMS imageMS;\n"
75 << "\n"
76 << "layout(set = 0, binding = 1, std140) uniform SampleBlock {\n"
77 << " int sampleNdx;\n"
78 << "};\n"
79 << "void main (void)\n"
80 << "{\n"
81 << " fs_out_color = subpassLoad(imageMS, sampleNdx);\n"
82 << "}\n";
83
84 programCollection.glslSources.add("per_sample_fetch_fs") << glu::FragmentSource(fs.str());
85 }
86
MSInstanceBaseResolveAndPerSampleFetch(Context & context,const ImageMSParams & imageMSParams)87 MSInstanceBaseResolveAndPerSampleFetch::MSInstanceBaseResolveAndPerSampleFetch(Context &context,
88 const ImageMSParams &imageMSParams)
89 : MultisampleInstanceBase(context, imageMSParams)
90 {
91 }
92
getMSStateCreateInfo(const ImageMSParams & imageMSParams) const93 VkPipelineMultisampleStateCreateInfo MSInstanceBaseResolveAndPerSampleFetch::getMSStateCreateInfo(
94 const ImageMSParams &imageMSParams) const
95 {
96 const VkPipelineMultisampleStateCreateInfo multisampleStateInfo = {
97 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
98 DE_NULL, // const void* pNext;
99 (VkPipelineMultisampleStateCreateFlags)0u, // VkPipelineMultisampleStateCreateFlags flags;
100 imageMSParams.numSamples, // VkSampleCountFlagBits rasterizationSamples;
101 VK_TRUE, // VkBool32 sampleShadingEnable;
102 imageMSParams.shadingRate, // float minSampleShading;
103 DE_NULL, // const VkSampleMask* pSampleMask;
104 VK_FALSE, // VkBool32 alphaToCoverageEnable;
105 VK_FALSE, // VkBool32 alphaToOneEnable;
106 };
107
108 return multisampleStateInfo;
109 }
110
createMSPassDescSetLayout(const ImageMSParams & imageMSParams)111 const VkDescriptorSetLayout *MSInstanceBaseResolveAndPerSampleFetch::createMSPassDescSetLayout(
112 const ImageMSParams &imageMSParams)
113 {
114 DE_UNREF(imageMSParams);
115
116 return DE_NULL;
117 }
118
createMSPassDescSet(const ImageMSParams & imageMSParams,const VkDescriptorSetLayout * descSetLayout)119 const VkDescriptorSet *MSInstanceBaseResolveAndPerSampleFetch::createMSPassDescSet(
120 const ImageMSParams &imageMSParams, const VkDescriptorSetLayout *descSetLayout)
121 {
122 DE_UNREF(imageMSParams);
123 DE_UNREF(descSetLayout);
124
125 return DE_NULL;
126 }
127
iterate(void)128 tcu::TestStatus MSInstanceBaseResolveAndPerSampleFetch::iterate(void)
129 {
130 const InstanceInterface &instance = m_context.getInstanceInterface();
131 const DeviceInterface &deviceInterface = m_context.getDeviceInterface();
132 const VkDevice device = m_context.getDevice();
133 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
134 Allocator &allocator = m_context.getDefaultAllocator();
135 const VkQueue queue = m_context.getUniversalQueue();
136 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
137
138 VkImageCreateInfo imageMSInfo;
139 VkImageCreateInfo imageRSInfo;
140 const uint32_t firstSubpassAttachmentsCount = 2u;
141
142 // Check if image size does not exceed device limits
143 validateImageSize(instance, physicalDevice, m_imageType, m_imageMSParams.imageSize);
144
145 // Check if device supports image format as color attachment
146 validateImageFeatureFlags(instance, physicalDevice, mapTextureFormat(m_imageFormat),
147 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
148
149 imageMSInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
150 imageMSInfo.pNext = DE_NULL;
151 imageMSInfo.flags = 0u;
152 imageMSInfo.imageType = mapImageType(m_imageType);
153 imageMSInfo.format = mapTextureFormat(m_imageFormat);
154 imageMSInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageMSParams.imageSize));
155 imageMSInfo.arrayLayers = getNumLayers(m_imageType, m_imageMSParams.imageSize);
156 imageMSInfo.mipLevels = 1u;
157 imageMSInfo.samples = m_imageMSParams.numSamples;
158 imageMSInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
159 imageMSInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
160 imageMSInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
161 imageMSInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
162 imageMSInfo.queueFamilyIndexCount = 0u;
163 imageMSInfo.pQueueFamilyIndices = DE_NULL;
164
165 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
166 {
167 imageMSInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
168 }
169
170 validateImageInfo(instance, physicalDevice, imageMSInfo);
171
172 const de::UniquePtr<ImageWithMemory> imageMS(
173 new ImageWithMemory(deviceInterface, device, allocator, imageMSInfo, MemoryRequirement::Any));
174
175 imageRSInfo = imageMSInfo;
176 imageRSInfo.samples = VK_SAMPLE_COUNT_1_BIT;
177 imageRSInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
178
179 validateImageInfo(instance, physicalDevice, imageRSInfo);
180
181 const de::UniquePtr<ImageWithMemory> imageRS(
182 new ImageWithMemory(deviceInterface, device, allocator, imageRSInfo, MemoryRequirement::Any));
183
184 const uint32_t numSamples = static_cast<uint32_t>(imageMSInfo.samples);
185
186 std::vector<de::SharedPtr<ImageWithMemory>> imagesPerSampleVec(numSamples);
187
188 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
189 {
190 imagesPerSampleVec[sampleNdx] = de::SharedPtr<ImageWithMemory>(
191 new ImageWithMemory(deviceInterface, device, allocator, imageRSInfo, MemoryRequirement::Any));
192 }
193
194 // Create render pass
195 std::vector<VkAttachmentDescription> attachments(firstSubpassAttachmentsCount + numSamples);
196
197 {
198 const VkAttachmentDescription attachmentMSDesc = {
199 (VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
200 imageMSInfo.format, // VkFormat format;
201 imageMSInfo.samples, // VkSampleCountFlagBits samples;
202 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
203 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
204 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
205 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
206 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
207 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
208 };
209
210 attachments[0] = attachmentMSDesc;
211
212 const VkAttachmentDescription attachmentRSDesc = {
213 (VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
214 imageRSInfo.format, // VkFormat format;
215 imageRSInfo.samples, // VkSampleCountFlagBits samples;
216 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
217 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
218 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
219 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
220 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
221 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
222 };
223
224 attachments[1] = attachmentRSDesc;
225
226 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
227 {
228 attachments[firstSubpassAttachmentsCount + sampleNdx] = attachmentRSDesc;
229 }
230 }
231
232 const VkAttachmentReference attachmentMSColorRef = {
233 0u, // uint32_t attachment;
234 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
235 };
236
237 const VkAttachmentReference attachmentMSInputRef = {
238 0u, // uint32_t attachment;
239 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout layout;
240 };
241
242 const VkAttachmentReference attachmentRSColorRef = {
243 1u, // uint32_t attachment;
244 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
245 };
246
247 std::vector<VkAttachmentReference> perSampleAttachmentRef(numSamples);
248
249 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
250 {
251 const VkAttachmentReference attachmentRef = {
252 firstSubpassAttachmentsCount + sampleNdx, // uint32_t attachment;
253 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
254 };
255
256 perSampleAttachmentRef[sampleNdx] = attachmentRef;
257 }
258
259 std::vector<uint32_t> preserveAttachments(1u + numSamples);
260
261 for (uint32_t attachNdx = 0u; attachNdx < 1u + numSamples; ++attachNdx)
262 {
263 preserveAttachments[attachNdx] = 1u + attachNdx;
264 }
265
266 std::vector<VkSubpassDescription> subpasses(1u + numSamples);
267 std::vector<VkSubpassDependency> subpassDependencies;
268
269 const VkSubpassDescription firstSubpassDesc = {
270 (VkSubpassDescriptionFlags)0u, // VkSubpassDescriptionFlags flags;
271 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
272 0u, // uint32_t inputAttachmentCount;
273 DE_NULL, // const VkAttachmentReference* pInputAttachments;
274 1u, // uint32_t colorAttachmentCount;
275 &attachmentMSColorRef, // const VkAttachmentReference* pColorAttachments;
276 &attachmentRSColorRef, // const VkAttachmentReference* pResolveAttachments;
277 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
278 0u, // uint32_t preserveAttachmentCount;
279 DE_NULL // const uint32_t* pPreserveAttachments;
280 };
281
282 subpasses[0] = firstSubpassDesc;
283
284 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
285 {
286 const VkSubpassDescription subpassDesc = {
287 (VkSubpassDescriptionFlags)0u, // VkSubpassDescriptionFlags flags;
288 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
289 1u, // uint32_t inputAttachmentCount;
290 &attachmentMSInputRef, // const VkAttachmentReference* pInputAttachments;
291 1u, // uint32_t colorAttachmentCount;
292 &perSampleAttachmentRef[sampleNdx], // const VkAttachmentReference* pColorAttachments;
293 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
294 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
295 1u + sampleNdx, // uint32_t preserveAttachmentCount;
296 dataPointer(preserveAttachments) // const uint32_t* pPreserveAttachments;
297 };
298
299 subpasses[1u + sampleNdx] = subpassDesc;
300
301 if (sampleNdx == 0u)
302 {
303 // The second subpass will be in charge of transitioning the multisample attachment from
304 // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
305 const VkSubpassDependency subpassDependency = {
306 0u, // uint32_t srcSubpass;
307 1u + sampleNdx, // uint32_t dstSubpass;
308 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask;
309 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask;
310 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
311 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask;
312 0u, // VkDependencyFlags dependencyFlags;
313 };
314
315 subpassDependencies.push_back(subpassDependency);
316 }
317 else
318 {
319 // Make sure subpass reads are in order. This serializes subpasses to make sure there are no layout transition hazards
320 // in the multisample image, from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
321 // caused by parallel execution of several subpasses.
322 const VkSubpassDependency readDependency = {
323 sampleNdx, // uint32_t srcSubpass;
324 1u + sampleNdx, // uint32_t dstSubpass;
325 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags srcStageMask;
326 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask;
327 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags srcAccessMask;
328 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask;
329 0u, // VkDependencyFlags dependencyFlags;
330 };
331
332 subpassDependencies.push_back(readDependency);
333 }
334 }
335
336 const VkRenderPassCreateInfo renderPassInfo = {
337 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
338 DE_NULL, // const void* pNext;
339 (VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags;
340 static_cast<uint32_t>(attachments.size()), // uint32_t attachmentCount;
341 dataPointer(attachments), // const VkAttachmentDescription* pAttachments;
342 static_cast<uint32_t>(subpasses.size()), // uint32_t subpassCount;
343 dataPointer(subpasses), // const VkSubpassDescription* pSubpasses;
344 static_cast<uint32_t>(subpassDependencies.size()), // uint32_t dependencyCount;
345 dataPointer(subpassDependencies) // const VkSubpassDependency* pDependencies;
346 };
347
348 RenderPassWrapper renderPass(m_imageMSParams.pipelineConstructionType, deviceInterface, device, &renderPassInfo);
349
350 const VkImageSubresourceRange fullImageRange =
351 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageMSInfo.mipLevels, 0u, imageMSInfo.arrayLayers);
352
353 // Create color attachments image views
354 typedef de::SharedPtr<Unique<VkImageView>> VkImageViewSp;
355 std::vector<VkImageViewSp> imageViewsShPtrs(firstSubpassAttachmentsCount + numSamples);
356 std::vector<VkImage> images(firstSubpassAttachmentsCount + numSamples);
357 std::vector<VkImageView> imageViews(firstSubpassAttachmentsCount + numSamples);
358
359 images[0] = **imageMS;
360 images[1] = **imageRS;
361
362 imageViewsShPtrs[0] = makeVkSharedPtr(makeImageView(
363 deviceInterface, device, **imageMS, mapImageViewType(m_imageType), imageMSInfo.format, fullImageRange));
364 imageViewsShPtrs[1] = makeVkSharedPtr(makeImageView(
365 deviceInterface, device, **imageRS, mapImageViewType(m_imageType), imageRSInfo.format, fullImageRange));
366
367 imageViews[0] = **imageViewsShPtrs[0];
368 imageViews[1] = **imageViewsShPtrs[1];
369
370 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
371 {
372 images[firstSubpassAttachmentsCount + sampleNdx] = **imagesPerSampleVec[sampleNdx];
373 imageViewsShPtrs[firstSubpassAttachmentsCount + sampleNdx] =
374 makeVkSharedPtr(makeImageView(deviceInterface, device, **imagesPerSampleVec[sampleNdx],
375 mapImageViewType(m_imageType), imageRSInfo.format, fullImageRange));
376 imageViews[firstSubpassAttachmentsCount + sampleNdx] =
377 **imageViewsShPtrs[firstSubpassAttachmentsCount + sampleNdx];
378 }
379
380 // Create framebuffer
381 const VkFramebufferCreateInfo framebufferInfo = {
382 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
383 DE_NULL, // const void* pNext;
384 (VkFramebufferCreateFlags)0u, // VkFramebufferCreateFlags flags;
385 *renderPass, // VkRenderPass renderPass;
386 static_cast<uint32_t>(imageViews.size()), // uint32_t attachmentCount;
387 dataPointer(imageViews), // const VkImageView* pAttachments;
388 imageMSInfo.extent.width, // uint32_t width;
389 imageMSInfo.extent.height, // uint32_t height;
390 imageMSInfo.arrayLayers, // uint32_t layers;
391 };
392
393 renderPass.createFramebuffer(deviceInterface, device, &framebufferInfo, images);
394
395 const VkDescriptorSetLayout *descriptorSetLayoutMSPass = createMSPassDescSetLayout(m_imageMSParams);
396
397 // Create pipeline layout
398 const VkPipelineLayoutCreateInfo pipelineLayoutMSPassParams = {
399 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
400 DE_NULL, // const void* pNext;
401 (VkPipelineLayoutCreateFlags)0u, // VkPipelineLayoutCreateFlags flags;
402 descriptorSetLayoutMSPass ? 1u : 0u, // uint32_t setLayoutCount;
403 descriptorSetLayoutMSPass, // const VkDescriptorSetLayout* pSetLayouts;
404 0u, // uint32_t pushConstantRangeCount;
405 DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
406 };
407
408 const PipelineLayoutWrapper pipelineLayoutMSPass(m_imageMSParams.pipelineConstructionType, deviceInterface, device,
409 &pipelineLayoutMSPassParams);
410
411 // Create vertex attributes data
412 const VertexDataDesc vertexDataDesc = getVertexDataDescripton();
413
414 de::SharedPtr<BufferWithMemory> vertexBuffer = de::SharedPtr<BufferWithMemory>(
415 new BufferWithMemory(deviceInterface, device, allocator,
416 makeBufferCreateInfo(vertexDataDesc.dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
417 MemoryRequirement::HostVisible));
418 const Allocation &vertexBufferAllocation = vertexBuffer->getAllocation();
419
420 uploadVertexData(vertexBufferAllocation, vertexDataDesc);
421
422 flushAlloc(deviceInterface, device, vertexBufferAllocation);
423
424 const VkVertexInputBindingDescription vertexBinding = {
425 0u, // uint32_t binding;
426 vertexDataDesc.dataStride, // uint32_t stride;
427 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
428 };
429
430 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
431 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
432 DE_NULL, // const void* pNext;
433 (VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags;
434 1u, // uint32_t vertexBindingDescriptionCount;
435 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
436 static_cast<uint32_t>(
437 vertexDataDesc.vertexAttribDescVec
438 .size()), // uint32_t vertexAttributeDescriptionCount;
439 dataPointer(
440 vertexDataDesc
441 .vertexAttribDescVec), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
442 };
443
444 const std::vector<VkViewport> viewports{makeViewport(imageMSInfo.extent)};
445 const std::vector<VkRect2D> scissors{makeRect2D(imageMSInfo.extent)};
446
447 const VkPipelineMultisampleStateCreateInfo multisampleStateInfo = getMSStateCreateInfo(m_imageMSParams);
448
449 // Create graphics pipeline for multisample pass
450 const ShaderWrapper vsMSPassModule(ShaderWrapper(
451 deviceInterface, device, m_context.getBinaryCollection().get("vertex_shader"), (VkShaderModuleCreateFlags)0u));
452 const ShaderWrapper fsMSPassModule(ShaderWrapper(deviceInterface, device,
453 m_context.getBinaryCollection().get("fragment_shader"),
454 (VkShaderModuleCreateFlags)0u));
455
456 GraphicsPipelineWrapper graphicsPipelineMSPass(instance, deviceInterface, physicalDevice, device,
457 m_context.getDeviceExtensions(),
458 m_imageMSParams.pipelineConstructionType);
459 graphicsPipelineMSPass.setDefaultColorBlendState()
460 .setDefaultDepthStencilState()
461 .setDefaultRasterizationState()
462 .setDefaultTopology(vertexDataDesc.primitiveTopology)
463 .setupVertexInputState(&vertexInputStateInfo)
464 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayoutMSPass, *renderPass, 0u, vsMSPassModule)
465 .setupFragmentShaderState(pipelineLayoutMSPass, *renderPass, 0u, fsMSPassModule, DE_NULL, &multisampleStateInfo)
466 .setupFragmentOutputState(*renderPass, 0u, DE_NULL, &multisampleStateInfo)
467 .setMonolithicPipelineLayout(pipelineLayoutMSPass)
468 .buildPipeline();
469
470 std::vector<GraphicsPipelineWrapper> graphicsPipelinesPerSampleFetch;
471 graphicsPipelinesPerSampleFetch.reserve(numSamples);
472
473 // Create descriptor set layout
474 const Unique<VkDescriptorSetLayout> descriptorSetLayout(
475 DescriptorSetLayoutBuilder()
476 .addSingleBinding(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_SHADER_STAGE_FRAGMENT_BIT)
477 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_FRAGMENT_BIT)
478 .build(deviceInterface, device));
479
480 const PipelineLayoutWrapper pipelineLayoutPerSampleFetchPass(m_imageMSParams.pipelineConstructionType,
481 deviceInterface, device, *descriptorSetLayout);
482
483 const uint32_t bufferPerSampleFetchPassSize = 4u * (uint32_t)sizeof(tcu::Vec4);
484
485 de::SharedPtr<BufferWithMemory> vertexBufferPerSampleFetchPass = de::SharedPtr<BufferWithMemory>(
486 new BufferWithMemory(deviceInterface, device, allocator,
487 makeBufferCreateInfo(bufferPerSampleFetchPassSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
488 MemoryRequirement::HostVisible));
489
490 // Create graphics pipelines for per sample texel fetch passes
491 {
492 const ShaderWrapper vsPerSampleFetchPassModule(
493 ShaderWrapper(deviceInterface, device, m_context.getBinaryCollection().get("per_sample_fetch_vs"),
494 (VkShaderModuleCreateFlags)0u));
495 const ShaderWrapper fsPerSampleFetchPassModule(
496 ShaderWrapper(deviceInterface, device, m_context.getBinaryCollection().get("per_sample_fetch_fs"),
497 (VkShaderModuleCreateFlags)0u));
498
499 std::vector<tcu::Vec4> vertices;
500
501 vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
502 vertices.push_back(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f));
503 vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
504 vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
505
506 const Allocation &vertexAllocPerSampleFetchPass = vertexBufferPerSampleFetchPass->getAllocation();
507
508 deMemcpy(vertexAllocPerSampleFetchPass.getHostPtr(), dataPointer(vertices),
509 static_cast<std::size_t>(bufferPerSampleFetchPassSize));
510
511 flushAlloc(deviceInterface, device, vertexAllocPerSampleFetchPass);
512
513 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
514 {
515 const uint32_t subpass = 1u + sampleNdx;
516 graphicsPipelinesPerSampleFetch.emplace_back(instance, deviceInterface, physicalDevice, device,
517 m_context.getDeviceExtensions(),
518 m_imageMSParams.pipelineConstructionType);
519 graphicsPipelinesPerSampleFetch.back()
520 .setDefaultMultisampleState()
521 .setDefaultColorBlendState()
522 .setDefaultDepthStencilState()
523 .setDefaultRasterizationState()
524 .setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
525 .setupVertexInputState()
526 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayoutPerSampleFetchPass, *renderPass,
527 subpass, vsPerSampleFetchPassModule)
528 .setupFragmentShaderState(pipelineLayoutPerSampleFetchPass, *renderPass, subpass,
529 fsPerSampleFetchPassModule)
530 .setupFragmentOutputState(*renderPass, subpass)
531 .setMonolithicPipelineLayout(pipelineLayoutPerSampleFetchPass)
532 .buildPipeline();
533 }
534 }
535
536 // Create descriptor pool
537 const Unique<VkDescriptorPool> descriptorPool(
538 DescriptorPoolBuilder()
539 .addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u)
540 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1u)
541 .build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
542
543 // Create descriptor set
544 const Unique<VkDescriptorSet> descriptorSet(
545 makeDescriptorSet(deviceInterface, device, *descriptorPool, *descriptorSetLayout));
546
547 const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(instance, physicalDevice).limits;
548
549 VkDeviceSize uboOffsetAlignment = sizeof(int32_t) < deviceLimits.minUniformBufferOffsetAlignment ?
550 deviceLimits.minUniformBufferOffsetAlignment :
551 sizeof(int32_t);
552
553 uboOffsetAlignment += (deviceLimits.minUniformBufferOffsetAlignment -
554 uboOffsetAlignment % deviceLimits.minUniformBufferOffsetAlignment) %
555 deviceLimits.minUniformBufferOffsetAlignment;
556
557 const VkBufferCreateInfo bufferSampleIDInfo =
558 makeBufferCreateInfo(uboOffsetAlignment * numSamples, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
559 const de::UniquePtr<BufferWithMemory> bufferSampleID(
560 new BufferWithMemory(deviceInterface, device, allocator, bufferSampleIDInfo, MemoryRequirement::HostVisible));
561
562 std::vector<uint32_t> sampleIDsOffsets(numSamples);
563
564 {
565 int8_t *sampleIDs = new int8_t[static_cast<uint32_t>(uboOffsetAlignment) * numSamples];
566
567 for (int32_t sampleNdx = 0u; sampleNdx < static_cast<int32_t>(numSamples); ++sampleNdx)
568 {
569 sampleIDsOffsets[sampleNdx] = static_cast<uint32_t>(sampleNdx * uboOffsetAlignment);
570 int8_t *samplePtr = sampleIDs + sampleIDsOffsets[sampleNdx];
571
572 deMemcpy(samplePtr, &sampleNdx, sizeof(int32_t));
573 }
574
575 deMemcpy(bufferSampleID->getAllocation().getHostPtr(), sampleIDs,
576 static_cast<uint32_t>(uboOffsetAlignment * numSamples));
577
578 flushAlloc(deviceInterface, device, bufferSampleID->getAllocation());
579
580 delete[] sampleIDs;
581 }
582
583 {
584 const VkDescriptorImageInfo descImageInfo =
585 makeDescriptorImageInfo(DE_NULL, imageViews[0], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
586 const VkDescriptorBufferInfo descBufferInfo = makeDescriptorBufferInfo(**bufferSampleID, 0u, sizeof(int32_t));
587
588 DescriptorSetUpdateBuilder()
589 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
590 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &descImageInfo)
591 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
592 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &descBufferInfo)
593 .update(deviceInterface, device);
594 }
595
596 // Create command buffer for compute and transfer oparations
597 const Unique<VkCommandPool> commandPool(
598 createCommandPool(deviceInterface, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
599 const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, device, *commandPool));
600
601 // Start recording commands
602 beginCommandBuffer(deviceInterface, *commandBuffer);
603
604 {
605 std::vector<VkImageMemoryBarrier> imageOutputAttachmentBarriers(firstSubpassAttachmentsCount + numSamples);
606
607 imageOutputAttachmentBarriers[0] =
608 makeImageMemoryBarrier(0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
609 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, **imageMS, fullImageRange);
610
611 imageOutputAttachmentBarriers[1] =
612 makeImageMemoryBarrier(0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
613 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, **imageRS, fullImageRange);
614
615 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
616 {
617 imageOutputAttachmentBarriers[firstSubpassAttachmentsCount + sampleNdx] = makeImageMemoryBarrier(
618 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
619 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, **imagesPerSampleVec[sampleNdx], fullImageRange);
620 }
621
622 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
623 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
624 static_cast<uint32_t>(imageOutputAttachmentBarriers.size()),
625 dataPointer(imageOutputAttachmentBarriers));
626 }
627
628 {
629 const VkDeviceSize vertexStartOffset = 0u;
630
631 std::vector<VkClearValue> clearValues(firstSubpassAttachmentsCount + numSamples);
632 for (uint32_t attachmentNdx = 0u; attachmentNdx < firstSubpassAttachmentsCount + numSamples; ++attachmentNdx)
633 {
634 clearValues[attachmentNdx] = makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
635 }
636
637 renderPass.begin(deviceInterface, *commandBuffer,
638 makeRect2D(0, 0, imageMSInfo.extent.width, imageMSInfo.extent.height),
639 (uint32_t)clearValues.size(), dataPointer(clearValues));
640
641 // Bind graphics pipeline
642 graphicsPipelineMSPass.bind(*commandBuffer);
643
644 const VkDescriptorSet *descriptorSetMSPass = createMSPassDescSet(m_imageMSParams, descriptorSetLayoutMSPass);
645
646 if (descriptorSetMSPass)
647 {
648 // Bind descriptor set
649 deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
650 *pipelineLayoutMSPass, 0u, 1u, descriptorSetMSPass, 0u, DE_NULL);
651 }
652
653 // Bind vertex buffer
654 deviceInterface.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer->get(), &vertexStartOffset);
655
656 // Perform a draw
657 deviceInterface.cmdDraw(*commandBuffer, vertexDataDesc.verticesCount, 1u, 0u, 0u);
658
659 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
660 {
661 renderPass.nextSubpass(deviceInterface, *commandBuffer, VK_SUBPASS_CONTENTS_INLINE);
662
663 // Bind graphics pipeline
664 graphicsPipelinesPerSampleFetch[sampleNdx].bind(*commandBuffer);
665
666 // Bind descriptor set
667 deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
668 *pipelineLayoutPerSampleFetchPass, 0u, 1u, &descriptorSet.get(), 1u,
669 &sampleIDsOffsets[sampleNdx]);
670
671 // Bind vertex buffer
672 deviceInterface.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBufferPerSampleFetchPass->get(),
673 &vertexStartOffset);
674
675 // Perform a draw
676 deviceInterface.cmdDraw(*commandBuffer, 4u, 1u, 0u, 0u);
677 }
678
679 // End render pass
680 renderPass.end(deviceInterface, *commandBuffer);
681 }
682
683 {
684 const VkImageMemoryBarrier imageRSTransferBarrier = makeImageMemoryBarrier(
685 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
686 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **imageRS, fullImageRange);
687
688 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
689 VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
690 &imageRSTransferBarrier);
691 }
692
693 // Copy data from imageRS to buffer
694 const uint32_t imageRSSizeInBytes =
695 getImageSizeInBytes(imageRSInfo.extent, imageRSInfo.arrayLayers, m_imageFormat, imageRSInfo.mipLevels, 1u);
696
697 const VkBufferCreateInfo bufferRSInfo = makeBufferCreateInfo(imageRSSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
698 const de::UniquePtr<BufferWithMemory> bufferRS(
699 new BufferWithMemory(deviceInterface, device, allocator, bufferRSInfo, MemoryRequirement::HostVisible));
700
701 {
702 const VkBufferImageCopy bufferImageCopy = {
703 0u, // VkDeviceSize bufferOffset;
704 0u, // uint32_t bufferRowLength;
705 0u, // uint32_t bufferImageHeight;
706 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
707 imageRSInfo.arrayLayers), // VkImageSubresourceLayers imageSubresource;
708 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
709 imageRSInfo.extent, // VkExtent3D imageExtent;
710 };
711
712 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, **imageRS, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
713 bufferRS->get(), 1u, &bufferImageCopy);
714 }
715
716 {
717 const VkBufferMemoryBarrier bufferRSHostReadBarrier = makeBufferMemoryBarrier(
718 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, bufferRS->get(), 0u, imageRSSizeInBytes);
719
720 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
721 0u, 0u, DE_NULL, 1u, &bufferRSHostReadBarrier, 0u, DE_NULL);
722 }
723
724 // Copy data from per sample images to buffers
725 std::vector<VkImageMemoryBarrier> imagesPerSampleTransferBarriers(numSamples);
726
727 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
728 {
729 imagesPerSampleTransferBarriers[sampleNdx] = makeImageMemoryBarrier(
730 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
731 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **imagesPerSampleVec[sampleNdx], fullImageRange);
732 }
733
734 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
735 VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
736 static_cast<uint32_t>(imagesPerSampleTransferBarriers.size()),
737 dataPointer(imagesPerSampleTransferBarriers));
738
739 std::vector<de::SharedPtr<BufferWithMemory>> buffersPerSample(numSamples);
740
741 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
742 {
743 buffersPerSample[sampleNdx] = de::SharedPtr<BufferWithMemory>(
744 new BufferWithMemory(deviceInterface, device, allocator, bufferRSInfo, MemoryRequirement::HostVisible));
745
746 const VkBufferImageCopy bufferImageCopy = {
747 0u, // VkDeviceSize bufferOffset;
748 0u, // uint32_t bufferRowLength;
749 0u, // uint32_t bufferImageHeight;
750 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
751 imageRSInfo.arrayLayers), // VkImageSubresourceLayers imageSubresource;
752 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
753 imageRSInfo.extent, // VkExtent3D imageExtent;
754 };
755
756 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, **imagesPerSampleVec[sampleNdx],
757 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **buffersPerSample[sampleNdx], 1u,
758 &bufferImageCopy);
759 }
760
761 std::vector<VkBufferMemoryBarrier> buffersPerSampleHostReadBarriers(numSamples);
762
763 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
764 {
765 buffersPerSampleHostReadBarriers[sampleNdx] =
766 makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
767 **buffersPerSample[sampleNdx], 0u, imageRSSizeInBytes);
768 }
769
770 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
771 0u, DE_NULL, static_cast<uint32_t>(buffersPerSampleHostReadBarriers.size()),
772 dataPointer(buffersPerSampleHostReadBarriers), 0u, DE_NULL);
773
774 // End recording commands
775 endCommandBuffer(deviceInterface, *commandBuffer);
776
777 // Submit commands for execution and wait for completion
778 submitCommandsAndWait(deviceInterface, device, queue, *commandBuffer);
779
780 // Retrieve data from bufferRS to host memory
781 const Allocation &bufferRSAlloc = bufferRS->getAllocation();
782
783 invalidateAlloc(deviceInterface, device, bufferRSAlloc);
784
785 const tcu::ConstPixelBufferAccess bufferRSData(m_imageFormat, imageRSInfo.extent.width, imageRSInfo.extent.height,
786 imageRSInfo.extent.depth * imageRSInfo.arrayLayers,
787 bufferRSAlloc.getHostPtr());
788
789 std::stringstream resolveName;
790 resolveName << "Resolve image " << getImageTypeName(m_imageType) << "_" << bufferRSData.getWidth() << "_"
791 << bufferRSData.getHeight() << "_" << bufferRSData.getDepth() << std::endl;
792
793 m_context.getTestContext().getLog() << tcu::TestLog::Section(resolveName.str(), resolveName.str())
794 << tcu::LogImage("resolve", "", bufferRSData) << tcu::TestLog::EndSection;
795
796 std::vector<tcu::ConstPixelBufferAccess> buffersPerSampleData(numSamples);
797
798 // Retrieve data from per sample buffers to host memory
799 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
800 {
801 const Allocation &bufferAlloc = buffersPerSample[sampleNdx]->getAllocation();
802
803 invalidateAlloc(deviceInterface, device, bufferAlloc);
804
805 buffersPerSampleData[sampleNdx] =
806 tcu::ConstPixelBufferAccess(m_imageFormat, imageRSInfo.extent.width, imageRSInfo.extent.height,
807 imageRSInfo.extent.depth * imageRSInfo.arrayLayers, bufferAlloc.getHostPtr());
808
809 std::stringstream sampleName;
810 sampleName << "Sample " << sampleNdx << " image" << std::endl;
811
812 m_context.getTestContext().getLog()
813 << tcu::TestLog::Section(sampleName.str(), sampleName.str())
814 << tcu::LogImage("sample", "", buffersPerSampleData[sampleNdx]) << tcu::TestLog::EndSection;
815 }
816
817 return verifyImageData(imageMSInfo, imageRSInfo, buffersPerSampleData, bufferRSData);
818 }
819
820 } // namespace multisample
821 } // namespace pipeline
822 } // namespace vkt
823