maplibre/render/systems/
resource_system.rs

1//! Prepares GPU-owned resources by initializing them if they are uninitialized or out-of-date.
2
3use std::{borrow::Cow, mem};
4
5use crate::{
6    context::MapContext,
7    render::{
8        eventually::Eventually,
9        resource::{BackingBufferDescriptor, RenderPipeline, Texture, TilePipeline},
10        settings::Msaa,
11        shaders,
12        shaders::{Shader, ShaderTileMetadata},
13        tile_view_pattern::{TileViewPattern, WgpuTileViewPattern, DEFAULT_TILE_VIEW_PATTERN_SIZE},
14        MaskPipeline, Renderer,
15    },
16    tcs::system::{System, SystemError, SystemResult},
17};
18
19#[derive(Default)]
20pub struct ResourceSystem;
21
22impl System for ResourceSystem {
23    fn name(&self) -> Cow<'static, str> {
24        "resource_system".into()
25    }
26
27    fn run(
28        &mut self,
29        MapContext {
30            renderer:
31                Renderer {
32                    settings,
33                    device,
34                    resources: state,
35                    ..
36                },
37            world,
38            ..
39        }: &mut MapContext,
40    ) -> SystemResult {
41        let Some((tile_view_pattern, mask_pipeline)) = world.resources.query_mut::<(
42            &mut Eventually<WgpuTileViewPattern>,
43            &mut Eventually<MaskPipeline>,
44        )>() else {
45            return Err(SystemError::Dependencies);
46        };
47
48        let surface = &mut state.surface;
49
50        let size = surface.size();
51
52        surface.reconfigure(device);
53
54        state
55            .render_target
56            .initialize(|| surface.create_view(device));
57
58        state.depth_texture.reinitialize(
59            || {
60                Texture::new(
61                    Some("depth texture"),
62                    device,
63                    settings.depth_texture_format,
64                    size.width(),
65                    size.height(),
66                    if surface.is_multisampling_supported(settings.msaa) {
67                        settings.msaa
68                    } else {
69                        Msaa { samples: 1 }
70                    },
71                    wgpu::TextureUsages::RENDER_ATTACHMENT,
72                )
73            },
74            &(size.width(), size.height()),
75        );
76
77        state.multisampling_texture.reinitialize(
78            || {
79                if settings.msaa.is_multisampling()
80                    && surface.is_multisampling_supported(settings.msaa)
81                {
82                    Some(Texture::new(
83                        Some("multisampling texture"),
84                        device,
85                        surface.surface_format(),
86                        size.width(),
87                        size.height(),
88                        settings.msaa,
89                        wgpu::TextureUsages::RENDER_ATTACHMENT,
90                    ))
91                } else {
92                    None
93                }
94            },
95            &(size.width(), size.height()),
96        );
97
98        tile_view_pattern.initialize(|| {
99            let tile_view_buffer_desc = wgpu::BufferDescriptor {
100                label: Some("tile view buffer"),
101                size: mem::size_of::<ShaderTileMetadata>() as wgpu::BufferAddress
102                    * DEFAULT_TILE_VIEW_PATTERN_SIZE,
103                usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
104                mapped_at_creation: false,
105            };
106
107            TileViewPattern::new(BackingBufferDescriptor::new(
108                device.create_buffer(&tile_view_buffer_desc),
109                tile_view_buffer_desc.size,
110            ))
111        });
112
113        mask_pipeline.initialize(|| {
114            let mask_shader = shaders::TileMaskShader {
115                format: surface.surface_format(),
116                draw_colors: false,
117                debug_lines: false,
118            };
119
120            let pipeline = TilePipeline::new(
121                "mask_pipeline".into(),
122                *settings,
123                mask_shader.describe_vertex(),
124                mask_shader.describe_fragment(),
125                true,
126                true,
127                false,
128                false,
129                surface.is_multisampling_supported(settings.msaa),
130                false,
131                false,
132            )
133            .describe_render_pipeline()
134            .initialize(device);
135            MaskPipeline(pipeline)
136        });
137
138        Ok(())
139    }
140}