Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  pass.rs

  Sprache: Rust
 

//! Generic pass functions that both compute and render passes need.

use crate::binding_model::{BindError, BindGroup, ImmediateUploadError};
use crate::command::encoder::EncodingState;
use crate::command::{
    bind::Binder, memory_init::SurfacesInDiscardState, query::QueryResetMap, DebugGroupError,
    QueryUseError,
};
use crate::device::{Device, DeviceError, MissingFeatures};
use crate::pipeline::LateSizedBufferGroup;
use crate::resource::{DestroyedResourceError, Labeled, ParentDevice, QuerySet};
use crate::track::{ResourceUsageCompatibilityError, UsageScope};
use crate::{api_log, binding_model};
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::str;
use thiserror::Error;
use wgt::error::{ErrorType, WebGpuError};
use wgt::DynamicOffset;

#[derive(Clone, Debug, Error)]
#[error(
    "Bind group index {index} is greater than the device's configured `max_bind_groups` limit {max}"
)]
pub struct BindGroupIndexOutOfRange {
    pub index: u32,
    pub max: u32,
}

#[derive(Clone, Debug, Error)]
#[error("Pipeline must be set")]
pub struct MissingPipeline;

#[derive(Clone, Debug, Error)]
#[error("Setting `values_offset` to be `None` is only for internal use in render bundles")]
pub struct InvalidValuesOffset;

impl WebGpuError for InvalidValuesOffset {
    fn webgpu_error_type(&self) -> ErrorType {
        ErrorType::Validation
    }
}

pub(cratestruct PassState<'scope, 'snatch_guard, 'cmd_enc> {
    pub(crate) base: EncodingState<'snatch_guard, 'cmd_enc>,

    /// Immediate texture inits required because of prior discards. Need to
    /// be inserted before texture reads.
    pub(crate) pending_discard_init_fixups: SurfacesInDiscardState,

    pub(crate) scope: UsageScope<'scope>,

    pub(crate) binder: Binder,

    pub(crate) temp_offsets: Vec<u32>,

    pub(crate) dynamic_offset_count: usize,

    pub(crate) string_offset: usize,
}

