Skip to main content

arcane_core/renderer/
rendertarget.rs

1/// Render target store: off-screen textures that TS can draw into,
2/// then use as sprite inputs.
3///
4/// Each render target owns a wgpu::Texture + TextureView created with
5/// RENDER_ATTACHMENT | TEXTURE_BINDING usage. The format matches the
6/// surface format so the same SpritePipeline can render into it.
7///
8/// Lifecycle:
9/// 1. `create()` — allocates GPU texture + view
10/// 2. `get_view()` — returns the view for render pass target
11/// 3. `destroy()` — drops GPU resources
12
13use std::collections::HashMap;
14
15use super::gpu::GpuContext;
16
17/// A single off-screen render target.
18pub struct RenderTargetEntry {
19    pub texture: wgpu::Texture,
20    pub view: wgpu::TextureView,
21    pub width: u32,
22    pub height: u32,
23}
24
25/// Stores all live render targets, keyed by their ID (which doubles as TextureId).
26pub struct RenderTargetStore {
27    pub targets: HashMap<u32, RenderTargetEntry>,
28}
29
30impl RenderTargetStore {
31    pub fn new() -> Self {
32        Self {
33            targets: HashMap::new(),
34        }
35    }
36
37    /// Allocate a new off-screen render target.
38    ///
39    /// The texture format matches the surface format (`surface_format`) so the
40    /// sprite pipeline can render into it without a format mismatch.
41    pub fn create(
42        &mut self,
43        gpu: &GpuContext,
44        id: u32,
45        width: u32,
46        height: u32,
47        surface_format: wgpu::TextureFormat,
48    ) {
49        let texture = gpu.device.create_texture(&wgpu::TextureDescriptor {
50            label: Some(&format!("render_target_{id}")),
51            size: wgpu::Extent3d {
52                width,
53                height,
54                depth_or_array_layers: 1,
55            },
56            mip_level_count: 1,
57            sample_count: 1,
58            dimension: wgpu::TextureDimension::D2,
59            // Must match surface format so SpritePipeline (compiled for surface_format)
60            // can render into this target without a pipeline/attachment format mismatch.
61            format: surface_format,
62            usage: wgpu::TextureUsages::RENDER_ATTACHMENT
63                | wgpu::TextureUsages::TEXTURE_BINDING,
64            view_formats: &[],
65        });
66
67        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
68        self.targets.insert(
69            id,
70            RenderTargetEntry {
71                texture,
72                view,
73                width,
74                height,
75            },
76        );
77    }
78
79    /// Get the TextureView for rendering INTO this target.
80    pub fn get_view(&self, id: u32) -> Option<&wgpu::TextureView> {
81        self.targets.get(&id).map(|e| &e.view)
82    }
83
84    /// Get dimensions of a render target.
85    pub fn get_dims(&self, id: u32) -> Option<(u32, u32)> {
86        self.targets.get(&id).map(|e| (e.width, e.height))
87    }
88
89    /// Drop GPU resources for a render target.
90    pub fn destroy(&mut self, id: u32) {
91        self.targets.remove(&id);
92    }
93}