|
| 1 | +/* Copyright (c) 2025, Holochip Inc. |
| 2 | + * |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + * |
| 5 | + * Licensed under the Apache License, Version 2.0 the "License"; |
| 6 | + * you may not use this file except in compliance with the License. |
| 7 | + * You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + */ |
| 17 | + |
| 18 | +#include "shader_quad_control.h" |
| 19 | + |
| 20 | +ShaderQuadControl::ShaderQuadControl() |
| 21 | +{ |
| 22 | + title = "Shader quad control"; |
| 23 | + set_api_version(VK_API_VERSION_1_2); |
| 24 | + |
| 25 | + add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| 26 | + // VK_KHR_shader_quad_control requires VK_KHR_shader_maximal_reconvergence per spec |
| 27 | + add_device_extension(VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME); |
| 28 | + add_device_extension(VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME); |
| 29 | +} |
| 30 | + |
| 31 | +ShaderQuadControl::~ShaderQuadControl() |
| 32 | +{ |
| 33 | + if (has_device()) |
| 34 | + { |
| 35 | + if (pipeline != VK_NULL_HANDLE) |
| 36 | + { |
| 37 | + vkDestroyPipeline(get_device().get_handle(), pipeline, nullptr); |
| 38 | + } |
| 39 | + if (pipeline_layout != VK_NULL_HANDLE) |
| 40 | + { |
| 41 | + vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout, nullptr); |
| 42 | + } |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +bool ShaderQuadControl::prepare(const vkb::ApplicationOptions &options) |
| 47 | +{ |
| 48 | + if (!ApiVulkanSample::prepare(options)) |
| 49 | + { |
| 50 | + return false; |
| 51 | + } |
| 52 | + |
| 53 | + create_pipeline_layout(); |
| 54 | + create_pipeline(); |
| 55 | + build_command_buffers(); |
| 56 | + |
| 57 | + prepared = true; |
| 58 | + return true; |
| 59 | +} |
| 60 | + |
| 61 | +void ShaderQuadControl::request_gpu_features(vkb::core::PhysicalDeviceC &gpu) |
| 62 | +{ |
| 63 | + REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceShaderQuadControlFeaturesKHR, shaderQuadControl); |
| 64 | +} |
| 65 | + |
| 66 | +void ShaderQuadControl::create_pipeline_layout() |
| 67 | +{ |
| 68 | + VkPipelineLayoutCreateInfo pipeline_layout_ci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; |
| 69 | + VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(), &pipeline_layout_ci, nullptr, &pipeline_layout)); |
| 70 | +} |
| 71 | + |
| 72 | +void ShaderQuadControl::create_pipeline() |
| 73 | +{ |
| 74 | + std::array<VkPipelineShaderStageCreateInfo, 2> stages{}; |
| 75 | + stages[0] = load_shader("shader_quad_control/glsl/quad_control.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); |
| 76 | + stages[1] = load_shader("shader_quad_control/glsl/quad_control.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); |
| 77 | + |
| 78 | + VkPipelineVertexInputStateCreateInfo vertex_input{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; |
| 79 | + |
| 80 | + VkPipelineInputAssemblyStateCreateInfo input_assembly{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; |
| 81 | + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; |
| 82 | + |
| 83 | + VkPipelineViewportStateCreateInfo viewport_state{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; |
| 84 | + viewport_state.viewportCount = 1; |
| 85 | + viewport_state.scissorCount = 1; |
| 86 | + |
| 87 | + VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; |
| 88 | + raster.polygonMode = VK_POLYGON_MODE_FILL; |
| 89 | + raster.cullMode = VK_CULL_MODE_NONE; |
| 90 | + raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; |
| 91 | + raster.lineWidth = 1.0f; |
| 92 | + |
| 93 | + VkPipelineMultisampleStateCreateInfo msaa{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; |
| 94 | + msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; |
| 95 | + |
| 96 | + VkPipelineDepthStencilStateCreateInfo depth_stencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; |
| 97 | + depth_stencil.depthTestEnable = VK_FALSE; |
| 98 | + depth_stencil.depthWriteEnable = VK_FALSE; |
| 99 | + |
| 100 | + VkPipelineColorBlendAttachmentState color_blend_attachment{}; |
| 101 | + color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| 102 | + |
| 103 | + VkPipelineColorBlendStateCreateInfo color_blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; |
| 104 | + color_blend.attachmentCount = 1; |
| 105 | + color_blend.pAttachments = &color_blend_attachment; |
| 106 | + |
| 107 | + std::array<VkDynamicState, 2> dynamic_states{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| 108 | + VkPipelineDynamicStateCreateInfo dynamic_state{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; |
| 109 | + dynamic_state.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()); |
| 110 | + dynamic_state.pDynamicStates = dynamic_states.data(); |
| 111 | + |
| 112 | + VkGraphicsPipelineCreateInfo pipeline_ci{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; |
| 113 | + pipeline_ci.stageCount = static_cast<uint32_t>(stages.size()); |
| 114 | + pipeline_ci.pStages = stages.data(); |
| 115 | + pipeline_ci.pVertexInputState = &vertex_input; |
| 116 | + pipeline_ci.pInputAssemblyState = &input_assembly; |
| 117 | + pipeline_ci.pViewportState = &viewport_state; |
| 118 | + pipeline_ci.pRasterizationState = &raster; |
| 119 | + pipeline_ci.pMultisampleState = &msaa; |
| 120 | + pipeline_ci.pDepthStencilState = &depth_stencil; |
| 121 | + pipeline_ci.pColorBlendState = &color_blend; |
| 122 | + pipeline_ci.pDynamicState = &dynamic_state; |
| 123 | + pipeline_ci.layout = pipeline_layout; |
| 124 | + pipeline_ci.renderPass = render_pass; |
| 125 | + |
| 126 | + VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), VK_NULL_HANDLE, 1, &pipeline_ci, nullptr, &pipeline)); |
| 127 | +} |
| 128 | + |
| 129 | +void ShaderQuadControl::build_command_buffers() |
| 130 | +{ |
| 131 | + VkCommandBufferBeginInfo begin_info{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; |
| 132 | + VkClearValue clear_values[2]; |
| 133 | + clear_values[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; |
| 134 | + clear_values[1].depthStencil = {1.0f, 0}; |
| 135 | + |
| 136 | + VkRenderPassBeginInfo render_pass_begin{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; |
| 137 | + render_pass_begin.renderPass = render_pass; |
| 138 | + render_pass_begin.renderArea.offset = {0, 0}; |
| 139 | + render_pass_begin.renderArea.extent = get_render_context().get_surface_extent(); |
| 140 | + render_pass_begin.clearValueCount = 2; |
| 141 | + render_pass_begin.pClearValues = clear_values; |
| 142 | + |
| 143 | + for (size_t i = 0; i < draw_cmd_buffers.size(); i++) |
| 144 | + { |
| 145 | + render_pass_begin.framebuffer = framebuffers[i]; |
| 146 | + VK_CHECK(vkBeginCommandBuffer(draw_cmd_buffers[i], &begin_info)); |
| 147 | + |
| 148 | + vkCmdBeginRenderPass(draw_cmd_buffers[i], &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); |
| 149 | + |
| 150 | + VkViewport viewport{}; |
| 151 | + viewport.width = static_cast<float>(get_render_context().get_surface_extent().width); |
| 152 | + viewport.height = static_cast<float>(get_render_context().get_surface_extent().height); |
| 153 | + viewport.minDepth = 0.0f; |
| 154 | + viewport.maxDepth = 1.0f; |
| 155 | + vkCmdSetViewport(draw_cmd_buffers[i], 0, 1, &viewport); |
| 156 | + |
| 157 | + VkRect2D scissor{{0, 0}, get_render_context().get_surface_extent()}; |
| 158 | + vkCmdSetScissor(draw_cmd_buffers[i], 0, 1, &scissor); |
| 159 | + |
| 160 | + vkCmdBindPipeline(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); |
| 161 | + vkCmdDraw(draw_cmd_buffers[i], 3, 1, 0, 0); |
| 162 | + |
| 163 | + draw_ui(draw_cmd_buffers[i]); |
| 164 | + vkCmdEndRenderPass(draw_cmd_buffers[i]); |
| 165 | + VK_CHECK(vkEndCommandBuffer(draw_cmd_buffers[i])); |
| 166 | + } |
| 167 | +} |
| 168 | + |
| 169 | +void ShaderQuadControl::draw() |
| 170 | +{ |
| 171 | + prepare_frame(); |
| 172 | + submit_info.commandBufferCount = 1; |
| 173 | + submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; |
| 174 | + VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE)); |
| 175 | + submit_frame(); |
| 176 | +} |
| 177 | + |
| 178 | +void ShaderQuadControl::render(float) |
| 179 | +{ |
| 180 | + if (!prepared) |
| 181 | + { |
| 182 | + return; |
| 183 | + } |
| 184 | + draw(); |
| 185 | +} |
| 186 | + |
| 187 | +std::unique_ptr<vkb::VulkanSampleC> create_shader_quad_control() |
| 188 | +{ |
| 189 | + return std::make_unique<ShaderQuadControl>(); |
| 190 | +} |
0 commit comments