pub(cratefn set_bind_group<E>(
    state: &mut PassState,
    device: &Arc<Device>,
    dynamic_offsets: &[DynamicOffset],
    index: u32,
    num_dynamic_offsets: usize,
    bind_group: Option<Arc<BindGroup>>,
    merge_bind_groups: bool,
) -> Result<(), E>
where
    E: From<DeviceError>
        + From<BindGroupIndexOutOfRange>
        + From<ResourceUsageCompatibilityError>
        + From<DestroyedResourceError>
        + From<BindError>,
{
    if let Some(ref bind_group) = bind_group {
        api_log!("Pass::set_bind_group {index} {}", bind_group.error_ident());
    } else {
        api_log!("Pass::set_bind_group {index} None");
    }

    let max_bind_groups = state.base.device.limits.max_bind_groups;
    if index >= max_bind_groups {
        return Err(BindGroupIndexOutOfRange {
            index,
            max: max_bind_groups,
        }
        .into());
    }

    state.temp_offsets.clear();
    state.temp_offsets.extend_from_slice(
        &dynamic_offsets
            [state.dynamic_offset_count..state.dynamic_offset_count + num_dynamic_offsets],
    );
    state.dynamic_offset_count += num_dynamic_offsets;

    if let Some(bind_group) = bind_group {
        // Add the bind group to the tracker. This is done for both compute and
        // render passes, and is used to fail submission of the command buffer if
        // any resource in any of the bind groups has been destroyed, whether or
        // not the bind group is actually used by the pipeline.
        let bind_group = state.base.tracker.bind_groups.insert_single(bind_group);

        bind_group.same_device(device)?;

        bind_group.validate_dynamic_bindings(index, &state.temp_offsets)?;

        if merge_bind_groups {
            // Merge the bind group's resources into the tracker. We only do this
            // for render passes. For compute passes it is done per dispatch in
            // [`flush_bindings`].
            unsafe {
                state.scope.merge_bind_group(&bind_group.used)?;
            }
        }
        //Note: stateless trackers are not merged: the lifetime reference
        // is held to the bind group itself.

        state
            .binder
            .assign_group(index as usize, bind_group, &state.temp_offsets);
    } else {
        if !state.temp_offsets.is_empty() {
            return Err(BindError::DynamicOffsetCountNotZero {
                group: index,
                actual: state.temp_offsets.len(),
            }
            .into());
        }

        state.binder.clear_group(index as usize);
    };

    Ok(())
}

/// Implementation of `flush_bindings` for both compute and render passes.
///
/// See the compute pass version of `State::flush_bindings` for an explanation
/// of some differences in handling the two types of passes.
pub(superfn flush_bindings_helper(state: &mut PassState) -> Result<(), DestroyedResourceError> {
    let start = state.binder.take_rebind_start_index();
    let entries = state.binder.list_valid_with_start(start);
    let pipeline_layout = state.binder.pipeline_layout.as_ref().unwrap();

    for (i, bind_group, dynamic_offsets) in entries {
        state.base.buffer_memory_init_actions.extend(
            bind_group.buffer_init_actions.iter().filter_map(|action| {
                action
                    .buffer
                    .initialization_status
                    .read()
                    .check_action(action)
            }),
        );
        for action in bind_group.texture_init_actions.iter() {
            state.pending_discard_init_fixups.extend(
                state
                    .base
                    .texture_memory_actions
                    .register_init_action(action),
            );
        }

        let used_resource = bind_group
            .used
            .acceleration_structures
            .into_iter()
            .map(|tlas| crate::ray_tracing::AsAction::UseTlas(tlas.clone()));

        state.base.as_actions.extend(used_resource);

        let raw_bg = bind_group.try_raw(state.base.snatch_guard)?;
        unsafe {
            state.base.raw_encoder.set_bind_group(
                pipeline_layout.raw(),
                i as u32,
                raw_bg,
                dynamic_offsets,
            );
        }
    }

    Ok(())
}

pub(superfn change_pipeline_layout<E, F: FnOnce()>(
    state: &mut PassState,
    pipeline_layout: &Arc<binding_model::PipelineLayout>,
    late_sized_buffer_groups: &[LateSizedBufferGroup],
    f: F,
) -> Result<(), E>
where
    E: From<DestroyedResourceError>,
{
    if state
        .binder
        .change_pipeline_layout(pipeline_layout, late_sized_buffer_groups)
    {
        f();

        super::immediates_clear(
            0,
            pipeline_layout.immediate_size,
            |clear_offset, clear_data| unsafe {
                state.base.raw_encoder.set_immediates(
                    pipeline_layout.raw(),
                    clear_offset,
                    clear_data,
                );
            },
        );
    }
    Ok(())
}

pub(cratefn set_immediates<E, F: FnOnce(&[u32])>(
    state: &mut PassState,
    immediates_data: &[u32],
    offset: u32,
    size_bytes: u32,
    values_offset: Option<u32>,
    f: F,
) -> Result<(), E>
where
    E: From<ImmediateUploadError> + From<InvalidValuesOffset> + From<MissingPipeline>,
{
    api_log!("Pass::set_immediates");

    let values_offset = values_offset.ok_or(InvalidValuesOffset)?;

    let pipeline_layout = state
        .binder
        .pipeline_layout
        .as_ref()
        .ok_or(MissingPipeline)?;

    pipeline_layout.validate_immediates_ranges(offset, size_bytes)?;

    let values_offset_usize = usize::try_from(values_offset)
        .expect("`values_offset` is outside the bounds of `usize` (!?)");
    if values_offset_usize > immediates_data.len() {
        return Err(ImmediateUploadError::ValueStartIndexOverrun {
            start_index: values_offset,
            data_size: immediates_data.len(),
        }
        .into());
    }

    // NOTE: The `validate_immediates_ranges` call above validates `size_bytes` is aligned.
    let size_immediate_elements = size_bytes / wgt::IMMEDIATE_DATA_ALIGNMENT;
    let size_immediate_elements_usize = usize::try_from(size_immediate_elements)
        .expect("`size_immediate_elements` is outside the bounds of `usize` (!?)");
    if size_immediate_elements_usize > immediates_data.len() - values_offset_usize {
        return Err(ImmediateUploadError::ValueEndIndexOverrun {
            start_index: values_offset,
            count: size_immediate_elements,
            data_size: immediates_data.len(),
        }
        .into());
    }

    // NOTE: These additions are will not overflow, because we've validated the range above.
    let values_end_offset = values_offset_usize + size_immediate_elements_usize;
    let data_slice = &immediates_data[(values_offset_usize)..values_end_offset];

    f(data_slice);

    unsafe {
        state
            .base
            .raw_encoder
            .set_immediates(pipeline_layout.raw(), offset, data_slice)
    }
    Ok(())
}

pub(cratefn write_timestamp<E>(
    state: &mut PassState,
    device: &Arc<Device>,
    pending_query_resets: Option<&mut QueryResetMap>,
    query_set: Arc<QuerySet>,
    query_index: u32,
) -> Result<(), E>
where
    E: From<MissingFeatures> + From<QueryUseError> + From<DeviceError>,
{
    api_log!(
        "Pass::write_timestamps {query_index} {}",
        query_set.error_ident()
    );

    query_set.same_device(device)?;

    state
        .base
        .device
        .require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES)?;

    let query_set = state.base.tracker.query_sets.insert_single(query_set);

    query_set.validate_and_write_timestamp(
        state.base.raw_encoder,
        query_index,
        pending_query_resets,
        state.base.query_set_writes,
    )?;
    Ok(())
}

pub(cratefn push_debug_group(state: &mut PassState, string_data: &[u8], len: usize) {
    *state.base.debug_scope_depth += 1;
    if !state
        .base
        .device
        .instance_flags
        .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
    {
        let label =
            str::from_utf8(&string_data[state.string_offset..state.string_offset + len]).unwrap();

        api_log!("Pass::push_debug_group {label:?}");
        unsafe {
            state.base.raw_encoder.begin_debug_marker(label);
        }
    }
    state.string_offset += len;
}

pub(cratefn pop_debug_group<E>(state: &mut PassState) -> Result<(), E>
where
    E: From<DebugGroupError>,
{
    api_log!("Pass::pop_debug_group");

    if *state.base.debug_scope_depth == 0 {
        return Err(DebugGroupError::InvalidPop.into());
    }
    *state.base.debug_scope_depth -= 1;
    if !state
        .base
        .device
        .instance_flags
        .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
    {
        unsafe {
            state.base.raw_encoder.end_debug_marker();
        }
    }
    Ok(())
}

pub(cratefn insert_debug_marker(state: &mut PassState, string_data: &[u8], len: usize) {
    if !state
        .base
        .device
        .instance_flags
        .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
    {
        let label =
            str::from_utf8(&string_data[state.string_offset..state.string_offset + len]).unwrap();
        api_log!("Pass::insert_debug_marker {label:?}");
        unsafe {
            state.base.raw_encoder.insert_debug_marker(label);
        }
    }
    state.string_offset += len;
}

Messung V0.5 in Prozent
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=434850
#Domains=661743