molgfx-render 0.3.3

The render graph, passes and the engine that drives a frame.
Documentation
//! Persistent scalar-volume resources and representation slots.

use super::super::volume_slot::{GpuVolumeResource, OccupancySync, VolumeSync};
use super::super::volume_uniforms::VolumeUniforms;
use super::GpuScene;
use crate::error::RenderError;
use crate::passes::OccupancyPass;
use molgfx_core::Scene;
use molgfx_gpu::{CommandEncoder, ComputePassDesc, Device};

impl<D: Device> GpuScene<D> {
    pub(super) fn sync_volume_resources(
        &mut self,
        device: &D,
        queue: &D::Queue,
        scene: &Scene,
    ) -> Result<bool, RenderError> {
        let occupancy_bounds_format = self.occupancy.as_ref().map(|(_, format)| *format);
        let mut changed = false;
        let structures = &self.structures;
        for resource in &mut self.volume_resources {
            if let Some((stream, structure_handle, selected_rows)) =
                scene.occupancy_stream(resource.handle)
            {
                let Some(placed) = scene.structure(structure_handle) else {
                    continue;
                };
                let Some(structure) = structures
                    .iter()
                    .find(|structure| structure.handle == structure_handle)
                else {
                    continue;
                };
                let Some(revision) = scene.volume_content_revision(resource.handle) else {
                    continue;
                };
                let Some((layout, _)) = self.occupancy.as_ref() else {
                    return Err(molgfx_gpu::GpuError::Capability {
                        name: "temporal occupancy runtime",
                    }
                    .into());
                };
                changed |= resource.sync_occupancy(&OccupancySync {
                    device,
                    queue,
                    layout,
                    bounds_format: occupancy_bounds_format.ok_or(
                        molgfx_gpu::GpuError::Capability {
                            name: "temporal occupancy bounds format",
                        },
                    )?,
                    stream,
                    selected_rows,
                    placed,
                    structure,
                    asset_arena: &self.asset_arena,
                    revision,
                })?;
            } else if let (Some(volume), Some(revision)) = (
                scene.volume(resource.handle),
                scene.volume_content_revision(resource.handle),
            ) {
                changed |= resource.sync_static(device, queue, volume, revision)?;
            }
        }
        Ok(changed)
    }

    pub(super) fn sync_volume_slots(
        &mut self,
        device: &D,
        queue: &D::Queue,
        scene: &Scene,
    ) -> Result<bool, RenderError> {
        let mut changed = false;
        for slot in &mut self.volume_slots {
            let Some(representation) = scene.representation(slot.representation) else {
                continue;
            };
            let Some(volume_handle) = representation.volume_handle() else {
                continue;
            };
            let Some((volume_view, volume_binding_revision)) = self
                .volume_resources
                .iter()
                .find(|resource| resource.handle == volume_handle)
                .and_then(GpuVolumeResource::binding)
            else {
                continue;
            };
            let Some(empty_space_bounds_view) = self
                .volume_resources
                .iter()
                .find(|resource| resource.handle == volume_handle)
                .and_then(GpuVolumeResource::empty_space_binding)
            else {
                continue;
            };
            let Some(representation_revision) =
                scene.representation_content_revision(slot.representation)
            else {
                continue;
            };
            let uniforms = if let Some(volume) = scene.volume(volume_handle) {
                VolumeUniforms::new(volume, representation)
            } else if let Some((stream, structure_handle, _)) =
                scene.occupancy_stream(volume_handle)
            {
                let Some(placed) = scene.structure(structure_handle) else {
                    continue;
                };
                VolumeUniforms::new_occupancy(stream, placed, representation)
            } else {
                continue;
            };
            changed |= slot.sync(&VolumeSync {
                device,
                queue,
                layout: &self.volume_layout,
                uniforms,
                representation,
                representation_revision,
                volume_handle,
                volume_view,
                empty_space_bounds_view,
                volume_binding_revision,
            })?;
        }
        Ok(changed)
    }

    pub(crate) fn record_occupancies(
        &mut self,
        encoder: &mut D::CommandEncoder,
        pipelines: Option<&OccupancyPass<D>>,
    ) {
        let Some(pipelines) = pipelines else {
            return;
        };
        if !self
            .volume_resources
            .iter()
            .any(GpuVolumeResource::occupancy_dirty)
        {
            return;
        }
        let mut pass = encoder.begin_compute_pass(&ComputePassDesc {
            label: "temporal occupancy accumulation",
            timestamps: None,
        });
        for resource in &mut self.volume_resources {
            resource.record_occupancy(&mut pass, pipelines);
        }
    }
}