mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
check sampler type in as_bind_group derives (#12637)
# Objective currently if we use an image with the wrong sampler type in a material, wgpu panics with an invalid texture format. turn this into a warning and fail more gracefully. ## Solution the expected sampler type is specified in the AsBindGroup derive, so we can just check the image sampler is what it should be. i am not totally sure about the mapping of image sampler type to #[sampler(type)], i assumed: ``` "filtering" => [ TextureSampleType::Float { filterable: true } ], "non_filtering" => [ TextureSampleType::Float { filterable: false }, TextureSampleType::Sint, TextureSampleType::Uint, ], "comparison" => [ TextureSampleType::Depth ], ```
This commit is contained in:
parent
f59a6a971a
commit
6e2f96f222
6 changed files with 60 additions and 3 deletions
|
@ -953,6 +953,7 @@ impl<M: Material> RenderAsset for PreparedMaterial<M> {
|
|||
Err(AsBindGroupError::RetryNextUpdate) => {
|
||||
Err(PrepareAssetError::RetryNextUpdate(material))
|
||||
}
|
||||
Err(other) => Err(PrepareAssetError::AsBindGroupError(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -355,6 +355,20 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||
|
||||
let fallback_image = get_fallback_image(&render_path, *dimension);
|
||||
|
||||
let expected_samplers = match sampler_binding_type {
|
||||
SamplerBindingType::Filtering => {
|
||||
quote!( [#render_path::render_resource::TextureSampleType::Float { filterable: true }] )
|
||||
}
|
||||
SamplerBindingType::NonFiltering => quote!([
|
||||
#render_path::render_resource::TextureSampleType::Float { filterable: false },
|
||||
#render_path::render_resource::TextureSampleType::Sint,
|
||||
#render_path::render_resource::TextureSampleType::Uint,
|
||||
]),
|
||||
SamplerBindingType::Comparison => {
|
||||
quote!( [#render_path::render_resource::TextureSampleType::Depth] )
|
||||
}
|
||||
};
|
||||
|
||||
// insert fallible texture-based entries at 0 so that if we fail here, we exit before allocating any buffers
|
||||
binding_impls.insert(0, quote! {
|
||||
(
|
||||
|
@ -362,7 +376,26 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||
#render_path::render_resource::OwnedBindingResource::Sampler({
|
||||
let handle: Option<&#asset_path::Handle<#render_path::texture::Image>> = (&self.#field_name).into();
|
||||
if let Some(handle) = handle {
|
||||
images.get(handle).ok_or_else(|| #render_path::render_resource::AsBindGroupError::RetryNextUpdate)?.sampler.clone()
|
||||
let image = images.get(handle).ok_or_else(|| #render_path::render_resource::AsBindGroupError::RetryNextUpdate)?;
|
||||
|
||||
let Some(sample_type) = image.texture_format.sample_type(None, None) else {
|
||||
return Err(#render_path::render_resource::AsBindGroupError::InvalidSamplerType(
|
||||
#binding_index,
|
||||
"None".to_string(),
|
||||
format!("{:?}", #expected_samplers),
|
||||
));
|
||||
};
|
||||
|
||||
let valid = #expected_samplers.contains(&sample_type);
|
||||
|
||||
if !valid {
|
||||
return Err(#render_path::render_resource::AsBindGroupError::InvalidSamplerType(
|
||||
#binding_index,
|
||||
format!("{:?}", sample_type),
|
||||
format!("{:?}", #expected_samplers),
|
||||
));
|
||||
}
|
||||
image.sampler.clone()
|
||||
} else {
|
||||
#fallback_image.sampler.clone()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::{ExtractSchedule, MainWorld, Render, RenderApp, RenderSet};
|
||||
use crate::{
|
||||
render_resource::AsBindGroupError, ExtractSchedule, MainWorld, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_app::{App, Plugin, SubApp};
|
||||
use bevy_asset::{Asset, AssetEvent, AssetId, Assets};
|
||||
use bevy_ecs::{
|
||||
|
@ -9,7 +11,10 @@ use bevy_ecs::{
|
|||
};
|
||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||
use bevy_render_macros::ExtractResource;
|
||||
use bevy_utils::{tracing::debug, HashMap, HashSet};
|
||||
use bevy_utils::{
|
||||
tracing::{debug, error},
|
||||
HashMap, HashSet,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use thiserror::Error;
|
||||
|
@ -18,6 +23,8 @@ use thiserror::Error;
|
|||
pub enum PrepareAssetError<E: Send + Sync + 'static> {
|
||||
#[error("Failed to prepare asset")]
|
||||
RetryNextUpdate(E),
|
||||
#[error("Failed to build bind group: {0}")]
|
||||
AsBindGroupError(AsBindGroupError),
|
||||
}
|
||||
|
||||
/// Describes how an asset gets extracted and prepared for rendering.
|
||||
|
@ -359,6 +366,12 @@ pub fn prepare_assets<A: RenderAsset>(
|
|||
Err(PrepareAssetError::RetryNextUpdate(extracted_asset)) => {
|
||||
prepare_next_frame.assets.push((id, extracted_asset));
|
||||
}
|
||||
Err(PrepareAssetError::AsBindGroupError(e)) => {
|
||||
error!(
|
||||
"{} Bind group construction failed: {e}",
|
||||
std::any::type_name::<A>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,6 +404,12 @@ pub fn prepare_assets<A: RenderAsset>(
|
|||
Err(PrepareAssetError::RetryNextUpdate(extracted_asset)) => {
|
||||
prepare_next_frame.assets.push((id, extracted_asset));
|
||||
}
|
||||
Err(PrepareAssetError::AsBindGroupError(e)) => {
|
||||
error!(
|
||||
"{} Bind group construction failed: {e}",
|
||||
std::any::type_name::<A>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -352,6 +352,8 @@ pub enum AsBindGroupError {
|
|||
/// The bind group could not be generated. Try again next frame.
|
||||
#[error("The bind group could not be generated")]
|
||||
RetryNextUpdate,
|
||||
#[error("At binding index{0}, the provided image sampler `{1}` does not match the required sampler type(s) `{2}`.")]
|
||||
InvalidSamplerType(u32, String, String),
|
||||
}
|
||||
|
||||
/// A prepared bind group returned as a result of [`AsBindGroup::as_bind_group`].
|
||||
|
|
|
@ -615,6 +615,7 @@ impl<M: Material2d> RenderAsset for PreparedMaterial2d<M> {
|
|||
Err(AsBindGroupError::RetryNextUpdate) => {
|
||||
Err(PrepareAssetError::RetryNextUpdate(material))
|
||||
}
|
||||
Err(other) => Err(PrepareAssetError::AsBindGroupError(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -624,6 +624,7 @@ impl<M: UiMaterial> RenderAsset for PreparedUiMaterial<M> {
|
|||
Err(AsBindGroupError::RetryNextUpdate) => {
|
||||
Err(PrepareAssetError::RetryNextUpdate(material))
|
||||
}
|
||||
Err(other) => Err(PrepareAssetError::AsBindGroupError(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue