tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

command.rs (30330B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use crate::{id, server::Global, FfiSlice, RawString};
      6 use std::{borrow::Cow, ffi};
      7 use wgc::{
      8    command::{
      9        ComputePassDescriptor, PassTimestampWrites, RenderPassColorAttachment,
     10        RenderPassDepthStencilAttachment,
     11    },
     12    id::{CommandEncoderId, TextureViewId},
     13 };
     14 use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat};
     15 
     16 use serde::{Deserialize, Serialize};
     17 
     18 /// A stream of commands for a render pass or compute pass.
     19 ///
     20 /// This also contains side tables referred to by certain commands,
     21 /// like dynamic offsets for [`SetBindGroup`] or string data for
     22 /// [`InsertDebugMarker`].
     23 ///
     24 /// Render passes use `Pass<RenderCommand>`, whereas compute
     25 /// passes use `Pass<ComputeCommand>`.
     26 ///
     27 /// [`SetBindGroup`]: RenderCommand::SetBindGroup
     28 /// [`InsertDebugMarker`]: RenderCommand::InsertDebugMarker
     29 #[doc(hidden)]
     30 #[derive(Debug, serde::Serialize, serde::Deserialize)]
     31 pub struct Pass<C> {
     32    pub label: Option<String>,
     33 
     34    /// The stream of commands.
     35    pub commands: Vec<C>,
     36 
     37    /// Dynamic offsets consumed by [`SetBindGroup`] commands in `commands`.
     38    ///
     39    /// Each successive `SetBindGroup` consumes the next
     40    /// [`num_dynamic_offsets`] values from this list.
     41    pub dynamic_offsets: Vec<wgt::DynamicOffset>,
     42 
     43    /// Strings used by debug instructions.
     44    ///
     45    /// Each successive [`PushDebugGroup`] or [`InsertDebugMarker`]
     46    /// instruction consumes the next `len` bytes from this vector.
     47    pub string_data: Vec<u8>,
     48 }
     49 
     50 #[derive(Deserialize, Serialize)]
     51 pub struct RecordedRenderPass {
     52    base: Pass<RenderCommand>,
     53    color_attachments: Vec<Option<RenderPassColorAttachment>>,
     54    depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<TextureViewId>>,
     55    timestamp_writes: Option<PassTimestampWrites>,
     56    occlusion_query_set_id: Option<id::QuerySetId>,
     57 }
     58 
     59 impl RecordedRenderPass {
     60    pub fn new(
     61        label: Option<String>,
     62        color_attachments: Vec<Option<RenderPassColorAttachment>>,
     63        depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<TextureViewId>>,
     64        timestamp_writes: Option<PassTimestampWrites>,
     65        occlusion_query_set_id: Option<id::QuerySetId>,
     66    ) -> Self {
     67        Self {
     68            base: Pass {
     69                label,
     70                commands: Vec::new(),
     71                dynamic_offsets: Vec::new(),
     72                string_data: Vec::new(),
     73            },
     74            color_attachments,
     75            depth_stencil_attachment,
     76            timestamp_writes,
     77            occlusion_query_set_id,
     78        }
     79    }
     80 }
     81 
     82 #[derive(serde::Deserialize, serde::Serialize)]
     83 pub struct RecordedComputePass {
     84    base: Pass<ComputeCommand>,
     85    timestamp_writes: Option<PassTimestampWrites>,
     86 }
     87 
     88 impl RecordedComputePass {
     89    pub fn new(desc: &ComputePassDescriptor) -> Self {
     90        Self {
     91            base: Pass {
     92                label: desc.label.as_ref().map(|cow| cow.to_string()),
     93                commands: Vec::new(),
     94                dynamic_offsets: Vec::new(),
     95                string_data: Vec::new(),
     96            },
     97            timestamp_writes: desc.timestamp_writes.clone(),
     98        }
     99    }
    100 }
    101 
    102 #[doc(hidden)]
    103 #[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
    104 pub enum RenderCommand {
    105    SetBindGroup {
    106        index: u32,
    107        num_dynamic_offsets: usize,
    108        bind_group_id: Option<id::BindGroupId>,
    109    },
    110    SetPipeline(id::RenderPipelineId),
    111    SetIndexBuffer {
    112        buffer_id: id::BufferId,
    113        index_format: wgt::IndexFormat,
    114        offset: BufferAddress,
    115        size: Option<BufferSize>,
    116    },
    117    SetVertexBuffer {
    118        slot: u32,
    119        buffer_id: id::BufferId,
    120        offset: BufferAddress,
    121        size: Option<BufferSize>,
    122    },
    123    SetBlendConstant(Color),
    124    SetStencilReference(u32),
    125    SetViewport {
    126        x: f32,
    127        y: f32,
    128        w: f32,
    129        h: f32,
    130        depth_min: f32,
    131        depth_max: f32,
    132    },
    133    SetScissor {
    134        x: u32,
    135        y: u32,
    136        w: u32,
    137        h: u32,
    138    },
    139    Draw {
    140        vertex_count: u32,
    141        instance_count: u32,
    142        first_vertex: u32,
    143        first_instance: u32,
    144    },
    145    DrawIndexed {
    146        index_count: u32,
    147        instance_count: u32,
    148        first_index: u32,
    149        base_vertex: i32,
    150        first_instance: u32,
    151    },
    152    MultiDrawIndirect {
    153        buffer_id: id::BufferId,
    154        offset: BufferAddress,
    155        /// Count of `None` represents a non-multi call.
    156        count: Option<u32>,
    157        indexed: bool,
    158    },
    159    MultiDrawIndirectCount {
    160        buffer_id: id::BufferId,
    161        offset: BufferAddress,
    162        count_buffer_id: id::BufferId,
    163        count_buffer_offset: BufferAddress,
    164        max_count: u32,
    165        indexed: bool,
    166    },
    167    PushDebugGroup {
    168        color: u32,
    169        len: usize,
    170    },
    171    PopDebugGroup,
    172    InsertDebugMarker {
    173        color: u32,
    174        len: usize,
    175    },
    176    WriteTimestamp {
    177        query_set_id: id::QuerySetId,
    178        query_index: u32,
    179    },
    180    BeginOcclusionQuery {
    181        query_index: u32,
    182    },
    183    EndOcclusionQuery,
    184    BeginPipelineStatisticsQuery {
    185        query_set_id: id::QuerySetId,
    186        query_index: u32,
    187    },
    188    EndPipelineStatisticsQuery,
    189    ExecuteBundle(id::RenderBundleId),
    190 }
    191 
    192 #[doc(hidden)]
    193 #[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
    194 pub enum ComputeCommand {
    195    SetBindGroup {
    196        index: u32,
    197        num_dynamic_offsets: usize,
    198        bind_group_id: Option<id::BindGroupId>,
    199    },
    200    SetPipeline(id::ComputePipelineId),
    201    Dispatch([u32; 3]),
    202    DispatchIndirect {
    203        buffer_id: id::BufferId,
    204        offset: wgt::BufferAddress,
    205    },
    206    PushDebugGroup {
    207        color: u32,
    208        len: usize,
    209    },
    210    PopDebugGroup,
    211    InsertDebugMarker {
    212        color: u32,
    213        len: usize,
    214    },
    215    WriteTimestamp {
    216        query_set_id: id::QuerySetId,
    217        query_index: u32,
    218    },
    219    BeginPipelineStatisticsQuery {
    220        query_set_id: id::QuerySetId,
    221        query_index: u32,
    222    },
    223    EndPipelineStatisticsQuery,
    224 }
    225 
    226 #[no_mangle]
    227 pub unsafe extern "C" fn wgpu_recorded_render_pass_set_bind_group(
    228    pass: &mut RecordedRenderPass,
    229    index: u32,
    230    bind_group_id: Option<id::BindGroupId>,
    231    offsets: FfiSlice<'_, DynamicOffset>,
    232 ) {
    233    let offsets = offsets.as_slice();
    234    pass.base.dynamic_offsets.extend_from_slice(offsets);
    235 
    236    pass.base.commands.push(RenderCommand::SetBindGroup {
    237        index,
    238        num_dynamic_offsets: offsets.len(),
    239        bind_group_id,
    240    });
    241 }
    242 
    243 #[no_mangle]
    244 pub extern "C" fn wgpu_recorded_render_pass_set_pipeline(
    245    pass: &mut RecordedRenderPass,
    246    pipeline_id: id::RenderPipelineId,
    247 ) {
    248    pass.base
    249        .commands
    250        .push(RenderCommand::SetPipeline(pipeline_id));
    251 }
    252 
    253 #[no_mangle]
    254 pub extern "C" fn wgpu_recorded_render_pass_set_vertex_buffer(
    255    pass: &mut RecordedRenderPass,
    256    slot: u32,
    257    buffer_id: id::BufferId,
    258    offset: BufferAddress,
    259    size: Option<&BufferSize>,
    260 ) {
    261    pass.base.commands.push(RenderCommand::SetVertexBuffer {
    262        slot,
    263        buffer_id,
    264        offset,
    265        size: size.copied(),
    266    });
    267 }
    268 
    269 #[no_mangle]
    270 pub extern "C" fn wgpu_recorded_render_pass_set_index_buffer(
    271    pass: &mut RecordedRenderPass,
    272    buffer_id: id::BufferId,
    273    index_format: IndexFormat,
    274    offset: BufferAddress,
    275    size: Option<&BufferSize>,
    276 ) {
    277    pass.base.commands.push(RenderCommand::SetIndexBuffer {
    278        buffer_id,
    279        index_format,
    280        offset,
    281        size: size.copied(),
    282    });
    283 }
    284 
    285 #[no_mangle]
    286 pub extern "C" fn wgpu_recorded_render_pass_set_blend_constant(
    287    pass: &mut RecordedRenderPass,
    288    color: &Color,
    289 ) {
    290    pass.base
    291        .commands
    292        .push(RenderCommand::SetBlendConstant(*color));
    293 }
    294 
    295 #[no_mangle]
    296 pub extern "C" fn wgpu_recorded_render_pass_set_stencil_reference(
    297    pass: &mut RecordedRenderPass,
    298    value: u32,
    299 ) {
    300    pass.base
    301        .commands
    302        .push(RenderCommand::SetStencilReference(value));
    303 }
    304 
    305 #[no_mangle]
    306 pub extern "C" fn wgpu_recorded_render_pass_set_viewport(
    307    pass: &mut RecordedRenderPass,
    308    x: f32,
    309    y: f32,
    310    w: f32,
    311    h: f32,
    312    depth_min: f32,
    313    depth_max: f32,
    314 ) {
    315    pass.base.commands.push(RenderCommand::SetViewport {
    316        x,
    317        y,
    318        w,
    319        h,
    320        depth_min,
    321        depth_max,
    322    });
    323 }
    324 
    325 #[no_mangle]
    326 pub extern "C" fn wgpu_recorded_render_pass_set_scissor_rect(
    327    pass: &mut RecordedRenderPass,
    328    x: u32,
    329    y: u32,
    330    w: u32,
    331    h: u32,
    332 ) {
    333    pass.base
    334        .commands
    335        .push(RenderCommand::SetScissor { x, y, w, h });
    336 }
    337 
    338 #[no_mangle]
    339 pub extern "C" fn wgpu_recorded_render_pass_draw(
    340    pass: &mut RecordedRenderPass,
    341    vertex_count: u32,
    342    instance_count: u32,
    343    first_vertex: u32,
    344    first_instance: u32,
    345 ) {
    346    pass.base.commands.push(RenderCommand::Draw {
    347        vertex_count,
    348        instance_count,
    349        first_vertex,
    350        first_instance,
    351    });
    352 }
    353 
    354 #[no_mangle]
    355 pub extern "C" fn wgpu_recorded_render_pass_draw_indexed(
    356    pass: &mut RecordedRenderPass,
    357    index_count: u32,
    358    instance_count: u32,
    359    first_index: u32,
    360    base_vertex: i32,
    361    first_instance: u32,
    362 ) {
    363    pass.base.commands.push(RenderCommand::DrawIndexed {
    364        index_count,
    365        instance_count,
    366        first_index,
    367        base_vertex,
    368        first_instance,
    369    });
    370 }
    371 
    372 #[no_mangle]
    373 pub extern "C" fn wgpu_recorded_render_pass_draw_indirect(
    374    pass: &mut RecordedRenderPass,
    375    buffer_id: id::BufferId,
    376    offset: BufferAddress,
    377 ) {
    378    pass.base.commands.push(RenderCommand::MultiDrawIndirect {
    379        buffer_id,
    380        offset,
    381        count: None,
    382        indexed: false,
    383    });
    384 }
    385 
    386 #[no_mangle]
    387 pub extern "C" fn wgpu_recorded_render_pass_draw_indexed_indirect(
    388    pass: &mut RecordedRenderPass,
    389    buffer_id: id::BufferId,
    390    offset: BufferAddress,
    391 ) {
    392    pass.base.commands.push(RenderCommand::MultiDrawIndirect {
    393        buffer_id,
    394        offset,
    395        count: None,
    396        indexed: true,
    397    });
    398 }
    399 
    400 #[no_mangle]
    401 pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indirect(
    402    pass: &mut RecordedRenderPass,
    403    buffer_id: id::BufferId,
    404    offset: BufferAddress,
    405    count: u32,
    406 ) {
    407    pass.base.commands.push(RenderCommand::MultiDrawIndirect {
    408        buffer_id,
    409        offset,
    410        count: Some(count),
    411        indexed: false,
    412    });
    413 }
    414 
    415 #[no_mangle]
    416 pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indexed_indirect(
    417    pass: &mut RecordedRenderPass,
    418    buffer_id: id::BufferId,
    419    offset: BufferAddress,
    420    count: u32,
    421 ) {
    422    pass.base.commands.push(RenderCommand::MultiDrawIndirect {
    423        buffer_id,
    424        offset,
    425        count: Some(count),
    426        indexed: true,
    427    });
    428 }
    429 
    430 #[no_mangle]
    431 pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indirect_count(
    432    pass: &mut RecordedRenderPass,
    433    buffer_id: id::BufferId,
    434    offset: BufferAddress,
    435    count_buffer_id: id::BufferId,
    436    count_buffer_offset: BufferAddress,
    437    max_count: u32,
    438 ) {
    439    pass.base
    440        .commands
    441        .push(RenderCommand::MultiDrawIndirectCount {
    442            buffer_id,
    443            offset,
    444            count_buffer_id,
    445            count_buffer_offset,
    446            max_count,
    447            indexed: false,
    448        });
    449 }
    450 
    451 #[no_mangle]
    452 pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indexed_indirect_count(
    453    pass: &mut RecordedRenderPass,
    454    buffer_id: id::BufferId,
    455    offset: BufferAddress,
    456    count_buffer_id: id::BufferId,
    457    count_buffer_offset: BufferAddress,
    458    max_count: u32,
    459 ) {
    460    pass.base
    461        .commands
    462        .push(RenderCommand::MultiDrawIndirectCount {
    463            buffer_id,
    464            offset,
    465            count_buffer_id,
    466            count_buffer_offset,
    467            max_count,
    468            indexed: true,
    469        });
    470 }
    471 
    472 /// # Safety
    473 ///
    474 /// This function is unsafe as there is no guarantee that the given `label`
    475 /// is a valid null-terminated string.
    476 #[no_mangle]
    477 pub unsafe extern "C" fn wgpu_recorded_render_pass_push_debug_group(
    478    pass: &mut RecordedRenderPass,
    479    label: RawString,
    480    color: u32,
    481 ) {
    482    let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes();
    483    pass.base.string_data.extend_from_slice(bytes);
    484 
    485    pass.base.commands.push(RenderCommand::PushDebugGroup {
    486        color,
    487        len: bytes.len(),
    488    });
    489 }
    490 
    491 #[no_mangle]
    492 pub extern "C" fn wgpu_recorded_render_pass_pop_debug_group(pass: &mut RecordedRenderPass) {
    493    pass.base.commands.push(RenderCommand::PopDebugGroup);
    494 }
    495 
    496 /// # Safety
    497 ///
    498 /// This function is unsafe as there is no guarantee that the given `label`
    499 /// is a valid null-terminated string.
    500 #[no_mangle]
    501 pub unsafe extern "C" fn wgpu_recorded_render_pass_insert_debug_marker(
    502    pass: &mut RecordedRenderPass,
    503    label: RawString,
    504    color: u32,
    505 ) {
    506    let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes();
    507    pass.base.string_data.extend_from_slice(bytes);
    508 
    509    pass.base.commands.push(RenderCommand::InsertDebugMarker {
    510        color,
    511        len: bytes.len(),
    512    });
    513 }
    514 
    515 #[no_mangle]
    516 pub extern "C" fn wgpu_recorded_render_pass_write_timestamp(
    517    pass: &mut RecordedRenderPass,
    518    query_set_id: id::QuerySetId,
    519    query_index: u32,
    520 ) {
    521    pass.base.commands.push(RenderCommand::WriteTimestamp {
    522        query_set_id,
    523        query_index,
    524    });
    525 }
    526 
    527 #[no_mangle]
    528 pub extern "C" fn wgpu_recorded_render_pass_begin_occlusion_query(
    529    pass: &mut RecordedRenderPass,
    530    query_index: u32,
    531 ) {
    532    pass.base
    533        .commands
    534        .push(RenderCommand::BeginOcclusionQuery { query_index });
    535 }
    536 
    537 #[no_mangle]
    538 pub extern "C" fn wgpu_recorded_render_pass_end_occlusion_query(pass: &mut RecordedRenderPass) {
    539    pass.base.commands.push(RenderCommand::EndOcclusionQuery);
    540 }
    541 
    542 #[no_mangle]
    543 pub extern "C" fn wgpu_recorded_render_pass_begin_pipeline_statistics_query(
    544    pass: &mut RecordedRenderPass,
    545    query_set_id: id::QuerySetId,
    546    query_index: u32,
    547 ) {
    548    pass.base
    549        .commands
    550        .push(RenderCommand::BeginPipelineStatisticsQuery {
    551            query_set_id,
    552            query_index,
    553        });
    554 }
    555 
    556 #[no_mangle]
    557 pub extern "C" fn wgpu_recorded_render_pass_end_pipeline_statistics_query(
    558    pass: &mut RecordedRenderPass,
    559 ) {
    560    pass.base
    561        .commands
    562        .push(RenderCommand::EndPipelineStatisticsQuery);
    563 }
    564 
    565 #[no_mangle]
    566 pub unsafe extern "C" fn wgpu_recorded_render_pass_execute_bundles(
    567    pass: &mut RecordedRenderPass,
    568    render_bundles: FfiSlice<'_, id::RenderBundleId>,
    569 ) {
    570    for &bundle_id in render_bundles.as_slice() {
    571        pass.base
    572            .commands
    573            .push(RenderCommand::ExecuteBundle(bundle_id));
    574    }
    575 }
    576 
    577 #[no_mangle]
    578 pub unsafe extern "C" fn wgpu_recorded_compute_pass_set_bind_group(
    579    pass: &mut RecordedComputePass,
    580    index: u32,
    581    bind_group_id: Option<id::BindGroupId>,
    582    offsets: FfiSlice<'_, DynamicOffset>,
    583 ) {
    584    let offsets = offsets.as_slice();
    585    pass.base.dynamic_offsets.extend_from_slice(offsets);
    586 
    587    pass.base.commands.push(ComputeCommand::SetBindGroup {
    588        index,
    589        num_dynamic_offsets: offsets.len(),
    590        bind_group_id,
    591    });
    592 }
    593 
    594 #[no_mangle]
    595 pub extern "C" fn wgpu_recorded_compute_pass_set_pipeline(
    596    pass: &mut RecordedComputePass,
    597    pipeline_id: id::ComputePipelineId,
    598 ) {
    599    pass.base
    600        .commands
    601        .push(ComputeCommand::SetPipeline(pipeline_id));
    602 }
    603 
    604 #[no_mangle]
    605 pub extern "C" fn wgpu_recorded_compute_pass_dispatch_workgroups(
    606    pass: &mut RecordedComputePass,
    607    groups_x: u32,
    608    groups_y: u32,
    609    groups_z: u32,
    610 ) {
    611    pass.base
    612        .commands
    613        .push(ComputeCommand::Dispatch([groups_x, groups_y, groups_z]));
    614 }
    615 
    616 #[no_mangle]
    617 pub extern "C" fn wgpu_recorded_compute_pass_dispatch_workgroups_indirect(
    618    pass: &mut RecordedComputePass,
    619    buffer_id: id::BufferId,
    620    offset: BufferAddress,
    621 ) {
    622    pass.base
    623        .commands
    624        .push(ComputeCommand::DispatchIndirect { buffer_id, offset });
    625 }
    626 
    627 /// # Safety
    628 ///
    629 /// This function is unsafe as there is no guarantee that the given `label`
    630 /// is a valid null-terminated string.
    631 #[no_mangle]
    632 pub unsafe extern "C" fn wgpu_recorded_compute_pass_push_debug_group(
    633    pass: &mut RecordedComputePass,
    634    label: RawString,
    635    color: u32,
    636 ) {
    637    let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes();
    638    pass.base.string_data.extend_from_slice(bytes);
    639 
    640    pass.base.commands.push(ComputeCommand::PushDebugGroup {
    641        color,
    642        len: bytes.len(),
    643    });
    644 }
    645 
    646 #[no_mangle]
    647 pub extern "C" fn wgpu_recorded_compute_pass_pop_debug_group(pass: &mut RecordedComputePass) {
    648    pass.base.commands.push(ComputeCommand::PopDebugGroup);
    649 }
    650 
    651 /// # Safety
    652 ///
    653 /// This function is unsafe as there is no guarantee that the given `label`
    654 /// is a valid null-terminated string.
    655 #[no_mangle]
    656 pub unsafe extern "C" fn wgpu_recorded_compute_pass_insert_debug_marker(
    657    pass: &mut RecordedComputePass,
    658    label: RawString,
    659    color: u32,
    660 ) {
    661    let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes();
    662    pass.base.string_data.extend_from_slice(bytes);
    663 
    664    pass.base.commands.push(ComputeCommand::InsertDebugMarker {
    665        color,
    666        len: bytes.len(),
    667    });
    668 }
    669 
    670 #[no_mangle]
    671 pub extern "C" fn wgpu_recorded_compute_pass_write_timestamp(
    672    pass: &mut RecordedComputePass,
    673    query_set_id: id::QuerySetId,
    674    query_index: u32,
    675 ) {
    676    pass.base.commands.push(ComputeCommand::WriteTimestamp {
    677        query_set_id,
    678        query_index,
    679    });
    680 }
    681 
    682 #[no_mangle]
    683 pub extern "C" fn wgpu_recorded_compute_pass_begin_pipeline_statistics_query(
    684    pass: &mut RecordedComputePass,
    685    query_set_id: id::QuerySetId,
    686    query_index: u32,
    687 ) {
    688    pass.base
    689        .commands
    690        .push(ComputeCommand::BeginPipelineStatisticsQuery {
    691            query_set_id,
    692            query_index,
    693        });
    694 }
    695 
    696 #[no_mangle]
    697 pub extern "C" fn wgpu_recorded_compute_pass_end_pipeline_statistics_query(
    698    pass: &mut RecordedComputePass,
    699 ) {
    700    pass.base
    701        .commands
    702        .push(ComputeCommand::EndPipelineStatisticsQuery);
    703 }
    704 
    705 pub fn replay_render_pass(
    706    global: &Global,
    707    device_id: id::DeviceId,
    708    id: CommandEncoderId,
    709    src_pass: &RecordedRenderPass,
    710    error_buf: &mut crate::error::OwnedErrorBuffer,
    711 ) {
    712    // Explicitly forbid `LoadOp::DontCare`, until wgpu#8780 is resolved.
    713    //
    714    // Since `DontCare` is not part of WebGPU (and is unlikely to become so),
    715    // only a corrupted content process could ever produce such a render pass,
    716    // so it suffices for us to just crash here if we see it.
    717    for attachment in &src_pass.color_attachments {
    718        if let Some(attachment) = attachment {
    719            assert!(!matches!(attachment.load_op, wgt::LoadOp::DontCare(_)));
    720        }
    721    }
    722    if let Some(ref attachment) = src_pass.depth_stencil_attachment {
    723        assert!(!matches!(
    724            attachment.depth.load_op,
    725            Some(wgt::LoadOp::DontCare(_))
    726        ));
    727        assert!(!matches!(
    728            attachment.stencil.load_op,
    729            Some(wgt::LoadOp::DontCare(_))
    730        ));
    731    }
    732 
    733    let (mut dst_pass, err) = global.command_encoder_begin_render_pass(
    734        id,
    735        &wgc::command::RenderPassDescriptor {
    736            label: src_pass.base.label.as_ref().map(|s| s.as_str().into()),
    737            color_attachments: Cow::Borrowed(&src_pass.color_attachments),
    738            depth_stencil_attachment: src_pass.depth_stencil_attachment.as_ref(),
    739            timestamp_writes: src_pass.timestamp_writes.as_ref(),
    740            occlusion_query_set: src_pass.occlusion_query_set_id,
    741            multiview_mask: None,
    742        },
    743    );
    744    if let Some(err) = err {
    745        error_buf.init(err, device_id);
    746        return;
    747    }
    748    match replay_render_pass_impl(global, src_pass, &mut dst_pass) {
    749        Ok(()) => (),
    750        Err(err) => {
    751            error_buf.init(err, device_id);
    752            return;
    753        }
    754    };
    755 
    756    match global.render_pass_end(&mut dst_pass) {
    757        Ok(()) => (),
    758        Err(err) => error_buf.init(err, device_id),
    759    }
    760 }
    761 
    762 pub fn replay_render_pass_impl(
    763    global: &Global,
    764    src_pass: &RecordedRenderPass,
    765    dst_pass: &mut wgc::command::RenderPass,
    766 ) -> Result<(), wgc::command::PassStateError> {
    767    let mut dynamic_offsets = src_pass.base.dynamic_offsets.as_slice();
    768    let mut dynamic_offsets = |len| {
    769        let offsets;
    770        (offsets, dynamic_offsets) = dynamic_offsets.split_at(len);
    771        offsets
    772    };
    773    let mut strings = src_pass.base.string_data.as_slice();
    774    let mut strings = |len| {
    775        let label;
    776        (label, strings) = strings.split_at(len);
    777        label
    778    };
    779    for command in &src_pass.base.commands {
    780        match *command {
    781            RenderCommand::SetBindGroup {
    782                index,
    783                num_dynamic_offsets,
    784                bind_group_id,
    785            } => {
    786                let offsets = dynamic_offsets(num_dynamic_offsets);
    787                global.render_pass_set_bind_group(dst_pass, index, bind_group_id, offsets)
    788            }
    789            RenderCommand::SetPipeline(pipeline_id) => {
    790                global.render_pass_set_pipeline(dst_pass, pipeline_id)
    791            }
    792            RenderCommand::SetIndexBuffer {
    793                buffer_id,
    794                index_format,
    795                offset,
    796                size,
    797            } => {
    798                global.render_pass_set_index_buffer(dst_pass, buffer_id, index_format, offset, size)
    799            }
    800            RenderCommand::SetVertexBuffer {
    801                slot,
    802                buffer_id,
    803                offset,
    804                size,
    805            } => global.render_pass_set_vertex_buffer(dst_pass, slot, buffer_id, offset, size),
    806            RenderCommand::SetBlendConstant(color) => {
    807                global.render_pass_set_blend_constant(dst_pass, color)
    808            }
    809            RenderCommand::SetStencilReference(value) => {
    810                global.render_pass_set_stencil_reference(dst_pass, value)
    811            }
    812            RenderCommand::SetViewport {
    813                x,
    814                y,
    815                w,
    816                h,
    817                depth_min,
    818                depth_max,
    819            } => global.render_pass_set_viewport(dst_pass, x, y, w, h, depth_min, depth_max),
    820            RenderCommand::SetScissor { x, y, w, h } => {
    821                global.render_pass_set_scissor_rect(dst_pass, x, y, w, h)
    822            }
    823            RenderCommand::Draw {
    824                vertex_count,
    825                instance_count,
    826                first_vertex,
    827                first_instance,
    828            } => global.render_pass_draw(
    829                dst_pass,
    830                vertex_count,
    831                instance_count,
    832                first_vertex,
    833                first_instance,
    834            ),
    835            RenderCommand::DrawIndexed {
    836                index_count,
    837                instance_count,
    838                first_index,
    839                base_vertex,
    840                first_instance,
    841            } => global.render_pass_draw_indexed(
    842                dst_pass,
    843                index_count,
    844                instance_count,
    845                first_index,
    846                base_vertex,
    847                first_instance,
    848            ),
    849            RenderCommand::MultiDrawIndirect {
    850                buffer_id,
    851                offset,
    852                count,
    853                indexed,
    854            } => match (indexed, count) {
    855                (false, Some(count)) => {
    856                    global.render_pass_multi_draw_indirect(dst_pass, buffer_id, offset, count)
    857                }
    858                (false, None) => global.render_pass_draw_indirect(dst_pass, buffer_id, offset),
    859                (true, Some(count)) => global
    860                    .render_pass_multi_draw_indexed_indirect(dst_pass, buffer_id, offset, count),
    861                (true, None) => {
    862                    global.render_pass_draw_indexed_indirect(dst_pass, buffer_id, offset)
    863                }
    864            },
    865            RenderCommand::MultiDrawIndirectCount {
    866                buffer_id,
    867                offset,
    868                count_buffer_id,
    869                count_buffer_offset,
    870                max_count,
    871                indexed,
    872            } => {
    873                if indexed {
    874                    global.render_pass_multi_draw_indexed_indirect_count(
    875                        dst_pass,
    876                        buffer_id,
    877                        offset,
    878                        count_buffer_id,
    879                        count_buffer_offset,
    880                        max_count,
    881                    )
    882                } else {
    883                    global.render_pass_multi_draw_indirect_count(
    884                        dst_pass,
    885                        buffer_id,
    886                        offset,
    887                        count_buffer_id,
    888                        count_buffer_offset,
    889                        max_count,
    890                    )
    891                }
    892            }
    893            RenderCommand::PushDebugGroup { color, len } => {
    894                let label = strings(len);
    895                let label = std::str::from_utf8(label).unwrap();
    896                global.render_pass_push_debug_group(dst_pass, label, color)
    897            }
    898            RenderCommand::PopDebugGroup => global.render_pass_pop_debug_group(dst_pass),
    899            RenderCommand::InsertDebugMarker { color, len } => {
    900                let label = strings(len);
    901                let label = std::str::from_utf8(label).unwrap();
    902                global.render_pass_insert_debug_marker(dst_pass, label, color)
    903            }
    904            RenderCommand::WriteTimestamp {
    905                query_set_id,
    906                query_index,
    907            } => global.render_pass_write_timestamp(dst_pass, query_set_id, query_index),
    908            RenderCommand::BeginOcclusionQuery { query_index } => {
    909                global.render_pass_begin_occlusion_query(dst_pass, query_index)
    910            }
    911            RenderCommand::EndOcclusionQuery => global.render_pass_end_occlusion_query(dst_pass),
    912            RenderCommand::BeginPipelineStatisticsQuery {
    913                query_set_id,
    914                query_index,
    915            } => global.render_pass_begin_pipeline_statistics_query(
    916                dst_pass,
    917                query_set_id,
    918                query_index,
    919            ),
    920            RenderCommand::EndPipelineStatisticsQuery => {
    921                global.render_pass_end_pipeline_statistics_query(dst_pass)
    922            }
    923            RenderCommand::ExecuteBundle(bundle_id) => {
    924                global.render_pass_execute_bundles(dst_pass, &[bundle_id])
    925            }
    926        }?
    927    }
    928 
    929    Ok(())
    930 }
    931 
    932 pub fn replay_compute_pass(
    933    global: &Global,
    934    device_id: id::DeviceId,
    935    id: CommandEncoderId,
    936    src_pass: &RecordedComputePass,
    937    error_buf: &mut crate::error::OwnedErrorBuffer,
    938 ) {
    939    let (mut dst_pass, err) = global.command_encoder_begin_compute_pass(
    940        id,
    941        &wgc::command::ComputePassDescriptor {
    942            label: src_pass.base.label.as_ref().map(|s| s.as_str().into()),
    943            timestamp_writes: src_pass.timestamp_writes.clone(),
    944        },
    945    );
    946    if let Some(err) = err {
    947        error_buf.init(err, device_id);
    948        return;
    949    }
    950    if let Err(err) = replay_compute_pass_impl(global, src_pass, &mut dst_pass) {
    951        error_buf.init(err, device_id);
    952        return;
    953    }
    954 
    955    match global.compute_pass_end(&mut dst_pass) {
    956        Ok(()) => (),
    957        Err(err) => error_buf.init(err, device_id),
    958    }
    959 }
    960 
    961 fn replay_compute_pass_impl(
    962    global: &Global,
    963    src_pass: &RecordedComputePass,
    964    dst_pass: &mut wgc::command::ComputePass,
    965 ) -> Result<(), wgc::command::PassStateError> {
    966    let mut dynamic_offsets = src_pass.base.dynamic_offsets.as_slice();
    967    let mut dynamic_offsets = |len| {
    968        let offsets;
    969        (offsets, dynamic_offsets) = dynamic_offsets.split_at(len);
    970        offsets
    971    };
    972    let mut strings = src_pass.base.string_data.as_slice();
    973    let mut strings = |len| {
    974        let label;
    975        (label, strings) = strings.split_at(len);
    976        label
    977    };
    978    for command in &src_pass.base.commands {
    979        match *command {
    980            ComputeCommand::SetBindGroup {
    981                index,
    982                num_dynamic_offsets,
    983                bind_group_id,
    984            } => {
    985                let offsets = dynamic_offsets(num_dynamic_offsets);
    986                global.compute_pass_set_bind_group(dst_pass, index, bind_group_id, offsets)?;
    987            }
    988            ComputeCommand::SetPipeline(pipeline_id) => {
    989                global.compute_pass_set_pipeline(dst_pass, pipeline_id)?;
    990            }
    991            ComputeCommand::Dispatch([x, y, z]) => {
    992                global.compute_pass_dispatch_workgroups(dst_pass, x, y, z)?;
    993            }
    994            ComputeCommand::DispatchIndirect { buffer_id, offset } => {
    995                global.compute_pass_dispatch_workgroups_indirect(dst_pass, buffer_id, offset)?;
    996            }
    997            ComputeCommand::PushDebugGroup { color, len } => {
    998                let label = strings(len);
    999                let label = std::str::from_utf8(label).unwrap();
   1000                global.compute_pass_push_debug_group(dst_pass, label, color)?;
   1001            }
   1002            ComputeCommand::PopDebugGroup => {
   1003                global.compute_pass_pop_debug_group(dst_pass)?;
   1004            }
   1005            ComputeCommand::InsertDebugMarker { color, len } => {
   1006                let label = strings(len);
   1007                let label = std::str::from_utf8(label).unwrap();
   1008                global.compute_pass_insert_debug_marker(dst_pass, label, color)?;
   1009            }
   1010            ComputeCommand::WriteTimestamp {
   1011                query_set_id,
   1012                query_index,
   1013            } => {
   1014                global.compute_pass_write_timestamp(dst_pass, query_set_id, query_index)?;
   1015            }
   1016            ComputeCommand::BeginPipelineStatisticsQuery {
   1017                query_set_id,
   1018                query_index,
   1019            } => {
   1020                global.compute_pass_begin_pipeline_statistics_query(
   1021                    dst_pass,
   1022                    query_set_id,
   1023                    query_index,
   1024                )?;
   1025            }
   1026            ComputeCommand::EndPipelineStatisticsQuery => {
   1027                global.compute_pass_end_pipeline_statistics_query(dst_pass)?;
   1028            }
   1029        }
   1030    }
   1031 
   1032    Ok(())
   1033 }