Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FallbackImage only supports TextureDimension::D2 #6920

Closed
bonsairobo opened this issue Dec 11, 2022 · 6 comments · Fixed by #6974
Closed

FallbackImage only supports TextureDimension::D2 #6920

bonsairobo opened this issue Dec 11, 2022 · 6 comments · Fixed by #6974
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior

Comments

@bonsairobo
Copy link
Contributor

bonsairobo commented Dec 11, 2022

Bevy version

0.9

What you did

I tried to use the AsBindGroup derive for a custom material that uses optional array textures:

#[derive(AsBindGroup, Reflect, FromReflect, Debug, Clone, TypeUuid)]
#[uuid = "2f3d7f74-4bf7-4f32-98cd-858edafa5ca2"]
#[bind_group_data(MyMaterialKey)]
#[uniform(0, MyMaterialUniform)]
#[reflect(Default, Debug)]
pub struct MyMaterial {
    pub base_color: Color,

    #[texture(1, dimension = "2d_array")]
    #[sampler(2)]
    pub base_color_texture: Option<Handle<Image>>,

   ...
}

What went wrong

The application crashed while trying to create the bind group. See full crash output below. The reason was:

wgpu error: Validation Error

Caused by:
    In Device::create_bind_group
    texture binding 1 expects dimension = D2Array, but given a view with dimension = D2

Additional information

Theory of Root Cause

As the title suggests, I believe the root cause is that FallbackImage is only ever created with TextureDimension::D2. So when I provide None for the optional image, the fallback has a mismatch with the expected texture binding layout.

stdout/stderr + backtrace

2022-12-11T23:41:31.770452Z  INFO winit::platform_impl::platform::x11::window: Guessed window scale factor: 1.25    
2022-12-11T23:41:33.156370Z  INFO bevy_render::renderer: AdapterInfo { name: "NVIDIA GeForce RTX 3070 Laptop GPU", vendor: 4318, device: 9373, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "510.85.02", backend: Vulkan }
2022-12-11T23:41:33.704555Z ERROR wgpu::backend::direct: Handling wgpu errors as fatal by default    
thread 'Compute Task Pool (2)' panicked at 'wgpu error: Validation Error

Caused by:
    In Device::create_bind_group
    texture binding 1 expects dimension = D2Array, but given a view with dimension = D2

