diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 90b62a0f94..b771caed59 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -611,6 +611,10 @@ impl super::Adapter { super::PrivateCapabilities::DEBUG_FNS, supported((3, 2), (4, 3)) && !web_gl, ); + private_caps.set( + super::PrivateCapabilities::INVALIDATE_FRAMEBUFFER, + supported((3, 0), (4, 3)), + ); let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32; let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 73f1ccafea..0b2b9ee028 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -474,6 +474,9 @@ impl crate::CommandEncoder for super::CommandEncoder { panic!("Multiple render attachments with external framebuffers are not supported."); } + // `COLOR_ATTACHMENT0` to `COLOR_ATTACHMENT31` gives 32 possible color attachments. + assert!(desc.color_attachments.len() <= 32); + match desc .color_attachments .first() diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 2c635a7302..d959e21057 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -750,14 +750,60 @@ impl crate::Device for super::Device { if conv::is_layered_target(target) { unsafe { - gl.tex_storage_3d( - target, - desc.mip_level_count as i32, - format_desc.internal, - desc.size.width as i32, - desc.size.height as i32, - desc.size.depth_or_array_layers as i32, - ) + if self + .shared + .private_caps + .contains(PrivateCapabilities::TEXTURE_STORAGE) + { + gl.tex_storage_3d( + target, + desc.mip_level_count as i32, + format_desc.internal, + desc.size.width as i32, + desc.size.height as i32, + desc.size.depth_or_array_layers as i32, + ) + } else if target == glow::TEXTURE_3D { + let mut width = desc.size.width; + let mut height = desc.size.width; + let mut depth = desc.size.depth_or_array_layers; + for i in 0..desc.mip_level_count { + gl.tex_image_3d( + target, + i as i32, + format_desc.internal as i32, + width as i32, + height as i32, + depth as i32, + 0, + format_desc.external, + format_desc.data_type, + None, + ); + width = max(1, width / 2); + height = max(1, height / 2); + depth = max(1, depth / 2); + } + } else { + let mut width = desc.size.width; + let mut height = desc.size.width; + for i in 0..desc.mip_level_count { + gl.tex_image_3d( + target, + i as i32, + format_desc.internal as i32, + width as i32, + height as i32, + desc.size.depth_or_array_layers as i32, + 0, + format_desc.external, + format_desc.data_type, + None, + ); + width = max(1, width / 2); + height = max(1, height / 2); + } + } }; } else if desc.sample_count > 1 { unsafe { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 72fb037a63..79f7484def 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -167,6 +167,8 @@ bitflags::bitflags! { const TEXTURE_STORAGE = 1 << 12; /// Supports `push_debug_group`, `pop_debug_group` and `debug_message_insert`. const DEBUG_FNS = 1 << 13; + /// Supports framebuffer invalidation. + const INVALIDATE_FRAMEBUFFER = 1 << 14; } } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 479ebe2720..e448f2e8b2 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -969,7 +969,13 @@ impl super::Queue { unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) }; } C::InvalidateAttachments(ref list) => { - unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) }; + if self + .shared + .private_caps + .contains(PrivateCapabilities::INVALIDATE_FRAMEBUFFER) + { + unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) }; + } } C::SetDrawColorBuffers(count) => { self.draw_buffer_count = count; @@ -990,16 +996,14 @@ impl super::Queue { && is_srgb { unsafe { self.perform_shader_clear(gl, draw_buffer, *color) }; - } else if draw_buffer < 32 { - // Prefer `clear_color` as `clear_buffer_f32_slice` crashes on Sandy Bridge + } else { + // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge // on Windows. unsafe { gl.draw_buffers(&[glow::COLOR_ATTACHMENT0 + draw_buffer]); gl.clear_color(color[0], color[1], color[2], color[3]); gl.clear(glow::COLOR_BUFFER_BIT); } - } else { - unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) }; } } C::ClearColorU(draw_buffer, ref color) => { @@ -1009,20 +1013,29 @@ impl super::Queue { unsafe { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color) }; } C::ClearDepth(depth) => { - unsafe { gl.clear_buffer_f32_slice(glow::DEPTH, 0, &[depth]) }; + // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge + // on Windows. + unsafe { + gl.clear_depth_f32(depth); + gl.clear(glow::DEPTH_BUFFER_BIT); + } } C::ClearStencil(value) => { - unsafe { gl.clear_buffer_i32_slice(glow::STENCIL, 0, &[value as i32]) }; + // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge + // on Windows. + unsafe { + gl.clear_stencil(value as i32); + gl.clear(glow::STENCIL_BUFFER_BIT); + } } C::ClearDepthAndStencil(depth, stencil_value) => { + // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge + // on Windows. unsafe { - gl.clear_buffer_depth_stencil( - glow::DEPTH_STENCIL, - 0, - depth, - stencil_value as i32, - ) - }; + gl.clear_depth_f32(depth); + gl.clear_stencil(stencil_value as i32); + gl.clear(glow::DEPTH_BUFFER_BIT | glow::STENCIL_BUFFER_BIT); + } } C::BufferBarrier(raw, usage) => { let mut flags = 0;