1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel Corporation
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Dynamic State Tests - Base Class
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktDynamicStateBaseClass.hpp"
28 
29 #include "vkPrograms.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 
36 namespace vkt
37 {
38 namespace DynamicState
39 {
40 
41 using namespace Draw;
42 
DynamicStateBaseClass(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName,const char * meshShaderName)43 DynamicStateBaseClass::DynamicStateBaseClass(Context &context, vk::PipelineConstructionType pipelineConstructionType,
44                                              const char *vertexShaderName, const char *fragmentShaderName,
45                                              const char *meshShaderName)
46     : TestInstance(context)
47     , m_pipelineConstructionType(pipelineConstructionType)
48     , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
49     , m_topology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
50     , m_vk(context.getDeviceInterface())
51     , m_pipeline(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(),
52                  context.getDevice(), context.getDeviceExtensions(), pipelineConstructionType)
53     , m_vertexShaderName(vertexShaderName ? vertexShaderName : "")
54     , m_fragmentShaderName(fragmentShaderName)
55     , m_meshShaderName(meshShaderName ? meshShaderName : "")
56     , m_isMesh(meshShaderName != nullptr)
57 {
58     // We must provide either the mesh shader or the vertex shader.
59     DE_ASSERT(static_cast<bool>(vertexShaderName) != static_cast<bool>(meshShaderName));
60 }
61 
initialize(void)62 void DynamicStateBaseClass::initialize(void)
63 {
64     const vk::VkDevice device       = m_context.getDevice();
65     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
66     const auto vertDescType = (m_isMesh ? vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : vk::VK_DESCRIPTOR_TYPE_MAX_ENUM);
67     std::vector<vk::VkPushConstantRange> pcRanges;
68 
69     // The mesh shading pipeline will contain a set with vertex data.
70 #ifndef CTS_USES_VULKANSC
71     if (m_isMesh)
72     {
73         vk::DescriptorSetLayoutBuilder setLayoutBuilder;
74         vk::DescriptorPoolBuilder poolBuilder;
75 
76         setLayoutBuilder.addSingleBinding(vertDescType, vk::VK_SHADER_STAGE_MESH_BIT_EXT);
77         m_meshSetLayout = setLayoutBuilder.build(m_vk, device);
78 
79         poolBuilder.addType(vertDescType);
80         m_descriptorPool = poolBuilder.build(m_vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
81 
82         m_descriptorSet = vk::makeDescriptorSet(m_vk, device, m_descriptorPool.get(), m_meshSetLayout.get());
83         pcRanges.push_back(
84             vk::makePushConstantRange(vk::VK_SHADER_STAGE_MESH_BIT_EXT, 0u, static_cast<uint32_t>(sizeof(uint32_t))));
85     }
86 #endif // CTS_USES_VULKANSC
87 
88     std::vector<vk::VkDescriptorSetLayout> rawSetLayouts;
89 
90     if (m_meshSetLayout)
91         rawSetLayouts.push_back(m_meshSetLayout.get());
92 
93     if (m_otherSetLayout)
94         rawSetLayouts.push_back(m_otherSetLayout.get());
95 
96     m_pipelineLayout =
97         vk::PipelineLayoutWrapper(m_pipelineConstructionType, m_vk, device, de::sizeU32(rawSetLayouts),
98                                   de::dataOrNull(rawSetLayouts), de::sizeU32(pcRanges), de::dataOrNull(pcRanges));
99 
100     const vk::VkExtent3D targetImageExtent = {WIDTH, HEIGHT, 1};
101     const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1,
102                                                 vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
103                                                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
104                                                     vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
105                                                     vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
106 
107     m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
108                                                m_context.getUniversalQueueFamilyIndex());
109 
110     const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D,
111                                                   m_colorAttachmentFormat);
112     m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
113 
114     const vk::VkVertexInputBindingDescription vertexInputBindingDescription = {
115         0,
116         (uint32_t)sizeof(tcu::Vec4) * 2,
117         vk::VK_VERTEX_INPUT_RATE_VERTEX,
118     };
119 
120     const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
121         {0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
122         {
123             1u,
124             0u,
125             vk::VK_FORMAT_R32G32B32A32_SFLOAT,
126             (uint32_t)(sizeof(float) * 4),
127         }};
128 
129     m_vertexInputState =
130         PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
131 
132     const vk::VkDeviceSize dataSize = de::dataSize(m_data);
133     const vk::VkBufferUsageFlags bufferUsage =
134         (m_isMesh ? vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
135     m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(dataSize, bufferUsage),
136                                             m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
137 
138     uint8_t *ptr = reinterpret_cast<unsigned char *>(m_vertexBuffer->getBoundMemory().getHostPtr());
139     deMemcpy(ptr, &m_data[0], (size_t)dataSize);
140 
141     vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
142 
143     // Update descriptor set for mesh shaders.
144     if (m_isMesh)
145     {
146         vk::DescriptorSetUpdateBuilder updateBuilder;
147         const auto location   = vk::DescriptorSetUpdateBuilder::Location::binding(0u);
148         const auto bufferInfo = vk::makeDescriptorBufferInfo(m_vertexBuffer->object(), 0ull, dataSize);
149 
150         updateBuilder.writeSingle(m_descriptorSet.get(), location, vertDescType, &bufferInfo);
151         updateBuilder.update(m_vk, device);
152     }
153 
154     const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
155     m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
156 
157     const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo = {
158         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
159         DE_NULL,                                            // const void* pNext;
160         *m_cmdPool,                                         // VkCommandPool commandPool;
161         vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,                // VkCommandBufferLevel level;
162         1u,                                                 // uint32_t bufferCount;
163     };
164     m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, &cmdBufferAllocateInfo);
165 
166     initRenderPass(device);
167     initFramebuffer(device);
168     initPipeline(device);
169 }
170 
initRenderPass(const vk::VkDevice device)171 void DynamicStateBaseClass::initRenderPass(const vk::VkDevice device)
172 {
173     RenderPassCreateInfo renderPassCreateInfo;
174     renderPassCreateInfo.addAttachment(AttachmentDescription(
175         m_colorAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
176         vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_STORE,
177         vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL));
178 
179     const vk::VkAttachmentReference colorAttachmentReference = {0, vk::VK_IMAGE_LAYOUT_GENERAL};
180 
181     renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
182                                                        &colorAttachmentReference, DE_NULL, AttachmentReference(), 0,
183                                                        DE_NULL));
184 
185     m_renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, m_vk, device, &renderPassCreateInfo);
186 }
187 
initFramebuffer(const vk::VkDevice device)188 void DynamicStateBaseClass::initFramebuffer(const vk::VkDevice device)
189 {
190     std::vector<vk::VkImageView> colorAttachments(1);
191     colorAttachments[0] = *m_colorTargetView;
192 
193     const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
194 
195     m_renderPass.createFramebuffer(m_vk, device, &framebufferCreateInfo, m_colorTargetImage->object());
196 }
197 
initPipeline(const vk::VkDevice device)198 void DynamicStateBaseClass::initPipeline(const vk::VkDevice device)
199 {
200     const PipelineCreateInfo::ColorBlendState colorBlendState(1, &m_attachmentState);
201     const PipelineCreateInfo::RasterizerState rasterizerState;
202     const PipelineCreateInfo::DepthStencilState depthStencilState;
203     const PipelineCreateInfo::DynamicState dynamicState;
204     const PipelineCreateInfo::MultiSampleState multisampleState;
205 
206     const auto &binaries = m_context.getBinaryCollection();
207     const vk::ShaderWrapper ms(m_isMesh ? vk::ShaderWrapper(m_vk, device, binaries.get(m_meshShaderName), 0) :
208                                           vk::ShaderWrapper());
209     const vk::ShaderWrapper vs(m_isMesh ? vk::ShaderWrapper() :
210                                           vk::ShaderWrapper(m_vk, device, binaries.get(m_vertexShaderName), 0));
211     const vk::ShaderWrapper fs(vk::ShaderWrapper(m_vk, device, binaries.get(m_fragmentShaderName), 0));
212     std::vector<vk::VkViewport> viewports{{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}};
213     std::vector<vk::VkRect2D> scissors{{{0u, 0u}, {0u, 0u}}};
214 
215     m_pipeline.setDefaultTopology(m_topology)
216         .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo *>(&dynamicState));
217 
218 #ifndef CTS_USES_VULKANSC
219     if (m_isMesh)
220     {
221         m_pipeline.setupPreRasterizationMeshShaderState(
222             viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vk::ShaderWrapper(), ms,
223             static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState));
224     }
225     else
226 #endif // CTS_USES_VULKANSC
227     {
228         m_pipeline.setupVertexInputState(&m_vertexInputState)
229             .setupPreRasterizationShaderState(
230                 viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vs,
231                 static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState));
232     }
233 
234     m_pipeline
235         .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fs,
236                                   static_cast<const vk::VkPipelineDepthStencilStateCreateInfo *>(&depthStencilState),
237                                   &multisampleState)
238         .setupFragmentOutputState(*m_renderPass, 0u,
239                                   static_cast<const vk::VkPipelineColorBlendStateCreateInfo *>(&colorBlendState),
240                                   &multisampleState)
241         .setMonolithicPipelineLayout(m_pipelineLayout)
242         .buildPipeline();
243 }
244 
iterate(void)245 tcu::TestStatus DynamicStateBaseClass::iterate(void)
246 {
247     DE_ASSERT(false);
248     return tcu::TestStatus::fail("Implement iterate() method!");
249 }
250 
beginRenderPass(void)251 void DynamicStateBaseClass::beginRenderPass(void)
252 {
253     const vk::VkClearColorValue clearColor = {{0.0f, 0.0f, 0.0f, 1.0f}};
254     beginRenderPassWithClearColor(clearColor);
255 }
256 
beginRenderPassWithClearColor(const vk::VkClearColorValue & clearColor,const bool skipBeginCmdBuffer,const bool previousTransfer)257 void DynamicStateBaseClass::beginRenderPassWithClearColor(const vk::VkClearColorValue &clearColor,
258                                                           const bool skipBeginCmdBuffer, const bool previousTransfer)
259 {
260     if (!skipBeginCmdBuffer)
261     {
262         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
263     }
264 
265     if (previousTransfer)
266     {
267         const auto transfer2Transfer = vk::makeMemoryBarrier(
268             vk::VK_ACCESS_TRANSFER_WRITE_BIT, (vk::VK_ACCESS_TRANSFER_WRITE_BIT | vk::VK_ACCESS_TRANSFER_READ_BIT));
269         vk::cmdPipelineMemoryBarrier(m_vk, *m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
270                                      vk::VK_PIPELINE_STAGE_TRANSFER_BIT, &transfer2Transfer);
271     }
272     else
273     {
274         initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
275                                       vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
276     }
277 
278     const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
279     m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1,
280                             &subresourceRange);
281 
282     const vk::VkMemoryBarrier memBarrier = {
283         vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, vk::VK_ACCESS_TRANSFER_WRITE_BIT,
284         vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
285 
286     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
287                             vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0,
288                             DE_NULL);
289 
290     m_renderPass.begin(m_vk, *m_cmdBuffer, vk::makeRect2D(0, 0, WIDTH, HEIGHT));
291 }
292 
setDynamicViewportState(const uint32_t width,const uint32_t height)293 void DynamicStateBaseClass::setDynamicViewportState(const uint32_t width, const uint32_t height)
294 {
295     vk::VkViewport viewport = vk::makeViewport(tcu::UVec2(width, height));
296     vk::VkRect2D scissor    = vk::makeRect2D(tcu::UVec2(width, height));
297     if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
298     {
299 #ifndef CTS_USES_VULKANSC
300         m_vk.cmdSetViewportWithCount(*m_cmdBuffer, 1, &viewport);
301         m_vk.cmdSetScissorWithCount(*m_cmdBuffer, 1, &scissor);
302 #else
303         m_vk.cmdSetViewportWithCountEXT(*m_cmdBuffer, 1, &viewport);
304         m_vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, 1, &scissor);
305 #endif
306     }
307     else
308     {
309         m_vk.cmdSetViewport(*m_cmdBuffer, 0, 1, &viewport);
310         m_vk.cmdSetScissor(*m_cmdBuffer, 0, 1, &scissor);
311     }
312 }
313 
setDynamicViewportState(uint32_t viewportCount,const vk::VkViewport * pViewports,const vk::VkRect2D * pScissors)314 void DynamicStateBaseClass::setDynamicViewportState(uint32_t viewportCount, const vk::VkViewport *pViewports,
315                                                     const vk::VkRect2D *pScissors)
316 {
317     if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
318     {
319 #ifndef CTS_USES_VULKANSC
320         m_vk.cmdSetViewportWithCount(*m_cmdBuffer, viewportCount, pViewports);
321         m_vk.cmdSetScissorWithCount(*m_cmdBuffer, viewportCount, pScissors);
322 #else
323         m_vk.cmdSetViewportWithCountEXT(*m_cmdBuffer, viewportCount, pViewports);
324         m_vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, viewportCount, pScissors);
325 #endif
326     }
327     else
328     {
329         m_vk.cmdSetViewport(*m_cmdBuffer, 0, viewportCount, pViewports);
330         m_vk.cmdSetScissor(*m_cmdBuffer, 0, viewportCount, pScissors);
331     }
332 }
333 
setDynamicRasterizationState(const float lineWidth,const float depthBiasConstantFactor,const float depthBiasClamp,const float depthBiasSlopeFactor)334 void DynamicStateBaseClass::setDynamicRasterizationState(const float lineWidth, const float depthBiasConstantFactor,
335                                                          const float depthBiasClamp, const float depthBiasSlopeFactor)
336 {
337     m_vk.cmdSetLineWidth(*m_cmdBuffer, lineWidth);
338     m_vk.cmdSetDepthBias(*m_cmdBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
339 }
340 
setDynamicBlendState(const float const1,const float const2,const float const3,const float const4)341 void DynamicStateBaseClass::setDynamicBlendState(const float const1, const float const2, const float const3,
342                                                  const float const4)
343 {
344     float blendConstantsants[4] = {const1, const2, const3, const4};
345     m_vk.cmdSetBlendConstants(*m_cmdBuffer, blendConstantsants);
346 }
347 
setDynamicDepthStencilState(const float minDepthBounds,const float maxDepthBounds,const uint32_t stencilFrontCompareMask,const uint32_t stencilFrontWriteMask,const uint32_t stencilFrontReference,const uint32_t stencilBackCompareMask,const uint32_t stencilBackWriteMask,const uint32_t stencilBackReference)348 void DynamicStateBaseClass::setDynamicDepthStencilState(
349     const float minDepthBounds, const float maxDepthBounds, const uint32_t stencilFrontCompareMask,
350     const uint32_t stencilFrontWriteMask, const uint32_t stencilFrontReference, const uint32_t stencilBackCompareMask,
351     const uint32_t stencilBackWriteMask, const uint32_t stencilBackReference)
352 {
353     m_vk.cmdSetDepthBounds(*m_cmdBuffer, minDepthBounds, maxDepthBounds);
354     m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, stencilFrontCompareMask);
355     m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, stencilFrontWriteMask);
356     m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, stencilFrontReference);
357     m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, stencilBackCompareMask);
358     m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, stencilBackWriteMask);
359     m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, stencilBackReference);
360 }
361 
362 #ifndef CTS_USES_VULKANSC
pushVertexOffset(const uint32_t vertexOffset,const vk::VkPipelineLayout pipelineLayout,const vk::VkShaderStageFlags stageFlags)363 void DynamicStateBaseClass::pushVertexOffset(const uint32_t vertexOffset, const vk::VkPipelineLayout pipelineLayout,
364                                              const vk::VkShaderStageFlags stageFlags)
365 {
366     m_vk.cmdPushConstants(*m_cmdBuffer, pipelineLayout, stageFlags, 0u, static_cast<uint32_t>(sizeof(uint32_t)),
367                           &vertexOffset);
368 }
369 #endif // CTS_USES_VULKANSC
370 
371 } // namespace DynamicState
372 } // namespace vkt
373