diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e447cc675..d11998c011 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -111,6 +111,11 @@ Bottom level categories: - Breaking change: [`wgpu_core::pipeline::ProgrammableStageDescriptor`](https://docs.rs/wgpu-core/latest/wgpu_core/pipeline/struct.ProgrammableStageDescriptor.html#structfield.entry_point) is now optional. By @ErichDonGubler in [#5305](https://github.com/gfx-rs/wgpu/pull/5305). - `Features::downlevel{_webgl2,}_features` was made const by @MultisampledNight in [#5343](https://github.com/gfx-rs/wgpu/pull/5343) +- More as_hal methods and improvements by @JMS55 in [#5452](https://github.com/gfx-rs/wgpu/pull/5452) + - Added `wgpu::CommandEncoder::as_hal_mut` + - Added `wgpu::TextureView::as_hal` + - `wgpu::Texture::as_hal` now returns a user-defined type to match the other as_hal functions + #### GLES - Log an error when GLES texture format heuristics fail. By @PolyMeilex in [#5266](https://github.com/gfx-rs/wgpu/issues/5266) @@ -124,7 +129,7 @@ Bottom level categories: #### WebGPU - Implement the `device_set_device_lost_callback` method for `ContextWebGpu`. By @suti in [#5438](https://github.com/gfx-rs/wgpu/pull/5438) -- Add support for storage texture access modes `ReadOnly` and `ReadWrite`. By @JolifantoBambla in [#5434](https://github.com/gfx-rs/wgpu/pull/5434) +- Add support for storage texture access modes `ReadOnly` and `ReadWrite`. By @JolifantoBambla in [#5434](https://github.com/gfx-rs/wgpu/pull/5434) ### Bug Fixes @@ -179,7 +184,7 @@ This release includes `wgpu`, `wgpu-core`, and `wgpu-hal`. All other crates are ### Major Changes -#### Vendored WebGPU Bindings from `web_sys` +#### Vendored WebGPU Bindings from `web_sys` **`--cfg=web_sys_unstable_apis` is no longer needed in your `RUSTFLAGS` to compile for WebGPU!!!** diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index febed4fc97..ab413db737 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -82,7 +82,7 @@ impl CommandEncoder { } } - fn open(&mut self) -> Result<&mut A::CommandEncoder, DeviceError> { + pub(crate) fn open(&mut self) -> Result<&mut A::CommandEncoder, DeviceError> { if !self.is_open { self.is_open = true; let label = self.label.as_deref(); diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index aca077caab..8256b95539 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -8,7 +8,10 @@ use crate::{ }, global::Global, hal_api::HalApi, - id::{AdapterId, BufferId, DeviceId, Id, Marker, SurfaceId, TextureId}, + id::{ + AdapterId, BufferId, CommandEncoderId, DeviceId, Id, Marker, SurfaceId, TextureId, + TextureViewId, + }, init_tracker::{BufferInitTracker, TextureInitTracker}, resource, resource_log, snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable}, @@ -924,11 +927,11 @@ impl Global { /// # Safety /// /// - The raw texture handle must not be manually destroyed - pub unsafe fn texture_as_hal)>( + pub unsafe fn texture_as_hal) -> R, R>( &self, id: TextureId, hal_texture_callback: F, - ) { + ) -> R { profiling::scope!("Texture::as_hal"); let hub = A::hub(self); @@ -937,7 +940,26 @@ impl Global { let snatch_guard = texture.device.snatchable_lock.read(); let hal_texture = texture.raw(&snatch_guard); - hal_texture_callback(hal_texture); + hal_texture_callback(hal_texture) + } + + /// # Safety + /// + /// - The raw texture view handle must not be manually destroyed + pub unsafe fn texture_view_as_hal) -> R, R>( + &self, + id: TextureViewId, + hal_texture_view_callback: F, + ) -> R { + profiling::scope!("TextureView::as_hal"); + + let hub = A::hub(self); + let texture_view_opt = { hub.texture_views.try_get(id).ok().flatten() }; + let texture_view = texture_view_opt.as_ref().unwrap(); + let snatch_guard = texture_view.device.snatchable_lock.read(); + let hal_texture_view = texture_view.raw(&snatch_guard); + + hal_texture_view_callback(hal_texture_view) } /// # Safety @@ -1005,6 +1027,29 @@ impl Global { hal_surface_callback(hal_surface) } + + /// # Safety + /// + /// - The raw command encoder handle must not be manually destroyed + pub unsafe fn command_encoder_as_hal_mut< + A: HalApi, + F: FnOnce(Option<&mut A::CommandEncoder>) -> R, + R, + >( + &self, + id: CommandEncoderId, + hal_command_encoder_callback: F, + ) -> R { + profiling::scope!("CommandEncoder::as_hal"); + + let hub = A::hub(self); + let cmd_buf = hub.command_buffers.get(id.transmute()).unwrap(); + let mut cmd_buf_data = cmd_buf.data.lock(); + let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf_raw = cmd_buf_data.encoder.open().ok(); + + hal_command_encoder_callback(cmd_buf_raw) + } } /// A texture that has been marked as destroyed and is staged for actual deletion soon. diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 9e8ba0a740..4bc84349b4 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -413,6 +413,15 @@ pub struct TextureView { attachment: FramebufferAttachment, } +impl TextureView { + /// # Safety + /// + /// - The image view handle must not be manually destroyed + pub unsafe fn raw_handle(&self) -> vk::ImageView { + self.raw + } +} + #[derive(Debug)] pub struct Sampler { raw: vk::Sampler, @@ -481,6 +490,15 @@ pub struct CommandEncoder { end_of_pass_timer_query: Option<(vk::QueryPool, u32)>, } +impl CommandEncoder { + /// # Safety + /// + /// - The command buffer handle must not be manually destroyed + pub unsafe fn raw_handle(&self) -> vk::CommandBuffer { + self.active + } +} + impl fmt::Debug for CommandEncoder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CommandEncoder") diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index c73daba2a9..98f1ca1de6 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -22,8 +22,11 @@ use std::{ slice, sync::Arc, }; -use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; -use wgc::device::DeviceLostClosure; +use wgc::{ + command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}, + device::DeviceLostClosure, + id::{CommandEncoderId, TextureViewId}, +}; use wgt::WasmNotSendSync; const LABEL: &str = "label"; @@ -207,14 +210,51 @@ impl ContextWgpuCore { } } - pub unsafe fn texture_as_hal)>( + pub unsafe fn texture_as_hal< + A: wgc::hal_api::HalApi, + F: FnOnce(Option<&A::Texture>) -> R, + R, + >( &self, texture: &Texture, hal_texture_callback: F, - ) { + ) -> R { + unsafe { + self.0 + .texture_as_hal::(texture.id, hal_texture_callback) + } + } + + pub unsafe fn texture_view_as_hal< + A: wgc::hal_api::HalApi, + F: FnOnce(Option<&A::TextureView>) -> R, + R, + >( + &self, + texture_view_id: TextureViewId, + hal_texture_view_callback: F, + ) -> R { unsafe { self.0 - .texture_as_hal::(texture.id, hal_texture_callback) + .texture_view_as_hal::(texture_view_id, hal_texture_view_callback) + } + } + + /// This method will start the wgpu_core level command recording. + pub unsafe fn command_encoder_as_hal_mut< + A: wgc::hal_api::HalApi, + F: FnOnce(Option<&mut A::CommandEncoder>) -> R, + R, + >( + &self, + command_encoder_id: CommandEncoderId, + hal_command_encoder_callback: F, + ) -> R { + unsafe { + self.0.command_encoder_as_hal_mut::( + command_encoder_id, + hal_command_encoder_callback, + ) } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d9ca4b521f..ecf5f88d88 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -3115,10 +3115,10 @@ impl Texture { /// /// - The raw handle obtained from the hal Texture must not be manually destroyed #[cfg(wgpu_core)] - pub unsafe fn as_hal)>( + pub unsafe fn as_hal) -> R, R>( &self, hal_texture_callback: F, - ) { + ) -> R { let texture = self.data.as_ref().downcast_ref().unwrap(); if let Some(ctx) = self @@ -3126,7 +3126,7 @@ impl Texture { .as_any() .downcast_ref::() { - unsafe { ctx.texture_as_hal::(texture, hal_texture_callback) } + unsafe { ctx.texture_as_hal::(texture, hal_texture_callback) } } else { hal_texture_callback(None) } @@ -3470,6 +3470,36 @@ impl CommandEncoder { destination_offset, ) } + + /// Returns the inner hal CommandEncoder using a callback. The hal command encoder will be `None` if the + /// backend type argument does not match with this wgpu CommandEncoder + /// + /// This method will start the wgpu_core level command recording. + /// + /// # Safety + /// + /// - The raw handle obtained from the hal CommandEncoder must not be manually destroyed + #[cfg(wgpu_core)] + pub unsafe fn as_hal_mut< + A: wgc::hal_api::HalApi, + F: FnOnce(Option<&mut A::CommandEncoder>) -> R, + R, + >( + &mut self, + hal_command_encoder_callback: F, + ) -> Option { + use core::id::CommandEncoderId; + + self.context + .as_any() + .downcast_ref::() + .map(|ctx| unsafe { + ctx.command_encoder_as_hal_mut::( + CommandEncoderId::from(self.id.unwrap()), + hal_command_encoder_callback, + ) + }) + } } /// [`Features::TIMESTAMP_QUERY_INSIDE_ENCODERS`] must be enabled on the device in order to call these functions. @@ -5021,6 +5051,34 @@ impl TextureView { pub fn global_id(&self) -> Id { Id(self.id.global_id(), PhantomData) } + + /// Returns the inner hal TextureView using a callback. The hal texture will be `None` if the + /// backend type argument does not match with this wgpu Texture + /// + /// # Safety + /// + /// - The raw handle obtained from the hal TextureView must not be manually destroyed + #[cfg(wgpu_core)] + pub unsafe fn as_hal) -> R, R>( + &self, + hal_texture_view_callback: F, + ) -> R { + use core::id::TextureViewId; + + let texture_view_id = TextureViewId::from(self.id); + + if let Some(ctx) = self + .context + .as_any() + .downcast_ref::() + { + unsafe { + ctx.texture_view_as_hal::(texture_view_id, hal_texture_view_callback) + } + } else { + hal_texture_view_callback(None) + } + } } impl Sampler {