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) => {
|
Head::Headless(buffered_texture) => {
|
||||||
let size = surface.size();
|
let size = surface.size();
|
||||||
command_encoder.copy_texture_to_buffer(
|
command_encoder.copy_texture_to_buffer(
|
||||||
buffered_texture.texture.as_image_copy(),
|
buffered_texture.copy_texture(),
|
||||||
wgpu::ImageCopyBuffer {
|
wgpu::ImageCopyBuffer {
|
||||||
buffer: &buffered_texture.output_buffer,
|
buffer: &buffered_texture.buffer(),
|
||||||
layout: wgpu::ImageDataLayout {
|
layout: wgpu::ImageDataLayout {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
bytes_per_row: Some(
|
bytes_per_row: Some(buffered_texture.bytes_per_row()),
|
||||||
std::num::NonZeroU32::new(
|
|
||||||
buffered_texture.buffer_dimensions.padded_bytes_per_row as u32,
|
|
||||||
)
|
|
||||||
.unwrap(), // TODO: remove unwrap
|
|
||||||
),
|
|
||||||
rows_per_image: None,
|
rows_per_image: None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wgpu::Extent3d {
|
wgpu::Extent3d {
|
||||||
width: size.width() as u32,
|
width: size.width(),
|
||||||
height: size.height() as u32,
|
height: size.height(),
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -12,6 +12,7 @@ use crate::{
|
|||||||
InitializationResult, InitializedRenderer, RendererBuilder, UninitializedRenderer,
|
InitializationResult, InitializedRenderer, RendererBuilder, UninitializedRenderer,
|
||||||
},
|
},
|
||||||
create_default_render_graph,
|
create_default_render_graph,
|
||||||
|
error::RenderError,
|
||||||
graph::RenderGraphError,
|
graph::RenderGraphError,
|
||||||
register_default_render_stages,
|
register_default_render_stages,
|
||||||
},
|
},
|
||||||
@ -30,7 +31,7 @@ pub enum MapError {
|
|||||||
#[error("initializing render graph failed")]
|
#[error("initializing render graph failed")]
|
||||||
RenderGraphInit(RenderGraphError),
|
RenderGraphInit(RenderGraphError),
|
||||||
#[error("initializing device failed")]
|
#[error("initializing device failed")]
|
||||||
DeviceInit,
|
DeviceInit(RenderError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MapContextState {
|
pub enum MapContextState {
|
||||||
@ -92,7 +93,7 @@ where
|
|||||||
.build()
|
.build()
|
||||||
.initialize_renderer::<E::MapWindowConfig>(&self.window)
|
.initialize_renderer::<E::MapWindowConfig>(&self.window)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| MapError::DeviceInit)?;
|
.map_err(|e| MapError::DeviceInit(e))?;
|
||||||
|
|
||||||
let window_size = self.window.size();
|
let window_size = self.window.size();
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,15 @@
|
|||||||
use std::fmt;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::render::graph::RenderGraphError;
|
use crate::render::graph::RenderGraphError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum RenderError {
|
pub enum RenderError {
|
||||||
Surface(wgpu::SurfaceError),
|
#[error("error in surface")]
|
||||||
Graph(RenderGraphError),
|
Surface(#[from] wgpu::SurfaceError),
|
||||||
Device(wgpu::RequestDeviceError),
|
#[error("error in render graph")]
|
||||||
}
|
Graph(#[from] RenderGraphError),
|
||||||
|
#[error("error while requesting device")]
|
||||||
impl fmt::Display for RenderError {
|
RequestDevice(#[from] wgpu::RequestDeviceError),
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderError {
|
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::{
|
use crate::{
|
||||||
render::{
|
render::{
|
||||||
|
error::RenderError,
|
||||||
graph::{EmptyNode, RenderGraph, RenderGraphError},
|
graph::{EmptyNode, RenderGraph, RenderGraphError},
|
||||||
main_pass::{MainPassDriverNode, MainPassNode},
|
main_pass::{MainPassDriverNode, MainPassNode},
|
||||||
},
|
},
|
||||||
@ -142,7 +143,7 @@ pub struct Renderer {
|
|||||||
pub instance: wgpu::Instance,
|
pub instance: wgpu::Instance,
|
||||||
pub device: Arc<wgpu::Device>, // TODO: Arc is needed for headless rendering. Is there a simpler solution?
|
pub device: Arc<wgpu::Device>, // TODO: Arc is needed for headless rendering. Is there a simpler solution?
|
||||||
pub queue: wgpu::Queue,
|
pub queue: wgpu::Queue,
|
||||||
pub adapter_info: wgpu::AdapterInfo,
|
pub adapter: wgpu::Adapter,
|
||||||
|
|
||||||
pub wgpu_settings: WgpuSettings,
|
pub wgpu_settings: WgpuSettings,
|
||||||
pub settings: RendererSettings,
|
pub settings: RendererSettings,
|
||||||
@ -157,30 +158,27 @@ impl Renderer {
|
|||||||
window: &MW,
|
window: &MW,
|
||||||
wgpu_settings: WgpuSettings,
|
wgpu_settings: WgpuSettings,
|
||||||
settings: RendererSettings,
|
settings: RendererSettings,
|
||||||
) -> Result<Self, wgpu::RequestDeviceError>
|
) -> Result<Self, RenderError>
|
||||||
where
|
where
|
||||||
MW: MapWindow + HeadedMapWindow,
|
MW: MapWindow + HeadedMapWindow,
|
||||||
{
|
{
|
||||||
let instance = wgpu::Instance::new(wgpu_settings.backends.unwrap_or(wgpu::Backends::all()));
|
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() {
|
let (adapter, device, queue) = Self::request_device(
|
||||||
Head::Headed(window_head) => Some(window_head.surface()),
|
|
||||||
Head::Headless(_) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (device, queue, adapter_info) = Self::request_device(
|
|
||||||
&instance,
|
&instance,
|
||||||
&wgpu_settings,
|
&wgpu_settings,
|
||||||
&wgpu::RequestAdapterOptions {
|
&wgpu::RequestAdapterOptions {
|
||||||
power_preference: wgpu_settings.power_preference,
|
power_preference: wgpu_settings.power_preference,
|
||||||
force_fallback_adapter: false,
|
force_fallback_adapter: false,
|
||||||
compatible_surface,
|
compatible_surface: Some(&surface),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let surface = Surface::from_surface(surface, &adapter, window, &settings);
|
||||||
|
|
||||||
match surface.head() {
|
match surface.head() {
|
||||||
Head::Headed(window) => window.configure(&device),
|
Head::Headed(window) => window.configure(&device),
|
||||||
Head::Headless(_) => {}
|
Head::Headless(_) => {}
|
||||||
@ -190,7 +188,7 @@ impl Renderer {
|
|||||||
instance,
|
instance,
|
||||||
device: Arc::new(device),
|
device: Arc::new(device),
|
||||||
queue,
|
queue,
|
||||||
adapter_info,
|
adapter,
|
||||||
wgpu_settings,
|
wgpu_settings,
|
||||||
settings,
|
settings,
|
||||||
state: RenderState::new(surface),
|
state: RenderState::new(surface),
|
||||||
@ -201,13 +199,13 @@ impl Renderer {
|
|||||||
window: &MW,
|
window: &MW,
|
||||||
wgpu_settings: WgpuSettings,
|
wgpu_settings: WgpuSettings,
|
||||||
settings: RendererSettings,
|
settings: RendererSettings,
|
||||||
) -> Result<Self, wgpu::RequestDeviceError>
|
) -> Result<Self, RenderError>
|
||||||
where
|
where
|
||||||
MW: MapWindow,
|
MW: MapWindow,
|
||||||
{
|
{
|
||||||
let instance = wgpu::Instance::new(wgpu_settings.backends.unwrap_or(wgpu::Backends::all()));
|
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,
|
&instance,
|
||||||
&wgpu_settings,
|
&wgpu_settings,
|
||||||
&wgpu::RequestAdapterOptions {
|
&wgpu::RequestAdapterOptions {
|
||||||
@ -224,7 +222,7 @@ impl Renderer {
|
|||||||
instance,
|
instance,
|
||||||
device: Arc::new(device),
|
device: Arc::new(device),
|
||||||
queue,
|
queue,
|
||||||
adapter_info,
|
adapter,
|
||||||
wgpu_settings,
|
wgpu_settings,
|
||||||
settings,
|
settings,
|
||||||
state: RenderState::new(surface),
|
state: RenderState::new(surface),
|
||||||
@ -240,7 +238,7 @@ impl Renderer {
|
|||||||
instance: &wgpu::Instance,
|
instance: &wgpu::Instance,
|
||||||
settings: &WgpuSettings,
|
settings: &WgpuSettings,
|
||||||
request_adapter_options: &wgpu::RequestAdapterOptions<'_>,
|
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
|
let adapter = instance
|
||||||
.request_adapter(request_adapter_options)
|
.request_adapter(request_adapter_options)
|
||||||
.await
|
.await
|
||||||
@ -384,7 +382,7 @@ impl Renderer {
|
|||||||
trace_path,
|
trace_path,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok((device, queue, adapter_info))
|
Ok((adapter, device, queue))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn instance(&self) -> &wgpu::Instance {
|
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
|
//! 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.
|
//! 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::{
|
use crate::{
|
||||||
render::{eventually::HasChanged, resource::texture::TextureView, settings::RendererSettings},
|
render::{eventually::HasChanged, resource::texture::TextureView, settings::RendererSettings},
|
||||||
@ -11,41 +11,54 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub struct BufferDimensions {
|
pub struct BufferDimensions {
|
||||||
pub width: usize,
|
pub width: u32,
|
||||||
pub height: usize,
|
pub height: u32,
|
||||||
pub unpadded_bytes_per_row: usize,
|
pub unpadded_bytes_per_row: NonZeroU32,
|
||||||
pub padded_bytes_per_row: usize,
|
pub padded_bytes_per_row: NonZeroU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufferDimensions {
|
impl BufferDimensions {
|
||||||
fn new(width: usize, height: usize) -> Self {
|
fn new(size: WindowSize) -> Self {
|
||||||
let bytes_per_pixel = size_of::<u32>();
|
let bytes_per_pixel = size_of::<u32>() as u32;
|
||||||
let unpadded_bytes_per_row = width * bytes_per_pixel;
|
let unpadded_bytes_per_row = size.width() * bytes_per_pixel;
|
||||||
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize;
|
|
||||||
|
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_padding = (align - unpadded_bytes_per_row % align) % align;
|
||||||
let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
|
let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
|
||||||
Self {
|
Self {
|
||||||
width,
|
width: size.width(),
|
||||||
height,
|
height: size.height(),
|
||||||
unpadded_bytes_per_row,
|
unpadded_bytes_per_row: NonZeroU32::new(unpadded_bytes_per_row)
|
||||||
padded_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 {
|
pub struct WindowHead {
|
||||||
surface: wgpu::Surface,
|
surface: wgpu::Surface,
|
||||||
surface_config: wgpu::SurfaceConfiguration,
|
size: WindowSize,
|
||||||
|
format: wgpu::TextureFormat,
|
||||||
|
present_mode: wgpu::PresentMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowHead {
|
impl WindowHead {
|
||||||
pub fn resize_and_configure(&mut self, width: u32, height: u32, device: &wgpu::Device) {
|
pub fn resize_and_configure(&mut self, width: u32, height: u32, device: &wgpu::Device) {
|
||||||
self.surface_config.height = width;
|
self.size = WindowSize::new(width, height).unwrap();
|
||||||
self.surface_config.width = height;
|
self.configure(device);
|
||||||
self.surface.configure(device, &self.surface_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(&self, device: &wgpu::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)
|
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()) };
|
self.surface = unsafe { instance.create_surface(window.raw()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn surface(&self) -> &wgpu::Surface {
|
pub fn surface(&self) -> &wgpu::Surface {
|
||||||
&self.surface
|
&self.surface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferedTextureHead {
|
pub struct BufferedTextureHead {
|
||||||
pub texture: wgpu::Texture,
|
texture: wgpu::Texture,
|
||||||
pub output_buffer: wgpu::Buffer,
|
texture_format: wgpu::TextureFormat,
|
||||||
pub buffer_dimensions: BufferDimensions,
|
output_buffer: wgpu::Buffer,
|
||||||
|
buffer_dimensions: BufferDimensions,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "headless")]
|
#[cfg(feature = "headless")]
|
||||||
@ -95,17 +110,33 @@ impl BufferedTextureHead {
|
|||||||
let mut png_writer = png_encoder
|
let mut png_writer = png_encoder
|
||||||
.write_header()
|
.write_header()
|
||||||
.unwrap() // TODO: Remove unwrap
|
.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
|
.unwrap(); // TODO: Remove unwrap
|
||||||
|
|
||||||
// from the padded_buffer we write just the unpadded bytes into the image
|
// 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
|
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
|
.unwrap(); // TODO: Remove unwrap
|
||||||
}
|
}
|
||||||
png_writer.finish().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 {
|
pub enum Head {
|
||||||
@ -119,8 +150,9 @@ pub struct Surface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
pub fn from_window<MW>(
|
pub fn from_surface<MW>(
|
||||||
instance: &wgpu::Instance,
|
surface: wgpu::Surface,
|
||||||
|
adapter: &wgpu::Adapter,
|
||||||
window: &MW,
|
window: &MW,
|
||||||
settings: &RendererSettings,
|
settings: &RendererSettings,
|
||||||
) -> Self
|
) -> Self
|
||||||
@ -128,22 +160,24 @@ impl Surface {
|
|||||||
MW: MapWindow + HeadedMapWindow,
|
MW: MapWindow + HeadedMapWindow,
|
||||||
{
|
{
|
||||||
let size = window.size();
|
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 {
|
Self {
|
||||||
size,
|
size,
|
||||||
head: Head::Headed(WindowHead {
|
head: Head::Headed(WindowHead {
|
||||||
surface,
|
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
|
// 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.
|
// up to the next multiple of wgpu::COPY_BYTES_PER_ROW_ALIGNMENT.
|
||||||
// https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding
|
// https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding
|
||||||
let buffer_dimensions =
|
let buffer_dimensions = BufferDimensions::new(size);
|
||||||
BufferDimensions::new(size.width() as usize, size.height() as usize);
|
|
||||||
// The output buffer lets us retrieve the data as an array
|
// The output buffer lets us retrieve the data as an array
|
||||||
let output_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let output_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("BufferedTextureHead buffer"),
|
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,
|
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
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"),
|
label: Some("Surface texture"),
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: size.width(),
|
width: size.width(),
|
||||||
@ -179,20 +218,29 @@ impl Surface {
|
|||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: settings.texture_format,
|
format,
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||||
});
|
};
|
||||||
|
let texture = device.create_texture(&texture_descriptor);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
size,
|
size,
|
||||||
head: Head::Headless(Arc::new(BufferedTextureHead {
|
head: Head::Headless(Arc::new(BufferedTextureHead {
|
||||||
texture,
|
texture,
|
||||||
|
texture_format: format,
|
||||||
output_buffer,
|
output_buffer,
|
||||||
buffer_dimensions,
|
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)]
|
#[tracing::instrument(name = "create_view", skip_all)]
|
||||||
pub fn create_view(&self, device: &wgpu::Device) -> TextureView {
|
pub fn create_view(&self, device: &wgpu::Device) -> TextureView {
|
||||||
match &self.head {
|
match &self.head {
|
||||||
@ -261,9 +309,10 @@ impl Surface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HasChanged for WindowHead {
|
impl HasChanged for WindowHead {
|
||||||
|
/// Tuple of width and height
|
||||||
type Criteria = (u32, u32);
|
type Criteria = (u32, u32);
|
||||||
|
|
||||||
fn has_changed(&self, criteria: &Self::Criteria) -> bool {
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct RendererSettings {
|
pub struct RendererSettings {
|
||||||
pub msaa: Msaa,
|
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,
|
pub depth_texture_format: TextureFormat,
|
||||||
/// Present mode for surfaces if a surface is used.
|
/// Present mode for surfaces if a surface is used.
|
||||||
pub present_mode: PresentMode,
|
pub present_mode: PresentMode,
|
||||||
@ -113,26 +114,7 @@ impl Default for RendererSettings {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
msaa: Msaa::default(),
|
msaa: Msaa::default(),
|
||||||
// WebGPU
|
texture_format: None,
|
||||||
#[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,
|
|
||||||
|
|
||||||
depth_texture_format: TextureFormat::Depth24PlusStencil8,
|
depth_texture_format: TextureFormat::Depth24PlusStencil8,
|
||||||
present_mode: PresentMode::AutoVsync,
|
present_mode: PresentMode::AutoVsync,
|
||||||
|
|||||||
@ -63,7 +63,7 @@ impl Stage for ResourceStage {
|
|||||||
Some(Texture::new(
|
Some(Texture::new(
|
||||||
Some("multisampling texture"),
|
Some("multisampling texture"),
|
||||||
device,
|
device,
|
||||||
settings.texture_format,
|
surface.surface_format(),
|
||||||
size.width(),
|
size.width(),
|
||||||
size.height(),
|
size.height(),
|
||||||
settings.msaa,
|
settings.msaa,
|
||||||
@ -96,7 +96,7 @@ impl Stage for ResourceStage {
|
|||||||
|
|
||||||
state.tile_pipeline.initialize(|| {
|
state.tile_pipeline.initialize(|| {
|
||||||
let tile_shader = shaders::TileShader {
|
let tile_shader = shaders::TileShader {
|
||||||
format: settings.texture_format,
|
format: surface.surface_format(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let pipeline = TilePipeline::new(
|
let pipeline = TilePipeline::new(
|
||||||
@ -120,7 +120,7 @@ impl Stage for ResourceStage {
|
|||||||
|
|
||||||
state.mask_pipeline.initialize(|| {
|
state.mask_pipeline.initialize(|| {
|
||||||
let mask_shader = shaders::TileMaskShader {
|
let mask_shader = shaders::TileMaskShader {
|
||||||
format: settings.texture_format,
|
format: surface.surface_format(),
|
||||||
draw_colors: false,
|
draw_colors: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
//! Utilities for the window system.
|
//! Utilities for the window system.
|
||||||
|
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||||
|
|
||||||
/// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one.
|
/// 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.
|
/// Window size with a width and an height in pixels.
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct WindowSize {
|
pub struct WindowSize {
|
||||||
width: u32,
|
width: NonZeroU32,
|
||||||
height: u32,
|
height: NonZeroU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowSize {
|
impl WindowSize {
|
||||||
pub fn new(width: u32, height: u32) -> Option<Self> {
|
pub fn new(width: u32, height: u32) -> Option<Self> {
|
||||||
if width == 0 || height == 0 {
|
Some(Self {
|
||||||
return None;
|
width: NonZeroU32::new(width)?,
|
||||||
}
|
height: NonZeroU32::new(height)?,
|
||||||
|
})
|
||||||
Some(Self { width, height })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> u32 {
|
pub fn width(&self) -> u32 {
|
||||||
|
self.width.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width_non_zero(&self) -> NonZeroU32 {
|
||||||
self.width
|
self.width
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self) -> u32 {
|
pub fn height(&self) -> u32 {
|
||||||
|
self.height.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height_non_zero(&self) -> NonZeroU32 {
|
||||||
self.height
|
self.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
error::Error,
|
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use js_sys::{Error as JSError, TypeError};
|
use js_sys::TypeError;
|
||||||
use maplibre::io::apc::{CallError, ProcedureError};
|
use maplibre::io::apc::{CallError, ProcedureError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
@ -34,7 +33,7 @@ impl From<JsValue> for WebError {
|
|||||||
.as_string() else { return WebError::InvalidMessage; };
|
.as_string() else { return WebError::InvalidMessage; };
|
||||||
|
|
||||||
WebError::TypeError(message.into())
|
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
|
let Some(message) = error
|
||||||
.message()
|
.message()
|
||||||
.as_string() else { return WebError::InvalidMessage; };
|
.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
|
/// Wraps several unrelated errors and implements Into<JSValue>. This should be used in Rust
|
||||||
/// functions called from JS-land as return error type.
|
/// functions called from JS-land as return error type.
|
||||||
#[derive(Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum WrappedError {
|
pub enum JSError {
|
||||||
ProcedureError(ProcedureError),
|
ProcedureError(#[from] ProcedureError),
|
||||||
CallError(CallError),
|
CallError(#[from] CallError),
|
||||||
WebError(WebError),
|
WebError(#[from] WebError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for WrappedError {
|
impl Display for JSError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
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<JSError> for JsValue {
|
||||||
|
fn from(val: JSError) -> Self {
|
||||||
impl From<WrappedError> for JsValue {
|
|
||||||
fn from(val: WrappedError) -> Self {
|
|
||||||
JsValue::from_str(&val.to_string())
|
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 maplibre_winit::{WinitEnvironment, WinitMapWindowConfig};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use crate::{error::WrappedError, platform::http_client::WHATWGFetchHttpClient};
|
use crate::{error::JSError, platform::http_client::WHATWGFetchHttpClient};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod platform;
|
mod platform;
|
||||||
@ -65,7 +65,7 @@ type CurrentEnvironment = WinitEnvironment<
|
|||||||
pub type MapType = Map<CurrentEnvironment>;
|
pub type MapType = Map<CurrentEnvironment>;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[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()
|
let mut kernel_builder = KernelBuilder::new()
|
||||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||||
.with_http_client(WHATWGFetchHttpClient::new());
|
.with_http_client(WHATWGFetchHttpClient::new());
|
||||||
|
|||||||
@ -2,11 +2,11 @@ use maplibre::io::apc::CallError;
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
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.
|
/// Entry point invoked by the worker.
|
||||||
#[wasm_bindgen]
|
#[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) };
|
let work = unsafe { Box::from_raw(ptr as *mut Work) };
|
||||||
JsFuture::from(work.execute())
|
JsFuture::from(work.execute())
|
||||||
.await
|
.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>>>;
|
pub type ReceivedType = RefCell<Vec<Message<UsedTransferables>>>;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum PassingAPCError {
|
|
||||||
#[error("creating a worker failed")]
|
|
||||||
Worker,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PassingAsyncProcedureCall {
|
pub struct PassingAsyncProcedureCall {
|
||||||
workers: Vec<Worker>,
|
workers: Vec<Worker>,
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use thiserror::Error;
|
|||||||
use wasm_bindgen::{prelude::*, JsCast};
|
use wasm_bindgen::{prelude::*, JsCast};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::WrappedError,
|
error::JSError,
|
||||||
platform::singlethreaded::{
|
platform::singlethreaded::{
|
||||||
apc::{MessageTag, ReceivedType},
|
apc::{MessageTag, ReceivedType},
|
||||||
transferables::FlatBufferTransferable,
|
transferables::FlatBufferTransferable,
|
||||||
@ -23,10 +23,7 @@ use crate::{
|
|||||||
|
|
||||||
/// Entry point invoked by the worker.
|
/// Entry point invoked by the worker.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn singlethreaded_worker_entry(
|
pub async fn singlethreaded_worker_entry(procedure_ptr: u32, input: String) -> Result<(), JSError> {
|
||||||
procedure_ptr: u32,
|
|
||||||
input: String,
|
|
||||||
) -> Result<(), WrappedError> {
|
|
||||||
let procedure: AsyncProcedure<UsedContext> = unsafe { mem::transmute(procedure_ptr) };
|
let procedure: AsyncProcedure<UsedContext> = unsafe { mem::transmute(procedure_ptr) };
|
||||||
|
|
||||||
let input =
|
let input =
|
||||||
@ -50,7 +47,7 @@ pub struct DeserializeMessage;
|
|||||||
pub unsafe fn singlethreaded_main_entry(
|
pub unsafe fn singlethreaded_main_entry(
|
||||||
received_ptr: *const ReceivedType,
|
received_ptr: *const ReceivedType,
|
||||||
in_transfer: js_sys::Array,
|
in_transfer: js_sys::Array,
|
||||||
) -> Result<(), WrappedError> {
|
) -> Result<(), JSError> {
|
||||||
let tag = in_transfer
|
let tag = in_transfer
|
||||||
.get(0)
|
.get(0)
|
||||||
.as_f64()
|
.as_f64()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user