Skip to content

Commit

Permalink
Fix several regressions from recent rendering changes. (#16890)
Browse files Browse the repository at this point in the history
This commit fixes the following regressions:

1. Transmission-specific calls to shader lighting functions didn't pass
the `enable_diffuse` parameter, breaking the `transmission` example.

2. The combination of bindless `StandardMaterial` and bindless lightmaps
caused us to blow past the 128 texture limit on M1/M2 chips in some
cases, in particular the `depth_of_field` example.
gfx-rs/wgpu#3334 should fix this, but in the
meantime this patch reduces the number of bindless lightmaps from 16 to
4 in order to stay under the limit.

3. The renderer was crashing on startup on Adreno 610 chips. This PR
simply disables bindless on Adreno 610 and lower.
  • Loading branch information
pcwalton authored Dec 22, 2024
1 parent 2027700 commit 6a4e0c8
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 51 deletions.
8 changes: 5 additions & 3 deletions crates/bevy_pbr/src/light_probe/environment_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use bevy_render::{
BindGroupLayoutEntryBuilder, Sampler, SamplerBindingType, Shader, ShaderStages,
TextureSampleType, TextureView,
},
renderer::RenderDevice,
renderer::{RenderAdapter, RenderDevice},
texture::{FallbackImage, GpuImage},
};

