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
 | 
			
		||||
 | 
			
		||||
#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 New Issue
	
	Block a user