Merge branch 'master' into beacon
This commit is contained in:
commit
aaf396256e
284 changed files with 18747 additions and 15450 deletions
|
|
@ -1,21 +1,49 @@
|
|||
//! Connect a window with a renderer.
|
||||
use crate::core::{Color, Size};
|
||||
use crate::graphics;
|
||||
use crate::graphics::color;
|
||||
use crate::graphics::compositor;
|
||||
use crate::graphics::{Error, Viewport};
|
||||
use crate::{Backend, Primitive, Renderer, Settings};
|
||||
use crate::graphics::error;
|
||||
use crate::graphics::{self, Viewport};
|
||||
use crate::settings::{self, Settings};
|
||||
use crate::{Engine, Renderer};
|
||||
|
||||
/// A window graphics backend for iced powered by `wgpu`.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Compositor {
|
||||
settings: Settings,
|
||||
instance: wgpu::Instance,
|
||||
adapter: wgpu::Adapter,
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
format: wgpu::TextureFormat,
|
||||
alpha_mode: wgpu::CompositeAlphaMode,
|
||||
engine: Engine,
|
||||
settings: Settings,
|
||||
}
|
||||
|
||||
/// A compositor error.
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// The surface creation failed.
|
||||
#[error("the surface creation failed: {0}")]
|
||||
SurfaceCreationFailed(#[from] wgpu::CreateSurfaceError),
|
||||
/// The surface is not compatible.
|
||||
#[error("the surface is not compatible")]
|
||||
IncompatibleSurface,
|
||||
/// No adapter was found for the options requested.
|
||||
#[error("no adapter was found for the options requested: {0:?}")]
|
||||
NoAdapterFound(String),
|
||||
/// No device request succeeded.
|
||||
#[error("no device request succeeded: {0:?}")]
|
||||
RequestDeviceFailed(Vec<(wgpu::Limits, wgpu::RequestDeviceError)>),
|
||||
}
|
||||
|
||||
impl From<Error> for graphics::Error {
|
||||
fn from(error: Error) -> Self {
|
||||
Self::GraphicsAdapterNotFound {
|
||||
backend: "wgpu",
|
||||
reason: error::Reason::RequestFailed(error.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Compositor {
|
||||
|
|
@ -25,9 +53,9 @@ impl Compositor {
|
|||
pub async fn request<W: compositor::Window>(
|
||||
settings: Settings,
|
||||
compatible_window: Option<W>,
|
||||
) -> Option<Self> {
|
||||
) -> Result<Self, Error> {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: settings.internal_backend,
|
||||
backends: settings.backends,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
|
@ -36,7 +64,7 @@ impl Compositor {
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if log::max_level() >= log::LevelFilter::Info {
|
||||
let available_adapters: Vec<_> = instance
|
||||
.enumerate_adapters(settings.internal_backend)
|
||||
.enumerate_adapters(settings.backends)
|
||||
.iter()
|
||||
.map(wgpu::Adapter::get_info)
|
||||
.collect();
|
||||
|
|
@ -47,23 +75,27 @@ impl Compositor {
|
|||
let compatible_surface = compatible_window
|
||||
.and_then(|window| instance.create_surface(window).ok());
|
||||
|
||||
let adapter_options = wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::util::power_preference_from_env()
|
||||
.unwrap_or(if settings.antialiasing.is_none() {
|
||||
wgpu::PowerPreference::LowPower
|
||||
} else {
|
||||
wgpu::PowerPreference::HighPerformance
|
||||
}),
|
||||
compatible_surface: compatible_surface.as_ref(),
|
||||
force_fallback_adapter: false,
|
||||
};
|
||||
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::util::power_preference_from_env()
|
||||
.unwrap_or(if settings.antialiasing.is_none() {
|
||||
wgpu::PowerPreference::LowPower
|
||||
} else {
|
||||
wgpu::PowerPreference::HighPerformance
|
||||
}),
|
||||
compatible_surface: compatible_surface.as_ref(),
|
||||
force_fallback_adapter: false,
|
||||
})
|
||||
.await?;
|
||||
.request_adapter(&adapter_options)
|
||||
.await
|
||||
.ok_or(Error::NoAdapterFound(format!("{:?}", adapter_options)))?;
|
||||
|
||||
log::info!("Selected: {:#?}", adapter.get_info());
|
||||
|
||||
let (format, alpha_mode) =
|
||||
compatible_surface.as_ref().and_then(|surface| {
|
||||
let (format, alpha_mode) = compatible_surface
|
||||
.as_ref()
|
||||
.and_then(|surface| {
|
||||
let capabilities = surface.get_capabilities(&adapter);
|
||||
|
||||
let mut formats = capabilities.formats.iter().copied();
|
||||
|
|
@ -90,12 +122,17 @@ impl Compositor {
|
|||
.contains(&wgpu::CompositeAlphaMode::PostMultiplied)
|
||||
{
|
||||
wgpu::CompositeAlphaMode::PostMultiplied
|
||||
} else if alpha_modes
|
||||
.contains(&wgpu::CompositeAlphaMode::PreMultiplied)
|
||||
{
|
||||
wgpu::CompositeAlphaMode::PreMultiplied
|
||||
} else {
|
||||
wgpu::CompositeAlphaMode::Auto
|
||||
};
|
||||
|
||||
format.zip(Some(preferred_alpha))
|
||||
})?;
|
||||
})
|
||||
.ok_or(Error::IncompatibleSurface)?;
|
||||
|
||||
log::info!(
|
||||
"Selected format: {format:?} with alpha mode: {alpha_mode:?}"
|
||||
|
|
@ -109,74 +146,71 @@ impl Compositor {
|
|||
let limits =
|
||||
[wgpu::Limits::default(), wgpu::Limits::downlevel_defaults()];
|
||||
|
||||
let mut limits = limits.into_iter().map(|limits| wgpu::Limits {
|
||||
let limits = limits.into_iter().map(|limits| wgpu::Limits {
|
||||
max_bind_groups: 2,
|
||||
..limits
|
||||
});
|
||||
|
||||
let (device, queue) =
|
||||
loop {
|
||||
let required_limits = limits.next()?;
|
||||
let device = adapter.request_device(
|
||||
let mut errors = Vec::new();
|
||||
|
||||
for required_limits in limits {
|
||||
let result = adapter
|
||||
.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: Some(
|
||||
"iced_wgpu::window::compositor device descriptor",
|
||||
),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits,
|
||||
required_limits: required_limits.clone(),
|
||||
},
|
||||
None,
|
||||
).await.ok();
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Some(device) = device {
|
||||
break Some(device);
|
||||
match result {
|
||||
Ok((device, queue)) => {
|
||||
let engine = Engine::new(
|
||||
&adapter,
|
||||
&device,
|
||||
&queue,
|
||||
format,
|
||||
settings.antialiasing,
|
||||
);
|
||||
|
||||
return Ok(Compositor {
|
||||
instance,
|
||||
adapter,
|
||||
device,
|
||||
queue,
|
||||
format,
|
||||
alpha_mode,
|
||||
engine,
|
||||
settings,
|
||||
});
|
||||
}
|
||||
}?;
|
||||
Err(error) => {
|
||||
errors.push((required_limits, error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Compositor {
|
||||
instance,
|
||||
settings,
|
||||
adapter,
|
||||
device,
|
||||
queue,
|
||||
format,
|
||||
alpha_mode,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a new rendering [`Backend`] for this [`Compositor`].
|
||||
pub fn create_backend(&self) -> Backend {
|
||||
Backend::new(
|
||||
&self.adapter,
|
||||
&self.device,
|
||||
&self.queue,
|
||||
self.settings,
|
||||
self.format,
|
||||
)
|
||||
Err(Error::RequestDeviceFailed(errors))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [`Compositor`] and its [`Backend`] for the given [`Settings`] and
|
||||
/// window.
|
||||
pub fn new<W: compositor::Window>(
|
||||
/// Creates a [`Compositor`] with the given [`Settings`] and window.
|
||||
pub async fn new<W: compositor::Window>(
|
||||
settings: Settings,
|
||||
compatible_window: W,
|
||||
) -> Result<Compositor, Error> {
|
||||
let compositor = futures::executor::block_on(Compositor::request(
|
||||
settings,
|
||||
Some(compatible_window),
|
||||
))
|
||||
.ok_or(Error::GraphicsAdapterNotFound)?;
|
||||
|
||||
Ok(compositor)
|
||||
Compositor::request(settings, Some(compatible_window)).await
|
||||
}
|
||||
|
||||
/// Presents the given primitives with the given [`Compositor`] and [`Backend`].
|
||||
/// Presents the given primitives with the given [`Compositor`].
|
||||
pub fn present(
|
||||
compositor: &mut Compositor,
|
||||
backend: &mut Backend,
|
||||
renderer: &mut Renderer,
|
||||
surface: &mut wgpu::Surface<'static>,
|
||||
primitives: &[Primitive],
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Result<(), compositor::SurfaceError> {
|
||||
|
|
@ -192,19 +226,20 @@ pub fn present(
|
|||
.texture
|
||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
backend.present(
|
||||
renderer.present(
|
||||
&mut compositor.engine,
|
||||
&compositor.device,
|
||||
&compositor.queue,
|
||||
&mut encoder,
|
||||
Some(background_color),
|
||||
frame.texture.format(),
|
||||
view,
|
||||
primitives,
|
||||
viewport,
|
||||
);
|
||||
|
||||
// Submit work
|
||||
let _submission = compositor.queue.submit(Some(encoder.finish()));
|
||||
let _ = compositor.engine.submit(&compositor.queue, encoder);
|
||||
|
||||
// Present the frame
|
||||
frame.present();
|
||||
|
||||
Ok(())
|
||||
|
|
@ -225,20 +260,41 @@ pub fn present(
|
|||
}
|
||||
|
||||
impl graphics::Compositor for Compositor {
|
||||
type Settings = Settings;
|
||||
type Renderer = Renderer;
|
||||
type Surface = wgpu::Surface<'static>;
|
||||
|
||||
fn new<W: compositor::Window>(
|
||||
settings: Self::Settings,
|
||||
async fn with_backend<W: compositor::Window>(
|
||||
settings: graphics::Settings,
|
||||
compatible_window: W,
|
||||
) -> Result<Self, Error> {
|
||||
new(settings, compatible_window)
|
||||
backend: Option<&str>,
|
||||
) -> Result<Self, graphics::Error> {
|
||||
match backend {
|
||||
None | Some("wgpu") => {
|
||||
let mut settings = Settings::from(settings);
|
||||
|
||||
if let Some(backends) = wgpu::util::backend_bits_from_env() {
|
||||
settings.backends = backends;
|
||||
}
|
||||
|
||||
if let Some(present_mode) = settings::present_mode_from_env() {
|
||||
settings.present_mode = present_mode;
|
||||
}
|
||||
|
||||
Ok(new(settings, compatible_window).await?)
|
||||
}
|
||||
Some(backend) => Err(graphics::Error::GraphicsAdapterNotFound {
|
||||
backend: "wgpu",
|
||||
reason: error::Reason::DidNotMatch {
|
||||
preferred_backend: backend.to_owned(),
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_renderer(&self) -> Self::Renderer {
|
||||
Renderer::new(
|
||||
self.create_backend(),
|
||||
&self.device,
|
||||
&self.engine,
|
||||
self.settings.default_font,
|
||||
self.settings.default_text_size,
|
||||
)
|
||||
|
|
@ -278,7 +334,7 @@ impl graphics::Compositor for Compositor {
|
|||
height,
|
||||
alpha_mode: self.alpha_mode,
|
||||
view_formats: vec![],
|
||||
desired_maximum_frame_latency: 2,
|
||||
desired_maximum_frame_latency: 1,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -299,16 +355,7 @@ impl graphics::Compositor for Compositor {
|
|||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Result<(), compositor::SurfaceError> {
|
||||
renderer.with_primitives(|backend, primitives| {
|
||||
present(
|
||||
self,
|
||||
backend,
|
||||
surface,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
)
|
||||
})
|
||||
present(self, renderer, surface, viewport, background_color)
|
||||
}
|
||||
|
||||
fn screenshot(
|
||||
|
|
@ -318,9 +365,7 @@ impl graphics::Compositor for Compositor {
|
|||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
renderer.with_primitives(|backend, primitives| {
|
||||
screenshot(self, backend, primitives, viewport, background_color)
|
||||
})
|
||||
screenshot(self, renderer, viewport, background_color)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,18 +373,11 @@ impl graphics::Compositor for Compositor {
|
|||
///
|
||||
/// Returns RGBA bytes of the texture data.
|
||||
pub fn screenshot(
|
||||
compositor: &Compositor,
|
||||
backend: &mut Backend,
|
||||
primitives: &[Primitive],
|
||||
compositor: &mut Compositor,
|
||||
renderer: &mut Renderer,
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
let mut encoder = compositor.device.create_command_encoder(
|
||||
&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("iced_wgpu.offscreen.encoder"),
|
||||
},
|
||||
);
|
||||
|
||||
let dimensions = BufferDimensions::new(viewport.physical_size());
|
||||
|
||||
let texture_extent = wgpu::Extent3d {
|
||||
|
|
@ -363,14 +401,20 @@ pub fn screenshot(
|
|||
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
backend.present(
|
||||
let mut encoder = compositor.device.create_command_encoder(
|
||||
&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("iced_wgpu.offscreen.encoder"),
|
||||
},
|
||||
);
|
||||
|
||||
renderer.present(
|
||||
&mut compositor.engine,
|
||||
&compositor.device,
|
||||
&compositor.queue,
|
||||
&mut encoder,
|
||||
Some(background_color),
|
||||
texture.format(),
|
||||
&view,
|
||||
primitives,
|
||||
viewport,
|
||||
);
|
||||
|
||||
|
|
@ -407,7 +451,7 @@ pub fn screenshot(
|
|||
texture_extent,
|
||||
);
|
||||
|
||||
let index = compositor.queue.submit(Some(encoder.finish()));
|
||||
let index = compositor.engine.submit(&compositor.queue, encoder);
|
||||
|
||||
let slice = output_buffer.slice(..);
|
||||
slice.map_async(wgpu::MapMode::Read, |_| {});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue