Update GPU execution and quantization to new node system (#1070)

* Update GPU and quantization to new node system

Squashed commit of the following:

commit 3b69bdafed79f0bb1279609537a8eeead3f06830
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Sun Mar 5 11:37:17 2023 +0100

    Disable dev tools by default

commit dbbbedd68e48d1162442574ad8877c9922d40e4a
Merge: b1018eb5 a8f6e11e
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Sun Mar 5 10:45:00 2023 +0100

    Merge branch 'vite' into tauri-restructure-lite

commit b1018eb5ee56c2d23f9d5a4f034608ec684bd746
Merge: 3195833e 0512cb24
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Fri Mar 3 17:06:21 2023 +0100

    Merge branch 'master' into tauri-restructure-lite

commit 3195833e4088a4ed7984955c72617b27b7e39bfc
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Fri Mar 3 17:06:02 2023 +0100

    Bump number of samples

commit 3e57e1e3280759cf4f75726635e31d2b8e9387f9
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Fri Mar 3 16:55:52 2023 +0100

    Move part of quantization code to gcore

commit 10c15b0bc6ffb51e2bf2d94cd4eb0e24d761fb6f
Merge: 2b3db45a 8fe8896c
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Fri Mar 3 14:28:56 2023 +0100

    Merge remote-tracking branch 'origin/master' into tauri-restructure-lite

commit 2b3db45aee44a20660f0b1204666bb81e5a7e4b6
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Fri Mar 3 14:17:11 2023 +0100

    Fix types in node registry

commit 9122f35c0ba9a86255709680d744a48d3c7dcac4
Merge: 26eefc43 2cf4ee0f
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Fri Mar 3 01:04:55 2023 +0100

    Merge remote-tracking branch 'origin/master' into tauri-restructure-lite

commit 26eefc437eaad873f8d38fdb1fae0a1e3ec189e4
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Mar 2 23:05:53 2023 +0100

    Add Quantize node to document_node_types

commit 3f7606a91329200b2c025010d4a0cffee840a11c
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Mar 2 17:47:51 2023 +0100

    Add quantization nodes to node registry

commit 22d8e477ef79eef5b57b1dc9805e41bbf81cae43
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Mar 2 17:13:28 2023 +0100

    Introduce scopes (#1053)

    * Implement let binding

    * Add lambda inputs

    * Fix tests

    * Fix proto network formatting

    * Generate a template Scoped network by default

    * Add comment to explain the lambda parameter

    * Move binding wrapping out of the template

    * Fix errors cause by image frames

commit 9e0c29d92a164d4a4063e93480e1e289ef5243fe
Author: Alexandru Ică <alexandru@seyhanlee.com>
Date:   Thu Mar 2 15:55:10 2023 +0200

    Make use of ImageFrame in the node system more extensively (#1055) (#1062)

    Make the node system use ImageFrame more extensively (#1055)

commit 5912ef9a1a807917eeb90c1f4835bd8a5de9c821
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Wed Mar 1 16:15:21 2023 +0100

    Split quantization into multiple nodes

commit 285d7b76c176b3e2679ea24eecb38ef867a79f3b
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Mon Feb 27 12:35:57 2023 +0100

    Fix gpu support

commit e0b6327eebba8caf7545c4fedc6670abc4c3652e
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Feb 16 22:08:53 2023 +0100

    Don't watch frontend files when using tauri

commit 58ae146f6da935cfd37afbd25e1c331b615252da
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Feb 16 21:48:54 2023 +0100

    Migrate vue code base to vite

commit f996390cc312618a60f98ccb9cd515f1bae5006d
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Feb 16 19:34:33 2023 +0100

    Start migrating vue to use vite

commit 29d752f47cfd1c74ee51fac6f3d75557a378471c
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Feb 16 19:00:53 2023 +0100

    Kill cargo watch process automatically

commit 4d1c76b07acadbf609dbab7d57d9a7769b81d4b5
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Feb 16 17:37:27 2023 +0100

    Start playing around with vite infrastructure

commit 8494f5e9227aa433fd5ca75b268a6a96b2706b36
Author: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
Date:   Thu Jan 19 18:40:46 2023 +0000

    Fix import style and eslint rules

commit 92490f7774a7351bb40091bcec78f79c28704768
Author: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
Date:   Thu Jan 19 18:25:09 2023 +0000

    Fix icons

commit dc67821abad87f8ff780b12ae96668af2f7bb355
Author: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
Date:   Thu Jan 19 18:20:48 2023 +0000

    Add license generator with rollup

commit 441e339d31b76dac4f91321d39a39900b5a79bc1
Author: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
Date:   Thu Jan 19 18:14:22 2023 +0000

    Use eslint --fix to fix TS-in-svelte type imports. Now it compiles.

commit 2e847d339e7dcd51ed4c4677ed337c1e20636724
Author: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
Date:   Thu Jan 19 17:31:49 2023 +0000

    Remove webpack and plugins

commit 3adab1b7f40ff17b91163e7ca47a403ef3c02fbc
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Thu Mar 2 16:10:19 2023 +0100

    Fix errors cause by image frames

commit 4e5f838995e213b4696225a473b9c56c0084e7a8
Author: Alexandru Ică <alexandru@seyhanlee.com>
Date:   Thu Mar 2 15:55:10 2023 +0200

    Make use of ImageFrame in the node system more extensively (#1055) (#1062)

    Make the node system use ImageFrame more extensively (#1055)

commit 1d4b0e29c693a53c068f1a30f0e857a9c1a59587
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Wed Mar 1 15:13:51 2023 +0100

    Update node graph guide readme with new syntax (#1061)

commit 6735d8c61f5709e22d2b22abd037bab417e868d6
Author: Rob Nadal <Robnadal44@gmail.com>
Date:   Tue Feb 28 18:59:06 2023 -0500

    Bezier-rs: Add function to smoothly join bezier curves (#1037)

    * Added bezier join

    * Stylistic changes per review

commit cd1d7aa7fbcce39fbbf7762d131ee16ad9cb46dd
Author: Dennis Kobert <dennis@kobert.dev>
Date:   Wed Feb 22 23:42:32 2023 +0100

    Implement let binding

    Add lambda inputs

    Fix tests

    Fix proto network formatting

    Generate a template Scoped network by default

    Add comment to explain the lambda parameter

    Move binding wrapping out of the template

* Update package-lock.json

* Regenerate package-lock.json and fix lint errors

* Readd git keep dir

* Revert change to panic.ts

* Fix clippy warnings

* Apply code review

* Clean up node_registry

* Fix test / spriv -> spirv typos
This commit is contained in:
Dennis Kobert
2023-03-05 13:22:14 +01:00
committed by Keavon Chambers
parent 4ea3802df1
commit b55e233fff
38 changed files with 2282 additions and 1924 deletions

View File

@@ -9,20 +9,20 @@ license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
std = ["dyn-any", "dyn-any/std", "alloc"]
std = ["dyn-any", "dyn-any/std", "alloc", "glam/std", "specta"]
default = ["async", "serde", "kurbo", "log", "std"]
log = ["dep:log"]
serde = ["dep:serde", "glam/serde"]
gpu = ["spirv-std", "bytemuck", "glam/bytemuck", "dyn-any"]
gpu = ["spirv-std", "bytemuck", "glam/bytemuck", "dyn-any", "glam/libm"]
async = ["async-trait", "alloc"]
nightly = []
alloc = ["dyn-any", "bezier-rs"]
alloc = ["dyn-any", "bezier-rs", "once_cell"]
type_id_logging = []
[dependencies]
dyn-any = {path = "../../libraries/dyn-any", features = ["derive", "glam"], optional = true, default-features = false }
spirv-std = { git = "https://github.com/EmbarkStudios/rust-gpu", features = ["glam"] , optional = true}
spirv-std = { version = "0.5", features = ["glam"] , optional = true}
bytemuck = {version = "1.8", features = ["derive"], optional = true}
async-trait = {version = "0.1", optional = true}
serde = {version = "1.0", features = ["derive"], optional = true, default-features = false }
@@ -32,10 +32,11 @@ bezier-rs = { path = "../../libraries/bezier-rs", optional = true }
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
"serde",
], optional = true }
glam = { version = "^0.22", default-features = false, features = ["scalar-math", "libm"]}
rand_chacha = "0.3.1"
spin = "0.9.2"
glam = { version = "^0.22", default-features = false, features = ["scalar-math"]}
node-macro = {path = "../node-macro"}
specta.workspace = true
once_cell = { version = "1.17.0", default-features = false }
specta.optional = true
once_cell = { version = "1.17.0", default-features = false, optional = true }
# forma = { version = "0.1.0", package = "forma-render" }

View File

@@ -11,6 +11,7 @@ pub mod consts;
pub mod generic;
pub mod ops;
pub mod structural;
#[cfg(feature = "std")]
pub mod uuid;
pub mod value;
@@ -22,6 +23,8 @@ pub mod raster;
#[cfg(feature = "alloc")]
pub mod vector;
pub mod quantization;
use core::any::TypeId;
pub use raster::Color;
@@ -33,6 +36,7 @@ pub trait Node<'i, Input: 'i>: 'i {
#[cfg(feature = "alloc")]
mod types;
#[cfg(feature = "alloc")]
pub use types::*;
pub trait NodeIO<'i, Input: 'i>: 'i + Node<'i, Input>

View File

@@ -0,0 +1,83 @@
use crate::raster::Color;
use crate::Node;
use dyn_any::{DynAny, StaticType};
#[derive(Clone, Debug, DynAny, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Quantization {
pub fn_index: usize,
pub a: f32,
pub b: f32,
pub c: f32,
pub d: f32,
}
impl core::hash::Hash for Quantization {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.fn_index.hash(state);
self.a.to_bits().hash(state);
self.b.to_bits().hash(state);
self.c.to_bits().hash(state);
self.d.to_bits().hash(state);
}
}
impl Default for Quantization {
fn default() -> Self {
Self {
fn_index: Default::default(),
a: 1.,
b: Default::default(),
c: Default::default(),
d: Default::default(),
}
}
}
pub type QuantizationChannels = [Quantization; 4];
fn quantize(value: f32, quantization: &Quantization) -> f32 {
let Quantization { fn_index, a, b, c, d } = quantization;
match fn_index {
1 => ((value + a) * d).abs().ln() * b + c,
_ => a * value + b,
}
}
fn decode(value: f32, quantization: &Quantization) -> f32 {
let Quantization { fn_index, a, b, c, d } = quantization;
match fn_index {
1 => -(-c / b).exp() * (a * d * (c / b).exp() - (value / b).exp()) / d,
_ => (value - b) / a,
}
}
pub struct QuantizeNode<Quantization> {
quantization: Quantization,
}
#[node_macro::node_fn(QuantizeNode)]
fn quantize_fn<'a>(color: Color, quantization: [Quantization; 4]) -> Color {
let quant = quantization.as_slice();
let r = quantize(color.r(), &quant[0]);
let g = quantize(color.g(), &quant[1]);
let b = quantize(color.b(), &quant[2]);
let a = quantize(color.a(), &quant[3]);
Color::from_rgbaf32_unchecked(r, g, b, a)
}
pub struct DeQuantizeNode<Quantization> {
quantization: Quantization,
}
#[node_macro::node_fn(DeQuantizeNode)]
fn dequantize_fn<'a>(color: Color, quantization: [Quantization; 4]) -> Color {
let quant = quantization.as_slice();
let r = decode(color.r(), &quant[0]);
let g = decode(color.g(), &quant[1]);
let b = decode(color.b(), &quant[2]);
let a = decode(color.a(), &quant[3]);
Color::from_rgbaf32_unchecked(r, g, b, a)
}

View File

@@ -2,6 +2,9 @@ use core::{fmt::Debug, marker::PhantomData};
use crate::Node;
#[cfg(target_arch = "spirv")]
use spirv_std::num_traits::float::Float;
pub mod color;
pub use self::color::Color;
@@ -180,6 +183,7 @@ impl<'a> ImageWindowIterator<'a> {
}
}
#[cfg(not(target_arch = "spirv"))]
impl<'a> Iterator for ImageWindowIterator<'a> {
type Item = (Color, (i32, i32));
#[inline]
@@ -194,6 +198,9 @@ impl<'a> Iterator for ImageWindowIterator<'a> {
if self.y > max_y {
return None;
}
#[cfg(target_arch = "spirv")]
let value = None;
#[cfg(not(target_arch = "spirv"))]
let value = Some((self.image.data[(self.x + self.y * self.image.width) as usize], (self.x as i32 - start_x, self.y as i32 - start_y)));
self.x += 1;
@@ -245,21 +252,49 @@ where
input.for_each(|x| map_node.eval(x));
}
#[cfg(target_arch = "spirv")]
const NOTHING: () = ();
use dyn_any::{DynAny, StaticType};
#[derive(Clone, Debug, PartialEq, DynAny, Default, Copy)]
#[derive(Clone, Debug, PartialEq, DynAny, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct ImageSlice<'a> {
pub width: u32,
pub height: u32,
#[cfg(not(target_arch = "spirv"))]
pub data: &'a [Color],
#[cfg(target_arch = "spirv")]
pub data: &'a (),
}
#[allow(clippy::derivable_impls)]
impl<'a> Default for ImageSlice<'a> {
#[cfg(not(target_arch = "spirv"))]
fn default() -> Self {
Self {
width: Default::default(),
height: Default::default(),
data: Default::default(),
}
}
#[cfg(target_arch = "spirv")]
fn default() -> Self {
Self {
width: Default::default(),
height: Default::default(),
data: &NOTHING,
}
}
}
impl ImageSlice<'_> {
#[cfg(not(target_arch = "spirv"))]
pub const fn empty() -> Self {
Self { width: 0, height: 0, data: &[] }
}
}
#[cfg(not(target_arch = "spirv"))]
impl<'a> IntoIterator for ImageSlice<'a> {
type Item = &'a Color;
type IntoIter = core::slice::Iter<'a, Color>;
@@ -268,6 +303,7 @@ impl<'a> IntoIterator for ImageSlice<'a> {
}
}
#[cfg(not(target_arch = "spirv"))]
impl<'a> IntoIterator for &'a ImageSlice<'a> {
type Item = &'a Color;
type IntoIter = core::slice::Iter<'a, Color>;

