-
Notifications
You must be signed in to change notification settings - Fork 792
add shader quad control sample demonstrating VK_KHR_shader_quad_control features. #1422
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gpx1000
wants to merge
5
commits into
KhronosGroup:main
Choose a base branch
from
gpx1000:shader_quad_control
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f3bb326
Reapply "add shader quad control sample demonstrating VK_KHR_shader_q…
gpx1000 b2b8574
update readme for antora code link.
gpx1000 ee4dfe9
Merge branch 'main' into shader_quad_control
gpx1000 bd06d1b
Remove unnecessary depth stencil state configuration
gpx1000 37dee33
Merge branch 'main' into shader_quad_control
gpx1000 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Copyright (c) 2025, Holochip Inc. | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 the "License"; | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| get_filename_component(FOLDER_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) | ||
| get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} PATH) | ||
| get_filename_component(CATEGORY_NAME ${PARENT_DIR} NAME) | ||
|
|
||
| add_sample( | ||
| ID ${FOLDER_NAME} | ||
| CATEGORY ${CATEGORY_NAME} | ||
| AUTHOR "Holochip" | ||
| NAME "Shader quad control" | ||
| DESCRIPTION "Demonstrates VK_KHR_shader_quad_control with a simple fullscreen draw using quad vote ops." | ||
| SHADER_FILES_GLSL | ||
| "shader_quad_control/glsl/quad_control.vert" | ||
| "shader_quad_control/glsl/quad_control.frag") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| //// | ||
| - Copyright (c) 2025, Holochip Inc. | ||
| - | ||
| - SPDX-License-Identifier: Apache-2.0 | ||
| - | ||
| - Licensed under the Apache License, Version 2.0 the "License"; | ||
| - you may not use this file except in compliance with the License. | ||
| - You may obtain a copy of the License at | ||
| - | ||
| - http://www.apache.org/licenses/LICENSE-2.0 | ||
| - | ||
| - Unless required by applicable law or agreed to in writing, software | ||
| - distributed under the License is distributed on an "AS IS" BASIS, | ||
| - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| - See the License for the specific language governing permissions and | ||
| - limitations under the License. | ||
| - | ||
| //// | ||
|
|
||
| ifdef::site-gen-antora[] | ||
| TIP: The source for this sample can be found in the https://github.com/KhronosGroup/Vulkan-Samples/tree/main/samples/extensions/shader_quad_control[Khronos Vulkan samples github repository]. | ||
| endif::[] | ||
|
|
||
| = Shader quad control (VK_KHR_shader_quad_control) | ||
|
|
||
| This sample demonstrates VK_KHR_shader_quad_control in a minimal graphics pipeline. | ||
| It renders a full‑screen triangle and uses quad‑scope operations in the fragment shader to | ||
| broadcast values within a 2x2 pixel quad. This produces a characteristic “blocky” 2x2 pattern, | ||
| clearly showing how quad operations affect shading. | ||
|
|
||
| == What is shader quad control? | ||
| VK_KHR_shader_quad_control exposes SPIR‑V and shading language capabilities that operate at the | ||
| scope of a fragment “quad” – the 2x2 group of fragment shader invocations that participate in | ||
| coherent derivative calculation. The extension adds: | ||
|
|
||
| - A shader execution mode to control quad formation: `layout(full_quads)` or `layout(quad_derivatives)`. | ||
| - Built‑ins and functions to communicate within a quad, like `subgroupQuadBroadcast(...)`, and vote | ||
| operations `subgroupQuadAll(...)` / `subgroupQuadAny(...)`. | ||
|
|
||
| Typical uses include: | ||
|
|
||
| - Stabilizing derivatives, LOD selection, and gradient‑sensitive operations across the 2x2 quad. | ||
| - Sharing values between lanes in a quad without using shared memory. | ||
|
|
||
| == What this sample does | ||
| - Creates a simple graphics pipeline (full‑screen triangle, no descriptors). | ||
| - The fragment shader enables `GL_EXT_shader_quad_control` and declares `layout(full_quads) in;`. | ||
| - It calls `subgroupQuadBroadcast(vUV, 0)` to broadcast the top‑left lane’s interpolant to the | ||
| whole quad, so each 2x2 block shows one color based on the leader lane. | ||
|
|
||
| This minimal approach keeps focus on the quad control feature rather than complex rendering. | ||
|
|
||
| == Required extensions and features | ||
| To run this sample, the device must support `VK_KHR_shader_quad_control`. | ||
|
|
||
| No descriptors or additional states are required for this minimal demo. The sample uses the | ||
| framework’s default render pass and a basic pipeline configuration. | ||
|
|
||
| == Fragment shader | ||
| The fragment shader uses quad control to broadcast a varying from the quad leader: | ||
|
|
||
| [source,glsl] | ||
| ---- | ||
| #version 450 | ||
| #extension GL_EXT_shader_quad_control : require | ||
|
|
||
| layout(full_quads) in; // Control quad scope | ||
| layout(location = 0) in vec2 vUV; // Interpolated UV from VS | ||
| layout(location = 0) out vec4 outColor; | ||
|
|
||
| void main() | ||
| { | ||
| vec2 uv_leader = subgroupQuadBroadcast(vUV, 0); // From top-left of the 2x2 quad | ||
| outColor = vec4(uv_leader, 0.5, 1.0); | ||
| } | ||
| ---- | ||
|
|
||
| Switching to `layout(quad_derivatives) in;` would instead ensure that implicit derivatives are | ||
| computed in a quad‑coherent way (useful if you perform gradient operations like texture LODs). | ||
| This sample focuses on the broadcasting operation for clarity. | ||
|
|
||
| == Specification | ||
| - Vulkan: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_quad_control.html[VK_KHR_shader_quad_control] | ||
| - GLSL: https://github.com/KhronosGroup/GLSL/blob/main/extensions/ext/GLSL_EXT_shader_quad_control.txt[GLSL_EXT_shader_quad_control] | ||
188 changes: 188 additions & 0 deletions
188
samples/extensions/shader_quad_control/shader_quad_control.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| /* Copyright (c) 2025, Holochip Inc. | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 the "License"; | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #include "shader_quad_control.h" | ||
|
|
||
| ShaderQuadControl::ShaderQuadControl() | ||
| { | ||
| title = "Shader quad control"; | ||
| set_api_version(VK_API_VERSION_1_2); | ||
|
|
||
| add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); | ||
| // VK_KHR_shader_quad_control requires VK_KHR_shader_maximal_reconvergence per spec | ||
| add_device_extension(VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME); | ||
| add_device_extension(VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME); | ||
| } | ||
|
|
||
| ShaderQuadControl::~ShaderQuadControl() | ||
| { | ||
| if (has_device()) | ||
| { | ||
| if (pipeline != VK_NULL_HANDLE) | ||
| { | ||
| vkDestroyPipeline(get_device().get_handle(), pipeline, nullptr); | ||
| } | ||
| if (pipeline_layout != VK_NULL_HANDLE) | ||
| { | ||
| vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout, nullptr); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| bool ShaderQuadControl::prepare(const vkb::ApplicationOptions &options) | ||
| { | ||
| if (!ApiVulkanSample::prepare(options)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| create_pipeline_layout(); | ||
| create_pipeline(); | ||
| build_command_buffers(); | ||
|
|
||
| prepared = true; | ||
| return true; | ||
| } | ||
|
|
||
| void ShaderQuadControl::request_gpu_features(vkb::core::PhysicalDeviceC &gpu) | ||
| { | ||
| REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceShaderQuadControlFeaturesKHR, shaderQuadControl); | ||
| } | ||
|
|
||
| void ShaderQuadControl::create_pipeline_layout() | ||
| { | ||
| VkPipelineLayoutCreateInfo pipeline_layout_ci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; | ||
| VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(), &pipeline_layout_ci, nullptr, &pipeline_layout)); | ||
| } | ||
|
|
||
| void ShaderQuadControl::create_pipeline() | ||
| { | ||
| std::array<VkPipelineShaderStageCreateInfo, 2> stages{}; | ||
| stages[0] = load_shader("shader_quad_control/glsl/quad_control.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); | ||
| stages[1] = load_shader("shader_quad_control/glsl/quad_control.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); | ||
|
|
||
| VkPipelineVertexInputStateCreateInfo vertex_input{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; | ||
|
|
||
| VkPipelineInputAssemblyStateCreateInfo input_assembly{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; | ||
| input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; | ||
|
|
||
| VkPipelineViewportStateCreateInfo viewport_state{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; | ||
| viewport_state.viewportCount = 1; | ||
| viewport_state.scissorCount = 1; | ||
|
|
||
| VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; | ||
| raster.polygonMode = VK_POLYGON_MODE_FILL; | ||
| raster.cullMode = VK_CULL_MODE_NONE; | ||
| raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; | ||
| raster.lineWidth = 1.0f; | ||
|
|
||
| VkPipelineMultisampleStateCreateInfo msaa{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; | ||
| msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; | ||
|
|
||
| VkPipelineDepthStencilStateCreateInfo depth_stencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; | ||
|
|
||
| VkPipelineColorBlendAttachmentState color_blend_attachment{}; | ||
| color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; | ||
|
|
||
| VkPipelineColorBlendStateCreateInfo color_blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; | ||
| color_blend.attachmentCount = 1; | ||
| color_blend.pAttachments = &color_blend_attachment; | ||
|
|
||
| std::array<VkDynamicState, 2> dynamic_states{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; | ||
| VkPipelineDynamicStateCreateInfo dynamic_state{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; | ||
| dynamic_state.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()); | ||
| dynamic_state.pDynamicStates = dynamic_states.data(); | ||
|
|
||
| VkGraphicsPipelineCreateInfo pipeline_ci{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; | ||
| pipeline_ci.stageCount = static_cast<uint32_t>(stages.size()); | ||
| pipeline_ci.pStages = stages.data(); | ||
| pipeline_ci.pVertexInputState = &vertex_input; | ||
| pipeline_ci.pInputAssemblyState = &input_assembly; | ||
| pipeline_ci.pViewportState = &viewport_state; | ||
| pipeline_ci.pRasterizationState = &raster; | ||
| pipeline_ci.pMultisampleState = &msaa; | ||
| pipeline_ci.pDepthStencilState = &depth_stencil; | ||
| pipeline_ci.pColorBlendState = &color_blend; | ||
| pipeline_ci.pDynamicState = &dynamic_state; | ||
| pipeline_ci.layout = pipeline_layout; | ||
| pipeline_ci.renderPass = render_pass; | ||
|
|
||
| VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), VK_NULL_HANDLE, 1, &pipeline_ci, nullptr, &pipeline)); | ||
| } | ||
|
|
||
| void ShaderQuadControl::build_command_buffers() | ||
| { | ||
| VkCommandBufferBeginInfo begin_info{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; | ||
| VkClearValue clear_values[2]; | ||
| clear_values[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; | ||
| clear_values[1].depthStencil = {1.0f, 0}; | ||
|
|
||
| VkRenderPassBeginInfo render_pass_begin{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; | ||
| render_pass_begin.renderPass = render_pass; | ||
| render_pass_begin.renderArea.offset = {0, 0}; | ||
| render_pass_begin.renderArea.extent = get_render_context().get_surface_extent(); | ||
| render_pass_begin.clearValueCount = 2; | ||
| render_pass_begin.pClearValues = clear_values; | ||
|
|
||
| for (size_t i = 0; i < draw_cmd_buffers.size(); i++) | ||
| { | ||
| render_pass_begin.framebuffer = framebuffers[i]; | ||
| VK_CHECK(vkBeginCommandBuffer(draw_cmd_buffers[i], &begin_info)); | ||
|
|
||
| vkCmdBeginRenderPass(draw_cmd_buffers[i], &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); | ||
|
|
||
| VkViewport viewport{}; | ||
| viewport.width = static_cast<float>(get_render_context().get_surface_extent().width); | ||
| viewport.height = static_cast<float>(get_render_context().get_surface_extent().height); | ||
| viewport.minDepth = 0.0f; | ||
| viewport.maxDepth = 1.0f; | ||
| vkCmdSetViewport(draw_cmd_buffers[i], 0, 1, &viewport); | ||
|
|
||
| VkRect2D scissor{{0, 0}, get_render_context().get_surface_extent()}; | ||
| vkCmdSetScissor(draw_cmd_buffers[i], 0, 1, &scissor); | ||
|
|
||
| vkCmdBindPipeline(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| vkCmdDraw(draw_cmd_buffers[i], 3, 1, 0, 0); | ||
|
|
||
| draw_ui(draw_cmd_buffers[i]); | ||
| vkCmdEndRenderPass(draw_cmd_buffers[i]); | ||
| VK_CHECK(vkEndCommandBuffer(draw_cmd_buffers[i])); | ||
| } | ||
| } | ||
|
|
||
| void ShaderQuadControl::draw() | ||
| { | ||
| prepare_frame(); | ||
| submit_info.commandBufferCount = 1; | ||
| submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; | ||
| VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE)); | ||
| submit_frame(); | ||
| } | ||
|
|
||
| void ShaderQuadControl::render(float) | ||
| { | ||
| if (!prepared) | ||
| { | ||
| return; | ||
| } | ||
| draw(); | ||
| } | ||
|
|
||
| std::unique_ptr<vkb::VulkanSampleC> create_shader_quad_control() | ||
| { | ||
| return std::make_unique<ShaderQuadControl>(); | ||
| } |
42 changes: 42 additions & 0 deletions
42
samples/extensions/shader_quad_control/shader_quad_control.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| /* Copyright (c) 2025, Holochip Inc. | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 the "License"; | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include "api_vulkan_sample.h" | ||
|
|
||
| class ShaderQuadControl : public ApiVulkanSample | ||
| { | ||
| public: | ||
| ShaderQuadControl(); | ||
| ~ShaderQuadControl() override; | ||
|
|
||
| bool prepare(const vkb::ApplicationOptions &options) override; | ||
| void build_command_buffers() override; | ||
| void request_gpu_features(vkb::core::PhysicalDeviceC &gpu) override; | ||
| void render(float delta_time) override; | ||
|
|
||
| private: | ||
| void create_pipeline_layout(); | ||
| void create_pipeline(); | ||
| void draw(); | ||
|
|
||
| VkPipeline pipeline{VK_NULL_HANDLE}; | ||
| VkPipelineLayout pipeline_layout{VK_NULL_HANDLE}; | ||
| }; | ||
|
|
||
| std::unique_ptr<vkb::VulkanSampleC> create_shader_quad_control(); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.