Description
Question/Bug Report
I am trying to create a compute shader using rust-gpu
and wgpu
crates. Currently just testing whether I can output true/false from the GPU. I have run into problems utilizing u8/u16 types for output.
For the full code with wgpu
running native on Nvidia GPU can be found at 149segolte/wgpu-dsp. This is the shader I am trying to compile:
#![cfg_attr(target_arch = "spirv", no_std)]
// HACK(eddyb) can't easily see warnings otherwise from `spirv-builder` builds.
// #![deny(warnings)]
use glam::UVec3;
use spirv_std::{glam, spirv};
#[allow(dead_code)]
pub struct Uniforms {
max_seeds: u32,
chunk: u32,
}
pub fn compute(_seed: u32) -> bool {
return false;
}
// LocalSize/numthreads of (x = 4, y = 4, z = 2)
#[spirv(compute(threads(4, 4, 2)))]
pub fn compute_shader(
#[spirv(num_workgroups)] num_workgroups: UVec3,
#[spirv(workgroup_id)] workgroup_id: UVec3,
#[spirv(local_invocation_index)] local_invocation_index: u32,
#[spirv(uniform, descriptor_set = 0, binding = 0)] uniforms: &Uniforms,
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] output: &mut [u8],
) {
let work_group_index = workgroup_id.x * num_workgroups.y * num_workgroups.z
+ workgroup_id.z * num_workgroups.y
+ workgroup_id.y;
let local_index = local_invocation_index;
let global_index = work_group_index * 32 + local_index;
let seed = global_index * (uniforms.chunk + 1);
if global_index >= uniforms.max_seeds {
return;
}
if compute(seed) {
output[global_index as usize] = 1;
} else {
output[global_index as usize] = 0;
}
}
For using u8
slice as output buffer, I enabled spirv_builder::Capability::Int8
in the build script before running the code. With max_seeds = 100_000_000
, when compute
function is set to return false
from the shader, programs outputs:
Valid: 0, Invalid: 100000000
But changing compute
to true
gives:
Valid: 2080768, Invalid: 97919232
Expected output is:
Valid: 100000000, Invalid: 0
When run with validation layers, the code runs and gives the same output but also shows the following errors:
[2025-04-02T07:13:54Z ERROR wgpu_hal::vulkan::instance] VALIDATION [VUID-RuntimeSpirv-storageBuffer8BitAccess-06328 (0xbbd18a7e)]
vkCreateShaderModule(): SPIR-V contains an 8-bit OpVariable with StorageBuffer Storage Class, but storageBuffer8BitAccess was not enabled.
%8 = OpVariable %24 12
The Vulkan spec states: If storageBuffer8BitAccess is VK_FALSE, then objects containing an 8-bit integer element must not have Storage Class of StorageBuffer, ShaderRecordBufferKHR, or PhysicalStorageBuffer (https://vulkan.lunarg.com/doc/view/1.4.309.0/linux/antora/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-storageBuffer8BitAccess-06328)
[2025-04-02T07:13:54Z ERROR wgpu_hal::vulkan::instance] VALIDATION [VUID-VkShaderModuleCreateInfo-pCode-08740 (0x6e224e9)]
vkCreateShaderModule(): SPIR-V Capability Int8 was declared, but one of the following requirements is required (VkPhysicalDeviceVulkan12Features::shaderInt8).
The Vulkan spec states: If pCode is a pointer to SPIR-V code, and pCode declares any of the capabilities listed in the SPIR-V Environment appendix, one of the corresponding requirements must be satisfied (https://vulkan.lunarg.com/doc/view/1.4.309.0/linux/antora/spec/latest/chapters/shaders.html#VUID-VkShaderModuleCreateInfo-pCode-08740)
[2025-04-02T07:13:54Z ERROR wgpu_hal::vulkan::instance] VALIDATION [VUID-VkShaderModuleCreateInfo-pCode-08740 (0x6e224e9)]
vkCreateShaderModule(): SPIR-V Capability VulkanMemoryModel was declared, but one of the following requirements is required (VkPhysicalDeviceVulkan12Features::vulkanMemoryModel).
The Vulkan spec states: If pCode is a pointer to SPIR-V code, and pCode declares any of the capabilities listed in the SPIR-V Environment appendix, one of the corresponding requirements must be satisfied (https://vulkan.lunarg.com/doc/view/1.4.309.0/linux/antora/spec/latest/chapters/shaders.html#VUID-VkShaderModuleCreateInfo-pCode-08740)
Similarly with u16
return type and spirv_builder::Capability::Int16
, false
case gives:
Valid: 0, Invalid: 100000000
And true
case gives:
Valid: 4161536, Invalid: 95838464
Validation layers give error:
[2025-04-02T07:42:59Z ERROR wgpu_hal::vulkan::instance] VALIDATION [VUID-RuntimeSpirv-storageBuffer16BitAccess-06331 (0x2df1cd5b)]
vkCreateShaderModule(): SPIR-V contains an 16-bit OpVariable with StorageBuffer Storage Class, but storageBuffer16BitAccess was not enabled.
%8 = OpVariable %24 12
The Vulkan spec states: If storageBuffer16BitAccess is VK_FALSE, then objects containing 16-bit integer or 16-bit floating-point elements must not have Storage Class of StorageBuffer, ShaderRecordBufferKHR, or PhysicalStorageBuffer (https://vulkan.lunarg.com/doc/view/1.4.309.0/linux/antora/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-storageBuffer16BitAccess-06331)
[2025-04-02T07:42:59Z ERROR wgpu_hal::vulkan::instance] VALIDATION [VUID-VkShaderModuleCreateInfo-pCode-08740 (0x6e224e9)]
vkCreateShaderModule(): SPIR-V Capability VulkanMemoryModel was declared, but one of the following requirements is required (VkPhysicalDeviceVulkan12Features::vulkanMemoryModel).
The Vulkan spec states: If pCode is a pointer to SPIR-V code, and pCode declares any of the capabilities listed in the SPIR-V Environment appendix, one of the corresponding requirements must be satisfied (https://vulkan.lunarg.com/doc/view/1.4.309.0/linux/antora/spec/latest/chapters/shaders.html#VUID-VkShaderModuleCreateInfo-pCode-08740)
System Info
-
Rust: 1.84.0-nightly (b19329a37 2024-11-21)
-
OS: Fedora 41 in a VM with GPU passthrough
-
GPU: NVIDIA GeForce RTX 2070 with Max-Q Design
-
SPIR-V: v2025.1 v2025.1.rc1-0-gf289d047
-
Adapter Info:
AdapterInfo {
name: "NVIDIA GeForce RTX 2070 with Max-Q Design",
vendor: 4318,
device: 8016,
device_type: DiscreteGpu,
driver: "NVIDIA",
driver_info: "565.77",
backend: Vulkan,
}
Note:
I did not directly use u32
(it would not require any extra configuration) as it ran into maximum buffer size limits and I do not yet understand GPU programming enough to copy chunks of output buffer. Also u32
seems to big to just pass booleans across memory. I am looking into spirv_std::arch::atomic_or and spirv_std::memory::{Scope, Semantics}
to use with u8
to reduce memory usage further.