View File

@@ -4,8 +4,12 @@ use crate::Node;
use core::fmt::Debug;
use dyn_any::{DynAny, StaticType};
#[cfg(target_arch = "spirv")]
use spirv_std::num_traits::float::Float;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, specta::Type, Hash)]
#[cfg_attr(feature = "std", derive(specta::Type))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, Hash)]
pub enum LuminanceCalculation {
#[default]
SRGB,
@@ -27,8 +31,8 @@ impl LuminanceCalculation {
}
}
impl std::fmt::Display for LuminanceCalculation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl core::fmt::Display for LuminanceCalculation {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
LuminanceCalculation::SRGB => write!(f, "sRGB"),
LuminanceCalculation::Perceptual => write!(f, "Perceptual"),
@@ -73,7 +77,8 @@ impl BlendMode {
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, specta::Type, Hash)]
#[cfg_attr(feature = "std", derive(specta::Type))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, Hash)]
pub enum BlendMode {
#[default]
// Basic group
@@ -116,8 +121,8 @@ pub enum BlendMode {
Luminosity,
}
impl std::fmt::Display for BlendMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl core::fmt::Display for BlendMode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
BlendMode::Normal => write!(f, "Normal"),
@@ -368,8 +373,7 @@ fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f64) -> Col
BlendMode::Color => backdrop.blend_color(source_color),
BlendMode::Luminosity => backdrop.blend_luminosity(source_color),
}
.lerp(backdrop, actual_opacity)
.unwrap();
.lerp(backdrop, actual_opacity);
}
#[derive(Debug, Clone, Copy)]

