mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Fix the WebGL 2 backend by giving the visibility_ranges
array a fixed length. (#13210)
WebGL 2 doesn't support variable-length uniform buffer arrays. So we arbitrarily set the length of the visibility ranges field to 64 on that platform. --------- Co-authored-by: IceSentry <c.giguere42@gmail.com>
This commit is contained in:
parent
4350ad0bd1
commit
0dddfa07ab
3 changed files with 49 additions and 7 deletions
|
@ -1,7 +1,11 @@
|
|||
#define_import_path bevy_pbr::mesh_functions
|
||||
|
||||
#import bevy_pbr::{
|
||||
mesh_view_bindings::{view, visibility_ranges},
|
||||
mesh_view_bindings::{
|
||||
view,
|
||||
visibility_ranges,
|
||||
VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE
|
||||
},
|
||||
mesh_bindings::mesh,
|
||||
mesh_types::MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT,
|
||||
view_transformations::position_world_to_clip,
|
||||
|
@ -90,8 +94,16 @@ fn mesh_tangent_local_to_world(model: mat4x4<f32>, vertex_tangent: vec4<f32>, in
|
|||
// camera distance to determine the dithering level.
|
||||
#ifdef VISIBILITY_RANGE_DITHER
|
||||
fn get_visibility_range_dither_level(instance_index: u32, world_position: vec4<f32>) -> i32 {
|
||||
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
|
||||
// If we're using a storage buffer, then the length is variable.
|
||||
let visibility_buffer_array_len = arrayLength(&visibility_ranges);
|
||||
#else // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
|
||||
// If we're using a uniform buffer, then the length is constant
|
||||
let visibility_buffer_array_len = VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE;
|
||||
#endif // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
|
||||
|
||||
let visibility_buffer_index = mesh[instance_index].flags & 0xffffu;
|
||||
if (visibility_buffer_index > arrayLength(&visibility_ranges)) {
|
||||
if (visibility_buffer_index > visibility_buffer_array_len) {
|
||||
return -16;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,11 @@
|
|||
@group(0) @binding(10) var<uniform> fog: types::Fog;
|
||||
@group(0) @binding(11) var<uniform> light_probes: types::LightProbes;
|
||||
|
||||
const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
|
||||
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
|
||||
@group(0) @binding(12) var<storage> visibility_ranges: array<vec4<f32>>;
|
||||
#else
|
||||
@group(0) @binding(12) var<uniform> visibility_ranges: array<vec4<f32>>;
|
||||
@group(0) @binding(12) var<uniform> visibility_ranges: array<vec4<f32>, VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE>;
|
||||
#endif
|
||||
|
||||
@group(0) @binding(13) var screen_space_ambient_occlusion_texture: texture_2d<f32>;
|
||||
|
|
|
@ -19,7 +19,7 @@ use bevy_reflect::Reflect;
|
|||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::{prelude::default, EntityHashMap, HashMap};
|
||||
use nonmax::NonMaxU16;
|
||||
use wgpu::BufferUsages;
|
||||
use wgpu::{BufferBindingType, BufferUsages};
|
||||
|
||||
use crate::{
|
||||
camera::Camera,
|
||||
|
@ -38,6 +38,11 @@ use super::{check_visibility, VisibilitySystems, WithMesh};
|
|||
/// buffer slot.
|
||||
pub const VISIBILITY_RANGES_STORAGE_BUFFER_COUNT: u32 = 4;
|
||||
|
||||
/// The size of the visibility ranges buffer in elements (not bytes) when fewer
|
||||
/// than 6 storage buffers are available and we're forced to use a uniform
|
||||
/// buffer instead (most notably, on WebGL 2).
|
||||
const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: usize = 64;
|
||||
|
||||
/// A plugin that enables [`VisibilityRange`]s, which allow entities to be
|
||||
/// hidden or shown based on distance to the camera.
|
||||
pub struct VisibilityRangePlugin;
|
||||
|
@ -424,9 +429,33 @@ pub fn write_render_visibility_ranges(
|
|||
return;
|
||||
}
|
||||
|
||||
// If the buffer is empty, push *something* so that we allocate it.
|
||||
if render_visibility_ranges.buffer.is_empty() {
|
||||
render_visibility_ranges.buffer.push(default());
|
||||
// Mess with the length of the buffer to meet API requirements if necessary.
|
||||
match render_device.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT)
|
||||
{
|
||||
// If we're using a uniform buffer, we must have *exactly*
|
||||
// `VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE` elements.
|
||||
BufferBindingType::Uniform
|
||||
if render_visibility_ranges.buffer.len() > VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE =>
|
||||
{
|
||||
render_visibility_ranges
|
||||
.buffer
|
||||
.truncate(VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE);
|
||||
}
|
||||
BufferBindingType::Uniform
|
||||
if render_visibility_ranges.buffer.len() < VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE =>
|
||||
{
|
||||
while render_visibility_ranges.buffer.len() < VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE {
|
||||
render_visibility_ranges.buffer.push(default());
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, if we're using a storage buffer, just ensure there's
|
||||
// something in the buffer, or else it won't get allocated.
|
||||
BufferBindingType::Storage { .. } if render_visibility_ranges.buffer.is_empty() => {
|
||||
render_visibility_ranges.buffer.push(default());
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Schedule the write.
|
||||
|
|
Loading…
Reference in a new issue