', /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.14.2/src/backend/direct.rs:2403:5
stack backtrace:
   0: rust_begin_unwind
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:142:14
   2: wgpu::backend::direct::default_error_handler
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.14.2/src/backend/direct.rs:2403:5
   3: core::ops::function::Fn::call
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:77:5
   4: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/boxed.rs:1954:9
   5: wgpu::backend::direct::ErrorSinkRaw::handle_error
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.14.2/src/backend/direct.rs:2389:17
   6: wgpu::backend::direct::Context::handle_error
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.14.2/src/backend/direct.rs:254:9
   7: <wgpu::backend::direct::Context as wgpu::Context>::device_create_bind_group
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.14.2/src/backend/direct.rs:1298:13
   8: wgpu::Device::create_bind_group
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.14.2/src/lib.rs:2170:17
   9: bevy_render::renderer::render_device::RenderDevice::create_bind_group
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_render-0.9.1/src/renderer/render_device.rs:75:31
  10: <bevy_triplanar_splatting::TriplanarMaterial as bevy_render::render_resource::bind_group::AsBindGroup>::as_bind_group
             at ./src/lib.rs:22:10
  11: bevy_pbr::material::prepare_material
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_pbr-0.9.1/src/material.rs:590:20
  12: bevy_pbr::material::prepare_materials
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_pbr-0.9.1/src/material.rs:566:15
  13: core::ops::function::FnMut::call_mut
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:164:5
  14: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:294:13
  15: <Func as bevy_ecs::system::function_system::SystemParamFunction<(),Out,(F0,F1,F2,F3,F4,F5,F6),()>>::run::call_inner
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/system/function_system.rs:579:21
  16: <Func as bevy_ecs::system::function_system::SystemParamFunction<(),Out,(F0,F1,F2,F3,F4,F5,F6),()>>::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/system/function_system.rs:582:17
  17: <bevy_ecs::system::function_system::FunctionSystem<In,Out,Param,Marker,F> as bevy_ecs::system::system::System>::run_unsafe
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/system/function_system.rs:409:19
  18: bevy_ecs::schedule::executor_parallel::ParallelExecutor::prepare_systems::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/schedule/executor_parallel.rs:218:26
  19: bevy_ecs::schedule::executor_parallel::ParallelExecutor::prepare_systems::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/schedule/executor_parallel.rs:258:21
  20: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/mod.rs:91:19
  21: async_executor::Executor::spawn::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.5.0/src/lib.rs:139:19
  22: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/mod.rs:91:19
  23: async_task::raw::RawTask<F,T,S>::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/async-task-4.3.0/src/raw.rs:511:20
  24: async_task::runnable::Runnable::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/async-task-4.3.0/src/runnable.rs:309:18
  25: async_executor::Executor::run::{{closure}}::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.5.0/src/lib.rs:230:21
  26: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/mod.rs:91:19
  27: <futures_lite::future::Or<F1,F2> as core::future::future::Future>::poll
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:529:33
  28: async_executor::Executor::run::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.5.0/src/lib.rs:237:31
  29: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/mod.rs:91:19
  30: futures_lite::future::block_on::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:89:27
  31: std::thread::local::LocalKey<T>::try_with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/thread/local.rs:445:16
  32: std::thread::local::LocalKey<T>::with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/thread/local.rs:421:9
  33: futures_lite::future::block_on
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:79:5
  34: bevy_tasks::task_pool::TaskPool::new_internal::{{closure}}::{{closure}}::{{closure}}::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.9.1/src/task_pool.rs:128:37
  35: std::panicking::try::do_call
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:492:40
  36: __rust_try
  37: std::panicking::try
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:456:19
  38: std::panic::catch_unwind
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panic.rs:137:14
  39: bevy_tasks::task_pool::TaskPool::new_internal::{{closure}}::{{closure}}::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.9.1/src/task_pool.rs:122:43
  40: std::thread::local::LocalKey<T>::try_with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/thread/local.rs:445:16
  41: std::thread::local::LocalKey<T>::with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/thread/local.rs:421:9
  42: bevy_tasks::task_pool::TaskPool::new_internal::{{closure}}::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.9.1/src/task_pool.rs:120:25
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.9.1/src/task_pool.rs:273:45
stack backtrace:
   0: rust_begin_unwind
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:142:14
   2: core::panicking::panic
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:48:5
   3: core::option::Option<T>::unwrap
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/option.rs:775:21
   4: bevy_tasks::task_pool::TaskPool::scope::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.9.1/src/task_pool.rs:273:34
   5: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/mod.rs:91:19
   6: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/future.rs:124:9
   7: <&mut F as core::future::future::Future>::poll
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/future/future.rs:112:9
   8: <futures_lite::future::PollOnce<F> as core::future::future::Future>::poll
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:194:15
   9: futures_lite::future::block_on::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:89:27
  10: std::thread::local::LocalKey<T>::try_with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/thread/local.rs:445:16
  11: std::thread::local::LocalKey<T>::with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/thread/local.rs:421:9
  12: futures_lite::future::block_on
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:79:5
  13: bevy_tasks::task_pool::TaskPool::scope
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.9.1/src/task_pool.rs:283:39
  14: <bevy_ecs::schedule::executor_parallel::ParallelExecutor as bevy_ecs::schedule::executor::ParallelSystemExecutor>::run_systems
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/schedule/executor_parallel.rs:127:9
  15: <bevy_ecs::schedule::stage::SystemStage as bevy_ecs::schedule::stage::Stage>::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.9.1/src/schedule/stage.rs:802:17
  16: <bevy_render::RenderPlugin as bevy_app::plugin::Plugin>::build::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_render-0.9.1/src/lib.rs:261:21
  17: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/boxed.rs:1954:9
  18: bevy_app::app::App::update
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.9.1/src/app.rs:154:13
  19: bevy_winit::winit_runner_with::{{closure}}
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_winit-0.9.1/src/lib.rs:600:21
  20: winit::platform_impl::platform::sticky_exit_callback
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.27.5/src/platform_impl/linux/mod.rs:849:9
  21: winit::platform_impl::platform::x11::EventLoop<T>::run_return::single_iteration
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.27.5/src/platform_impl/linux/x11/mod.rs:363:17
  22: winit::platform_impl::platform::x11::EventLoop<T>::run_return
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.27.5/src/platform_impl/linux/x11/mod.rs:448:31
  23: winit::platform_impl::platform::x11::EventLoop<T>::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.27.5/src/platform_impl/linux/x11/mod.rs:503:25
  24: winit::platform_impl::platform::EventLoop<T>::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.27.5/src/platform_impl/linux/mod.rs:755:56
  25: winit::event_loop::EventLoop<T>::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.27.5/src/event_loop.rs:278:9
  26: bevy_winit::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_winit-0.9.1/src/lib.rs:263:5
  27: bevy_winit::winit_runner_with
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_winit-0.9.1/src/lib.rs:645:9
  28: bevy_winit::winit_runner
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_winit-0.9.1/src/lib.rs:303:5
  29: core::ops::function::Fn::call
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:77:5
  30: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/boxed.rs:1954:9
  31: bevy_app::app::App::run
             at /home/duncan/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.9.1/src/app.rs:168:9
  32: render::main
             at ./examples/render.rs:6:5
  33: core::ops::function::FnOnce::call_once
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:248:5
@bonsairobo bonsairobo added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Dec 11, 2022
@bonsairobo
Copy link
Contributor Author

