mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-31 10:17:21 +00:00
Shaders: graster-nodes
no-std fixups (#2984)
* wgpu-executor: remove useless features * wgpu-executor: cleanup copy-pasted code * gcore-shaders: no_std fixups
This commit is contained in:
parent
1742e6000a
commit
caa228a1ec
13 changed files with 84 additions and 129 deletions
|
@ -152,7 +152,7 @@ kurbo = { version = "0.11.0", features = ["serde"] }
|
||||||
petgraph = { version = "0.7.1", default-features = false, features = [
|
petgraph = { version = "0.7.1", default-features = false, features = [
|
||||||
"graphmap",
|
"graphmap",
|
||||||
] }
|
] }
|
||||||
half = { version = "2.4.1", default-features = false, features = ["bytemuck", "serde"] }
|
half = { version = "2.4.1", default-features = false, features = ["bytemuck"] }
|
||||||
tinyvec = { version = "1", features = ["std"] }
|
tinyvec = { version = "1", features = ["std"] }
|
||||||
criterion = { version = "0.5", features = ["html_reports"] }
|
criterion = { version = "0.5", features = ["html_reports"] }
|
||||||
iai-callgrind = { version = "0.12.3" }
|
iai-callgrind = { version = "0.12.3" }
|
||||||
|
|
|
@ -7,7 +7,7 @@ authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = ["dep:dyn-any", "dep:serde", "dep:specta", "dep:log"]
|
std = ["dep:dyn-any", "dep:serde", "dep:specta", "dep:log", "half/std", "half/serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local std dependencies
|
# Local std dependencies
|
||||||
|
@ -16,7 +16,7 @@ dyn-any = { workspace = true, optional = true }
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
bytemuck = { workspace = true }
|
bytemuck = { workspace = true }
|
||||||
glam = { version = "0.29", default-features = false, features = ["nostd-libm", "scalar-math"] }
|
glam = { version = "0.29", default-features = false, features = ["nostd-libm", "scalar-math"] }
|
||||||
half = { workspace = true }
|
half = { workspace = true, default-features = false }
|
||||||
num-derive = { workspace = true }
|
num-derive = { workspace = true }
|
||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
|
#[cfg(target_arch = "spirv")]
|
||||||
|
use num_traits::float::Float;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
#[cfg_attr(feature = "std", derive(dyn_any::DynAny, specta::Type, serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "std", derive(dyn_any::DynAny, specta::Type, serde::Serialize, serde::Deserialize))]
|
||||||
|
@ -24,7 +26,7 @@ impl Hash for AlphaBlending {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for AlphaBlending {
|
impl Display for AlphaBlending {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
let round = |x: f32| (x * 1e3).round() / 1e3;
|
let round = |x: f32| (x * 1e3).round() / 1e3;
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -203,7 +205,7 @@ impl BlendMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BlendMode {
|
impl Display for BlendMode {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
// Normal group
|
// Normal group
|
||||||
BlendMode::Normal => write!(f, "Normal"),
|
BlendMode::Normal => write!(f, "Normal"),
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use super::color_traits::{Alpha, AlphaMut, AssociatedAlpha, Luminance, LuminanceMut, Pixel, RGB, RGBMut, Rec709Primaries, SRGB};
|
use super::color_traits::{Alpha, AlphaMut, AssociatedAlpha, Luminance, LuminanceMut, Pixel, RGB, RGBMut, Rec709Primaries, SRGB};
|
||||||
use super::discrete_srgb::{float_to_srgb_u8, srgb_u8_to_float};
|
use super::discrete_srgb::{float_to_srgb_u8, srgb_u8_to_float};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use core::fmt::Debug;
|
||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
use half::f16;
|
use half::f16;
|
||||||
#[cfg(target_arch = "spirv")]
|
#[cfg(target_arch = "spirv")]
|
||||||
use spirv_std::num_traits::Euclid;
|
use num_traits::Euclid;
|
||||||
#[cfg(target_arch = "spirv")]
|
#[cfg(target_arch = "spirv")]
|
||||||
use spirv_std::num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Pod, Zeroable)]
|
#[derive(Default, Clone, Copy, PartialEq, Pod, Zeroable)]
|
||||||
|
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
|
||||||
#[cfg_attr(feature = "std", derive(dyn_any::DynAny, serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "std", derive(dyn_any::DynAny, serde::Serialize, serde::Deserialize))]
|
||||||
pub struct RGBA16F {
|
pub struct RGBA16F {
|
||||||
red: f16,
|
red: f16,
|
||||||
|
@ -18,6 +20,14 @@ pub struct RGBA16F {
|
||||||
alpha: f16,
|
alpha: f16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// hack around half still masking out impl Debug for f16 on spirv
|
||||||
|
#[cfg(target_arch = "spirv")]
|
||||||
|
impl core::fmt::Debug for RGBA16F {
|
||||||
|
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Color> for RGBA16F {
|
impl From<Color> for RGBA16F {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(c: Color) -> Self {
|
fn from(c: Color) -> Self {
|
||||||
|
@ -215,7 +225,7 @@ pub struct Color {
|
||||||
|
|
||||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
impl Hash for Color {
|
impl Hash for Color {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.red.to_bits().hash(state);
|
self.red.to_bits().hash(state);
|
||||||
self.green.to_bits().hash(state);
|
self.green.to_bits().hash(state);
|
||||||
self.blue.to_bits().hash(state);
|
self.blue.to_bits().hash(state);
|
||||||
|
@ -256,7 +266,7 @@ impl AlphaMut for Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pixel for Color {
|
impl Pixel for Color {
|
||||||
#[cfg(not(target_arch = "spirv"))]
|
#[cfg(feature = "std")]
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
self.to_rgba8_srgb().to_vec()
|
self.to_rgba8_srgb().to_vec()
|
||||||
}
|
}
|
||||||
|
@ -793,6 +803,7 @@ impl Color {
|
||||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
||||||
/// assert_eq!("3240a261", color.to_rgba_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
/// assert_eq!("3240a261", color.to_rgba_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub fn to_rgba_hex_srgb(&self) -> String {
|
pub fn to_rgba_hex_srgb(&self) -> String {
|
||||||
let gamma = self.to_gamma_srgb();
|
let gamma = self.to_gamma_srgb();
|
||||||
format!(
|
format!(
|
||||||
|
@ -810,6 +821,7 @@ impl Color {
|
||||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
||||||
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub fn to_rgb_hex_srgb(&self) -> String {
|
pub fn to_rgb_hex_srgb(&self) -> String {
|
||||||
self.to_gamma_srgb().to_rgb_hex_srgb_from_gamma()
|
self.to_gamma_srgb().to_rgb_hex_srgb_from_gamma()
|
||||||
}
|
}
|
||||||
|
@ -820,6 +832,7 @@ impl Color {
|
||||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
||||||
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub fn to_rgb_hex_srgb_from_gamma(&self) -> String {
|
pub fn to_rgb_hex_srgb_from_gamma(&self) -> String {
|
||||||
format!("{:02x?}{:02x?}{:02x?}", (self.r() * 255.) as u8, (self.g() * 255.) as u8, (self.b() * 255.) as u8)
|
format!("{:02x?}{:02x?}{:02x?}", (self.r() * 255.) as u8, (self.g() * 255.) as u8, (self.b() * 255.) as u8)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ pub trait Linear {
|
||||||
fn lerp(self, other: Self, value: Self) -> Self
|
fn lerp(self, other: Self, value: Self) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized + Copy,
|
Self: Sized + Copy,
|
||||||
Self: std::ops::Sub<Self, Output = Self>,
|
Self: core::ops::Sub<Self, Output = Self>,
|
||||||
Self: std::ops::Mul<Self, Output = Self>,
|
Self: core::ops::Mul<Self, Output = Self>,
|
||||||
Self: std::ops::Add<Self, Output = Self>,
|
Self: core::ops::Add<Self, Output = Self>,
|
||||||
{
|
{
|
||||||
self + (other - self) * value
|
self + (other - self) * value
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ pub trait SRGB: Rec709Primaries {}
|
||||||
|
|
||||||
// TODO: Come up with a better name for this trait
|
// TODO: Come up with a better name for this trait
|
||||||
pub trait Pixel: Clone + Pod + Zeroable + Default {
|
pub trait Pixel: Clone + Pod + Zeroable + Default {
|
||||||
#[cfg(not(target_arch = "spirv"))]
|
#[cfg(feature = "std")]
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
bytemuck::bytes_of(self).to_vec()
|
bytemuck::bytes_of(self).to_vec()
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub fn float_to_srgb_u8(mut f: f32) -> u8 {
|
||||||
// We clamped f to [0, 1], and the integer representations
|
// We clamped f to [0, 1], and the integer representations
|
||||||
// of the positive finite non-NaN floats are monotonic.
|
// of the positive finite non-NaN floats are monotonic.
|
||||||
// This makes the later LUT lookup panicless.
|
// This makes the later LUT lookup panicless.
|
||||||
unsafe { std::hint::unreachable_unchecked() }
|
unsafe { core::hint::unreachable_unchecked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute a piecewise linear interpolation that is always
|
// Compute a piecewise linear interpolation that is always
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
pub mod blending;
|
pub mod blending;
|
||||||
pub mod choice_type;
|
pub mod choice_type;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
|
|
@ -20,5 +20,6 @@ pub mod types {
|
||||||
/// DVec2 with px unit
|
/// DVec2 with px unit
|
||||||
pub type PixelSize = glam::DVec2;
|
pub type PixelSize = glam::DVec2;
|
||||||
/// String with one or more than one line
|
/// String with one or more than one line
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub type TextArea = String;
|
pub type TextArea = String;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ license = "MIT OR Apache-2.0"
|
||||||
default = ["wgpu"]
|
default = ["wgpu"]
|
||||||
wgpu = ["wgpu-executor", "gpu", "graphene-std/wgpu"]
|
wgpu = ["wgpu-executor", "gpu", "graphene-std/wgpu"]
|
||||||
wayland = ["graphene-std/wayland"]
|
wayland = ["graphene-std/wayland"]
|
||||||
profiling = ["wgpu-executor/profiling"]
|
|
||||||
passthrough = ["wgpu-executor/passthrough"]
|
|
||||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "wgpu-executor"]
|
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "wgpu-executor"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -16,7 +16,6 @@ use graphene_svg_renderer::{Render, RenderParams, RenderSvgSegmentList, SvgRende
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
#[cfg(target_family = "wasm")]
|
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
|
@ -169,7 +168,8 @@ fn render_svg(data: impl Render, mut render: SvgRender, render_params: RenderPar
|
||||||
async fn render_canvas(render_config: RenderConfig, data: impl Render, editor: &WasmEditorApi, surface_handle: Option<wgpu_executor::WgpuSurface>, render_params: RenderParams) -> RenderOutputType {
|
async fn render_canvas(render_config: RenderConfig, data: impl Render, editor: &WasmEditorApi, surface_handle: Option<wgpu_executor::WgpuSurface>, render_params: RenderParams) -> RenderOutputType {
|
||||||
use graphene_application_io::{ImageTexture, SurfaceFrame};
|
use graphene_application_io::{ImageTexture, SurfaceFrame};
|
||||||
|
|
||||||
let footprint = render_config.viewport;
|
let mut footprint = render_config.viewport;
|
||||||
|
footprint.resolution = footprint.resolution.max(glam::UVec2::splat(1));
|
||||||
let Some(exec) = editor.application_io.as_ref().unwrap().gpu_executor() else {
|
let Some(exec) = editor.application_io.as_ref().unwrap().gpu_executor() else {
|
||||||
unreachable!("Attempted to render with Vello when no GPU executor is available");
|
unreachable!("Attempted to render with Vello when no GPU executor is available");
|
||||||
};
|
};
|
||||||
|
@ -196,7 +196,7 @@ async fn render_canvas(render_config: RenderConfig, data: impl Render, editor: &
|
||||||
let frame = SurfaceFrame {
|
let frame = SurfaceFrame {
|
||||||
surface_id: surface_handle.window_id,
|
surface_id: surface_handle.window_id,
|
||||||
resolution: render_config.viewport.resolution,
|
resolution: render_config.viewport.resolution,
|
||||||
transform: glam::DAffine2::IDENTITY,
|
transform: DAffine2::IDENTITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
RenderOutputType::CanvasFrame(frame)
|
RenderOutputType::CanvasFrame(frame)
|
||||||
|
|
|
@ -4,11 +4,6 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
profiling = []
|
|
||||||
passthrough = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
graphene-core = { workspace = true, features = ["wgpu"] }
|
graphene-core = { workspace = true, features = ["wgpu"] }
|
||||||
|
|
|
@ -32,15 +32,10 @@ impl Context {
|
||||||
let (device, queue) = adapter
|
let (device, queue) = adapter
|
||||||
.request_device(&wgpu::DeviceDescriptor {
|
.request_device(&wgpu::DeviceDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
// #[cfg(not(feature = "passthrough"))]
|
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
required_features: wgpu::Features::empty(),
|
required_features: wgpu::Features::empty(),
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
required_features: wgpu::Features::PUSH_CONSTANTS,
|
required_features: wgpu::Features::PUSH_CONSTANTS,
|
||||||
// Currently disabled because not all backend support passthrough.
|
|
||||||
// TODO: reenable only when vulkan adapter is available
|
|
||||||
// #[cfg(feature = "passthrough")]
|
|
||||||
// required_features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH,
|
|
||||||
required_limits,
|
required_limits,
|
||||||
memory_hints: Default::default(),
|
memory_hints: Default::default(),
|
||||||
trace: wgpu::Trace::Off,
|
trace: wgpu::Trace::Off,
|
||||||
|
|
|
@ -42,6 +42,7 @@ pub struct Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TargetTexture {
|
pub struct TargetTexture {
|
||||||
|
texture: wgpu::Texture,
|
||||||
view: wgpu::TextureView,
|
view: wgpu::TextureView,
|
||||||
size: UVec2,
|
size: UVec2,
|
||||||
}
|
}
|
||||||
|
@ -60,7 +61,47 @@ const VELLO_SURFACE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unor
|
||||||
impl WgpuExecutor {
|
impl WgpuExecutor {
|
||||||
pub async fn render_vello_scene(&self, scene: &Scene, surface: &WgpuSurface, size: UVec2, context: &RenderContext, background: Color) -> Result<()> {
|
pub async fn render_vello_scene(&self, scene: &Scene, surface: &WgpuSurface, size: UVec2, context: &RenderContext, background: Color) -> Result<()> {
|
||||||
let mut guard = surface.surface.target_texture.lock().await;
|
let mut guard = surface.surface.target_texture.lock().await;
|
||||||
let target_texture = if let Some(target_texture) = &*guard
|
|
||||||
|
let surface_inner = &surface.surface.inner;
|
||||||
|
let surface_caps = surface_inner.get_capabilities(&self.context.adapter);
|
||||||
|
surface_inner.configure(
|
||||||
|
&self.context.device,
|
||||||
|
&SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::STORAGE_BINDING,
|
||||||
|
format: VELLO_SURFACE_FORMAT,
|
||||||
|
width: size.x,
|
||||||
|
height: size.y,
|
||||||
|
present_mode: surface_caps.present_modes[0],
|
||||||
|
alpha_mode: wgpu::CompositeAlphaMode::Opaque,
|
||||||
|
view_formats: vec![],
|
||||||
|
desired_maximum_frame_latency: 2,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.render_vello_scene_to_target_texture(scene, size, context, background, &mut guard).await?;
|
||||||
|
|
||||||
|
let surface_texture = surface_inner.get_current_texture()?;
|
||||||
|
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Surface Blit") });
|
||||||
|
surface.surface.blitter.copy(
|
||||||
|
&self.context.device,
|
||||||
|
&mut encoder,
|
||||||
|
&guard.as_ref().unwrap().view,
|
||||||
|
&surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
||||||
|
);
|
||||||
|
self.context.queue.submit([encoder.finish()]);
|
||||||
|
surface_texture.present();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn render_vello_scene_to_texture(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Color) -> Result<wgpu::Texture> {
|
||||||
|
let mut output = None;
|
||||||
|
self.render_vello_scene_to_target_texture(scene, size, context, background, &mut output).await?;
|
||||||
|
Ok(output.unwrap().texture)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn render_vello_scene_to_target_texture(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Color, output: &mut Option<TargetTexture>) -> Result<()> {
|
||||||
|
let target_texture = if let Some(target_texture) = output
|
||||||
&& target_texture.size == size
|
&& target_texture.size == size
|
||||||
{
|
{
|
||||||
target_texture
|
target_texture
|
||||||
|
@ -80,31 +121,13 @@ impl WgpuExecutor {
|
||||||
view_formats: &[],
|
view_formats: &[],
|
||||||
});
|
});
|
||||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
*guard = Some(TargetTexture { size, view });
|
*output = Some(TargetTexture { texture, view, size });
|
||||||
guard.as_ref().unwrap()
|
output.as_mut().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let surface_inner = &surface.surface.inner;
|
let [r, g, b, a] = background.to_rgba8_srgb();
|
||||||
let surface_caps = surface_inner.get_capabilities(&self.context.adapter);
|
|
||||||
surface_inner.configure(
|
|
||||||
&self.context.device,
|
|
||||||
&SurfaceConfiguration {
|
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::STORAGE_BINDING,
|
|
||||||
format: VELLO_SURFACE_FORMAT,
|
|
||||||
width: size.x,
|
|
||||||
height: size.y,
|
|
||||||
present_mode: surface_caps.present_modes[0],
|
|
||||||
alpha_mode: wgpu::CompositeAlphaMode::Opaque,
|
|
||||||
view_formats: vec![],
|
|
||||||
desired_maximum_frame_latency: 2,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let [r, g, b, _] = background.to_rgba8_srgb();
|
|
||||||
let render_params = RenderParams {
|
let render_params = RenderParams {
|
||||||
// We are using an explicit opaque color here to eliminate the alpha premultiplication step
|
base_color: vello::peniko::Color::from_rgba8(r, g, b, a),
|
||||||
// which would be required to support a transparent webgpu canvas
|
|
||||||
base_color: vello::peniko::Color::from_rgba8(r, g, b, 0xff),
|
|
||||||
width: size.x,
|
width: size.x,
|
||||||
height: size.y,
|
height: size.y,
|
||||||
antialiasing_method: AaConfig::Msaa16,
|
antialiasing_method: AaConfig::Msaa16,
|
||||||
|
@ -126,66 +149,9 @@ impl WgpuExecutor {
|
||||||
renderer.override_image(image, None);
|
renderer.override_image(image, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let surface_texture = surface_inner.get_current_texture()?;
|
|
||||||
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Surface Blit") });
|
|
||||||
surface.surface.blitter.copy(
|
|
||||||
&self.context.device,
|
|
||||||
&mut encoder,
|
|
||||||
&target_texture.view,
|
|
||||||
&surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
|
||||||
);
|
|
||||||
self.context.queue.submit([encoder.finish()]);
|
|
||||||
surface_texture.present();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render_vello_scene_to_texture(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Color) -> Result<wgpu::Texture> {
|
|
||||||
let texture = self.context.device.create_texture(&wgpu::TextureDescriptor {
|
|
||||||
label: None,
|
|
||||||
size: wgpu::Extent3d {
|
|
||||||
width: size.x.max(1),
|
|
||||||
height: size.y.max(1),
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
},
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
|
|
||||||
format: VELLO_SURFACE_FORMAT,
|
|
||||||
view_formats: &[],
|
|
||||||
});
|
|
||||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
let [r, g, b, a] = background.to_rgba8_srgb();
|
|
||||||
let render_params = RenderParams {
|
|
||||||
base_color: vello::peniko::Color::from_rgba8(r, g, b, a),
|
|
||||||
width: size.x,
|
|
||||||
height: size.y,
|
|
||||||
antialiasing_method: AaConfig::Msaa16,
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut renderer = self.vello_renderer.lock().await;
|
|
||||||
for (image, texture) in context.resource_overrides.iter() {
|
|
||||||
let texture_view = wgpu::TexelCopyTextureInfoBase {
|
|
||||||
texture: texture.clone(),
|
|
||||||
mip_level: 0,
|
|
||||||
origin: Origin3d::ZERO,
|
|
||||||
aspect: TextureAspect::All,
|
|
||||||
};
|
|
||||||
renderer.override_image(image, Some(texture_view));
|
|
||||||
}
|
|
||||||
renderer.render_to_texture(&self.context.device, &self.context.queue, scene, &view, &render_params)?;
|
|
||||||
for (image, _) in context.resource_overrides.iter() {
|
|
||||||
renderer.override_image(image, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(texture)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
pub fn create_surface(&self, canvas: graphene_application_io::WasmSurfaceHandle) -> Result<SurfaceHandle<Surface>> {
|
pub fn create_surface(&self, canvas: graphene_application_io::WasmSurfaceHandle) -> Result<SurfaceHandle<Surface>> {
|
||||||
let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas.surface))?;
|
let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas.surface))?;
|
||||||
|
@ -212,26 +178,9 @@ impl WgpuExecutor {
|
||||||
|
|
||||||
impl WgpuExecutor {
|
impl WgpuExecutor {
|
||||||
pub async fn new() -> Option<Self> {
|
pub async fn new() -> Option<Self> {
|
||||||
let context = Context::new().await?;
|
Self::with_context(Context::new().await?)
|
||||||
|
|
||||||
let vello_renderer = Renderer::new(
|
|
||||||
&context.device,
|
|
||||||
RendererOptions {
|
|
||||||
// surface_format: Some(wgpu::TextureFormat::Rgba8Unorm),
|
|
||||||
pipeline_cache: None,
|
|
||||||
use_cpu: false,
|
|
||||||
antialiasing_support: AaSupport::all(),
|
|
||||||
num_init_threads: std::num::NonZeroUsize::new(1),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to create Vello renderer: {:?}", e))
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
Some(Self {
|
|
||||||
context,
|
|
||||||
vello_renderer: vello_renderer.into(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_context(context: Context) -> Option<Self> {
|
pub fn with_context(context: Context) -> Option<Self> {
|
||||||
let vello_renderer = Renderer::new(
|
let vello_renderer = Renderer::new(
|
||||||
&context.device,
|
&context.device,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue