我正在尝试索引 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来索引到纹理数组中。
我希望有人能帮我
解决方案似乎如下。第一个原始数组不适合着色器,必须使用像这样的特殊类型:
#[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()