Skip to content

Commit dc33a84

Browse files
committed
Support both quad and linear derivative group modes in compute shader derivatives sample
Enhances the compute shader derivatives sample to support both derivative group modes (quads and linear) with runtime fallback. Splits shader into two variants (quad/linear), selects appropriate shader based on device capabilities, and prioritizes quads when available. Adds validation for required storage image features and updates documentation to clarify KHR extension requirement over deprecated NV variant.
1 parent c15713f commit dc33a84

7 files changed

Lines changed: 127 additions & 24 deletions

File tree

samples/extensions/compute_shader_derivatives/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ add_sample(
2626
NAME "Compute shader derivatives"
2727
DESCRIPTION "Demonstrates VK_KHR_compute_shader_derivatives with a minimal compute dispatch using dFdx/dFdy in compute"
2828
SHADER_FILES_SLANG
29-
"compute_shader_derivatives/slang/derivatives.comp.slang"
29+
"compute_shader_derivatives/slang/derivatives_quad.comp.slang"
30+
"compute_shader_derivatives/slang/derivatives_linear.comp.slang"
3031
"compute_shader_derivatives/slang/fullscreen.vert.slang"
3132
"compute_shader_derivatives/slang/fullscreen.frag.slang"
3233
)

samples/extensions/compute_shader_derivatives/compute_shader_derivatives.cpp

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ ComputeShaderDerivatives::ComputeShaderDerivatives()
3232

3333
// Needed for feature chaining
3434
add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
35-
// Device extension providing the feature
35+
// Device extension providing the feature (KHR is required)
3636
add_device_extension(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME);
37-
// Toolchains may still emit SPV_NV_compute_shader_derivatives; enable NV extension if available to satisfy validation
38-
add_device_extension(VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME, /*optional*/ true);
37+
// Note for developers/tooling:
38+
// If your shader compiler/toolchain only emits SPV_NV_compute_shader_derivatives instead of SPV_KHR,
39+
// please update to a newer Vulkan SDK, glslang, and SPIR-V Tools that support the KHR variant.
40+
// This sample intentionally does not enable the NV extension and only targets VK_KHR_compute_shader_derivatives.
3941
// Shader draw parameters (required for SV_VertexID in Slang-generated vertex shader SPIR-V)
4042
add_device_extension(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, /*optional*/ true);
4143
}
@@ -172,13 +174,28 @@ void ComputeShaderDerivatives::create_output_buffer_and_descriptors()
172174

173175
void ComputeShaderDerivatives::request_gpu_features(vkb::core::PhysicalDeviceC &gpu)
174176
{
175-
// Require quads derivative group (the sample shader uses layout(derivative_group_quadsNV/derivative_group_quads_khr))
176-
REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR, computeDerivativeGroupQuads);
177-
// Users may switch to the linear mode by changing the shader qualifier
177+
// Request both derivative group modes as OPTIONAL, prefer Quads if available at runtime.
178+
// Some implementations only support computeDerivativeGroupLinear.
179+
REQUEST_OPTIONAL_FEATURE(gpu, VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR, computeDerivativeGroupQuads);
180+
REQUEST_OPTIONAL_FEATURE(gpu, VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR, computeDerivativeGroupLinear);
178181

179182
// Storage image read/write without format (required for storage images without explicit format qualifiers)
180-
gpu.get_mutable_requested_features().shaderStorageImageReadWithoutFormat = VK_TRUE;
181-
gpu.get_mutable_requested_features().shaderStorageImageWriteWithoutFormat = VK_TRUE;
183+
if (gpu.get_features().shaderStorageImageReadWithoutFormat)
184+
{
185+
gpu.get_mutable_requested_features().shaderStorageImageReadWithoutFormat = VK_TRUE;
186+
}
187+
else
188+
{
189+
throw std::runtime_error("GPU does not support shaderStorageImageReadWithoutFormat feature, which is required for this sample.");
190+
}
191+
if (gpu.get_features().shaderStorageImageWriteWithoutFormat)
192+
{
193+
gpu.get_mutable_requested_features().shaderStorageImageWriteWithoutFormat = VK_TRUE;
194+
}
195+
else
196+
{
197+
throw std::runtime_error("GPU does not support shaderStorageImageWriteWithoutFormat feature, which is required for this sample.");
198+
}
182199
}
183200

