Rustgpu 如何索引到纹理数组中?

问题描述 投票:0回答:1

我正在尝试索引 rustgpu 中的纹理数组,我有以下着色器代码:

#![cfg_attr(target_arch = "spirv", no_std, feature(lang_items))]
#![allow(internal_features)]

extern crate bytemuck;
extern crate spirv_std;

pub use spirv_std::glam::*;
use spirv_std::image::*;
use spirv_std::num_traits::Float;
use spirv_std::spirv;

type Texture2D = Image!(2D, type=f32, sampled);

// Fragment shader
#[spirv(fragment)]
pub fn main_fs(
    in_normal: Vec3,
    in_uv: Vec3,
    in_position: Vec3,
    in_camera_position: Vec3,
    #[spirv(descriptor_set = 1, binding = 1)] image: &[SampledImage<Texture2D>; 69],
    output: &mut Vec4,
)
{
    let index = in_uv.z.round() as usize;
    let albedo = image[index].sample(in_uv.xy());

    *output = albedo;
}

// Vertex shader
pub struct CamUBO
{
    model: Mat4,
    view: Mat4,
    proj: Mat4,
}

#[spirv(vertex)]
pub fn main_vs(
    in_position: Vec3,
    in_normal: Vec3,
    in_uv: Vec3,
    #[spirv(uniform, descriptor_set = 1, binding = 0)] camera_ubo: &CamUBO,

    #[spirv(position, invariant)] screen_pos: &mut Vec4,
    out_normal: &mut Vec3,
    out_uv: &mut Vec3,
    out_position: &mut Vec3,
    out_camera_position: &mut Vec3,
)
{
    *screen_pos = camera_ubo.proj
        * camera_ubo.view
        * camera_ubo.model
        * Vec4::new(in_position.x, in_position.y, in_position.z, 1.0);

    *out_position = screen_pos.xyz();
    *out_normal = (camera_ubo.model * in_normal.extend(0.0)).xyz();
    *out_uv = in_uv;
    *out_camera_position = -camera_ubo.view.col(3).xyz();
}

编译失败,出现以下错误:

error: function pointer types are not allowed
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/metadata.rs:94:1
    |
94  | pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: used by `fmt::rt::Argument<'_>`
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

error: cannot offset a pointer to an arbitrary element
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

error: `u8` without `OpCapability Int8`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:507:1
    |
507 | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: used by unnamed global (%68396)
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

error: cannot cast between pointer types
       from `*struct fmt::rt::Argument<'_> { value: *struct fmt::rt::Opaque {  }, formatter: *fn(*struct fmt::rt::Opaque {  }, *struct fmt::Formatter<'_> { width: struct option::Option<usize> { u32, u32 }, precision: struct option::Option<usize> { u32, u32 }, fill: u32, buf: struct &mut dyn fmt::Write { *struct dyn fmt::Write {  }, *[u32; 3] }, flags: u32, align: u8 }) -> bool }`
         to `*u8`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

error: cannot cast between pointer types
       from `*u8`
         to `**fn(*struct fmt::rt::Opaque {  }, *struct fmt::Formatter<'_> { width: struct option::Option<usize> { u32, u32 }, precision: struct option::Option<usize> { u32, u32 }, fill: u32, buf: struct &mut dyn fmt::Write { *struct dyn fmt::Write {  }, *[u32; 3] }, flags: u32, align: u8 }) -> bool`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

error: const_bitcast
    |
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

error: cannot cast between pointer types
       from `*[struct fmt::rt::Argument<'_> { value: *struct fmt::rt::Opaque {  }, formatter: *fn(*struct fmt::rt::Opaque {  }, *struct fmt::Formatter<'_> { width: struct option::Option<usize> { u32, u32 }, precision: struct option::Option<usize> { u32, u32 }, fill: u32, buf: struct &mut dyn fmt::Write { *struct dyn fmt::Write {  }, *[u32; 3] }, flags: u32, align: u8 }) -> bool }; 2]`
         to `*[struct fmt::rt::Argument<'_> { value: *struct fmt::rt::Opaque {  }, formatter: *fn(*struct fmt::rt::Opaque {  }, *struct fmt::Formatter<'_> { width: struct option::Option<usize> { u32, u32 }, precision: struct option::Option<usize> { u32, u32 }, fill: u32, buf: struct &mut dyn fmt::Write { *struct dyn fmt::Write {  }, *[u32; 3] }, flags: u32, align: u8 }) -> bool }]`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: used from within `core::panicking::panic_bounds_check`
   --> /home/makogan/.rustup/toolchains/nightly-2024-01-08-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:208:5
    |
