maplibre/raster/
upload_system.rs

1//! Uploads data to the GPU which is needed for rendering.
2use crate::{
3    context::MapContext,
4    coords::ViewRegion,
5    raster::{
6        resource::RasterResources, AvailableRasterLayerData, RasterLayerData,
7        RasterLayersDataComponent,
8    },
9    render::{
10        eventually::{Eventually, Eventually::Initialized},
11        tile_view_pattern::DEFAULT_TILE_SIZE,
12        view_state::ViewStatePadding,
13        Renderer,
14    },
15    style::Style,
16    tcs::{
17        system::{SystemError, SystemResult},
18        tiles::Tiles,
19    },
20};
21
22pub fn upload_system(
23    MapContext {
24        world,
25        style,
26        view_state,
27        renderer: Renderer { device, queue, .. },
28        ..
29    }: &mut MapContext,
30) -> SystemResult {
31    let Some(Initialized(raster_resources)) = world
32        .resources
33        .query_mut::<&mut Eventually<RasterResources>>()
34    else {
35        return Err(SystemError::Dependencies);
36    };
37    let view_region = view_state.create_view_region(
38        view_state.zoom().zoom_level(DEFAULT_TILE_SIZE),
39        ViewStatePadding::Loose,
40    );
41
42    if let Some(view_region) = &view_region {
43        upload_raster_layer(
44            raster_resources,
45            device,
46            queue,
47            &world.tiles,
48            style,
49            view_region,
50        );
51    }
52
53    Ok(())
54}
55
56#[tracing::instrument(skip_all)]
57fn upload_raster_layer(
58    raster_resources: &mut RasterResources,
59    device: &wgpu::Device,
60    queue: &wgpu::Queue,
61    tiles: &Tiles,
62    style: &Style,
63    view_region: &ViewRegion,
64) {
65    for coords in view_region.iter() {
66        if raster_resources.get_bound_texture(&coords).is_some() {
67            continue;
68        }
69
70        let Some(raster_layers) = tiles.query::<&RasterLayersDataComponent>(coords) else {
71            continue;
72        };
73
74        for style_layer in &style.layers {
75            let style_source_layer = style_layer.source_layer.as_ref().unwrap(); // FIXME: Remove unwrap
76
77            let Some(AvailableRasterLayerData { coords, image, .. }) = raster_layers
78                .layers
79                .iter()
80                .flat_map(|data| match data {
81                    RasterLayerData::Available(data) => Some(data),
82                    RasterLayerData::Missing(_) => None,
83                })
84                .find(|layer| style_source_layer.as_str() == layer.source_layer)
85            else {
86                continue;
87            };
88
89            let (width, height) = image.dimensions();
90
91            let texture = raster_resources.create_texture(
92                None,
93                device,
94                wgpu::TextureFormat::Rgba8UnormSrgb,
95                width,
96                height,
97                wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
98            );
99
100            queue.write_texture(
101                wgpu::ImageCopyTexture {
102                    aspect: wgpu::TextureAspect::All,
103                    texture: &texture.texture,
104                    mip_level: 0,
105                    origin: wgpu::Origin3d::ZERO,
106                },
107                image,
108                wgpu::ImageDataLayout {
109                    offset: 0,
110                    bytes_per_row: Some(4 * width),
111                    rows_per_image: Some(height),
112                },
113                texture.size,
114            );
115
116            raster_resources.bind_texture(device, coords, texture);
117        }
118    }
119}