/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ mod allocator; mod bind; mod bundle; mod compute; mod draw; mod render; mod transfer; pub(crate) use self::allocator::CommandAllocator; pub use self::allocator::CommandAllocatorError; pub use self::bundle::*; pub use self::compute::*; pub use self::draw::*; pub use self::render::*; pub use self::transfer::*; use crate::{ device::{all_buffer_stages, all_image_stages}, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Storage, Token}, id, resource::{Buffer, Texture}, span, track::TrackerSet, Label, PrivateFeatures, Stored, }; use hal::command::CommandBuffer as _; use thiserror::Error; use std::thread::ThreadId; const PUSH_CONSTANT_CLEAR_ARRAY: &[u32] = &[0_u32; 64]; #[derive(Debug)] pub struct CommandBuffer { pub(crate) raw: Vec, is_recording: bool, recorded_thread_id: ThreadId, pub(crate) device_id: Stored, pub(crate) trackers: TrackerSet, pub(crate) used_swap_chain: Option<(Stored, B::Framebuffer)>, limits: wgt::Limits, private_features: PrivateFeatures, #[cfg(feature = "trace")] pub(crate) commands: Option>, #[cfg(debug_assertions)] pub(crate) label: String, } impl CommandBuffer { fn get_encoder( storage: &mut Storage, id: id::CommandEncoderId, ) -> Result<&mut Self, CommandEncoderError> { match storage.get_mut(id) { Ok(cmd_buf) if cmd_buf.is_recording => Ok(cmd_buf), Ok(_) => Err(CommandEncoderError::NotRecording), Err(_) => Err(CommandEncoderError::Invalid), } } pub(crate) fn insert_barriers( raw: &mut B::CommandBuffer, base: &mut TrackerSet, head: &TrackerSet, buffer_guard: &Storage, id::BufferId>, texture_guard: &Storage, id::TextureId>, ) { use hal::command::CommandBuffer as _; debug_assert_eq!(B::VARIANT, base.backend()); debug_assert_eq!(B::VARIANT, head.backend()); let buffer_barriers = base.buffers.merge_replace(&head.buffers).map(|pending| { let buf = &buffer_guard[pending.id]; pending.into_hal(buf) }); let texture_barriers = base.textures.merge_replace(&head.textures).map(|pending| { let tex = &texture_guard[pending.id]; pending.into_hal(tex) }); base.views.merge_extend(&head.views).unwrap(); base.bind_groups.merge_extend(&head.bind_groups).unwrap(); base.samplers.merge_extend(&head.samplers).unwrap(); base.compute_pipes .merge_extend(&head.compute_pipes) .unwrap(); base.render_pipes.merge_extend(&head.render_pipes).unwrap(); base.bundles.merge_extend(&head.bundles).unwrap(); let stages = all_buffer_stages() | all_image_stages(); unsafe { raw.pipeline_barrier( stages..stages, hal::memory::Dependencies::empty(), buffer_barriers.chain(texture_barriers), ); } } } impl crate::hub::Resource for CommandBuffer { const TYPE: &'static str = "CommandBuffer"; fn life_guard(&self) -> &crate::LifeGuard { unreachable!() } fn label(&self) -> &str { #[cfg(debug_assertions)] return &self.label; #[cfg(not(debug_assertions))] return ""; } } #[derive(Copy, Clone, Debug)] pub struct BasePassRef<'a, C> { pub commands: &'a [C], pub dynamic_offsets: &'a [wgt::DynamicOffset], pub string_data: &'a [u8], pub push_constant_data: &'a [u32], } #[doc(hidden)] #[derive(Debug)] #[cfg_attr( any(feature = "serial-pass", feature = "trace"), derive(serde::Serialize) )] #[cfg_attr( any(feature = "serial-pass", feature = "replay"), derive(serde::Deserialize) )] pub struct BasePass { pub commands: Vec, pub dynamic_offsets: Vec, pub string_data: Vec, pub push_constant_data: Vec, } impl BasePass { fn new() -> Self { Self { commands: Vec::new(), dynamic_offsets: Vec::new(), string_data: Vec::new(), push_constant_data: Vec::new(), } } #[cfg(feature = "trace")] fn from_ref(base: BasePassRef) -> Self { Self { commands: base.commands.to_vec(), dynamic_offsets: base.dynamic_offsets.to_vec(), string_data: base.string_data.to_vec(), push_constant_data: base.push_constant_data.to_vec(), } } pub fn as_ref(&self) -> BasePassRef { BasePassRef { commands: &self.commands, dynamic_offsets: &self.dynamic_offsets, string_data: &self.string_data, push_constant_data: &self.push_constant_data, } } } #[derive(Clone, Debug, Error)] pub enum CommandEncoderError { #[error("command encoder is invalid")] Invalid, #[error("command encoder must be active")] NotRecording, } impl Global { pub fn command_encoder_finish( &self, encoder_id: id::CommandEncoderId, _desc: &wgt::CommandBufferDescriptor