Skip to main content

cvkg_render_gpu/passes/
accessibility.rs

1use crate::color_blindness::ColorBlindUniforms;
2use crate::kvasir::node::{ExecutionContext, KvasirNode};
3use crate::kvasir::nodes::{PassId, RES_SCENE};
4use crate::kvasir::resource::ResourceId;
5
6pub struct AccessibilityNode {
7    pub inputs: Vec<ResourceId>,
8    pub outputs: Vec<ResourceId>,
9}
10
11impl AccessibilityNode {
12    pub fn new() -> Self {
13        Self {
14            // Reads from RES_SCENE (scene texture sampled in the shader).
15            // Writes to the swapchain render target (not a graph resource).
16            inputs: vec![RES_SCENE],
17            outputs: vec![], // render target write is implicit, not a graph edge
18        }
19    }
20}
21
22impl KvasirNode for AccessibilityNode {
23    fn label(&self) -> &'static str {
24        "Accessibility"
25    }
26
27    fn inputs(&self) -> &[ResourceId] {
28        &self.inputs
29    }
30
31    fn outputs(&self) -> &[ResourceId] {
32        &self.outputs
33    }
34
35    fn pass_id(&self) -> PassId {
36        PassId::Accessibility
37    }
38
39    fn execute(&self, ctx: &mut ExecutionContext) {
40        if ctx.renderer.color_blind_mode.is_identity() {
41            return;
42        }
43
44        let uniforms = ColorBlindUniforms::new(
45            ctx.renderer.color_blind_mode,
46            ctx.renderer.color_blind_intensity,
47        );
48        ctx.queue.write_buffer(
49            &ctx.renderer.color_blind_uniform_buffer,
50            0,
51            bytemuck::bytes_of(&uniforms),
52        );
53
54        // Sample from the scene texture, render to the swapchain target.
55        let scene_view = match ctx.registry.get_texture_view(crate::kvasir::nodes::RES_SCENE) {
56            Some(v) => v,
57            None => {
58                log::error!("[Accessibility] Missing scene texture view");
59                return;
60            }
61        };
62        let target_view = ctx.target_view;
63
64        let color_blind_bind_group = ctx.get_or_create_bind_group(
65            (crate::kvasir::nodes::RES_SCENE, 99998, false),
66            &ctx.renderer.color_blind_bind_group_layout,
67            &[
68                wgpu::BindGroupEntry {
69                    binding: 0,
70                    resource: wgpu::BindingResource::TextureView(&scene_view),
71                },
72                wgpu::BindGroupEntry {
73                    binding: 1,
74                    resource: wgpu::BindingResource::Sampler(&ctx.renderer.sampler),
75                },
76                wgpu::BindGroupEntry {
77                    binding: 2,
78                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
79                        buffer: &ctx.renderer.color_blind_uniform_buffer,
80                        offset: 0,
81                        size: wgpu::BufferSize::new(
82                            std::mem::size_of::<ColorBlindUniforms>() as u64
83                        ),
84                    }),
85                },
86            ],
87            Some("Color Blind Bind Group"),
88        );
89
90        let mut p = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
91            label: Some("Surtr Accessibility"),
92            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
93                view: target_view,
94                resolve_target: None,
95                ops: wgpu::Operations {
96                    load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
97                    store: wgpu::StoreOp::Store,
98                },
99                depth_slice: None,
100            })],
101            depth_stencil_attachment: None,
102            timestamp_writes: None,
103            occlusion_query_set: None,
104            multiview_mask: None,
105        });
106
107        p.set_pipeline(&ctx.renderer.color_blind_pipeline);
108        p.set_bind_group(0, &color_blind_bind_group, &[]);
109        p.draw(0..3, 0..1);
110    }
111}