208 |     panic!("index out of bounds: the len is {len} but the index is {index}")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: called by `mesh_shader::main_fs`
   --> src/lib.rs:34:18
    |
34  |     let albedo = image[index].sample(in_uv.xy());
    |                  ^^^^^^^^^^^^
note: called by `main_fs`
   --> src/lib.rs:24:8
    |
24  | pub fn main_fs(
    |        ^^^^^^^

warning: `mesh-shader` (lib) generated 3 warnings
error: could not compile `mesh-shader` (lib) due to 7 previous errors; 3 warnings emitted
thread 'main' panicked at crates/vulkan_bindings/src/shader_parsing/rust_gpu_parsing.rs:44:14:
called `Result::unwrap()` on an `Err` value: BuildFailed
stack backtrace:
   0: rust_begin_unwind
             at /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/core/src/panicking.rs:72:14
   2: core::result::unwrap_failed
             at /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/core/src/result.rs:1649:5
   3: vulkan_bindings::shader_parsing::rust_gpu_parsing::parse_shader
   4: vulkan_bindings::shader_program::ShaderProgram::new
   5: <vulkan_bindings::RenderContext as ne_core::gpu_api::GpuApi>::add_shader_from_memory
   6: <vulkan_bindings::RenderContext as ne_core::gpu_api::GpuApi>::add_shader
   7: _02_mesh::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

最相关的部分可能是

error: cannot offset a pointer to an arbitrary element
。这似乎是问题的根源,因为当我通过常量索引纹理数组时,我确实成功编译了。

但是,这段代码是我的一些 hlsl 代码的翻译:

[[vk::binding(1, 1)]]
Texture2D<float4> textures[69];
[[vk::binding(2, 1)]]
SamplerState textures_sampler[69];

#include <linalg.hlsl>

vec4 Lambert(
    vec3 position,
    vec3 normal,
    vec3 albedo,
    vec3 light_position,
    vec3 light_color)
{
    vec4 color = vec4(0, 0, 0, 0);
    vec3 l = normalize(light_position - position);

    vec3 n = normalize(normal);

    float intensity = length(light_color);
    light_color = normalize(light_color);
    color = vec4(
        dot(l, n) * albedo * light_color,
        1);

    return color;
}

float4 main(
    [[vk::location(0)]] float3 normal : NORMAL0,
    [[vk::location(1)]] float3 uv : UV0,
    [[vk::location(2)]] float3 position : POSITION0,
    [[vk::location(3)]] float3 camera_position : CAMPOS0
) : SV_TARGET
{
    uint index = int(round(uv.z));
    float4 albedo = textures[index].Sample(textures_sampler[index], uv.xy);

    return (Lambert(
        position,
        normal,
        albedo.xyz,
        vec3(5, 1000, 5),
        normalize(vec3(1, 1, 1))) * 2.0 + 0.1);
}

因此原则上应该可以生成适当的spirv来索引到纹理数组中。

我希望有人能帮我

rust gpu shader spir-v rustgpu
1个回答
0
投票

解决方案似乎如下。第一个原始数组不适合着色器,必须使用像这样的特殊类型:

#[spirv(fragment)]
pub fn main_fs(
    in_normal: Vec3,
    in_uv: Vec3,
    in_position: Vec3,
    in_camera_position: Vec3,
    #[spirv(descriptor_set = 1, binding = 1)] image: &RuntimeArray<SampledTexture2D>, // this is a slice, almost
    output: &mut Vec4,
)

然后使用spirv builder编译时需要以下参数:

        SpirvBuilder::new(path, "spirv-unknown-vulkan1.2")
            .print_metadata(MetadataPrintout::DependencyOnly)
            .preserve_bindings(true)
            .spirv_metadata(SpirvMetadata::NameVariables)
            .scalar_block_layout(true)
            .multimodule(true)
            .capability(Capability::SampledImageArrayDynamicIndexing) // Don't know if we need it
            .capability(Capability::RuntimeDescriptorArray) // Definitely need it
            .extension("SPV_EXT_descriptor_indexing") // Probably need it
            .extra_arg("target-feature=+RuntimeDescriptorArray,") // Might need it
            .build()
            .unwrap()
© www.soinside.com 2019 - 2024. All rights reserved.