use super::resource::ResourceId;
use crate::renderer::GpuRenderer;
use cvkg_core::PassNode;
#[derive(Debug, thiserror::Error)]
pub enum KvasirError {
#[error("Cycle detected in render graph: {0:?}")]
CycleDetected(Vec<String>),
#[error("Missing resource: {0}")]
MissingResource(String),
#[error("Invalid node configuration: {0}")]
InvalidNodeConfig(String),
#[error("Graph compilation failed: {0}")]
CompilationFailed(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GraphId(pub u64);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ExecutionHint {
Raster,
Compute,
Hybrid,
}
pub struct ExecutionContext<'a> {
pub device: &'a wgpu::Device,
pub queue: &'a wgpu::Queue,
pub encoder: &'a mut wgpu::CommandEncoder,
pub registry: &'a crate::kvasir::registry::ResourceRegistry,
pub renderer: &'a crate::renderer::GpuRenderer,
pub target_view: &'a wgpu::TextureView,
pub depth_view: &'a wgpu::TextureView,
pub blur_env_bind_group_a: &'a wgpu::BindGroup,
pub blur_env_bind_group_b: &'a wgpu::BindGroup,
pub bloom_env_bind_group_a: &'a wgpu::BindGroup,
pub bloom_env_bind_group_b: &'a wgpu::BindGroup,
pub scale_factor: f32,
}
impl<'a> ExecutionContext<'a> {
pub fn begin_render_pass(
&mut self,
desc: &wgpu::RenderPassDescriptor<'_>,
) -> wgpu::RenderPass<'_> {
self.encoder.begin_render_pass(desc)
}
pub fn get_or_create_bind_group(
&self,
key: (crate::kvasir::resource::ResourceId, u32, bool),
layout: &wgpu::BindGroupLayout,
entries: &[wgpu::BindGroupEntry<'_>],
label: Option<&str>,
) -> wgpu::BindGroup {
let mut cache = GpuRenderer::lock_or_clear_cache(&self.renderer.bind_group_cache);
let full_key = (self.renderer.current_window, key.0, key.1, key.2);
if let std::collections::hash_map::Entry::Vacant(e) = cache.entry(full_key) {
let bg = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
label,
layout,
entries,
});
e.insert(bg.clone());
bg
} else {
cache.get(&full_key).unwrap().clone()
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub trait KvasirNode: Send + Sync {
fn label(&self) -> &'static str;
fn inputs(&self) -> &[ResourceId];
fn outputs(&self) -> &[ResourceId];
fn pass_id(&self) -> super::nodes::PassId;
fn execute(&self, ctx: &mut ExecutionContext);
}
#[cfg(target_arch = "wasm32")]
pub trait KvasirNode {
fn label(&self) -> &'static str;
fn inputs(&self) -> &[ResourceId];
fn outputs(&self) -> &[ResourceId];
fn pass_id(&self) -> super::nodes::PassId;
fn execute(&self, ctx: &mut ExecutionContext);
}
use crate::passes::accessibility::AccessibilityNode;
use crate::passes::backdrop_region::BackdropRegionNode;
use crate::passes::bloom::{BloomBlurNode, BloomExtractNode};
use crate::passes::composite::CompositeNode;
use crate::passes::effects::{EffectCompositeNode, OffscreenGeometryNode};
use crate::passes::geometry::GeometryNode;
use crate::passes::glass::{BackdropBlurNode, BackdropCopyNode, GlassNode};
use crate::passes::opaque3d::Opaque3dNode;
use crate::passes::pre_world_panel::PreWorldPanelNode;
use crate::passes::shadow::ShadowNode;
use crate::passes::svg_filter::SvgFilterNode;
use crate::passes::tonemap::ToneMapNode;
use crate::passes::ui::UINode;
use crate::passes::volumetric::VolumetricNode;
impl PassNode for GeometryNode {}
impl PassNode for UINode {}
impl PassNode for ShadowNode {}
impl PassNode for Opaque3dNode {}
impl PassNode for CompositeNode {}
impl PassNode for GlassNode {}
impl PassNode for BackdropCopyNode {}
impl PassNode for BackdropBlurNode {}
impl PassNode for BloomExtractNode {}
impl PassNode for BloomBlurNode {}
impl PassNode for VolumetricNode {}
impl PassNode for ToneMapNode {}
impl PassNode for AccessibilityNode {}
impl PassNode for BackdropRegionNode {}
impl PassNode for PreWorldPanelNode {}
impl PassNode for OffscreenGeometryNode {}
impl PassNode for EffectCompositeNode {}
impl PassNode for SvgFilterNode {}
#[cfg(test)]
mod p1_2_aliasing_contract_tests {
use super::*;
#[test]
fn renderer_field_is_immutable() {
fn _assert_immutable(_: &GpuRenderer) {}
let _f: fn(&GpuRenderer) = _assert_immutable;
}
#[test]
fn encoder_field_is_mutable() {
fn _assert_mut(_: &mut wgpu::CommandEncoder) {}
let _f: fn(&mut wgpu::CommandEncoder) = _assert_mut;
}
}