leptos-helios 0.8.1

High-performance Rust visualization library with Canvas2D, WebGPU, and WebAssembly support
Documentation
//! Main renderer and pipeline management
//!
//! This module provides the main renderer and render pipeline management
//! for different chart types and rendering backends.

use std::collections::HashMap;
use std::sync::Arc;
use std::time::Instant;

use super::errors::*;
use super::performance::*;

// WebGPU integration
#[cfg(feature = "webgpu")]
use wgpu::*;

/// Chart type classification
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ChartType {
    Point,
    Line,
    Bar,
    Area,
    Text,
    Rect,
    Scatter,
    BoxPlot,
    Violin,
    Heatmap,
    Histogram,
    Density,
    Contour,
    Radar,
    Sankey,
    Treemap,
    Composite,
    // Phase 3 Advanced Chart Types
    Point3D,
    Surface3D,
    Choropleth,
    NetworkGraph,
    DotMap,
    FlowMap,
}

impl ChartType {
    pub fn from_spec(spec: &crate::chart::ChartSpec) -> Self {
        match spec.mark {
            crate::chart::MarkType::Point { .. } => ChartType::Point,
            crate::chart::MarkType::Line { .. } => ChartType::Line,
            crate::chart::MarkType::Bar { .. } => ChartType::Bar,
            crate::chart::MarkType::Area { .. } => ChartType::Area,
            crate::chart::MarkType::Text { .. } => ChartType::Text,
            crate::chart::MarkType::Rect { .. } => ChartType::Rect,
            crate::chart::MarkType::Scatter { .. } => ChartType::Scatter,
            crate::chart::MarkType::BoxPlot { .. } => ChartType::BoxPlot,
            crate::chart::MarkType::Violin { .. } => ChartType::Violin,
            crate::chart::MarkType::Heatmap { .. } => ChartType::Heatmap,
            crate::chart::MarkType::Histogram { .. } => ChartType::Histogram,
            crate::chart::MarkType::Density { .. } => ChartType::Density,
            crate::chart::MarkType::Contour { .. } => ChartType::Contour,
            crate::chart::MarkType::Radar { .. } => ChartType::Radar,
            crate::chart::MarkType::Sankey { .. } => ChartType::Sankey,
            crate::chart::MarkType::Treemap { .. } => ChartType::Treemap,
            crate::chart::MarkType::Composite(_) => ChartType::Composite,
            // Phase 3 Advanced Chart Types
            crate::chart::MarkType::Point3D { .. } => ChartType::Point3D,
            crate::chart::MarkType::Surface3D { .. } => ChartType::Surface3D,
            crate::chart::MarkType::Choropleth { .. } => ChartType::Choropleth,
            crate::chart::MarkType::NetworkGraph { .. } => ChartType::NetworkGraph,
            crate::chart::MarkType::DotMap { .. } => ChartType::DotMap,
            crate::chart::MarkType::FlowMap { .. } => ChartType::FlowMap,
        }
    }

    pub fn name(&self) -> &'static str {
        match self {
            ChartType::Point => "point",
            ChartType::Line => "line",
            ChartType::Bar => "bar",
            ChartType::Area => "area",
            ChartType::Text => "text",
            ChartType::Rect => "rect",
            ChartType::Scatter => "scatter",
            ChartType::BoxPlot => "boxplot",
            ChartType::Violin => "violin",
            ChartType::Heatmap => "heatmap",
            ChartType::Histogram => "histogram",
            ChartType::Density => "density",
            ChartType::Contour => "contour",
            ChartType::Radar => "radar",
            ChartType::Sankey => "sankey",
            ChartType::Treemap => "treemap",
            ChartType::Composite => "composite",
            ChartType::Point3D => "point3d",
            ChartType::Surface3D => "surface3d",
            ChartType::Choropleth => "choropleth",
            ChartType::NetworkGraph => "networkgraph",
            ChartType::DotMap => "dotmap",
            ChartType::FlowMap => "flowmap",
        }
    }
}

/// Main renderer
pub struct Renderer {
    backend: RenderBackend,
    pipelines: HashMap<ChartType, RenderPipeline>,
    frame_timer: FrameTimer,
    quality_manager: AdaptiveQualityManager,
}

impl Renderer {
    pub async fn new() -> Result<Self, RenderError> {
        let backend = RenderBackend::create_optimal().await?;
        let frame_timer = FrameTimer::new();
        let quality_manager = AdaptiveQualityManager::new();

        Ok(Self {
            backend,
            pipelines: HashMap::new(),
            frame_timer,
            quality_manager,
        })
    }

    pub fn render(&mut self, spec: &crate::chart::ChartSpec) -> RenderStats {
        let start_time = Instant::now();

        // Adaptive quality based on frame timing
        let quality_level = self.frame_timer.suggest_quality();
        let _render_config = self.quality_manager.get_render_config(quality_level);

        // Get or create render pipeline for chart type
        let chart_type = ChartType::from_spec(spec);
        let _pipeline = self.get_or_create_pipeline(chart_type);

        // Execute render pass - create a simple stats object
        let frame_time = start_time.elapsed();

        RenderStats {
            frame_time,
            triangles_rendered: 1000, // Placeholder
            draw_calls: 1,
            memory_used: 1024 * 1024, // 1MB placeholder
            gpu_utilization: 0.5,
            cache_hit_rate: 0.95,
        }
    }

    fn get_or_create_pipeline(&mut self, chart_type: ChartType) -> &RenderPipeline {
        if !self.pipelines.contains_key(&chart_type) {
            let pipeline = RenderPipeline::new(&self.backend, chart_type.clone());
            self.pipelines.insert(chart_type.clone(), pipeline);
        }
        self.pipelines.get(&chart_type).unwrap()
    }

    pub fn get_backend(&self) -> &RenderBackend {
        &self.backend
    }

    pub fn get_performance_stats(&self) -> RenderStats {
        RenderStats {
            frame_time: self.frame_timer.get_average_frame_time(),
            triangles_rendered: 0,
            draw_calls: 0,
            memory_used: 0,
            gpu_utilization: 0.0,
            cache_hit_rate: 0.0,
        }
    }
}

/// Render pipeline for specific chart types
pub struct RenderPipeline {
    #[allow(dead_code)]
    chart_type: ChartType,
    #[allow(dead_code)]
    webgpu_pipeline: Option<Arc<wgpu::RenderPipeline>>,
    #[allow(dead_code)]
    bind_group_layout: Option<Arc<BindGroupLayout>>,
    #[allow(dead_code)]
    vertex_buffer: Option<Arc<Buffer>>,
    #[allow(dead_code)]
    index_buffer: Option<Arc<Buffer>>,
    #[allow(dead_code)]
    uniform_buffer: Option<Arc<Buffer>>,
    #[allow(dead_code)]
    shader_module: Option<Arc<ShaderModule>>,
}

impl RenderPipeline {
    pub fn new(backend: &RenderBackend, chart_type: ChartType) -> Self {
        match backend {
            RenderBackend::WebGPU { device, .. } => {
                if let Some(device) = device {
                    Self::create_webgpu_pipeline(device, chart_type)
                } else {
                    Self::fallback_pipeline(chart_type)
                }
            }
            _ => Self::fallback_pipeline(chart_type),
        }
    }

    #[cfg(feature = "webgpu")]
    fn create_webgpu_pipeline(device: &Arc<Device>, chart_type: ChartType) -> Self {
        // Create shader module
        let shader_source = Self::get_shader_source(&chart_type);
        let shader_module = device.create_shader_module(ShaderModuleDescriptor {
            label: Some(&format!("{}_shader", chart_type.name())),
            source: ShaderSource::Wgsl(shader_source.into()),
        });

        // Create bind group layout
        let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
            label: Some(&format!("{}_bind_group_layout", chart_type.name())),
            entries: &[],
        });

        // Create render pipeline layout
        let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
            label: Some(&format!("{}_pipeline_layout", chart_type.name())),
            bind_group_layouts: &[&bind_group_layout],
            push_constant_ranges: &[],
        });

        // Create render pipeline
        let render_pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
            label: Some(&format!("{}_render_pipeline", chart_type.name())),
            layout: Some(&pipeline_layout),
            vertex: VertexState {
                module: &shader_module,
                entry_point: Some("vs_main"),
                buffers: &[],
                compilation_options: wgpu::PipelineCompilationOptions::default(),
            },
            fragment: Some(FragmentState {
                module: &shader_module,
                entry_point: Some("fs_main"),
                targets: &[Some(ColorTargetState {
                    format: TextureFormat::Bgra8UnormSrgb,
                    blend: Some(BlendState::REPLACE),
                    write_mask: ColorWrites::ALL,
                })],
                compilation_options: wgpu::PipelineCompilationOptions::default(),
            }),
            primitive: PrimitiveState {
                topology: PrimitiveTopology::TriangleList,
                strip_index_format: None,
                front_face: FrontFace::Ccw,
                cull_mode: Some(Face::Back),
                polygon_mode: PolygonMode::Fill,
                unclipped_depth: false,
                conservative: false,
            },
            depth_stencil: None,
            multisample: MultisampleState {
                count: 1,
                mask: !0,
                alpha_to_coverage_enabled: false,
            },
            multiview: None,
            cache: None,
        });

        Self {
            chart_type,
            webgpu_pipeline: Some(Arc::new(render_pipeline)),
            bind_group_layout: Some(Arc::new(bind_group_layout)),
            vertex_buffer: None,
            index_buffer: None,
            uniform_buffer: None,
            shader_module: Some(Arc::new(shader_module)),
        }
    }

    fn fallback_pipeline(chart_type: ChartType) -> Self {
        Self {
            chart_type,
            webgpu_pipeline: None,
            bind_group_layout: None,
            vertex_buffer: None,
            index_buffer: None,
            uniform_buffer: None,
            shader_module: None,
        }
    }

    fn get_shader_source(chart_type: &ChartType) -> &'static str {
        match chart_type {
            ChartType::Point => include_str!("shaders/point.wgsl"),
            ChartType::Line => include_str!("shaders/line.wgsl"),
            ChartType::Bar => include_str!("shaders/bar.wgsl"),
            ChartType::Area => include_str!("shaders/area.wgsl"),
            _ => include_str!("shaders/default.wgsl"),
        }
    }
}