mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-18 18:38:05 +08:00
Shaders: rust-gpu integration to compile shader nodes to WGSL (#3097)
* shaders: shader compilation setup * nix: use rustc_codegen_spirv.so from nix * shaders: codegen for per_pixel_adjust shader nodes * shaders: disable nodes needing bool * shaders: `#[repr(u32)]` some enums * shaders: add lint ignores from rust-gpu * shaders: fix node-macro tests * gcore-shaders: toml cleanup * shader-nodes feature: put rust-gpu to wgsl compile behind feature gate * shaders: fix use TokenStream2 * shaders: allow providing shader externally * Update iai runner in workflow --------- Co-authored-by: Timon Schelling <me@timon.zip> Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
@@ -6,8 +6,18 @@ description = "graphene raster data format"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["rlib", "dylib"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
shader-nodes = [
|
||||
"std",
|
||||
"dep:graphene-raster-nodes-shaders",
|
||||
]
|
||||
std = [
|
||||
"dep:graphene-core",
|
||||
"dep:dyn-any",
|
||||
@@ -19,8 +29,6 @@ std = [
|
||||
"dep:serde",
|
||||
"dep:specta",
|
||||
"dep:kurbo",
|
||||
"glam/debug-glam-assert",
|
||||
"glam/serde",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
@@ -31,10 +39,12 @@ node-macro = { workspace = true }
|
||||
# Local std dependencies
|
||||
dyn-any = { workspace = true, optional = true }
|
||||
graphene-core = { workspace = true, optional = true }
|
||||
graphene-raster-nodes-shaders = { path = "./shaders", optional = true }
|
||||
|
||||
# Workspace dependencies
|
||||
bytemuck = { workspace = true }
|
||||
glam = { workspace = true }
|
||||
spirv-std = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
|
||||
# Workspace std dependencies
|
||||
|
||||
13
node-graph/graster-nodes/shaders/Cargo.toml
Normal file
13
node-graph/graster-nodes/shaders/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "graphene-raster-nodes-shaders"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "graphene raster data format"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[build-dependencies]
|
||||
cargo-gpu = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
55
node-graph/graster-nodes/shaders/build.rs
Normal file
55
node-graph/graster-nodes/shaders/build.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use cargo_gpu::InstalledBackend;
|
||||
use cargo_gpu::spirv_builder::{MetadataPrintout, SpirvMetadata};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
env_logger::builder().init();
|
||||
|
||||
// Skip building the shader if they are provided externally
|
||||
println!("cargo:rerun-if-env-changed=GRAPHENE_RASTER_NODES_SHADER_PATH");
|
||||
if !std::env::var("GRAPHENE_RASTER_NODES_SHADER_PATH").unwrap_or_default().is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Allows overriding the PATH to inject the rust-gpu rust toolchain when building the rest of the project with stable rustc.
|
||||
// Used in nix shell. Do not remove without checking with developers using nix.
|
||||
println!("cargo:rerun-if-env-changed=RUST_GPU_PATH_OVERRIDE");
|
||||
if let Ok(path_override) = std::env::var("RUST_GPU_PATH_OVERRIDE") {
|
||||
let current_path = std::env::var("PATH").unwrap_or_default();
|
||||
let new_path = format!("{path_override}:{current_path}");
|
||||
// SAFETY: Build script is single-threaded therefore this cannot lead to undefined behavior.
|
||||
unsafe {
|
||||
std::env::set_var("PATH", &new_path);
|
||||
}
|
||||
}
|
||||
|
||||
let shader_crate = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/.."));
|
||||
|
||||
println!("cargo:rerun-if-env-changed=RUSTC_CODEGEN_SPIRV_PATH");
|
||||
let rustc_codegen_spirv_path = std::env::var("RUSTC_CODEGEN_SPIRV_PATH").unwrap_or_default();
|
||||
let backend = if rustc_codegen_spirv_path.is_empty() {
|
||||
// install the toolchain and build the `rustc_codegen_spirv` codegen backend with it
|
||||
cargo_gpu::Install::from_shader_crate(shader_crate.clone()).run()?
|
||||
} else {
|
||||
// use the `RUSTC_CODEGEN_SPIRV` environment variable to find the codegen backend
|
||||
let mut backend = InstalledBackend::default();
|
||||
backend.rustc_codegen_spirv_location = PathBuf::from(rustc_codegen_spirv_path);
|
||||
backend.toolchain_channel = "nightly".to_string();
|
||||
backend.target_spec_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
backend
|
||||
};
|
||||
|
||||
// build the shader crate
|
||||
let mut builder = backend.to_spirv_builder(shader_crate, "spirv-unknown-naga-wgsl");
|
||||
builder.print_metadata = MetadataPrintout::DependencyOnly;
|
||||
builder.spirv_metadata = SpirvMetadata::Full;
|
||||
builder.shader_crate_features.default_features = false;
|
||||
let wgsl_result = builder.build()?;
|
||||
let path_to_spv = wgsl_result.module.unwrap_single();
|
||||
|
||||
// needs to be fixed upstream
|
||||
let path_to_wgsl = path_to_spv.with_extension("wgsl");
|
||||
|
||||
println!("cargo::rustc-env=GRAPHENE_RASTER_NODES_SHADER_PATH={}", path_to_wgsl.display());
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"allows-weak-linkage": false,
|
||||
"arch": "spirv",
|
||||
"crt-objects-fallback": "false",
|
||||
"crt-static-allows-dylibs": true,
|
||||
"crt-static-respected": true,
|
||||
"data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64",
|
||||
"dll-prefix": "",
|
||||
"dll-suffix": ".spv.json",
|
||||
"dynamic-linking": true,
|
||||
"emit-debug-gdb-scripts": false,
|
||||
"env": "naga-wgsl",
|
||||
"linker-flavor": "unix",
|
||||
"linker-is-gnu": false,
|
||||
"llvm-target": "spirv-unknown-naga-wgsl",
|
||||
"main-needs-argc-argv": false,
|
||||
"metadata": {
|
||||
"description": null,
|
||||
"host_tools": null,
|
||||
"std": null,
|
||||
"tier": null
|
||||
},
|
||||
"panic-strategy": "abort",
|
||||
"simd-types-indirect": false,
|
||||
"target-pointer-width": "32"
|
||||
}
|
||||
1
node-graph/graster-nodes/shaders/src/lib.rs
Normal file
1
node-graph/graster-nodes/shaders/src/lib.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub const WGSL_SHADER: &str = include_str!(env!("GRAPHENE_RASTER_NODES_SHADER_PATH"));
|
||||
@@ -33,6 +33,7 @@ use num_traits::float::Float;
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, node_macro::ChoiceType)]
|
||||
#[cfg_attr(feature = "std", derive(dyn_any::DynAny, specta::Type, serde::Serialize, serde::Deserialize))]
|
||||
#[widget(Dropdown)]
|
||||
#[repr(u32)]
|
||||
pub enum LuminanceCalculation {
|
||||
#[default]
|
||||
#[label("sRGB")]
|
||||
@@ -52,6 +53,7 @@ fn luminance<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
luminance_calc: LuminanceCalculation,
|
||||
) -> T {
|
||||
@@ -68,7 +70,7 @@ fn luminance<T: Adjust<Color>>(
|
||||
input
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Raster"), shader_node(PerPixelAdjust))]
|
||||
#[node_macro::node(category("Raster"), cfg(feature = "std"))]
|
||||
fn gamma_correction<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
@@ -77,6 +79,7 @@ fn gamma_correction<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
#[default(2.2)]
|
||||
#[range((0.01, 10.))]
|
||||
@@ -98,6 +101,7 @@ fn extract_channel<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
channel: RedGreenBlueAlpha,
|
||||
) -> T {
|
||||
@@ -122,6 +126,7 @@ fn make_opaque<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
) -> T {
|
||||
input.adjust(|color| {
|
||||
@@ -139,7 +144,7 @@ fn make_opaque<T: Adjust<Color>>(
|
||||
//
|
||||
// Some further analysis available at:
|
||||
// https://geraldbakker.nl/psnumbers/brightness-contrast.html
|
||||
#[node_macro::node(name("Brightness/Contrast"), category("Raster: Adjustment"), properties("brightness_contrast_properties"), shader_node(PerPixelAdjust))]
|
||||
#[node_macro::node(name("Brightness/Contrast"), category("Raster: Adjustment"), properties("brightness_contrast_properties"), cfg(feature = "std"))]
|
||||
fn brightness_contrast<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
@@ -148,6 +153,7 @@ fn brightness_contrast<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
brightness: SignedPercentageF32,
|
||||
contrast: SignedPercentageF32,
|
||||
@@ -238,6 +244,7 @@ fn levels<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
#[default(0.)] shadows: PercentageF32,
|
||||
#[default(50.)] midtones: PercentageF32,
|
||||
@@ -306,6 +313,7 @@ fn black_and_white<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
#[default(Color::BLACK)] tint: Color,
|
||||
#[default(40.)]
|
||||
@@ -379,6 +387,7 @@ fn hue_saturation<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
hue_shift: AngleF32,
|
||||
saturation_shift: SignedPercentageF32,
|
||||
@@ -414,6 +423,7 @@ fn invert<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
) -> T {
|
||||
input.adjust(|color| {
|
||||
@@ -437,6 +447,7 @@ fn threshold<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
#[default(50.)] min_luminance: PercentageF32,
|
||||
#[default(100.)] max_luminance: PercentageF32,
|
||||
@@ -483,6 +494,7 @@ fn vibrance<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
vibrance: SignedPercentageF32,
|
||||
) -> T {
|
||||
@@ -551,6 +563,7 @@ pub enum RedGreenBlue {
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, node_macro::ChoiceType)]
|
||||
#[cfg_attr(feature = "std", derive(dyn_any::DynAny, specta::Type, serde::Serialize, serde::Deserialize))]
|
||||
#[widget(Radio)]
|
||||
#[repr(u32)]
|
||||
pub enum RedGreenBlueAlpha {
|
||||
#[default]
|
||||
Red,
|
||||
@@ -640,7 +653,7 @@ pub enum DomainWarpType {
|
||||
// Aims for interoperable compatibility with:
|
||||
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=%27mixr%27%20%3D%20Channel%20Mixer
|
||||
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Lab%20color%20only-,Channel%20Mixer,-Key%20is%20%27mixr
|
||||
#[node_macro::node(category("Raster: Adjustment"), properties("channel_mixer_properties"), shader_node(PerPixelAdjust))]
|
||||
#[node_macro::node(category("Raster: Adjustment"), properties("channel_mixer_properties"), cfg(feature = "std"))]
|
||||
fn channel_mixer<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
@@ -649,6 +662,7 @@ fn channel_mixer<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
|
||||
monochrome: bool,
|
||||
@@ -769,7 +783,7 @@ pub enum SelectiveColorChoice {
|
||||
//
|
||||
// Algorithm based on:
|
||||
// https://blog.pkh.me/p/22-understanding-selective-coloring-in-adobe-photoshop.html
|
||||
#[node_macro::node(category("Raster: Adjustment"), properties("selective_color_properties"), shader_node(PerPixelAdjust))]
|
||||
#[node_macro::node(category("Raster: Adjustment"), properties("selective_color_properties"), cfg(feature = "std"))]
|
||||
fn selective_color<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
@@ -778,6 +792,7 @@ fn selective_color<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
|
||||
mode: RelativeAbsolute,
|
||||
@@ -921,6 +936,7 @@ fn posterize<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
#[default(4)]
|
||||
#[hard_min(2.)]
|
||||
@@ -955,6 +971,7 @@ fn exposure<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
exposure: f32,
|
||||
offset: f32,
|
||||
|
||||
@@ -141,6 +141,7 @@ fn blend<T: Blend<Color> + Send>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
over: T,
|
||||
#[expose]
|
||||
#[implementations(
|
||||
@@ -149,6 +150,7 @@ fn blend<T: Blend<Color> + Send>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
under: T,
|
||||
blend_mode: BlendMode,
|
||||
#[default(100.)] opacity: PercentageF32,
|
||||
@@ -165,6 +167,7 @@ fn color_overlay<T: Adjust<Color>>(
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
#[default(Color::BLACK)] color: Color,
|
||||
blend_mode: BlendMode,
|
||||
|
||||
Reference in New Issue
Block a user