mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Automatically choose texture format based on adapter (#224)
* Automatically choose texture format based on adapter * Use compatible_surface properly
This commit is contained in:
parent
516d642079
commit
4fcd142e0d
@ -37,23 +37,18 @@ impl Node for CopySurfaceBufferNode {
|
||||
Head::Headless(buffered_texture) => {
|
||||
let size = surface.size();
|
||||
command_encoder.copy_texture_to_buffer(
|
||||
buffered_texture.texture.as_image_copy(),
|
||||
buffered_texture.copy_texture(),
|
||||
wgpu::ImageCopyBuffer {
|
||||
buffer: &buffered_texture.output_buffer,
|
||||
buffer: &buffered_texture.buffer(),
|
||||
layout: wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(
|
||||
std::num::NonZeroU32::new(
|
||||
buffered_texture.buffer_dimensions.padded_bytes_per_row as u32,
|
||||
)
|
||||
.unwrap(), // TODO: remove unwrap
|
||||
),
|
||||
bytes_per_row: Some(buffered_texture.bytes_per_row()),
|
||||
rows_per_image: None,
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: size.width() as u32,
|
||||
height: size.height() as u32,
|
||||
width: size.width(),
|
||||
height: size.height(),
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
|
||||
@ -12,6 +12,7 @@ use crate::{
|
||||
InitializationResult, InitializedRenderer, RendererBuilder, UninitializedRenderer,
|
||||
},
|
||||
create_default_render_graph,
|
||||
error::RenderError,
|
||||
graph::RenderGraphError,
|
||||
register_default_render_stages,
|
||||
},
|
||||
@ -30,7 +31,7 @@ pub enum MapError {
|
||||
#[error("initializing render graph failed")]
|
||||
RenderGraphInit(RenderGraphError),
|
||||
#[error("initializing device failed")]
|
||||
DeviceInit,
|
||||
DeviceInit(RenderError),
|
||||
}
|
||||
|
||||
pub enum MapContextState {
|
||||
@ -92,7 +93,7 @@ where
|
||||
.build()
|
||||
.initialize_renderer::<E::MapWindowConfig>(&self.window)
|
||||
.await
|
||||
.map_err(|e| MapError::DeviceInit)?;
|
||||
.map_err(|e| MapError::DeviceInit(e))?;
|
||||
|
||||
let window_size = self.window.size();
|
||||
|
||||
|
||||
@ -1,22 +1,15 @@
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::render::graph::RenderGraphError;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RenderError {
|
||||
Surface(wgpu::SurfaceError),
|
||||
Graph(RenderGraphError),
|
||||
Device(wgpu::RequestDeviceError),
|
||||
}
|
||||
|
||||
impl fmt::Display for RenderError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RenderError::Surface(e) => write!(f, "{}", e),
|
||||
RenderError::Graph(e) => write!(f, "{:?}", e),
|
||||
RenderError::Device(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
#[error("error in surface")]
|
||||
Surface(#[from] wgpu::SurfaceError),
|
||||
#[error("error in render graph")]
|
||||
Graph(#[from] RenderGraphError),
|
||||
#[error("error while requesting device")]
|
||||
RequestDevice(#[from] wgpu::RequestDeviceError),
|
||||
}
|
||||
|
||||
impl RenderError {
|
||||
@ -30,21 +23,3 @@ impl RenderError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RenderGraphError> for RenderError {
|
||||
fn from(e: RenderGraphError) -> Self {
|
||||
RenderError::Graph(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<wgpu::SurfaceError> for RenderError {
|
||||
fn from(e: wgpu::SurfaceError) -> Self {
|
||||
RenderError::Surface(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<wgpu::RequestDeviceError> for RenderError {
|
||||
fn from(e: wgpu::RequestDeviceError) -> Self {
|
||||
RenderError::Device(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ pub use stages::register_default_render_stages;
|
||||
|
||||
use crate::{
|
||||
render::{
|
||||
error::RenderError,
|
||||
graph::{EmptyNode, RenderGraph, RenderGraphError},
|
||||
main_pass::{MainPassDriverNode, MainPassNode},
|
||||
},
|
||||
@ -142,7 +143,7 @@ pub struct Renderer {
|
||||
pub instance: wgpu::Instance,
|
||||
pub device: Arc<wgpu::Device>, // TODO: Arc is needed for headless rendering. Is there a simpler solution?
|
||||
pub queue: wgpu::Queue,
|
||||
pub adapter_info: wgpu::AdapterInfo,
|
||||
pub adapter: wgpu::Adapter,
|
||||
|
||||
pub wgpu_settings: WgpuSettings,
|
||||
pub settings: RendererSettings,
|
||||
@ -157,30 +158,27 @@ impl Renderer {
|
||||
window: &MW,
|
||||
wgpu_settings: WgpuSettings,
|
||||
settings: RendererSettings,
|
||||
) -> Result<Self, wgpu::RequestDeviceError>
|
||||
) -> Result<Self, RenderError>
|
||||
where
|
||||
MW: MapWindow + HeadedMapWindow,
|
||||
{
|
||||
let instance = wgpu::Instance::new(wgpu_settings.backends.unwrap_or(wgpu::Backends::all()));
|
||||
|
||||
let surface = Surface::from_window(&instance, window, &settings);
|
||||
let surface: wgpu::Surface = unsafe { instance.create_surface(window.raw()) };
|
||||
|
||||
let compatible_surface = match &surface.head() {
|
||||
Head::Headed(window_head) => Some(window_head.surface()),
|
||||
Head::Headless(_) => None,
|
||||
};
|
||||
|
||||
let (device, queue, adapter_info) = Self::request_device(
|
||||
let (adapter, device, queue) = Self::request_device(
|
||||
&instance,
|
||||
&wgpu_settings,
|
||||
&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu_settings.power_preference,
|
||||
force_fallback_adapter: false,
|
||||
compatible_surface,
|
||||
compatible_surface: Some(&surface),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
let surface = Surface::from_surface(surface, &adapter, window, &settings);
|
||||
|
||||
match surface.head() {
|
||||
Head::Headed(window) => window.configure(&device),
|
||||
Head::Headless(_) => {}
|
||||
@ -190,7 +188,7 @@ impl Renderer {
|
||||
instance,
|
||||
device: Arc::new(device),
|
||||
queue,
|
||||
adapter_info,
|
||||
adapter,
|
||||
wgpu_settings,
|
||||
settings,
|
||||
state: RenderState::new(surface),
|
||||
@ -201,13 +199,13 @@ impl Renderer {
|
||||
window: &MW,
|
||||
wgpu_settings: WgpuSettings,
|
||||
settings: RendererSettings,
|
||||
) -> Result<Self, wgpu::RequestDeviceError>
|
||||
) -> Result<Self, RenderError>
|
||||
where
|
||||
MW: MapWindow,
|
||||
{
|
||||
let instance = wgpu::Instance::new(wgpu_settings.backends.unwrap_or(wgpu::Backends::all()));
|
||||
|
||||
let (device, queue, adapter_info) = Self::request_device(
|
||||
let (adapter, device, queue) = Self::request_device(
|
||||
&instance,
|
||||
&wgpu_settings,
|
||||
&wgpu::RequestAdapterOptions {
|
||||
@ -224,7 +222,7 @@ impl Renderer {
|
||||
instance,
|
||||
device: Arc::new(device),
|
||||
queue,
|
||||
adapter_info,
|
||||
adapter,
|
||||
wgpu_settings,
|
||||
settings,
|
||||
state: RenderState::new(surface),
|
||||
@ -240,7 +238,7 @@ impl Renderer {
|
||||
instance: &wgpu::Instance,
|
||||
settings: &WgpuSettings,
|
||||
request_adapter_options: &wgpu::RequestAdapterOptions<'_>,
|
||||
) -> Result<(wgpu::Device, wgpu::Queue, wgpu::AdapterInfo), wgpu::RequestDeviceError> {
|
||||
) -> Result<(wgpu::Adapter, wgpu::Device, wgpu::Queue), wgpu::RequestDeviceError> {
|
||||
let adapter = instance
|
||||
.request_adapter(request_adapter_options)
|
||||
.await
|
||||
@ -384,7 +382,7 @@ impl Renderer {
|
||||
trace_path,
|
||||
)
|
||||
.await?;
|
||||
Ok((device, queue, adapter_info))
|
||||
Ok((adapter, device, queue))
|
||||
}
|
||||
|
||||
pub fn instance(&self) -> &wgpu::Instance {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
//! Utilities for handling surfaces which can be either headless or headed. A headed surface has
|
||||
//! a handle to a window. A headless surface renders to a texture.
|
||||
|
||||
use std::{mem::size_of, sync::Arc};
|
||||
use std::{mem::size_of, num::NonZeroU32, sync::Arc};
|
||||
|
||||
use wgpu::CompositeAlphaMode;
|
||||
use log::debug;
|
||||
|
||||
use crate::{
|
||||
render::{eventually::HasChanged, resource::texture::TextureView, settings::RendererSettings},
|
||||
@ -11,41 +11,54 @@ use crate::{
|
||||
};
|
||||
|
||||
pub struct BufferDimensions {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub unpadded_bytes_per_row: usize,
|
||||
pub padded_bytes_per_row: usize,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub unpadded_bytes_per_row: NonZeroU32,
|
||||
pub padded_bytes_per_row: NonZeroU32,
|
||||
}
|
||||
|
||||
impl BufferDimensions {
|
||||
fn new(width: usize, height: usize) -> Self {
|
||||
let bytes_per_pixel = size_of::<u32>();
|
||||
let unpadded_bytes_per_row = width * bytes_per_pixel;
|
||||
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize;
|
||||
fn new(size: WindowSize) -> Self {
|
||||
let bytes_per_pixel = size_of::<u32>() as u32;
|
||||
let unpadded_bytes_per_row = size.width() * bytes_per_pixel;
|
||||
|
||||
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
|
||||
let padded_bytes_per_row_padding = (align - unpadded_bytes_per_row % align) % align;
|
||||
let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
unpadded_bytes_per_row,
|
||||
padded_bytes_per_row,
|
||||
width: size.width(),
|
||||
height: size.height(),
|
||||
unpadded_bytes_per_row: NonZeroU32::new(unpadded_bytes_per_row)
|
||||
.expect("can not be zero"), // expect is fine because this can never happen
|
||||
padded_bytes_per_row: NonZeroU32::new(padded_bytes_per_row).expect("can not be zero"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WindowHead {
|
||||
surface: wgpu::Surface,
|
||||
surface_config: wgpu::SurfaceConfiguration,
|
||||
size: WindowSize,
|
||||
format: wgpu::TextureFormat,
|
||||
present_mode: wgpu::PresentMode,
|
||||
}
|
||||
|
||||
impl WindowHead {
|
||||
pub fn resize_and_configure(&mut self, width: u32, height: u32, device: &wgpu::Device) {
|
||||
self.surface_config.height = width;
|
||||
self.surface_config.width = height;
|
||||
self.surface.configure(device, &self.surface_config);
|
||||
self.size = WindowSize::new(width, height).unwrap();
|
||||
self.configure(device);
|
||||
}
|
||||
|
||||
pub fn configure(&self, device: &wgpu::Device) {
|
||||
self.surface.configure(device, &self.surface_config);
|
||||
let surface_config = wgpu::SurfaceConfiguration {
|
||||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: self.format,
|
||||
width: self.size.width(),
|
||||
height: self.size.height(),
|
||||
present_mode: self.present_mode,
|
||||
};
|
||||
|
||||
self.surface.configure(device, &surface_config);
|
||||
}
|
||||
|
||||
pub fn recreate_surface<MW>(&mut self, window: &MW, instance: &wgpu::Instance)
|
||||
@ -54,15 +67,17 @@ impl WindowHead {
|
||||
{
|
||||
self.surface = unsafe { instance.create_surface(window.raw()) };
|
||||
}
|
||||
|
||||
pub fn surface(&self) -> &wgpu::Surface {
|
||||
&self.surface
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferedTextureHead {
|
||||
pub texture: wgpu::Texture,
|
||||
pub output_buffer: wgpu::Buffer,
|
||||
pub buffer_dimensions: BufferDimensions,
|
||||
texture: wgpu::Texture,
|
||||
texture_format: wgpu::TextureFormat,
|
||||
output_buffer: wgpu::Buffer,
|
||||
buffer_dimensions: BufferDimensions,
|
||||
}
|
||||
|
||||
#[cfg(feature = "headless")]
|
||||
@ -95,17 +110,33 @@ impl BufferedTextureHead {
|
||||
let mut png_writer = png_encoder
|
||||
.write_header()
|
||||
.unwrap() // TODO: Remove unwrap
|
||||
.into_stream_writer_with_size(self.buffer_dimensions.unpadded_bytes_per_row)
|
||||
.into_stream_writer_with_size(
|
||||
self.buffer_dimensions.unpadded_bytes_per_row.get() as usize
|
||||
)
|
||||
.unwrap(); // TODO: Remove unwrap
|
||||
|
||||
// from the padded_buffer we write just the unpadded bytes into the image
|
||||
for chunk in padded_buffer.chunks(self.buffer_dimensions.padded_bytes_per_row) {
|
||||
for chunk in
|
||||
padded_buffer.chunks(self.buffer_dimensions.padded_bytes_per_row.get() as usize)
|
||||
{
|
||||
png_writer
|
||||
.write_all(&chunk[..self.buffer_dimensions.unpadded_bytes_per_row])
|
||||
.write_all(&chunk[..self.buffer_dimensions.unpadded_bytes_per_row.get() as usize])
|
||||
.unwrap(); // TODO: Remove unwrap
|
||||
}
|
||||
png_writer.finish().unwrap(); // TODO: Remove unwrap
|
||||
}
|
||||
|
||||
pub fn copy_texture(&self) -> wgpu::ImageCopyTexture<'_> {
|
||||
self.texture.as_image_copy()
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &wgpu::Buffer {
|
||||
&self.output_buffer
|
||||
}
|
||||
|
||||
pub fn bytes_per_row(&self) -> NonZeroU32 {
|
||||
self.buffer_dimensions.padded_bytes_per_row
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Head {
|
||||
@ -119,8 +150,9 @@ pub struct Surface {
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
pub fn from_window<MW>(
|
||||
instance: &wgpu::Instance,
|
||||
pub fn from_surface<MW>(
|
||||
surface: wgpu::Surface,
|
||||
adapter: &wgpu::Adapter,
|
||||
window: &MW,
|
||||
settings: &RendererSettings,
|
||||
) -> Self
|
||||
@ -128,22 +160,24 @@ impl Surface {
|
||||
MW: MapWindow + HeadedMapWindow,
|
||||
{
|
||||
let size = window.size();
|
||||
let surface_config = wgpu::SurfaceConfiguration {
|
||||
alpha_mode: CompositeAlphaMode::Auto,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: settings.texture_format,
|
||||
width: size.width(),
|
||||
height: size.height(),
|
||||
present_mode: settings.present_mode,
|
||||
};
|
||||
|
||||
let surface = unsafe { instance.create_surface(window.raw()) };
|
||||
debug!(
|
||||
"supported formats by adapter: {:?}",
|
||||
surface.get_supported_formats(adapter)
|
||||
);
|
||||
|
||||
let format = settings
|
||||
.texture_format
|
||||
.or_else(|| surface.get_supported_formats(adapter).first().cloned())
|
||||
.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
|
||||
|
||||
Self {
|
||||
size,
|
||||
head: Head::Headed(WindowHead {
|
||||
surface,
|
||||
surface_config,
|
||||
size,
|
||||
format,
|
||||
present_mode: settings.present_mode,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -159,17 +193,22 @@ impl Surface {
|
||||
// So we calculate padded_bytes_per_row by rounding unpadded_bytes_per_row
|
||||
// up to the next multiple of wgpu::COPY_BYTES_PER_ROW_ALIGNMENT.
|
||||
// https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding
|
||||
let buffer_dimensions =
|
||||
BufferDimensions::new(size.width() as usize, size.height() as usize);
|
||||
let buffer_dimensions = BufferDimensions::new(size);
|
||||
|
||||
// The output buffer lets us retrieve the data as an array
|
||||
let output_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("BufferedTextureHead buffer"),
|
||||
size: (buffer_dimensions.padded_bytes_per_row * buffer_dimensions.height) as u64,
|
||||
size: (buffer_dimensions.padded_bytes_per_row.get() * buffer_dimensions.height) as u64,
|
||||
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
// FIXME: Is this a sane default?
|
||||
let format = settings
|
||||
.texture_format
|
||||
.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
|
||||
|
||||
let texture_descriptor = wgpu::TextureDescriptor {
|
||||
label: Some("Surface texture"),
|
||||
size: wgpu::Extent3d {
|
||||
width: size.width(),
|
||||
@ -179,20 +218,29 @@ impl Surface {
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: settings.texture_format,
|
||||
format,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
});
|
||||
};
|
||||
let texture = device.create_texture(&texture_descriptor);
|
||||
|
||||
Self {
|
||||
size,
|
||||
head: Head::Headless(Arc::new(BufferedTextureHead {
|
||||
texture,
|
||||
texture_format: format,
|
||||
output_buffer,
|
||||
buffer_dimensions,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn surface_format(&self) -> wgpu::TextureFormat {
|
||||
match &self.head {
|
||||
Head::Headed(headed) => headed.format,
|
||||
Head::Headless(headless) => headless.texture_format,
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "create_view", skip_all)]
|
||||
pub fn create_view(&self, device: &wgpu::Device) -> TextureView {
|
||||
match &self.head {
|
||||
@ -261,9 +309,10 @@ impl Surface {
|
||||
}
|
||||
|
||||
impl HasChanged for WindowHead {
|
||||
/// Tuple of width and height
|
||||
type Criteria = (u32, u32);
|
||||
|
||||
fn has_changed(&self, criteria: &Self::Criteria) -> bool {
|
||||
self.surface_config.width != criteria.0 || self.surface_config.height != criteria.1
|
||||
self.size.width() != criteria.0 || self.size.height() != criteria.1
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +103,8 @@ impl Default for Msaa {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct RendererSettings {
|
||||
pub msaa: Msaa,
|
||||
pub texture_format: TextureFormat,
|
||||
/// Explicitly set a texture format or let the renderer automatically choose one
|
||||
pub texture_format: Option<TextureFormat>,
|
||||
pub depth_texture_format: TextureFormat,
|
||||
/// Present mode for surfaces if a surface is used.
|
||||
pub present_mode: PresentMode,
|
||||
@ -113,26 +114,7 @@ impl Default for RendererSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
msaa: Msaa::default(),
|
||||
// WebGPU
|
||||
#[cfg(all(target_arch = "wasm32", not(feature = "web-webgl")))]
|
||||
texture_format: wgpu::TextureFormat::Bgra8Unorm,
|
||||
// WebGL
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web-webgl"))]
|
||||
texture_format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
// Vulkan Android
|
||||
#[cfg(target_os = "android")]
|
||||
texture_format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
/// MacOS and iOS (Metal).
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
texture_format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||
/// For Vulkan/OpenGL
|
||||
#[cfg(not(any(
|
||||
target_os = "android",
|
||||
target_os = "macos",
|
||||
any(target_os = "macos", target_os = "ios"),
|
||||
target_arch = "wasm32"
|
||||
)))]
|
||||
texture_format: TextureFormat::Bgra8UnormSrgb,
|
||||
texture_format: None,
|
||||
|
||||
depth_texture_format: TextureFormat::Depth24PlusStencil8,
|
||||
present_mode: PresentMode::AutoVsync,
|
||||
|
||||
@ -63,7 +63,7 @@ impl Stage for ResourceStage {
|
||||
Some(Texture::new(
|
||||
Some("multisampling texture"),
|
||||
device,
|
||||
settings.texture_format,
|
||||
surface.surface_format(),
|
||||
size.width(),
|
||||
size.height(),
|
||||
settings.msaa,
|
||||
@ -96,7 +96,7 @@ impl Stage for ResourceStage {
|
||||
|
||||
state.tile_pipeline.initialize(|| {
|
||||
let tile_shader = shaders::TileShader {
|
||||
format: settings.texture_format,
|
||||
format: surface.surface_format(),
|
||||
};
|
||||
|
||||
let pipeline = TilePipeline::new(
|
||||
@ -120,7 +120,7 @@ impl Stage for ResourceStage {
|
||||
|
||||
state.mask_pipeline.initialize(|| {
|
||||
let mask_shader = shaders::TileMaskShader {
|
||||
format: settings.texture_format,
|
||||
format: surface.surface_format(),
|
||||
draw_colors: false,
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
//! Utilities for the window system.
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||
|
||||
/// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one.
|
||||
@ -31,23 +33,31 @@ pub trait MapWindowConfig: 'static {
|
||||
/// Window size with a width and an height in pixels.
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub struct WindowSize {
|
||||
width: u32,
|
||||
height: u32,
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
}
|
||||
|
||||
impl WindowSize {
|
||||
pub fn new(width: u32, height: u32) -> Option<Self> {
|
||||
if width == 0 || height == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self { width, height })
|
||||
Some(Self {
|
||||
width: NonZeroU32::new(width)?,
|
||||
height: NonZeroU32::new(height)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.width.get()
|
||||
}
|
||||
|
||||
pub fn width_non_zero(&self) -> NonZeroU32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.height.get()
|
||||
}
|
||||
|
||||
pub fn height_non_zero(&self) -> NonZeroU32 {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,10 @@
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
error::Error,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
|
||||
use js_sys::{Error as JSError, TypeError};
|
||||
use js_sys::TypeError;
|
||||
use maplibre::io::apc::{CallError, ProcedureError};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
@ -34,7 +33,7 @@ impl From<JsValue> for WebError {
|
||||
.as_string() else { return WebError::InvalidMessage; };
|
||||
|
||||
WebError::TypeError(message.into())
|
||||
} else if let Some(error) = value.dyn_ref::<JSError>() {
|
||||
} else if let Some(error) = value.dyn_ref::<js_sys::Error>() {
|
||||
let Some(message) = error
|
||||
.message()
|
||||
.as_string() else { return WebError::InvalidMessage; };
|
||||
@ -48,41 +47,25 @@ impl From<JsValue> for WebError {
|
||||
|
||||
/// Wraps several unrelated errors and implements Into<JSValue>. This should be used in Rust
|
||||
/// functions called from JS-land as return error type.
|
||||
#[derive(Debug)]
|
||||
pub enum WrappedError {
|
||||
ProcedureError(ProcedureError),
|
||||
CallError(CallError),
|
||||
WebError(WebError),
|
||||
#[derive(Error, Debug)]
|
||||
pub enum JSError {
|
||||
ProcedureError(#[from] ProcedureError),
|
||||
CallError(#[from] CallError),
|
||||
WebError(#[from] WebError),
|
||||
}
|
||||
|
||||
impl Display for WrappedError {
|
||||
impl Display for JSError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Error from Rust: {:?}", self)
|
||||
match self {
|
||||
JSError::ProcedureError(inner) => inner.fmt(f),
|
||||
JSError::CallError(inner) => inner.fmt(f),
|
||||
JSError::WebError(inner) => inner.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for WrappedError {}
|
||||
|
||||
impl From<WrappedError> for JsValue {
|
||||
fn from(val: WrappedError) -> Self {
|
||||
impl From<JSError> for JsValue {
|
||||
fn from(val: JSError) -> Self {
|
||||
JsValue::from_str(&val.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CallError> for WrappedError {
|
||||
fn from(e: CallError) -> Self {
|
||||
WrappedError::CallError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProcedureError> for WrappedError {
|
||||
fn from(e: ProcedureError) -> Self {
|
||||
WrappedError::ProcedureError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebError> for WrappedError {
|
||||
fn from(e: WebError) -> Self {
|
||||
WrappedError::WebError(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ use maplibre::{
|
||||
use maplibre_winit::{WinitEnvironment, WinitMapWindowConfig};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::{error::WrappedError, platform::http_client::WHATWGFetchHttpClient};
|
||||
use crate::{error::JSError, platform::http_client::WHATWGFetchHttpClient};
|
||||
|
||||
mod error;
|
||||
mod platform;
|
||||
@ -65,7 +65,7 @@ type CurrentEnvironment = WinitEnvironment<
|
||||
pub type MapType = Map<CurrentEnvironment>;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub async fn run_maplibre(new_worker: js_sys::Function) -> Result<(), WrappedError> {
|
||||
pub async fn run_maplibre(new_worker: js_sys::Function) -> Result<(), JSError> {
|
||||
let mut kernel_builder = KernelBuilder::new()
|
||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||
.with_http_client(WHATWGFetchHttpClient::new());
|
||||
|
||||
@ -2,11 +2,11 @@ use maplibre::io::apc::CallError;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
|
||||
use crate::{platform::multithreaded::pool::Work, WrappedError};
|
||||
use crate::{platform::multithreaded::pool::Work, JSError};
|
||||
|
||||
/// Entry point invoked by the worker.
|
||||
#[wasm_bindgen]
|
||||
pub async fn multithreaded_worker_entry(ptr: u32) -> Result<(), WrappedError> {
|
||||
pub async fn multithreaded_worker_entry(ptr: u32) -> Result<(), JSError> {
|
||||
let work = unsafe { Box::from_raw(ptr as *mut Work) };
|
||||
JsFuture::from(work.execute())
|
||||
.await
|
||||
|
||||
@ -103,15 +103,8 @@ impl Context<UsedTransferables, UsedHttpClient> for PassingContext {
|
||||
}
|
||||
}
|
||||
|
||||
type NewWorker = Box<dyn Fn() -> Result<Worker, WebError>>;
|
||||
pub type ReceivedType = RefCell<Vec<Message<UsedTransferables>>>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PassingAPCError {
|
||||
#[error("creating a worker failed")]
|
||||
Worker,
|
||||
}
|
||||
|
||||
pub struct PassingAsyncProcedureCall {
|
||||
workers: Vec<Worker>,
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ use thiserror::Error;
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
|
||||
use crate::{
|
||||
error::WrappedError,
|
||||
error::JSError,
|
||||
platform::singlethreaded::{
|
||||
apc::{MessageTag, ReceivedType},
|
||||
transferables::FlatBufferTransferable,
|
||||
@ -23,10 +23,7 @@ use crate::{
|
||||
|
||||
/// Entry point invoked by the worker.
|
||||
#[wasm_bindgen]
|
||||
pub async fn singlethreaded_worker_entry(
|
||||
procedure_ptr: u32,
|
||||
input: String,
|
||||
) -> Result<(), WrappedError> {
|
||||
pub async fn singlethreaded_worker_entry(procedure_ptr: u32, input: String) -> Result<(), JSError> {
|
||||
let procedure: AsyncProcedure<UsedContext> = unsafe { mem::transmute(procedure_ptr) };
|
||||
|
||||
let input =
|
||||
@ -50,7 +47,7 @@ pub struct DeserializeMessage;
|
||||
pub unsafe fn singlethreaded_main_entry(
|
||||
received_ptr: *const ReceivedType,
|
||||
in_transfer: js_sys::Array,
|
||||
) -> Result<(), WrappedError> {
|
||||
) -> Result<(), JSError> {
|
||||
let tag = in_transfer
|
||||
.get(0)
|
||||
.as_f64()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user