Introduce custom backend-specific primitives
This commit is contained in:
parent
8d65e40a11
commit
0ae1baa37b
28 changed files with 618 additions and 263 deletions
|
|
@ -100,26 +100,28 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
|
|||
background_color: Color,
|
||||
overlay: &[T],
|
||||
) -> Result<(), SurfaceError> {
|
||||
renderer.with_primitives(|backend, primitives| {
|
||||
match (self, backend, surface) {
|
||||
(
|
||||
Self::TinySkia(_compositor),
|
||||
crate::Backend::TinySkia(backend),
|
||||
Surface::TinySkia(surface),
|
||||
) => iced_tiny_skia::window::compositor::present(
|
||||
match (self, renderer, surface) {
|
||||
(
|
||||
Self::TinySkia(_compositor),
|
||||
crate::Renderer::TinySkia(renderer),
|
||||
Surface::TinySkia(surface),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_tiny_skia::window::compositor::present(
|
||||
backend,
|
||||
surface,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
overlay,
|
||||
),
|
||||
#[cfg(feature = "wgpu")]
|
||||
(
|
||||
Self::Wgpu(compositor),
|
||||
crate::Backend::Wgpu(backend),
|
||||
Surface::Wgpu(surface),
|
||||
) => iced_wgpu::window::compositor::present(
|
||||
)
|
||||
}),
|
||||
#[cfg(feature = "wgpu")]
|
||||
(
|
||||
Self::Wgpu(compositor),
|
||||
crate::Renderer::Wgpu(renderer),
|
||||
Surface::Wgpu(surface),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_wgpu::window::compositor::present(
|
||||
compositor,
|
||||
backend,
|
||||
surface,
|
||||
|
|
@ -127,14 +129,14 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
|
|||
viewport,
|
||||
background_color,
|
||||
overlay,
|
||||
),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided renderer or surface are not compatible \
|
||||
)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided renderer or surface are not compatible \
|
||||
with the compositor."
|
||||
),
|
||||
}
|
||||
})
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn screenshot<T: AsRef<str>>(
|
||||
|
|
@ -145,12 +147,27 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
|
|||
background_color: Color,
|
||||
overlay: &[T],
|
||||
) -> Vec<u8> {
|
||||
renderer.with_primitives(|backend, primitives| match (self, backend, surface) {
|
||||
(Self::TinySkia(_compositor), crate::Backend::TinySkia(backend), Surface::TinySkia(surface)) => {
|
||||
iced_tiny_skia::window::compositor::screenshot(surface, backend, primitives, viewport, background_color, overlay)
|
||||
},
|
||||
match (self, renderer, surface) {
|
||||
(
|
||||
Self::TinySkia(_compositor),
|
||||
Renderer::TinySkia(renderer),
|
||||
Surface::TinySkia(surface),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_tiny_skia::window::compositor::screenshot(
|
||||
surface,
|
||||
backend,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
overlay,
|
||||
)
|
||||
}),
|
||||
#[cfg(feature = "wgpu")]
|
||||
(Self::Wgpu(compositor), crate::Backend::Wgpu(backend), Surface::Wgpu(_)) => {
|
||||
(
|
||||
Self::Wgpu(compositor),
|
||||
Renderer::Wgpu(renderer),
|
||||
Surface::Wgpu(_),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_wgpu::window::compositor::screenshot(
|
||||
compositor,
|
||||
backend,
|
||||
|
|
@ -159,12 +176,13 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
|
|||
background_color,
|
||||
overlay,
|
||||
)
|
||||
},
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided renderer or backend are not compatible with the compositor."
|
||||
"The provided renderer or backend are not compatible \
|
||||
with the compositor."
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +233,7 @@ impl Candidate {
|
|||
|
||||
Ok((
|
||||
Compositor::TinySkia(compositor),
|
||||
Renderer::new(crate::Backend::TinySkia(backend)),
|
||||
Renderer::TinySkia(iced_tiny_skia::Renderer::new(backend)),
|
||||
))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
|
|
@ -232,7 +250,7 @@ impl Candidate {
|
|||
|
||||
Ok((
|
||||
Compositor::Wgpu(compositor),
|
||||
Renderer::new(crate::Backend::Wgpu(backend)),
|
||||
Renderer::Wgpu(iced_wgpu::Renderer::new(backend)),
|
||||
))
|
||||
}
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ mod cache;
|
|||
pub use cache::Cache;
|
||||
|
||||
use crate::core::{Point, Rectangle, Size, Vector};
|
||||
use crate::graphics::geometry::{Fill, Geometry, Path, Stroke, Text};
|
||||
use crate::Backend;
|
||||
use crate::graphics::geometry::{Fill, Path, Stroke, Text};
|
||||
use crate::Renderer;
|
||||
|
||||
pub enum Frame {
|
||||
TinySkia(iced_tiny_skia::geometry::Frame),
|
||||
|
|
@ -12,6 +12,12 @@ pub enum Frame {
|
|||
Wgpu(iced_wgpu::geometry::Frame),
|
||||
}
|
||||
|
||||
pub enum Geometry {
|
||||
TinySkia(iced_tiny_skia::Primitive),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::Primitive),
|
||||
}
|
||||
|
||||
macro_rules! delegate {
|
||||
($frame:expr, $name:ident, $body:expr) => {
|
||||
match $frame {
|
||||
|
|
@ -23,13 +29,13 @@ macro_rules! delegate {
|
|||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new<Theme>(renderer: &crate::Renderer<Theme>, size: Size) -> Self {
|
||||
match renderer.backend() {
|
||||
Backend::TinySkia(_) => {
|
||||
pub fn new<Theme>(renderer: &Renderer<Theme>, size: Size) -> Self {
|
||||
match renderer {
|
||||
Renderer::TinySkia(_) => {
|
||||
Frame::TinySkia(iced_tiny_skia::geometry::Frame::new(size))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Backend::Wgpu(_) => {
|
||||
Renderer::Wgpu(_) => {
|
||||
Frame::Wgpu(iced_wgpu::geometry::Frame::new(size))
|
||||
}
|
||||
}
|
||||
|
|
@ -169,6 +175,10 @@ impl Frame {
|
|||
}
|
||||
|
||||
pub fn into_geometry(self) -> Geometry {
|
||||
Geometry(delegate!(self, frame, frame.into_primitive()))
|
||||
match self {
|
||||
Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use crate::core::Size;
|
||||
use crate::geometry::{Frame, Geometry};
|
||||
use crate::graphics::Primitive;
|
||||
use crate::Renderer;
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -21,10 +20,17 @@ enum State {
|
|||
Empty,
|
||||
Filled {
|
||||
bounds: Size,
|
||||
primitive: Arc<Primitive>,
|
||||
primitive: Internal,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Internal {
|
||||
TinySkia(Arc<iced_tiny_skia::Primitive>),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(Arc<iced_wgpu::Primitive>),
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
/// Creates a new empty [`Cache`].
|
||||
pub fn new() -> Self {
|
||||
|
|
@ -62,9 +68,21 @@ impl Cache {
|
|||
} = self.state.borrow().deref()
|
||||
{
|
||||
if *cached_bounds == bounds {
|
||||
return Geometry(Primitive::Cache {
|
||||
content: primitive.clone(),
|
||||
});
|
||||
match primitive {
|
||||
Internal::TinySkia(primitive) => {
|
||||
return Geometry::TinySkia(
|
||||
iced_tiny_skia::Primitive::Cache {
|
||||
content: primitive.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Internal::Wgpu(primitive) => {
|
||||
return Geometry::Wgpu(iced_wgpu::Primitive::Cache {
|
||||
content: primitive.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +92,15 @@ impl Cache {
|
|||
let primitive = {
|
||||
let geometry = frame.into_geometry();
|
||||
|
||||
Arc::new(geometry.0)
|
||||
match geometry {
|
||||
Geometry::TinySkia(primitive) => {
|
||||
Internal::TinySkia(Arc::new(primitive))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Geometry::Wgpu(primitive) => {
|
||||
Internal::Wgpu(Arc::new(primitive))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
*self.state.borrow_mut() = State::Filled {
|
||||
|
|
@ -82,6 +108,18 @@ impl Cache {
|
|||
primitive: primitive.clone(),
|
||||
};
|
||||
|
||||
Geometry(Primitive::Cache { content: primitive })
|
||||
match primitive {
|
||||
Internal::TinySkia(primitive) => {
|
||||
Geometry::TinySkia(iced_tiny_skia::Primitive::Cache {
|
||||
content: primitive,
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Internal::Wgpu(primitive) => {
|
||||
Geometry::Wgpu(iced_wgpu::Primitive::Cache {
|
||||
content: primitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,17 +3,259 @@ pub mod compositor;
|
|||
#[cfg(feature = "geometry")]
|
||||
pub mod geometry;
|
||||
|
||||
mod backend;
|
||||
mod settings;
|
||||
|
||||
pub use iced_graphics as graphics;
|
||||
pub use iced_graphics::core;
|
||||
|
||||
pub use backend::Backend;
|
||||
pub use compositor::Compositor;
|
||||
pub use settings::Settings;
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub use geometry::Geometry;
|
||||
|
||||
use crate::core::renderer;
|
||||
use crate::core::text::{self, Text};
|
||||
use crate::core::{Background, Font, Point, Rectangle, Size, Vector};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// The default graphics renderer for [`iced`].
|
||||
///
|
||||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
pub type Renderer<Theme> = iced_graphics::Renderer<Backend, Theme>;
|
||||
pub enum Renderer<Theme> {
|
||||
TinySkia(iced_tiny_skia::Renderer<Theme>),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::Renderer<Theme>),
|
||||
}
|
||||
|
||||
macro_rules! delegate {
|
||||
($renderer:expr, $name:ident, $body:expr) => {
|
||||
match $renderer {
|
||||
Self::TinySkia($name) => $body,
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu($name) => $body,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<T> Renderer<T> {
|
||||
#[cfg(feature = "wgpu")]
|
||||
pub fn draw_with_wgpu(&mut self, primitive: iced_wgpu::Primitive) {
|
||||
if let Self::Wgpu(renderer) = self {
|
||||
renderer.draw_primitive(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::Renderer for Renderer<T> {
|
||||
type Theme = T;
|
||||
|
||||
fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) {
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
let primitives = renderer.start_layer();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
renderer.end_layer(primitives, bounds);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
let primitives = renderer.start_layer();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
renderer.end_layer(primitives, bounds);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_translation(
|
||||
&mut self,
|
||||
translation: Vector,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
let primitives = renderer.start_translation();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
renderer.end_translation(primitives, translation);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
let primitives = renderer.start_translation();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
renderer.end_translation(primitives, translation);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_quad(
|
||||
&mut self,
|
||||
quad: renderer::Quad,
|
||||
background: impl Into<Background>,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.fill_quad(quad, background));
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
delegate!(self, renderer, renderer.clear());
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> text::Renderer for Renderer<T> {
|
||||
type Font = Font;
|
||||
|
||||
const ICON_FONT: Font = iced_tiny_skia::Renderer::<T>::ICON_FONT;
|
||||
const CHECKMARK_ICON: char = iced_tiny_skia::Renderer::<T>::CHECKMARK_ICON;
|
||||
const ARROW_DOWN_ICON: char =
|
||||
iced_tiny_skia::Renderer::<T>::ARROW_DOWN_ICON;
|
||||
|
||||
fn default_font(&self) -> Self::Font {
|
||||
delegate!(self, renderer, renderer.default_font())
|
||||
}
|
||||
|
||||
fn default_size(&self) -> f32 {
|
||||
delegate!(self, renderer, renderer.default_size())
|
||||
}
|
||||
|
||||
fn measure(
|
||||
&self,
|
||||
content: &str,
|
||||
size: f32,
|
||||
line_height: text::LineHeight,
|
||||
font: Font,
|
||||
bounds: Size,
|
||||
shaping: text::Shaping,
|
||||
) -> Size {
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.measure(content, size, line_height, font, bounds, shaping)
|
||||
)
|
||||
}
|
||||
|
||||
fn hit_test(
|
||||
&self,
|
||||
content: &str,
|
||||
size: f32,
|
||||
line_height: text::LineHeight,
|
||||
font: Font,
|
||||
bounds: Size,
|
||||
shaping: text::Shaping,
|
||||
point: Point,
|
||||
nearest_only: bool,
|
||||
) -> Option<text::Hit> {
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.hit_test(
|
||||
content,
|
||||
size,
|
||||
line_height,
|
||||
font,
|
||||
bounds,
|
||||
shaping,
|
||||
point,
|
||||
nearest_only
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn load_font(&mut self, bytes: Cow<'static, [u8]>) {
|
||||
delegate!(self, renderer, renderer.load_font(bytes));
|
||||
}
|
||||
|
||||
fn fill_text(&mut self, text: Text<'_, Self::Font>) {
|
||||
delegate!(self, renderer, renderer.fill_text(text));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
impl<T> crate::core::image::Renderer for Renderer<T> {
|
||||
type Handle = crate::core::image::Handle;
|
||||
|
||||
fn dimensions(&self, handle: &crate::core::image::Handle) -> Size<u32> {
|
||||
delegate!(self, renderer, renderer.dimensions(handle))
|
||||
}
|
||||
|
||||
fn draw(&mut self, handle: crate::core::image::Handle, bounds: Rectangle) {
|
||||
delegate!(self, renderer, renderer.draw(handle, bounds));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
impl<T> crate::core::svg::Renderer for Renderer<T> {
|
||||
fn dimensions(&self, handle: &crate::core::svg::Handle) -> Size<u32> {
|
||||
delegate!(self, renderer, renderer.dimensions(handle))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
handle: crate::core::svg::Handle,
|
||||
color: Option<crate::core::Color>,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.draw(handle, color, bounds))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
impl<T> crate::graphics::geometry::Renderer for Renderer<T> {
|
||||
type Geometry = crate::Geometry;
|
||||
|
||||
fn draw(&mut self, layers: Vec<Self::Geometry>) {
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
for layer in layers {
|
||||
match layer {
|
||||
crate::Geometry::TinySkia(primitive) => {
|
||||
renderer.draw_primitive(primitive);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
for layer in layers {
|
||||
match layer {
|
||||
crate::Geometry::Wgpu(primitive) => {
|
||||
renderer.draw_primitive(primitive);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue