From 9e0fd17726ecda0cc88e8a20f911de60f1017b1a Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Fri, 24 May 2024 00:39:56 +0200 Subject: [PATCH] [hal] Document resource destruction methods, and a few other things. (#5627) Document some more safety expectations for - resource destruction methods - `CommandEncoder` methods - `Queue::submit` Document `Fence` creation a bit. Document the `Queue` trait a bit. Document `vulkan` shader module handling a bit. --- wgpu-hal/src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 16cc5fe21..35b9ea0d0 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -529,6 +529,70 @@ pub trait Adapter: WasmNotSendSync { unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp; } +/// A connection to a GPU and a pool of resources to use with it. +/// +/// A `wgpu-hal` `Device` represents an open connection to a specific graphics +/// processor, controlled via the backend [`Device::A`]. A `Device` is mostly +/// used for creating resources. Each `Device` has an associated [`Queue`] used +/// for command submission. +/// +/// On Vulkan a `Device` corresponds to a logical device ([`VkDevice`]). Other +/// backends don't have an exact analog: for example, [`ID3D12Device`]s and +/// [`MTLDevice`]s are owned by the backends' [`wgpu_hal::Adapter`] +/// implementations, and shared by all [`wgpu_hal::Device`]s created from that +/// `Adapter`. +/// +/// A `Device`'s life cycle is generally: +/// +/// 1) Obtain a `Device` and its associated [`Queue`] by calling +/// [`Adapter::open`]. +/// +/// Alternatively, the backend-specific types that implement [`Adapter`] often +/// have methods for creating a `wgpu-hal` `Device` from a platform-specific +/// handle. For example, [`vulkan::Adapter::device_from_raw`] can create a +/// [`vulkan::Device`] from an [`ash::Device`]. +/// +/// 1) Create resources to use on the device by calling methods like +/// [`Device::create_texture`] or [`Device::create_shader_module`]. +/// +/// 1) Call [`Device::create_command_encoder`] to obtain a [`CommandEncoder`], +/// which you can use to build [`CommandBuffer`]s holding commands to be +/// executed on the GPU. +/// +/// 1) Call [`Queue::submit`] on the `Device`'s associated [`Queue`] to submit +/// [`CommandBuffer`]s for execution on the GPU. If needed, call +/// [`Device::wait`] to wait for them to finish execution. +/// +/// 1) Free resources with methods like [`Device::destroy_texture`] or +/// [`Device::destroy_shader_module`]. +/// +/// 1) Shut down the device by calling [`Device::exit`]. +/// +/// [`vkDevice`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VkDevice +/// [`ID3D12Device`]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12device +/// [`MTLDevice`]: https://developer.apple.com/documentation/metal/mtldevice +/// [`wgpu_hal::Adapter`]: Adapter +/// [`wgpu_hal::Device`]: Device +/// [`vulkan::Adapter::device_from_raw`]: vulkan/struct.Adapter.html#method.device_from_raw +/// [`vulkan::Device`]: vulkan/struct.Device.html +/// [`ash::Device`]: https://docs.rs/ash/latest/ash/struct.Device.html +/// [`CommandBuffer`]: Api::CommandBuffer +/// +/// # Safety +/// +/// As with other `wgpu-hal` APIs, [validation] is the caller's +/// responsibility. Here are the general requirements for all `Device` +/// methods: +/// +/// - Any resource passed to a `Device` method must have been created by that +/// `Device`. For example, a [`Texture`] passed to [`Device::destroy_texture`] must +/// have been created with the `Device` passed as `self`. +/// +/// - Resources may not be destroyed if they are used by any submitted command +/// buffers that have not yet finished execution. +/// +/// [validation]: index.html#validation-is-the-calling-codes-responsibility-not-wgpu-hals +/// [`Texture`]: Api::Texture pub trait Device: WasmNotSendSync { type A: Api; @@ -721,22 +785,35 @@ pub trait Queue: WasmNotSendSync { /// themselves are unordered. If each thread uses a separate [`Fence`], this /// problem does not arise. /// - /// Valid usage: + /// # Safety /// - /// - All of the [`CommandBuffer`][cb]s were created from - /// [`CommandEncoder`][ce]s that are associated with this queue. + /// - Each [`CommandBuffer`][cb] in `command_buffers` must have been created + /// from a [`CommandEncoder`][ce] that was constructed from the + /// [`Device`][d] associated with this [`Queue`]. /// - /// - All of those [`CommandBuffer`][cb]s must remain alive until - /// the submitted commands have finished execution. (Since - /// command buffers must not outlive their encoders, this - /// implies that the encoders must remain alive as well.) + /// - Each [`CommandBuffer`][cb] must remain alive until the submitted + /// commands have finished execution. Since command buffers must not + /// outlive their encoders, this implies that the encoders must remain + /// alive as well. /// - /// - All of the [`SurfaceTexture`][st]s that the command buffers - /// write to appear in the `surface_textures` argument. + /// - All resources used by a submitted [`CommandBuffer`][cb] + /// ([`Texture`][t]s, [`BindGroup`][bg]s, [`RenderPipeline`][rp]s, and so + /// on) must remain alive until the command buffer finishes execution. + /// + /// - Every [`SurfaceTexture`][st] that any command in `command_buffers` + /// writes to must appear in the `surface_textures` argument. + /// + /// - Each [`SurfaceTexture`][st] in `surface_textures` must be configured + /// for use with the [`Device`][d] associated with this [`Queue`], + /// typically by calling [`Surface::configure`]. /// /// [`Fence`]: Api::Fence /// [cb]: Api::CommandBuffer /// [ce]: Api::CommandEncoder + /// [d]: Api::Device + /// [t]: Api::Texture + /// [bg]: Api::BindGroup + /// [rp]: Api::RenderPipeline /// [st]: Api::SurfaceTexture unsafe fn submit( &self,