molgfx-render 0.2.1

The render graph, passes and the engine that drives a frame.
Documentation
impl<D: Device> GpuInteractions<D> {
    fn sync_visuals(
        &mut self,
        device: &D,
        queue: &D::Queue,
        layout: &D::BindGroupLayout,
        scene: &Scene,
        resources: GenericVisualResources<'_, D>,
    ) -> Result<(), RenderError> {
        self.visuals.retain(|handle, _| {
            self.visual_plans
                .iter()
                .any(|plan| plan.source == RelationVisualSource::Scene(*handle))
        });
        for plan in &self.visual_plans {
            if let RelationVisualSource::Scene(handle) = plan.source {
                self.visuals
                    .entry(handle)
                    .or_insert_with(GenericVisualState::new)
                    .sync(
                        device,
                        queue,
                        &GenericVisualTarget {
                            scene,
                            domain: RowDomain::Relations(handle),
                            color: plan.color,
                            opacity: plan.opacity,
                            row_count: plan.count as usize,
                        },
                        resources,
                    )?;
            }
        }
        self.rebuild_cull_streams(device, queue, layout, resources, None)
    }

    fn rebuild_cull_streams(
        &mut self,
        device: &D,
        queue: &D::Queue,
        layout: &D::BindGroupLayout,
        resources: GenericVisualResources<'_, D>,
        paged_properties: Option<&D::Buffer>,
    ) -> Result<(), RenderError> {
        let (Some(base), Some(output), Some(visible), Some(args)) = (
            self.base.get(),
            self.buffer.get(),
            self.visible.get(),
            self.args.as_ref(),
        ) else {
            self.cull_streams.clear();
            return Ok(());
        };
        let shared = resources.binding_revision();
        let plan_count = if paged_properties.is_some() {
            self.visual_plans.len()
        } else {
            self.scene_visual_count
        };
        for (index, plan) in self.visual_plans.iter().copied().take(plan_count).enumerate() {
            let visual_revision = match plan.source {
                RelationVisualSource::Scene(handle) => self
                    .visuals
                    .get(&handle)
                    .map_or(0, GenericVisualState::binding_revision),
                RelationVisualSource::Paged(id) => self
                    .paged_visuals
                    .get(&id)
                    .map_or(0, PagedRelationVisualState::binding_revision),
                RelationVisualSource::Fallback => 0,
            };
            let bindings = match plan.source {
                RelationVisualSource::Paged(_) => [
                    self.paged_visual_arenas.binding_revision(),
                    0,
                    0,
                    visual_revision,
                ],
                RelationVisualSource::Scene(_) | RelationVisualSource::Fallback => {
                    [shared[0], shared[1], shared[2], visual_revision]
                }
            };
            let reusable = self
                .cull_streams
                .get(index)
                .is_some_and(|stream| stream.source == plan.source && stream.bindings == bindings);
            if reusable {
                continue;
            }
            let config = device.create_buffer(&BufferDesc {
                label: "relation cull range",
                size: std::mem::size_of::<RelationCullConfig>() as u64,
                usage: BufferUsage::UNIFORM.union(BufferUsage::COPY_DST),
            })?;
            queue.write_buffer(
                &config,
                0,
                bytemuck::bytes_of(&RelationCullConfig {
                    counts: [plan.first, plan.count, 0, 0],
                }),
            );
            let visual = self.visual_entries(plan.source, resources, paged_properties);
            let group = device.create_bind_group(&BindGroupDesc {
                label: "group1: relation visual culling",
                layout,
                entries: &[
                    BindGroupEntry::Buffer { binding: 0, buffer: base },
                    BindGroupEntry::Buffer { binding: 1, buffer: output },
                    BindGroupEntry::Buffer { binding: 2, buffer: visible },
                    BindGroupEntry::Buffer { binding: 3, buffer: args },
                    BindGroupEntry::Buffer { binding: 4, buffer: &config },
                    BindGroupEntry::Buffer { binding: 5, buffer: visual.instructions },
                    BindGroupEntry::Buffer { binding: 6, buffer: visual.parameters },
                    BindGroupEntry::Buffer { binding: 7, buffer: visual.properties },
                    BindGroupEntry::Buffer { binding: 8, buffer: visual.results },
                    BindGroupEntry::Buffer { binding: 9, buffer: visual.config },
                ],
            });
            let stream = RelationCullStream {
                source: plan.source,
                groups: workgroups_2d(u64::from(plan.count).div_ceil(64)),
                _config: config,
                group,
                bindings,
            };
            if let Some(existing) = self.cull_streams.get_mut(index) {
                *existing = stream;
            } else {
                self.cull_streams.push(stream);
            }
        }
        if paged_properties.is_some() || self.paged_synced.is_none() {
            self.cull_streams.truncate(plan_count);
        }
        Ok(())
    }

    fn visual_entries<'a>(
        &'a self,
        source: RelationVisualSource,
        resources: GenericVisualResources<'a, D>,
        paged_properties: Option<&'a D::Buffer>,
    ) -> VisualCullEntries<'a, D> {
        match source {
            RelationVisualSource::Scene(handle) => self
                .visuals
                .get(&handle)
                .map_or(resources.fallback, |state| state.entries(resources)),
            RelationVisualSource::Paged(id) => match paged_properties
                .and_then(|properties| {
                    self.paged_visuals
                        .get(&id)
                        .and_then(|state| state.entries(properties, &self.paged_visual_arenas))
                }) {
                    Some(entries) => entries,
                    None => resources.fallback,
                },
            RelationVisualSource::Fallback => resources.fallback,
        }
    }
}