Expand Down Expand Up @@ -232,10 +232,11 @@ impl ExtractInstance for EnvironmentMapIds {
/// specular binding arrays respectively, in addition to the sampler.
pub(crate) fn get_bind_group_layout_entries(
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> [BindGroupLayoutEntryBuilder; 4] {
let mut texture_cube_binding =
binding_types::texture_cube(TextureSampleType::Float { filterable: true });
if binding_arrays_are_usable(render_device) {
if binding_arrays_are_usable(render_device, render_adapter) {
texture_cube_binding =
texture_cube_binding.count(NonZero::<u32>::new(MAX_VIEW_LIGHT_PROBES as _).unwrap());
}
Expand All @@ -256,8 +257,9 @@ impl<'a> RenderViewEnvironmentMapBindGroupEntries<'a> {
images: &'a RenderAssets<GpuImage>,
fallback_image: &'a FallbackImage,
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> RenderViewEnvironmentMapBindGroupEntries<'a> {
if binding_arrays_are_usable(render_device) {
if binding_arrays_are_usable(render_device, render_adapter) {
let mut diffuse_texture_views = vec![];
let mut specular_texture_views = vec![];
let mut sampler = None;
Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_pbr/src/light_probe/irradiance_volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ use bevy_render::{
binding_types, BindGroupLayoutEntryBuilder, Sampler, SamplerBindingType, Shader,
TextureSampleType, TextureView,
},
renderer::RenderDevice,
renderer::{RenderAdapter, RenderDevice},
texture::{FallbackImage, GpuImage},
};
use bevy_utils::default;
Expand Down Expand Up @@ -242,8 +242,9 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> {
images: &'a RenderAssets<GpuImage>,
fallback_image: &'a FallbackImage,
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> RenderViewIrradianceVolumeBindGroupEntries<'a> {
if binding_arrays_are_usable(render_device) {
if binding_arrays_are_usable(render_device, render_adapter) {
RenderViewIrradianceVolumeBindGroupEntries::get_multiple(
render_view_irradiance_volumes,
images,
Expand Down Expand Up @@ -328,10 +329,11 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> {
/// respectively.
pub(crate) fn get_bind_group_layout_entries(
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> [BindGroupLayoutEntryBuilder; 2] {
let mut texture_3d_binding =
binding_types::texture_3d(TextureSampleType::Float { filterable: true });
if binding_arrays_are_usable(render_device) {
if binding_arrays_are_usable(render_device, render_adapter) {
texture_3d_binding =
texture_3d_binding.count(NonZero::<u32>::new(MAX_VIEW_LIGHT_PROBES as _).unwrap());
}
Expand Down
11 changes: 8 additions & 3 deletions crates/bevy_pbr/src/light_probe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use bevy_render::{
primitives::{Aabb, Frustum},
render_asset::RenderAssets,
render_resource::{DynamicUniformBuffer, Sampler, Shader, ShaderType, TextureView},
renderer::{RenderDevice, RenderQueue},
renderer::{RenderAdapter, RenderDevice, RenderQueue},
settings::WgpuFeatures,
sync_world::RenderEntity,
texture::{FallbackImage, GpuImage},
Expand Down Expand Up @@ -778,15 +778,20 @@ pub(crate) fn add_cubemap_texture_view<'a>(
/// enough texture bindings available in the fragment shader.
///
/// 3. If binding arrays aren't supported on the hardware, then we obviously
/// can't use them.
/// can't use them. Adreno <= 610 claims to support bindless, but seems to be
/// too buggy to be usable.
///
/// 4. If binding arrays are supported on the hardware, but they can only be
/// accessed by uniform indices, that's not good enough, and we bail out.
///
/// If binding arrays aren't usable, we disable reflection probes and limit the
/// number of irradiance volumes in the scene to 1.
pub(crate) fn binding_arrays_are_usable(render_device: &RenderDevice) -> bool {
pub(crate) fn binding_arrays_are_usable(
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> bool {
!cfg!(feature = "shader_format_glsl")
&& bevy_render::get_adreno_model(render_adapter).is_none_or(|model| model > 610)
&& render_device.limits().max_storage_textures_per_shader_stage
>= (STANDARD_MATERIAL_FRAGMENT_SHADER_MIN_TEXTURE_BINDINGS + MAX_VIEW_LIGHT_PROBES)
as u32
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/lightmap/lightmap.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#import bevy_pbr::mesh_bindings::mesh

#ifdef MULTIPLE_LIGHTMAPS_IN_ARRAY
@group(1) @binding(4) var lightmaps_textures: binding_array<texture_2d<f32>>;
@group(1) @binding(5) var lightmaps_samplers: binding_array<sampler>;
@group(1) @binding(4) var lightmaps_textures: binding_array<texture_2d<f32>, 4>;
@group(1) @binding(5) var lightmaps_samplers: binding_array<sampler, 4>;
#else // MULTIPLE_LIGHTMAPS_IN_ARRAY
@group(1) @binding(4) var lightmaps_texture: texture_2d<f32>;
@group(1) @binding(5) var lightmaps_sampler: sampler;
Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_pbr/src/lightmap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{
render_asset::RenderAssets,
render_resource::{Sampler, Shader, TextureView, WgpuSampler, WgpuTextureView},
renderer::RenderAdapter,
sync_world::MainEntity,
texture::{FallbackImage, GpuImage},
view::ViewVisibility,
Expand All @@ -71,7 +72,7 @@ pub const LIGHTMAP_SHADER_HANDLE: Handle<Shader> =
///
/// If bindless textures aren't in use, then only a single lightmap can be bound
/// at a time.
pub const LIGHTMAPS_PER_SLAB: usize = 16;
pub const LIGHTMAPS_PER_SLAB: usize = 4;

/// A plugin that provides an implementation of lightmaps.
pub struct LightmapPlugin;
Expand Down Expand Up @@ -332,7 +333,9 @@ impl Default for Lightmap {
impl FromWorld for RenderLightmaps {
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
let bindless_supported = binding_arrays_are_usable(render_device);
let render_adapter = world.resource::<RenderAdapter>();

let bindless_supported = binding_arrays_are_usable(render_device, render_adapter);

RenderLightmaps {
render_lightmaps: default(),
Expand Down
9 changes: 5 additions & 4 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use bevy_render::{
RenderCommandResult, SortedRenderPhasePlugin, TrackedRenderPass,
},
render_resource::*,
renderer::{RenderDevice, RenderQueue},
renderer::{RenderAdapter, RenderDevice, RenderQueue},
texture::DefaultImageSampler,
view::{
prepare_view_targets, NoFrustumCulling, NoIndirectDrawing, RenderVisibilityRanges,
Expand Down Expand Up @@ -1484,11 +1484,12 @@ impl FromWorld for MeshPipeline {
fn from_world(world: &mut World) -> Self {
let mut system_state: SystemState<(
Res<RenderDevice>,
Res<RenderAdapter>,
Res<DefaultImageSampler>,
Res<RenderQueue>,
Res<MeshPipelineViewLayouts>,
)> = SystemState::new(world);
let (render_device, default_sampler, render_queue, view_layouts) =
let (render_device, render_adapter, default_sampler, render_queue, view_layouts) =
system_state.get_mut(world);

let clustered_forward_buffer_binding_type = render_device
Expand Down Expand Up @@ -1532,9 +1533,9 @@ impl FromWorld for MeshPipeline {
view_layouts: view_layouts.clone(),
clustered_forward_buffer_binding_type,
dummy_white_gpu_image,
mesh_layouts: MeshLayouts::new(&render_device),
mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(&render_device),
binding_arrays_are_usable: binding_arrays_are_usable(&render_device),
binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
skins_use_uniform_buffers: skin::skins_use_uniform_buffers(&render_device),
}
}
Expand Down
17 changes: 12 additions & 5 deletions crates/bevy_pbr/src/render/mesh_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
//! Bind group layout related definitions for the mesh pipeline.
use bevy_math::Mat4;
use bevy_render::{mesh::morph::MAX_MORPH_WEIGHTS, render_resource::*, renderer::RenderDevice};
use bevy_render::{
mesh::morph::MAX_MORPH_WEIGHTS,
render_resource::*,
renderer::{RenderAdapter, RenderDevice},
};

use crate::{binding_arrays_are_usable, render::skin::MAX_JOINTS, LightmapSlab};

Expand Down Expand Up @@ -194,10 +198,10 @@ impl MeshLayouts {
/// Prepare the layouts used by the default bevy [`Mesh`].
///
/// [`Mesh`]: bevy_render::prelude::Mesh
pub fn new(render_device: &RenderDevice) -> Self {
pub fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
MeshLayouts {
model_only: Self::model_only_layout(render_device),
lightmapped: Self::lightmapped_layout(render_device),
lightmapped: Self::lightmapped_layout(render_device, render_adapter),
skinned: Self::skinned_layout(render_device),
skinned_motion: Self::skinned_motion_layout(render_device),
morphed: Self::morphed_layout(render_device),
Expand Down Expand Up @@ -329,8 +333,11 @@ impl MeshLayouts {
)
}

fn lightmapped_layout(render_device: &RenderDevice) -> BindGroupLayout {
if binding_arrays_are_usable(render_device) {
fn lightmapped_layout(
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> BindGroupLayout {
if binding_arrays_are_usable(render_device, render_adapter) {
render_device.create_bind_group_layout(
"lightmapped_mesh_layout",
&BindGroupLayoutEntries::with_indices(
Expand Down
8 changes: 6 additions & 2 deletions crates/bevy_pbr/src/render/mesh_view_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ fn layout_entries(
);

// EnvironmentMapLight
let environment_map_entries = environment_map::get_bind_group_layout_entries(render_device);
let environment_map_entries =
environment_map::get_bind_group_layout_entries(render_device, render_adapter);
entries = entries.extend_with_indices((
(17, environment_map_entries[0]),
(18, environment_map_entries[1]),
Expand All @@ -323,7 +324,7 @@ fn layout_entries(
// Irradiance volumes
if IRRADIANCE_VOLUMES_ARE_USABLE {
let irradiance_volume_entries =
irradiance_volume::get_bind_group_layout_entries(render_device);
irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter);
entries = entries.extend_with_indices((
(21, irradiance_volume_entries[0]),
(22, irradiance_volume_entries[1]),
Expand Down Expand Up @@ -493,6 +494,7 @@ pub struct MeshViewBindGroup {
pub fn prepare_mesh_view_bind_groups(
mut commands: Commands,
render_device: Res<RenderDevice>,
render_adapter: Res<RenderAdapter>,
mesh_pipeline: Res<MeshPipeline>,
shadow_samplers: Res<ShadowSamplers>,
(light_meta, global_light_meta): (Res<LightMeta>, Res<GlobalClusterableObjectMeta>),
Expand Down Expand Up @@ -607,6 +609,7 @@ pub fn prepare_mesh_view_bind_groups(
&images,
&fallback_image,
&render_device,
&render_adapter,
);

match environment_map_bind_group_entries {
Expand Down Expand Up @@ -642,6 +645,7 @@ pub fn prepare_mesh_view_bind_groups(
&images,
&fallback_image,
&render_device,
&render_adapter,
))
} else {
None
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_pbr/src/render/pbr_functions.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ fn apply_pbr_lighting(
}

let transmitted_light_contrib =
lighting::point_light(light_id, &transmissive_lighting_input);
lighting::point_light(light_id, &transmissive_lighting_input, enable_diffuse);
transmitted_light += transmitted_light_contrib * transmitted_shadow;
#endif
}
Expand Down Expand Up @@ -501,7 +501,7 @@ fn apply_pbr_lighting(
}

let transmitted_light_contrib =
lighting::spot_light(light_id, &transmissive_lighting_input);
lighting::spot_light(light_id, &transmissive_lighting_input, enable_diffuse);
transmitted_light += transmitted_light_contrib * transmitted_shadow;
#endif
}
Expand Down Expand Up @@ -557,7 +557,7 @@ fn apply_pbr_lighting(
}

let transmitted_light_contrib =
lighting::directional_light(i, &transmissive_lighting_input);
lighting::directional_light(i, &transmissive_lighting_input, enable_diffuse);
transmitted_light += transmitted_light_contrib * transmitted_shadow;
#endif
}
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_pbr/src/ssr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use bevy_render::{
ShaderStages, ShaderType, SpecializedRenderPipeline, SpecializedRenderPipelines,
TextureFormat, TextureSampleType,
},
renderer::{RenderContext, RenderDevice, RenderQueue},
renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue},
view::{ExtractedView, Msaa, ViewTarget, ViewUniformOffset},
Render, RenderApp, RenderSet,
};
Expand Down Expand Up @@ -354,6 +354,7 @@ impl FromWorld for ScreenSpaceReflectionsPipeline {
fn from_world(world: &mut World) -> Self {
let mesh_view_layouts = world.resource::<MeshPipelineViewLayouts>().clone();
let render_device = world.resource::<RenderDevice>();
let render_adapter = world.resource::<RenderAdapter>();

// Create the bind group layout.
let bind_group_layout = render_device.create_bind_group_layout(
Expand Down Expand Up @@ -404,7 +405,7 @@ impl FromWorld for ScreenSpaceReflectionsPipeline {
depth_linear_sampler,
depth_nearest_sampler,
bind_group_layout,
binding_arrays_are_usable: binding_arrays_are_usable(render_device),
binding_arrays_are_usable: binding_arrays_are_usable(render_device, render_adapter),
}
}
}
Expand Down
26 changes: 5 additions & 21 deletions crates/bevy_render/src/batching/gpu_preprocessing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,28 +354,12 @@ impl FromWorld for GpuPreprocessingSupport {
let adapter = world.resource::<RenderAdapter>();
let device = world.resource::<RenderDevice>();

// filter some Qualcomm devices on Android as they crash when using GPU preprocessing.
// Filter some Qualcomm devices on Android as they crash when using GPU
// preprocessing.
// We filter out Adreno 730 and earlier GPUs (except 720, as it's newer
// than 730).
fn is_non_supported_android_device(adapter: &RenderAdapter) -> bool {
if cfg!(target_os = "android") {
let adapter_name = adapter.get_info().name;

// Filter out Adreno 730 and earlier GPUs (except 720, as it's newer than 730)
// while also taking suffixes into account like Adreno 642L.
let non_supported_adreno_model = |model: &str| -> bool {
let model = model
.chars()
.map_while(|c| c.to_digit(10))
.fold(0, |acc, digit| acc * 10 + digit);

model != 720 && model <= 730
};

adapter_name
.strip_prefix("Adreno (TM) ")
.is_some_and(non_supported_adreno_model)
} else {
false
}
crate::get_adreno_model(adapter).is_some_and(|model| model != 720 && model <= 730)
}

let max_supported_mode = if device.limits().max_compute_workgroup_size_x == 0 || is_non_supported_android_device(adapter)
Expand Down
22 changes: 21 additions & 1 deletion crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ use bevy_window::{PrimaryWindow, RawHandleWrapperHolder};
use extract_resource::ExtractResourcePlugin;
use globals::GlobalsPlugin;
use render_asset::RenderAssetBytesPerFrame;
use renderer::{RenderDevice, RenderQueue};
use renderer::{RenderAdapter, RenderDevice, RenderQueue};
use settings::RenderResources;
use sync_world::{
despawn_temporary_render_entities, entity_sync_system, SyncToRenderWorld, SyncWorldPlugin,
Expand Down Expand Up @@ -514,3 +514,23 @@ fn apply_extract_commands(render_world: &mut World) {
.apply_deferred(render_world);
});
}

/// If the [`RenderAdapter`] is a Qualcomm Adreno, returns its model number.
///
/// This lets us work around hardware bugs.
pub fn get_adreno_model(adapter: &RenderAdapter) -> Option<u32> {
if !cfg!(target_os = "android") {
return None;
}

let adapter_name = adapter.get_info().name;
let adreno_model = adapter_name.strip_prefix("Adreno (TM) ")?;

// Take suffixes into account (like Adreno 642L).
Some(
adreno_model
.chars()
.map_while(|c| c.to_digit(10))
.fold(0, |acc, digit| acc * 10 + digit),
)
}

0 comments on commit 6a4e0c8

Please sign in to comment.