184201
void ComputeShaderDerivatives::create_compute_pipeline()
@@ -230,8 +247,11 @@ void ComputeShaderDerivatives::create_compute_pipeline()
230247

231248
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
232249

233-
// Load compute shader
234-
VkPipelineShaderStageCreateInfo stage = load_shader("compute_shader_derivatives/slang/derivatives.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT);
250+
// Load compute shader based on selected derivative group mode
251+
const char *comp_path = use_quads_ ?
252+
"compute_shader_derivatives/slang/derivatives_quad.comp.spv" :
253+
"compute_shader_derivatives/slang/derivatives_linear.comp.spv";
254+
VkPipelineShaderStageCreateInfo stage = load_shader(comp_path, VK_SHADER_STAGE_COMPUTE_BIT);
235255

236256
VkComputePipelineCreateInfo compute_ci{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
237257
compute_ci.stage = stage;
@@ -361,15 +381,29 @@ void ComputeShaderDerivatives::create_graphics_pipeline()
361381

362382
bool ComputeShaderDerivatives::prepare(const vkb::ApplicationOptions &options)
363383
{
364-
if (!ApiVulkanSample::prepare(options))
384+
if (!ApiVulkanSample::prepare(options))
385+
{
386+
return false;
387+
}
388+
389+
// Decide which derivative group to use at runtime based on enabled device features.
390+
// Prefer Quads when available; otherwise, fall back to Linear.
391+
VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR csd_features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR};
392+
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
393+
features2.pNext = &csd_features;
394+
vkGetPhysicalDeviceFeatures2(get_device().get_gpu().get_handle(), &features2);
395+
use_quads_ = (csd_features.computeDerivativeGroupQuads == VK_TRUE);
396+
if (!use_quads_ && csd_features.computeDerivativeGroupLinear != VK_TRUE)
365397
{
398+
// Neither mode is available: cannot run this sample.
399+
LOGE("VK_KHR_compute_shader_derivatives present but neither quads nor linear derivative groups are reported as supported.");
366400
return false;
367401
}
368402

369-
// Create resources in order: image, buffer, then pipelines
370-
create_storage_image();
371-
create_output_buffer_and_descriptors();
372-
create_compute_pipeline();
403+
// Create resources in order: image, buffer, then pipelines
404+
create_storage_image();
405+
create_output_buffer_and_descriptors();
406+
create_compute_pipeline();
373407
create_graphics_pipeline();
374408

375409
prepared = true;

samples/extensions/compute_shader_derivatives/compute_shader_derivatives.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class ComputeShaderDerivatives : public ApiVulkanSample
3939
void create_compute_pipeline();
4040
void create_graphics_pipeline();
4141

42+
// Which derivative group mode the sample will use at runtime.
43+
// Prefer quads when available; otherwise fall back to linear.
44+
bool use_quads_{false};
45+
4246
// Image dimensions for visualization
4347
static constexpr uint32_t image_width{512};
4448
static constexpr uint32_t image_height{512};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* Copyright (c) 2026, 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+
// Compute shader demonstrating derivatives in compute (Linear mode).
19+
// Many implementations only support computeDerivativeGroupLinear.
20+
// Mapping 1D lanes to 2D coordinates for linear groups follows the DX SM 6.6 spec:
21+
// https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_Derivatives.html
22+
// Intuition: lanes are ordered linearly across the group; hardware derives a
23+
// consistent local 2D mapping to evaluate ddx/ddy even when quads aren't supported.
24+
// Note: ddx/ddy in compute require VK_KHR_compute_shader_derivatives at runtime.
25+
// Tooling note: If your toolchain emits SPV_NV_compute_shader_derivatives instead of SPV_KHR,
26+
// please update to a newer Vulkan SDK, glslang, and SPIR-V Tools that support the KHR variant.
27+
28+
// Output image for gradient magnitude visualization
29+
[[vk::binding(0, 0)]] RWTexture2D<float4> gOutputImage : register(u0, space0);
30+
31+
// 8x8 local size; derivative groups are defined by implementation in Linear mode
32+
[shader("compute")]
33+
[numthreads(8, 8, 1)]
34+
[DerivativeGroupLinear] // Enable linear-based derivative computation
35+
void main(uint3 tid : SV_DispatchThreadID)
36+
{
37+
// Get image dimensions
38+
uint2 dims;
39+
gOutputImage.GetDimensions(dims.x, dims.y);
40+
41+
if (tid.x >= dims.x || tid.y >= dims.y)
42+
return;
43+
44+
// Normalized coordinates [0, 1]
45+
float2 uv = float2(tid.xy) / float2(dims - 1);
46+
47+
// Procedural function (same as Quad variant) to produce identical output
48+
float2 center = float2(0.5, 0.5);
49+
float2 delta = uv - center;
50+
float dist = length(delta);
51+
52+
float value = sin(dist * 10.0) * 0.5 + 0.5;
53+
value *= (1.0 - smoothstep(0.0, 0.7, dist));
54+
55+
// Derivatives of the function
56+
float dx = ddx(value);
57+
float dy = ddy(value);
58+
59+
float gradientMag = sqrt(dx * dx + dy * dy);
60+
float edgeIntensity = saturate(gradientMag * 10.0);
61+
62+
float3 color;
63+
color.r = edgeIntensity;
64+
color.g = edgeIntensity * 0.5;
65+
color.b = value * (1.0 - edgeIntensity);
66+
67+
gOutputImage[tid.xy] = float4(color, 1.0);
68+
}
Binary file not shown.

shaders/compute_shader_derivatives/slang/derivatives.comp.slang renamed to shaders/compute_shader_derivatives/slang/derivatives_quad.comp.slang

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
* limitations under the License.
1616
*/
1717

18-
// Compute shader demonstrating derivatives in compute with a practical use case.
18+
// Compute shader demonstrating derivatives in compute (Quad mode).
1919
// This shader computes a procedural 2D function and uses derivatives to calculate
2020
// gradient magnitude - demonstrating edge detection and spatial analysis capabilities.
2121
// Note: ddx/ddy in compute require VK_KHR_compute_shader_derivatives at runtime.
22+
// Tooling note: If your toolchain emits SPV_NV_compute_shader_derivatives instead of SPV_KHR,
23+
// please update to a newer Vulkan SDK, glslang, and SPIR-V Tools that support the KHR variant.
2224

2325
// Output image for gradient magnitude visualization
2426
[[vk::binding(0, 0)]] RWTexture2D<float4> gOutputImage : register(u0, space0);
@@ -40,7 +42,6 @@ void main(uint3 tid : SV_DispatchThreadID)
4042
float2 uv = float2(tid.xy) / float2(dims - 1);
4143

4244
// Create an interesting procedural function: radial gradient with modulation
43-
// This demonstrates a practical use case for derivatives in compute
4445
float2 center = float2(0.5, 0.5);
4546
float2 delta = uv - center;
4647
float dist = length(delta);
@@ -50,21 +51,16 @@ void main(uint3 tid : SV_DispatchThreadID)
5051
value *= (1.0 - smoothstep(0.0, 0.7, dist));
5152

5253
// Compute derivatives of the function - this is the key feature!
53-
// These derivatives tell us how quickly the function changes spatially
5454
float dx = ddx(value);
5555
float dy = ddy(value);
5656

5757
// Gradient magnitude - useful for edge detection, LOD selection, and filtering
58-
// High gradient = rapid spatial changes (edges)
5958
float gradientMag = sqrt(dx * dx + dy * dy);
6059

6160
// Visualize gradient magnitude as edge detection
62-
// Scale up the gradient for better visibility
6361
float edgeIntensity = saturate(gradientMag * 10.0);
6462

65-
// Create a color visualization:
66-
// - Base pattern in blue channel
67-
// - Edges (high gradient) in red/yellow
63+
// Create a color visualization
6864
float3 color;
6965
color.r = edgeIntensity; // Red for edges
7066
color.g = edgeIntensity * 0.5; // Some yellow for strong edges

shaders/compute_shader_derivatives/slang/derivatives.comp.spv renamed to shaders/compute_shader_derivatives/slang/derivatives_quad.comp.spv

File renamed without changes.

0 commit comments

Comments
 (0)