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
@ -1,7 +1,11 @@
|
|||||||
#define_import_path bevy_pbr::mesh_functions
|
#define_import_path bevy_pbr::mesh_functions
|
||||||
|
|
||||||
#import bevy_pbr::{
|
#import bevy_pbr::{
|
||||||
mesh_view_bindings::{view, visibility_ranges},
|
mesh_view_bindings::{
|
||||||
|
view,
|
||||||
|
visibility_ranges,
|
||||||
|
VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE
|
||||||
|
},
|
||||||
mesh_bindings::mesh,
|
mesh_bindings::mesh,
|
||||||
mesh_types::MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT,
|
mesh_types::MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT,
|
||||||
view_transformations::position_world_to_clip,
|
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.
|
// camera distance to determine the dithering level.
|
||||||
#ifdef VISIBILITY_RANGE_DITHER
|
#ifdef VISIBILITY_RANGE_DITHER
|
||||||
fn get_visibility_range_dither_level(instance_index: u32, world_position: vec4<f32>) -> i32 {
|
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;
|
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;
|
return -16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,10 +35,11 @@
|
|||||||
@group(0) @binding(10) var<uniform> fog: types::Fog;
|
@group(0) @binding(10) var<uniform> fog: types::Fog;
|
||||||
@group(0) @binding(11) var<uniform> light_probes: types::LightProbes;
|
@group(0) @binding(11) var<uniform> light_probes: types::LightProbes;
|
||||||
|
|
||||||
|
const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
|
||||||
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
|
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
|
||||||
@group(0) @binding(12) var<storage> visibility_ranges: array<vec4<f32>>;
|
@group(0) @binding(12) var<storage> visibility_ranges: array<vec4<f32>>;
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
@group(0) @binding(13) var screen_space_ambient_occlusion_texture: texture_2d<f32>;
|
@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_transform::components::GlobalTransform;
|
||||||
use bevy_utils::{prelude::default, EntityHashMap, HashMap};
|
use bevy_utils::{prelude::default, EntityHashMap, HashMap};
|
||||||
use nonmax::NonMaxU16;
|
use nonmax::NonMaxU16;
|
||||||
use wgpu::BufferUsages;
|
use wgpu::{BufferBindingType, BufferUsages};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::Camera,
|
camera::Camera,
|
||||||
@ -38,6 +38,11 @@ use super::{check_visibility, VisibilitySystems, WithMesh};
|
|||||||
/// buffer slot.
|
/// buffer slot.
|
||||||
pub const VISIBILITY_RANGES_STORAGE_BUFFER_COUNT: u32 = 4;
|
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
|
/// A plugin that enables [`VisibilityRange`]s, which allow entities to be
|
||||||
/// hidden or shown based on distance to the camera.
|
/// hidden or shown based on distance to the camera.
|
||||||
pub struct VisibilityRangePlugin;
|
pub struct VisibilityRangePlugin;
|
||||||
@ -424,9 +429,33 @@ pub fn write_render_visibility_ranges(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the buffer is empty, push *something* so that we allocate it.
|
// Mess with the length of the buffer to meet API requirements if necessary.
|
||||||
if render_visibility_ranges.buffer.is_empty() {
|
match render_device.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT)
|
||||||
render_visibility_ranges.buffer.push(default());
|
{
|
||||||
|
// 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.
|
// Schedule the write.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user