Skip to content

How to use Int8/Int16 capability support #225

Closed
@149segolte

Description

@149segolte

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions