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}