diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 9e1982837..1033feece 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -3,7 +3,7 @@ use crate::device::trace::Command as TraceCommand; use crate::{ command::{CommandBuffer, CommandEncoderError}, conv, - device::Device, + device::{Device, MissingDownlevelFlags}, error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id::{BufferId, CommandEncoderId, Id, TextureId, Valid}, @@ -108,6 +108,8 @@ pub enum TransferError { }, #[error(transparent)] MemoryInitFailure(#[from] super::ClearError), + #[error("Cannot encode this copy because of a missing downelevel flag")] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } impl PrettyError for TransferError { @@ -839,6 +841,18 @@ impl Global { ); } + if format_desc.sample_type == wgt::TextureSampleType::Depth + && !device + .downlevel + .flags + .contains(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES) + { + return Err(TransferError::MissingDownlevelFlags(MissingDownlevelFlags( + wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES, + )) + .into()); + } + cmd_buf .buffer_memory_init_actions .extend(dst_buffer.initialization_status.create_action( diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index e599b428d..6f1c3455c 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -359,6 +359,10 @@ impl super::Adapter { super::PrivateCapabilities::CAN_DISABLE_DRAW_BUFFER, !cfg!(target_arch = "wasm32"), ); + private_caps.set( + super::PrivateCapabilities::GET_BUFFER_SUB_DATA, + cfg!(target_arch = "wasm32"), + ); let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32; let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32; @@ -706,6 +710,32 @@ impl crate::Adapter for super::Adapter { } } +impl super::AdapterShared { + pub(super) unsafe fn get_buffer_sub_data( + &self, + gl: &glow::Context, + target: u32, + offset: i32, + dst_data: &mut [u8], + ) { + if self + .private_caps + .contains(super::PrivateCapabilities::GET_BUFFER_SUB_DATA) + { + gl.get_buffer_sub_data(target, offset, dst_data); + } else { + log::error!("Fake map"); + let length = dst_data.len(); + let buffer_mapping = + gl.map_buffer_range(target, offset, length as _, glow::MAP_READ_BIT); + + std::ptr::copy_nonoverlapping(buffer_mapping, dst_data.as_mut_ptr(), length); + + gl.unmap_buffer(target); + } + } +} + // SAFE: WASM doesn't have threads #[cfg(target_arch = "wasm32")] unsafe impl Sync for super::Adapter {} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 628eaf092..29a6155f1 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -457,7 +457,7 @@ impl crate::Device for super::Device { let ptr = if let Some(ref map_read_allocation) = buffer.data { let mut guard = map_read_allocation.lock().unwrap(); let slice = guard.as_mut_slice(); - gl.get_buffer_sub_data(buffer.target, 0, slice); + self.shared.get_buffer_sub_data(gl, buffer.target, 0, slice); slice.as_mut_ptr() } else { gl.map_buffer_range( @@ -478,11 +478,7 @@ impl crate::Device for super::Device { } unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { if let Some(raw) = buffer.raw { - if !self - .shared - .workarounds - .contains(super::Workarounds::EMULATE_BUFFER_MAP) - { + if buffer.data.is_none() { let gl = &self.shared.context.lock(); gl.bind_buffer(buffer.target, Some(raw)); gl.unmap_buffer(buffer.target); diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index c48225f6d..d62799814 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -135,6 +135,8 @@ bitflags::bitflags! { const INDEX_BUFFER_ROLE_CHANGE = 1 << 5; /// Indicates that the device supports disabling draw buffers const CAN_DISABLE_DRAW_BUFFER = 1 << 6; + /// Supports `glGetBufferSubData` + const GET_BUFFER_SUB_DATA = 1 << 7; } } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 2c9b9978f..aef7e7772 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -274,7 +274,12 @@ impl super::Queue { [copy.dst_offset as usize..copy.dst_offset as usize + size]; gl.bind_buffer(copy_src_target, Some(src)); - gl.get_buffer_sub_data(copy_src_target, copy.src_offset as i32, dst_data); + self.shared.get_buffer_sub_data( + gl, + copy_src_target, + copy.src_offset as i32, + dst_data, + ); } (None, Some(dst)) => { let data = src.data.as_ref().unwrap().lock().unwrap(); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index b1bb6180a..8f0d40204 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -991,6 +991,10 @@ bitflags::bitflags! { /// Supports sample-rate shading. const MULTISAMPLED_SHADING = 1 << 12; + /// Supports copies between depth textures and buffers. + /// + /// GLES/WebGL don't support this. + const DEPTH_TEXTURE_AND_BUFFER_COPIES = 1 << 13; } } diff --git a/wgpu/tests/zero_init_texture_after_discard.rs b/wgpu/tests/zero_init_texture_after_discard.rs index 74c29340e..ec77e909f 100644 --- a/wgpu/tests/zero_init_texture_after_discard.rs +++ b/wgpu/tests/zero_init_texture_after_discard.rs @@ -68,38 +68,43 @@ fn discarding_color_target_resets_texture_init_state_check_visible_on_copy_in_sa #[test] fn discarding_depth_target_resets_texture_init_state_check_visible_on_copy_in_same_encoder() { - initialize_test(TestParameters::default(), |ctx| { - for format in [ - wgpu::TextureFormat::Depth32Float, - //wgpu::TextureFormat::Depth24Plus, // Can't copy to or from buffer - //wgpu::TextureFormat::Depth24PlusStencil8, // Can only copy stencil aspect to/from buffer - ] { - let (texture, readback_buffer) = create_white_texture_and_readback_buffer(&ctx, format); - { - let mut encoder = ctx - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Depth Discard"), - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &texture.create_view(&wgpu::TextureViewDescriptor::default()), - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Load, - store: false, // discard! + initialize_test( + TestParameters::default() + .downlevel_flags(wgpu::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES), + |ctx| { + for format in [ + wgpu::TextureFormat::Depth32Float, + //wgpu::TextureFormat::Depth24Plus, // Can't copy to or from buffer + //wgpu::TextureFormat::Depth24PlusStencil8, // Can only copy stencil aspect to/from buffer + ] { + let (texture, readback_buffer) = + create_white_texture_and_readback_buffer(&ctx, format); + { + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Depth Discard"), + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &texture.create_view(&wgpu::TextureViewDescriptor::default()), + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: false, // discard! + }), + stencil_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: false, // discard! + }), }), - stencil_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Load, - store: false, // discard! - }), - }), - }); - copy_texture_to_buffer(&mut encoder, &texture, &readback_buffer); - ctx.queue.submit([encoder.finish()]); + }); + copy_texture_to_buffer(&mut encoder, &texture, &readback_buffer); + ctx.queue.submit([encoder.finish()]); + } + assert_buffer_is_zero(&readback_buffer, &ctx.device); } - assert_buffer_is_zero(&readback_buffer, &ctx.device); - } - }); + }, + ); } #[test]