bonsairobo commented Dec 11, 2022

Thankfully it's not too hard to work around this by making the texture mandatory, and then the user can supply their own fallback.

@torsteingrindvik
Copy link
Contributor

I've been having problems with this too, 3D textures for me.

Like you said if not using Option<_> for the image you can work around it.

I found it easiest to use include_bytes! to create an image on the spot and use that, but that's circumventing the asset system and can lead to annoying loading times.

If using the asset system I was tripped up by errors stating I was supplying a 2D image even though I was modifying the texture descriptor and view after the asset was created.
Turns out it's very easy to assign a Handle<Image> to some material and have it crash your app while it's in LoadingStage::Loading.
I then had to make sure my render pipeline setup was not attempting to run any pipeline with such items until it was both loaded and I hade done some fixups on the loaded image.

Summary: +1 to finding a solution to this, as this took me quite some time to debug.

@bonsairobo
Copy link
Contributor Author

bonsairobo commented Dec 12, 2022

If using the asset system I was tripped up by errors stating I was supplying a 2D image even though I was modifying the texture descriptor and view after the asset was created.

I also tried fixing up my images after they were loaded by the asset server, and none of the system orderings that I tried worked. For me it was necessary to wait until the images had been loaded and modified before trying to spawn anything with those handles.

@torsteingrindvik
Copy link
Contributor

If using the asset system I was tripped up by errors stating I was supplying a 2D image even though I was modifying the texture descriptor and view after the asset was created.

I also tried fixing up my images after they were loaded by the asset server, and none of the system orderings that I tried worked. For me it was necessary to wait until the images had been loaded and modified before trying to spawn anything with those handles.

Yes, in effect that's what I am doing too. I hold off on adding my custom material until it's loaded and modified. Because as soon as I do my_material_assets.add(<instance>) the Material2dPlugin systems will pick it up and try to use the Handle<Image> within my material, and that crashes unless the image has had a "fixup".

@bonsairobo
Copy link
Contributor Author

From looking at the AsBindGroup derive macro implementation, the fallback image's TextureView is used when the binding's Option<Handle<Image>> is None. Because this relies on already having a view that matches the desired binding dimensions, I think the solution will require creating a separate GpuImage for each possible TextureViewDimension.

Quoting the docs on FallbackImage:

FallbackImage defaults to a 1x1 fully white texture, making blending colors with it a no-op.

Assuming this holds for any TextureViewDimension, it should be OK to create more fallbacks.

This solution would require removing the Deref impl from FallbackImage.

I can take a swing at implementing this solution unless someone quickly yells at me that I should do something else ;)

@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen and removed S-Needs-Triage This issue needs to be labelled labels Jan 31, 2023
@bonsairobo
Copy link
Contributor Author

PR is ready for review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants