mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
[core] Document command encoding and command buffers.
Flesh out the documentation for `wgpu_core`'s `CommandBuffer`, `CommandEncoder`, and associated types. Allow doc links to private items. `wgpu-core` isn't entirely user-facing, so it's useful to document internal items.
This commit is contained in:
parent
5b8be97a88
commit
c9212c6d46
@ -38,23 +38,115 @@ use crate::device::trace::Command as TraceCommand;
|
|||||||
|
|
||||||
const PUSH_CONSTANT_CLEAR_ARRAY: &[u32] = &[0_u32; 64];
|
const PUSH_CONSTANT_CLEAR_ARRAY: &[u32] = &[0_u32; 64];
|
||||||
|
|
||||||
|
/// The current state of a [`CommandBuffer`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum CommandEncoderStatus {
|
pub(crate) enum CommandEncoderStatus {
|
||||||
|
/// Ready to record commands. An encoder's initial state.
|
||||||
|
///
|
||||||
|
/// Command building methods like [`command_encoder_clear_buffer`] and
|
||||||
|
/// [`command_encoder_run_compute_pass`] require the encoder to be in this
|
||||||
|
/// state.
|
||||||
|
///
|
||||||
|
/// [`command_encoder_clear_buffer`]: Global::command_encoder_clear_buffer
|
||||||
|
/// [`command_encoder_run_compute_pass`]: Global::command_encoder_run_compute_pass
|
||||||
Recording,
|
Recording,
|
||||||
|
|
||||||
|
/// Command recording is complete, and the buffer is ready for submission.
|
||||||
|
///
|
||||||
|
/// [`Global::command_encoder_finish`] transitions a
|
||||||
|
/// `CommandBuffer` from the `Recording` state into this state.
|
||||||
|
///
|
||||||
|
/// [`Global::queue_submit`] drops command buffers unless they are
|
||||||
|
/// in this state.
|
||||||
Finished,
|
Finished,
|
||||||
|
|
||||||
|
/// An error occurred while recording a compute or render pass.
|
||||||
|
///
|
||||||
|
/// When a `CommandEncoder` is left in this state, we have also
|
||||||
|
/// returned an error result from the function that encountered
|
||||||
|
/// the problem. Future attempts to use the encoder (that is,
|
||||||
|
/// calls to [`CommandBuffer::get_encoder`]) will also return
|
||||||
|
/// errors.
|
||||||
|
///
|
||||||
|
/// Calling [`Global::command_encoder_finish`] in this state
|
||||||
|
/// discards the command buffer under construction.
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A raw [`CommandEncoder`][rce], and the raw [`CommandBuffer`][rcb]s built from it.
|
||||||
|
///
|
||||||
|
/// Each wgpu-core [`CommandBuffer`] owns an instance of this type, which is
|
||||||
|
/// where the commands are actually stored.
|
||||||
|
///
|
||||||
|
/// This holds a `Vec` of raw [`CommandBuffer`][rcb]s, not just one. We are not
|
||||||
|
/// always able to record commands in the order in which they must ultimately be
|
||||||
|
/// submitted to the queue, but raw command buffers don't permit inserting new
|
||||||
|
/// commands into the middle of a recorded stream. However, hal queue submission
|
||||||
|
/// accepts a series of command buffers at once, so we can simply break the
|
||||||
|
/// stream up into multiple buffers, and then reorder the buffers. See
|
||||||
|
/// [`CommandEncoder::close_and_swap`] for a specific example of this.
|
||||||
|
///
|
||||||
|
/// Note that a [`CommandEncoderId`] actually refers to a [`CommandBuffer`].
|
||||||
|
/// Methods that take a command encoder id actually look up the command buffer,
|
||||||
|
/// and then use its encoder.
|
||||||
|
///
|
||||||
|
/// [rce]: wgpu_hal::Api::CommandEncoder
|
||||||
|
/// [rcb]: wgpu_hal::Api::CommandBuffer
|
||||||
pub(crate) struct CommandEncoder<A: HalApi> {
|
pub(crate) struct CommandEncoder<A: HalApi> {
|
||||||
|
/// The underlying `wgpu_hal` [`CommandEncoder`].
|
||||||
|
///
|
||||||
|
/// Successfully executed command buffers' encoders are saved in a
|
||||||
|
/// [`wgpu_hal::device::CommandAllocator`] for recycling.
|
||||||
|
///
|
||||||
|
/// [`CommandEncoder`]: wgpu_hal::Api::CommandEncoder
|
||||||
raw: A::CommandEncoder,
|
raw: A::CommandEncoder,
|
||||||
|
|
||||||
|
/// All the raw command buffers for our owning [`CommandBuffer`], in
|
||||||
|
/// submission order.
|
||||||
|
///
|
||||||
|
/// These command buffers were all constructed with `raw`. The
|
||||||
|
/// [`wgpu_hal::CommandEncoder`] trait forbids these from outliving `raw`,
|
||||||
|
/// and requires that we provide all of these when we call
|
||||||
|
/// [`raw.reset_all()`][CE::ra], so the encoder and its buffers travel
|
||||||
|
/// together.
|
||||||
|
///
|
||||||
|
/// [CE::ra]: wgpu_hal::CommandEncoder::reset_all
|
||||||
list: Vec<A::CommandBuffer>,
|
list: Vec<A::CommandBuffer>,
|
||||||
|
|
||||||
|
/// True if `raw` is in the "recording" state.
|
||||||
|
///
|
||||||
|
/// See the documentation for [`wgpu_hal::CommandEncoder`] for
|
||||||
|
/// details on the states `raw` can be in.
|
||||||
is_open: bool,
|
is_open: bool,
|
||||||
|
|
||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: handle errors better
|
//TODO: handle errors better
|
||||||
impl<A: HalApi> CommandEncoder<A> {
|
impl<A: HalApi> CommandEncoder<A> {
|
||||||
/// Closes the live encoder
|
/// Finish the current command buffer, if any, and place it
|
||||||
|
/// at the second-to-last position in our list.
|
||||||
|
///
|
||||||
|
/// If we have opened this command encoder, finish its current
|
||||||
|
/// command buffer, and insert it just before the last element in
|
||||||
|
/// [`self.list`][l]. If this command buffer is closed, do nothing.
|
||||||
|
///
|
||||||
|
/// On return, the underlying hal encoder is closed.
|
||||||
|
///
|
||||||
|
/// What is this for?
|
||||||
|
///
|
||||||
|
/// The `wgpu_hal` contract requires that each render or compute pass's
|
||||||
|
/// commands be preceded by calls to [`transition_buffers`] and
|
||||||
|
/// [`transition_textures`], to put the resources the pass operates on in
|
||||||
|
/// the appropriate state. Unfortunately, we don't know which transitions
|
||||||
|
/// are needed until we're done recording the pass itself. Rather than
|
||||||
|
/// iterating over the pass twice, we note the necessary transitions as we
|
||||||
|
/// record its commands, finish the raw command buffer for the actual pass,
|
||||||
|
/// record a new raw command buffer for the transitions, and jam that buffer
|
||||||
|
/// in just before the pass's. This is the function that jams in the
|
||||||
|
/// transitions' command buffer.
|
||||||
|
///
|
||||||
|
/// [l]: CommandEncoder::list
|
||||||
fn close_and_swap(&mut self) -> Result<(), DeviceError> {
|
fn close_and_swap(&mut self) -> Result<(), DeviceError> {
|
||||||
if self.is_open {
|
if self.is_open {
|
||||||
self.is_open = false;
|
self.is_open = false;
|
||||||
@ -65,6 +157,16 @@ impl<A: HalApi> CommandEncoder<A> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finish the current command buffer, if any, and add it to the
|
||||||
|
/// end of [`self.list`][l].
|
||||||
|
///
|
||||||
|
/// If we have opened this command encoder, finish its current
|
||||||
|
/// command buffer, and push it onto the end of [`self.list`][l].
|
||||||
|
/// If this command buffer is closed, do nothing.
|
||||||
|
///
|
||||||
|
/// On return, the underlying hal encoder is closed.
|
||||||
|
///
|
||||||
|
/// [l]: CommandEncoder::list
|
||||||
fn close(&mut self) -> Result<(), DeviceError> {
|
fn close(&mut self) -> Result<(), DeviceError> {
|
||||||
if self.is_open {
|
if self.is_open {
|
||||||
self.is_open = false;
|
self.is_open = false;
|
||||||
@ -75,6 +177,9 @@ impl<A: HalApi> CommandEncoder<A> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Discard the command buffer under construction, if any.
|
||||||
|
///
|
||||||
|
/// The underlying hal encoder is closed, if it was recording.
|
||||||
pub(crate) fn discard(&mut self) {
|
pub(crate) fn discard(&mut self) {
|
||||||
if self.is_open {
|
if self.is_open {
|
||||||
self.is_open = false;
|
self.is_open = false;
|
||||||
@ -82,6 +187,9 @@ impl<A: HalApi> CommandEncoder<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Begin recording a new command buffer, if we haven't already.
|
||||||
|
///
|
||||||
|
/// The underlying hal encoder is put in the "recording" state.
|
||||||
pub(crate) fn open(&mut self) -> Result<&mut A::CommandEncoder, DeviceError> {
|
pub(crate) fn open(&mut self) -> Result<&mut A::CommandEncoder, DeviceError> {
|
||||||
if !self.is_open {
|
if !self.is_open {
|
||||||
self.is_open = true;
|
self.is_open = true;
|
||||||
@ -92,6 +200,10 @@ impl<A: HalApi> CommandEncoder<A> {
|
|||||||
Ok(&mut self.raw)
|
Ok(&mut self.raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Begin recording a new command buffer for a render pass, with
|
||||||
|
/// its own label.
|
||||||
|
///
|
||||||
|
/// The underlying hal encoder is put in the "recording" state.
|
||||||
fn open_pass(&mut self, label: Option<&str>) -> Result<(), DeviceError> {
|
fn open_pass(&mut self, label: Option<&str>) -> Result<(), DeviceError> {
|
||||||
self.is_open = true;
|
self.is_open = true;
|
||||||
unsafe { self.raw.begin_encoding(label)? };
|
unsafe { self.raw.begin_encoding(label)? };
|
||||||
@ -111,12 +223,27 @@ pub(crate) struct BakedCommands<A: HalApi> {
|
|||||||
pub(crate) struct DestroyedBufferError(pub id::BufferId);
|
pub(crate) struct DestroyedBufferError(pub id::BufferId);
|
||||||
pub(crate) struct DestroyedTextureError(pub id::TextureId);
|
pub(crate) struct DestroyedTextureError(pub id::TextureId);
|
||||||
|
|
||||||
|
/// The mutable state of a [`CommandBuffer`].
|
||||||
pub struct CommandBufferMutable<A: HalApi> {
|
pub struct CommandBufferMutable<A: HalApi> {
|
||||||
|
/// The [`wgpu_hal::Api::CommandBuffer`]s we've built so far, and the encoder
|
||||||
|
/// they belong to.
|
||||||
pub(crate) encoder: CommandEncoder<A>,
|
pub(crate) encoder: CommandEncoder<A>,
|
||||||
|
|
||||||
|
/// The current state of this command buffer's encoder.
|
||||||
status: CommandEncoderStatus,
|
status: CommandEncoderStatus,
|
||||||
|
|
||||||
|
/// All the resources that the commands recorded so far have referred to.
|
||||||
pub(crate) trackers: Tracker<A>,
|
pub(crate) trackers: Tracker<A>,
|
||||||
|
|
||||||
|
/// The regions of buffers and textures these commands will read and write.
|
||||||
|
///
|
||||||
|
/// This is used to determine which portions of which
|
||||||
|
/// buffers/textures we actually need to initialize. If we're
|
||||||
|
/// definitely going to write to something before we read from it,
|
||||||
|
/// we don't need to clear its contents.
|
||||||
buffer_memory_init_actions: Vec<BufferInitTrackerAction<A>>,
|
buffer_memory_init_actions: Vec<BufferInitTrackerAction<A>>,
|
||||||
texture_memory_actions: CommandBufferTextureMemoryActions<A>,
|
texture_memory_actions: CommandBufferTextureMemoryActions<A>,
|
||||||
|
|
||||||
pub(crate) pending_query_resets: QueryResetMap<A>,
|
pub(crate) pending_query_resets: QueryResetMap<A>,
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
pub(crate) commands: Option<Vec<TraceCommand>>,
|
pub(crate) commands: Option<Vec<TraceCommand>>,
|
||||||
@ -133,11 +260,36 @@ impl<A: HalApi> CommandBufferMutable<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A buffer of commands to be submitted to the GPU for execution.
|
||||||
|
///
|
||||||
|
/// Whereas the WebGPU API uses two separate types for command buffers and
|
||||||
|
/// encoders, this type is a fusion of the two:
|
||||||
|
///
|
||||||
|
/// - During command recording, this holds a [`CommandEncoder`] accepting this
|
||||||
|
/// buffer's commands. In this state, the [`CommandBuffer`] type behaves like
|
||||||
|
/// a WebGPU `GPUCommandEncoder`.
|
||||||
|
///
|
||||||
|
/// - Once command recording is finished by calling
|
||||||
|
/// [`Global::command_encoder_finish`], no further recording is allowed. The
|
||||||
|
/// internal [`CommandEncoder`] is retained solely as a storage pool for the
|
||||||
|
/// raw command buffers. In this state, the value behaves like a WebGPU
|
||||||
|
/// `GPUCommandBuffer`.
|
||||||
|
///
|
||||||
|
/// - Once a command buffer is submitted to the queue, it is removed from the id
|
||||||
|
/// registry, and its contents are taken to construct a [`BakedCommands`],
|
||||||
|
/// whose contents eventually become the property of the submission queue.
|
||||||
pub struct CommandBuffer<A: HalApi> {
|
pub struct CommandBuffer<A: HalApi> {
|
||||||
pub(crate) device: Arc<Device<A>>,
|
pub(crate) device: Arc<Device<A>>,
|
||||||
limits: wgt::Limits,
|
limits: wgt::Limits,
|
||||||
support_clear_texture: bool,
|
support_clear_texture: bool,
|
||||||
pub(crate) info: ResourceInfo<CommandBuffer<A>>,
|
pub(crate) info: ResourceInfo<CommandBuffer<A>>,
|
||||||
|
|
||||||
|
/// The mutable state of this command buffer.
|
||||||
|
///
|
||||||
|
/// This `Option` is populated when the command buffer is first created.
|
||||||
|
/// When this is submitted, dropped, or destroyed, its contents are
|
||||||
|
/// extracted into a [`BakedCommands`] by
|
||||||
|
/// [`CommandBuffer::extract_baked_commands`].
|
||||||
pub(crate) data: Mutex<Option<CommandBufferMutable<A>>>,
|
pub(crate) data: Mutex<Option<CommandBufferMutable<A>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +400,12 @@ impl<A: HalApi> CommandBuffer<A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<A: HalApi> CommandBuffer<A> {
|
impl<A: HalApi> CommandBuffer<A> {
|
||||||
|
/// Return the [`CommandBuffer`] for `id`, for recording new commands.
|
||||||
|
///
|
||||||
|
/// In `wgpu_core`, the [`CommandBuffer`] type serves both as encoder and
|
||||||
|
/// buffer, which is why this function takes an [`id::CommandEncoderId`] but
|
||||||
|
/// returns a [`CommandBuffer`]. The returned command buffer must be in the
|
||||||
|
/// "recording" state. Otherwise, an error is returned.
|
||||||
fn get_encoder(
|
fn get_encoder(
|
||||||
hub: &Hub<A>,
|
hub: &Hub<A>,
|
||||||
id: id::CommandEncoderId,
|
id: id::CommandEncoderId,
|
||||||
|
@ -150,6 +150,16 @@ struct ActiveSubmission<A: HalApi> {
|
|||||||
/// Buffers to be mapped once this submission has completed.
|
/// Buffers to be mapped once this submission has completed.
|
||||||
mapped: Vec<Arc<Buffer<A>>>,
|
mapped: Vec<Arc<Buffer<A>>>,
|
||||||
|
|
||||||
|
/// Command buffers used by this submission, and the encoder that owns them.
|
||||||
|
///
|
||||||
|
/// [`wgpu_hal::Queue::submit`] requires the submitted command buffers to
|
||||||
|
/// remain alive until the submission has completed execution. Command
|
||||||
|
/// encoders double as allocation pools for command buffers, so holding them
|
||||||
|
/// here and cleaning them up in [`LifetimeTracker::triage_submissions`]
|
||||||
|
/// satisfies that requirement.
|
||||||
|
///
|
||||||
|
/// Once this submission has completed, the command buffers are reset and
|
||||||
|
/// the command encoder is recycled.
|
||||||
encoders: Vec<EncoderInFlight<A>>,
|
encoders: Vec<EncoderInFlight<A>>,
|
||||||
|
|
||||||
/// List of queue "on_submitted_work_done" closures to be called once this
|
/// List of queue "on_submitted_work_done" closures to be called once this
|
||||||
|
@ -377,11 +377,24 @@ fn map_buffer<A: HalApi>(
|
|||||||
Ok(mapping.ptr)
|
Ok(mapping.ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A pool of free [`wgpu_hal::CommandEncoder`]s, owned by a `Device`.
|
||||||
|
///
|
||||||
|
/// Each encoder in this list is in the "closed" state.
|
||||||
|
///
|
||||||
|
/// Since a raw [`CommandEncoder`][ce] is itself a pool for allocating
|
||||||
|
/// raw [`CommandBuffer`][cb]s, this is a pool of pools.
|
||||||
|
///
|
||||||
|
/// [ce]: wgpu_hal::CommandEncoder
|
||||||
|
/// [cb]: wgpu_hal::Api::CommandBuffer
|
||||||
pub(crate) struct CommandAllocator<A: HalApi> {
|
pub(crate) struct CommandAllocator<A: HalApi> {
|
||||||
free_encoders: Vec<A::CommandEncoder>,
|
free_encoders: Vec<A::CommandEncoder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: HalApi> CommandAllocator<A> {
|
impl<A: HalApi> CommandAllocator<A> {
|
||||||
|
/// Return a fresh [`wgpu_hal::CommandEncoder`] in the "closed" state.
|
||||||
|
///
|
||||||
|
/// If we have free encoders in the pool, take one of those. Otherwise,
|
||||||
|
/// create a new one on `device`.
|
||||||
fn acquire_encoder(
|
fn acquire_encoder(
|
||||||
&mut self,
|
&mut self,
|
||||||
device: &A::Device,
|
device: &A::Device,
|
||||||
@ -396,10 +409,14 @@ impl<A: HalApi> CommandAllocator<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add `encoder` back to the free pool.
|
||||||
fn release_encoder(&mut self, encoder: A::CommandEncoder) {
|
fn release_encoder(&mut self, encoder: A::CommandEncoder) {
|
||||||
self.free_encoders.push(encoder);
|
self.free_encoders.push(encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Free the pool of command encoders.
|
||||||
|
///
|
||||||
|
/// This is only called when the `Device` is dropped.
|
||||||
fn dispose(self, device: &A::Device) {
|
fn dispose(self, device: &A::Device) {
|
||||||
resource_log!(
|
resource_log!(
|
||||||
"CommandAllocator::dispose encoders {}",
|
"CommandAllocator::dispose encoders {}",
|
||||||
|
@ -152,13 +152,18 @@ pub enum TempResource<A: HalApi> {
|
|||||||
Texture(Arc<Texture<A>>),
|
Texture(Arc<Texture<A>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A queue execution for a particular command encoder.
|
/// A series of [`CommandBuffers`] that have been submitted to a
|
||||||
|
/// queue, and the [`wgpu_hal::CommandEncoder`] that built them.
|
||||||
pub(crate) struct EncoderInFlight<A: HalApi> {
|
pub(crate) struct EncoderInFlight<A: HalApi> {
|
||||||
raw: A::CommandEncoder,
|
raw: A::CommandEncoder,
|
||||||
cmd_buffers: Vec<A::CommandBuffer>,
|
cmd_buffers: Vec<A::CommandBuffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: HalApi> EncoderInFlight<A> {
|
impl<A: HalApi> EncoderInFlight<A> {
|
||||||
|
/// Free all of our command buffers.
|
||||||
|
///
|
||||||
|
/// Return the command encoder, fully reset and ready to be
|
||||||
|
/// reused.
|
||||||
pub(crate) unsafe fn land(mut self) -> A::CommandEncoder {
|
pub(crate) unsafe fn land(mut self) -> A::CommandEncoder {
|
||||||
unsafe { self.raw.reset_all(self.cmd_buffers.into_iter()) };
|
unsafe { self.raw.reset_all(self.cmd_buffers.into_iter()) };
|
||||||
self.raw
|
self.raw
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
unused_braces,
|
unused_braces,
|
||||||
// It gets in the way a lot and does not prevent bugs in practice.
|
// It gets in the way a lot and does not prevent bugs in practice.
|
||||||
clippy::pattern_type_mismatch,
|
clippy::pattern_type_mismatch,
|
||||||
|
// `wgpu-core` isn't entirely user-facing, so it's useful to document internal items.
|
||||||
|
rustdoc::private_intra_doc_links
|
||||||
)]
|
)]
|
||||||
#![warn(
|
#![warn(
|
||||||
trivial_casts,
|
trivial_casts,
|
||||||
|
@ -303,6 +303,15 @@ pub trait Api: Clone + fmt::Debug + Sized {
|
|||||||
|
|
||||||
type Queue: Queue<A = Self>;
|
type Queue: Queue<A = Self>;
|
||||||
type CommandEncoder: CommandEncoder<A = Self>;
|
type CommandEncoder: CommandEncoder<A = Self>;
|
||||||
|
|
||||||
|
/// This API's command buffer type.
|
||||||
|
///
|
||||||
|
/// The only thing you can do with `CommandBuffer`s is build them
|
||||||
|
/// with a [`CommandEncoder`] and then pass them to
|
||||||
|
/// [`Queue::submit`] for execution, or destroy them by passing
|
||||||
|
/// them to [`CommandEncoder::reset_all`].
|
||||||
|
///
|
||||||
|
/// [`CommandEncoder`]: Api::CommandEncoder
|
||||||
type CommandBuffer: WasmNotSendSync + fmt::Debug;
|
type CommandBuffer: WasmNotSendSync + fmt::Debug;
|
||||||
|
|
||||||
type Buffer: fmt::Debug + WasmNotSendSync + 'static;
|
type Buffer: fmt::Debug + WasmNotSendSync + 'static;
|
||||||
@ -545,11 +554,21 @@ pub trait Queue: WasmNotSendSync {
|
|||||||
/// Submits the command buffers for execution on GPU.
|
/// Submits the command buffers for execution on GPU.
|
||||||
///
|
///
|
||||||
/// Valid usage:
|
/// Valid usage:
|
||||||
/// - all of the command buffers were created from command pools
|
///
|
||||||
/// that are associated with this queue.
|
/// - All of the [`CommandBuffer`][cb]s were created from
|
||||||
/// - all of the command buffers had `CommandBuffer::finish()` called.
|
/// [`CommandEncoder`][ce]s that are associated with this queue.
|
||||||
/// - all surface textures that the command buffers write to must be
|
///
|
||||||
/// passed to the surface_textures argument.
|
/// - 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.)
|
||||||
|
///
|
||||||
|
/// - All of the [`SurfaceTexture`][st]s that the command buffers
|
||||||
|
/// write to appear in the `surface_textures` argument.
|
||||||
|
///
|
||||||
|
/// [cb]: Api::CommandBuffer
|
||||||
|
/// [ce]: Api::CommandEncoder
|
||||||
|
/// [st]: Api::SurfaceTexture
|
||||||
unsafe fn submit(
|
unsafe fn submit(
|
||||||
&self,
|
&self,
|
||||||
command_buffers: &[&<Self::A as Api>::CommandBuffer],
|
command_buffers: &[&<Self::A as Api>::CommandBuffer],
|
||||||
@ -564,7 +583,12 @@ pub trait Queue: WasmNotSendSync {
|
|||||||
unsafe fn get_timestamp_period(&self) -> f32;
|
unsafe fn get_timestamp_period(&self) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encoder and allocation pool for `CommandBuffer`.
|
/// Encoder and allocation pool for `CommandBuffer`s.
|
||||||
|
///
|
||||||
|
/// A `CommandEncoder` not only constructs `CommandBuffer`s but also
|
||||||
|
/// acts as the allocation pool that owns the buffers' underlying
|
||||||
|
/// storage. Thus, `CommandBuffer`s must not outlive the
|
||||||
|
/// `CommandEncoder` that created them.
|
||||||
///
|
///
|
||||||
/// The life cycle of a `CommandBuffer` is as follows:
|
/// The life cycle of a `CommandBuffer` is as follows:
|
||||||
///
|
///
|
||||||
@ -577,14 +601,17 @@ pub trait Queue: WasmNotSendSync {
|
|||||||
///
|
///
|
||||||
/// - Call methods like `copy_buffer_to_buffer`, `begin_render_pass`,
|
/// - Call methods like `copy_buffer_to_buffer`, `begin_render_pass`,
|
||||||
/// etc. on a "recording" `CommandEncoder` to add commands to the
|
/// etc. on a "recording" `CommandEncoder` to add commands to the
|
||||||
/// list.
|
/// list. (If an error occurs, you must call `discard_encoding`; see
|
||||||
|
/// below.)
|
||||||
///
|
///
|
||||||
/// - Call `end_encoding` on a recording `CommandEncoder` to close the
|
/// - Call `end_encoding` on a recording `CommandEncoder` to close the
|
||||||
/// encoder and construct a fresh `CommandBuffer` consisting of the
|
/// encoder and construct a fresh `CommandBuffer` consisting of the
|
||||||
/// list of commands recorded up to that point.
|
/// list of commands recorded up to that point.
|
||||||
///
|
///
|
||||||
/// - Call `discard_encoding` on a recording `CommandEncoder` to drop
|
/// - Call `discard_encoding` on a recording `CommandEncoder` to drop
|
||||||
/// the commands recorded thus far and close the encoder.
|
/// the commands recorded thus far and close the encoder. This is
|
||||||
|
/// the only safe thing to do on a `CommandEncoder` if an error has
|
||||||
|
/// occurred while recording commands.
|
||||||
///
|
///
|
||||||
/// - Call `reset_all` on a closed `CommandEncoder`, passing all the
|
/// - Call `reset_all` on a closed `CommandEncoder`, passing all the
|
||||||
/// live `CommandBuffers` built from it. All the `CommandBuffer`s
|
/// live `CommandBuffers` built from it. All the `CommandBuffer`s
|
||||||
@ -602,6 +629,10 @@ pub trait Queue: WasmNotSendSync {
|
|||||||
/// built it.
|
/// built it.
|
||||||
///
|
///
|
||||||
/// - A `CommandEncoder` must not outlive its `Device`.
|
/// - A `CommandEncoder` must not outlive its `Device`.
|
||||||
|
///
|
||||||
|
/// It is the user's responsibility to meet this requirements. This
|
||||||
|
/// allows `CommandEncoder` implementations to keep their state
|
||||||
|
/// tracking to a minimum.
|
||||||
pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
|
pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
|
||||||
type A: Api;
|
type A: Api;
|
||||||
|
|
||||||
@ -616,6 +647,9 @@ pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
|
|||||||
|
|
||||||
/// Discard the command list under construction, if any.
|
/// Discard the command list under construction, if any.
|
||||||
///
|
///
|
||||||
|
/// If an error has occurred while recording commands, this
|
||||||
|
/// is the only safe thing to do with the encoder.
|
||||||
|
///
|
||||||
/// This puts this `CommandEncoder` in the "closed" state.
|
/// This puts this `CommandEncoder` in the "closed" state.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -447,6 +447,7 @@ pub struct BindGroup {
|
|||||||
set: gpu_descriptor::DescriptorSet<vk::DescriptorSet>,
|
set: gpu_descriptor::DescriptorSet<vk::DescriptorSet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Miscellaneous allocation recycling pool for `CommandAllocator`.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Temp {
|
struct Temp {
|
||||||
marker: Vec<u8>,
|
marker: Vec<u8>,
|
||||||
@ -476,11 +477,31 @@ impl Temp {
|
|||||||
pub struct CommandEncoder {
|
pub struct CommandEncoder {
|
||||||
raw: vk::CommandPool,
|
raw: vk::CommandPool,
|
||||||
device: Arc<DeviceShared>,
|
device: Arc<DeviceShared>,
|
||||||
|
|
||||||
|
/// The current command buffer, if `self` is in the ["recording"]
|
||||||
|
/// state.
|
||||||
|
///
|
||||||
|
/// ["recording"]: crate::CommandEncoder
|
||||||
|
///
|
||||||
|
/// If non-`null`, the buffer is in the Vulkan "recording" state.
|
||||||
active: vk::CommandBuffer,
|
active: vk::CommandBuffer,
|
||||||
|
|
||||||
|
/// What kind of pass we are currently within: compute or render.
|
||||||
bind_point: vk::PipelineBindPoint,
|
bind_point: vk::PipelineBindPoint,
|
||||||
|
|
||||||
|
/// Allocation recycling pool for this encoder.
|
||||||
temp: Temp,
|
temp: Temp,
|
||||||
|
|
||||||
|
/// A pool of available command buffers.
|
||||||
|
///
|
||||||
|
/// These are all in the Vulkan "initial" state.
|
||||||
free: Vec<vk::CommandBuffer>,
|
free: Vec<vk::CommandBuffer>,
|
||||||
|
|
||||||
|
/// A pool of discarded command buffers.
|
||||||
|
///
|
||||||
|
/// These could be in any Vulkan state except "pending".
|
||||||
discarded: Vec<vk::CommandBuffer>,
|
discarded: Vec<vk::CommandBuffer>,
|
||||||
|
|
||||||
/// If this is true, the active renderpass enabled a debug span,
|
/// If this is true, the active renderpass enabled a debug span,
|
||||||
/// and needs to be disabled on renderpass close.
|
/// and needs to be disabled on renderpass close.
|
||||||
rpass_debug_marker_active: bool,
|
rpass_debug_marker_active: bool,
|
||||||
|
Loading…
Reference in New Issue
Block a user