View File

@@ -20,7 +20,8 @@ use bytemuck::{Pod, Zeroable};
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "gpu", derive(Pod, Zeroable))]
#[derive(Debug, Clone, Copy, PartialEq, Default, DynAny, specta::Type)]
#[cfg_attr(feature = "std", derive(specta::Type))]
#[derive(Debug, Default, Clone, Copy, PartialEq, DynAny)]
pub struct Color {
red: f32,
green: f32,
@@ -30,7 +31,7 @@ pub struct Color {
#[allow(clippy::derived_hash_with_manual_eq)]
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.green.to_bits().hash(state);
self.blue.to_bits().hash(state);
@@ -119,7 +120,6 @@ impl Color {
/// use graphene_core::raster::color::Color;
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.);
/// ```
#[cfg(not(target_arch = "spirv"))]
pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Color {
let temp1 = if lightness < 0.5 {
lightness * (saturation + 1.)
@@ -127,12 +127,16 @@ impl Color {
lightness + saturation - lightness * saturation
};
let temp2 = 2. * lightness - temp1;
#[cfg(not(target_arch = "spirv"))]
let rem = |x: f32| x.rem_euclid(1.);
#[cfg(target_arch = "spirv")]
let rem = |x: f32| x.rem_euclid(&1.);
let mut red = (hue + 1. / 3.).rem_euclid(1.);
let mut green = hue.rem_euclid(1.);
let mut blue = (hue - 1. / 3.).rem_euclid(1.);
let mut red = rem(hue + 1. / 3.);
let mut green = rem(hue);
let mut blue = rem(hue - 1. / 3.);
for channel in [&mut red, &mut green, &mut blue] {
fn map_channel(channel: &mut f32, temp2: f32, temp1: f32) {
*channel = if *channel * 6. < 1. {
temp2 + (temp1 - temp2) * 6. * *channel
} else if *channel * 2. < 1. {
@@ -144,6 +148,9 @@ impl Color {
}
.clamp(0., 1.);
}
map_channel(&mut red, temp2, temp1);
map_channel(&mut green, temp2, temp1);
map_channel(&mut blue, temp2, temp1);
Color { red, green, blue, alpha }
}
@@ -427,6 +434,7 @@ impl Color {
/// let color = Color::from_rgba8(0x7C, 0x67, 0xFA, 0x61);
/// assert!("7C67FA61" == color.rgba_hex())
/// ```
#[cfg(feature = "std")]
pub fn rgba_hex(&self) -> String {
format!(
"{:02X?}{:02X?}{:02X?}{:02X?}",
@@ -443,6 +451,7 @@ impl Color {
/// let color = Color::from_rgba8(0x7C, 0x67, 0xFA, 0x61);
/// assert!("7C67FA" == color.rgb_hex())
/// ```
#[cfg(feature = "std")]
pub fn rgb_hex(&self) -> String {
format!("{:02X?}{:02X?}{:02X?}", (self.r() * 255.) as u8, (self.g() * 255.) as u8, (self.b() * 255.) as u8,)
}
@@ -536,9 +545,9 @@ impl Color {
/// Linearly interpolates between two colors based on t.
///
/// T must be between 0 and 1.
pub fn lerp(self, other: Color, t: f32) -> Option<Self> {
pub fn lerp(self, other: Color, t: f32) -> Self {
assert!((0. ..=1.).contains(&t));
Color::from_rgbaf32(
Color::from_rgbaf32_unchecked(
self.red + ((other.red - self.red) * t),
self.green + ((other.green - self.green) * t),
self.blue + ((other.blue - self.blue) * t),
@@ -600,6 +609,7 @@ impl Color {
blue: f(self.blue, other.blue),
alpha: self.alpha,
};
#[cfg(feature = "log")]
if *self == Color::RED {
debug!("{} {} {} {}", color.red, color.green, color.blue, color.alpha);
}

View File

@@ -133,8 +133,8 @@ impl Gradient {
((time - self.positions[index].0) / self.positions.get(index + 1).map(|end| end.0 - self.positions[index].0).unwrap_or_default()) as f32,
),
// Use the start or the end colour if applicable
(Some(v), _) | (_, Some(v)) => Some(v),
_ => Some(Color::WHITE),
(Some(v), _) | (_, Some(v)) => v,
_ => Color::WHITE,
};
// Compute the correct index to keep the positions in order
@@ -146,7 +146,7 @@ impl Gradient {
let new_color = get_color(index - 1, new_position);
// Insert the new stop
self.positions.insert(index, (new_position, new_color));
self.positions.insert(index, (new_position, Some(new_color)));
Some(index)
}