From cb6d72b49b43b3a06f48d5339c383b17c8431d47 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 25 Dec 2022 01:20:57 +0100 Subject: [PATCH] wgpu: Split up gradient shader based on type and repeat --- Cargo.lock | 1 + render/Cargo.toml | 1 + render/src/tessellator.rs | 3 +- render/wgpu/shaders/gradient/common.wgsl | 56 +------------------ render/wgpu/shaders/gradient/mode/focal.wgsl | 7 +++ render/wgpu/shaders/gradient/mode/linear.wgsl | 3 + render/wgpu/shaders/gradient/mode/radial.wgsl | 3 + .../wgpu/shaders/gradient/repeat/clamp.wgsl | 3 + .../wgpu/shaders/gradient/repeat/mirror.wgsl | 13 +++++ .../wgpu/shaders/gradient/repeat/repeat.wgsl | 3 + render/wgpu/shaders/gradient_storage.wgsl | 1 - render/wgpu/shaders/gradient_uniform.wgsl | 1 - render/wgpu/src/commands.rs | 23 ++++++-- render/wgpu/src/lib.rs | 16 ------ render/wgpu/src/mesh.rs | 13 ++++- render/wgpu/src/pipelines.rs | 38 +++++++------ render/wgpu/src/shaders.rs | 44 +++++++++++---- swf/src/types.rs | 2 +- 18 files changed, 122 insertions(+), 109 deletions(-) create mode 100644 render/wgpu/shaders/gradient/mode/focal.wgsl create mode 100644 render/wgpu/shaders/gradient/mode/linear.wgsl create mode 100644 render/wgpu/shaders/gradient/mode/radial.wgsl create mode 100644 render/wgpu/shaders/gradient/repeat/clamp.wgsl create mode 100644 render/wgpu/shaders/gradient/repeat/mirror.wgsl create mode 100644 render/wgpu/shaders/gradient/repeat/repeat.wgsl diff --git a/Cargo.lock b/Cargo.lock index 80a77cbc8..95cb23b34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3448,6 +3448,7 @@ version = "0.1.0" dependencies = [ "approx", "downcast-rs", + "enum-map", "flate2", "gc-arena", "gif 0.12.0", diff --git a/render/Cargo.toml b/render/Cargo.toml index dbb0abb5b..cbea53ae1 100644 --- a/render/Cargo.toml +++ b/render/Cargo.toml @@ -19,6 +19,7 @@ lyon = { version = "1.0.1", optional = true } thiserror = "1.0" wasm-bindgen = { version = "=0.2.83", optional = true } gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" } +enum-map = "2.4.2" [dependencies.jpeg-decoder] version = "0.3.0" diff --git a/render/src/tessellator.rs b/render/src/tessellator.rs index fa0f19f5c..4c8b6a3ce 100644 --- a/render/src/tessellator.rs +++ b/render/src/tessellator.rs @@ -1,5 +1,6 @@ use crate::bitmap::BitmapSource; use crate::shape_utils::{DistilledShape, DrawCommand, DrawPath}; +use enum_map::Enum; use lyon::path::Path; use lyon::tessellation::{ self, @@ -440,7 +441,7 @@ impl StrokeVertexConstructor for RuffleVertexCtor { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Enum)] pub enum GradientType { Linear, Radial, diff --git a/render/wgpu/shaders/gradient/common.wgsl b/render/wgpu/shaders/gradient/common.wgsl index d03b52adb..113472e09 100644 --- a/render/wgpu/shaders/gradient/common.wgsl +++ b/render/wgpu/shaders/gradient/common.wgsl @@ -5,58 +5,6 @@ struct VertexOutput { @group(2) @binding(0) var textureTransforms: TextureTransforms; -fn find_t(gradient_type: i32, focal_point: f32, uv: vec2) -> f32 { - switch( gradient_type ){ - // Radial gradient - case 1: { - return length(uv * 2.0 - 1.0); - } - - // Focal gradient - case 2: { - let uv = uv * 2.0 - 1.0; - var d: vec2 = vec2(focal_point, 0.0) - uv; - let l = length(d); - d = d / l; - return l / (sqrt(1.0 - focal_point * focal_point * d.y * d.y) + focal_point * d.x); - } - - // Linear gradient - default: { - return uv.x; - } - } -} - -fn normalize_t(repeat_mode: i32, t: f32) -> f32 { - switch( repeat_mode ){ - // Repeat - case 1: { - return fract(t); - } - - // Mirror - case 2: { - var result: f32 = t; - if( result < 0.0 ) - { - result = -t; - } - if( (i32(result) & 1) == 0 ) { - result = fract(result); - } else { - result = 1.0 - fract(result); - } - return result; - } - - // Clamp - default: { - return clamp(t, 0.0, 1.0); - } - } -} - @vertex fn main_vertex(in: VertexInput) -> VertexOutput { let matrix_ = textureTransforms.matrix_; @@ -70,8 +18,8 @@ fn main_fragment(in: VertexOutput) -> @location(0) vec4 { let last = gradient.num_colors - 1u; // Calculate normalized `t` position in gradient, [0.0, 1.0] being the bounds of the ratios. - var t: f32 = find_t(gradient.gradient_type, gradient.focal_point, in.uv); - t = normalize_t(gradient.repeat_mode, t); + var t: f32 = find_t(gradient.focal_point, in.uv); + t = normalize_t(t); t = clamp(t, ratio(0u), ratio(last)); // Find the two gradient colors bordering our position. diff --git a/render/wgpu/shaders/gradient/mode/focal.wgsl b/render/wgpu/shaders/gradient/mode/focal.wgsl new file mode 100644 index 000000000..6f48350bf --- /dev/null +++ b/render/wgpu/shaders/gradient/mode/focal.wgsl @@ -0,0 +1,7 @@ +fn find_t(focal_point: f32, uv: vec2) -> f32 { + let uv = uv * 2.0 - 1.0; + var d: vec2 = vec2(focal_point, 0.0) - uv; + let l = length(d); + d = d / l; + return l / (sqrt(1.0 - focal_point * focal_point * d.y * d.y) + focal_point * d.x); +} \ No newline at end of file diff --git a/render/wgpu/shaders/gradient/mode/linear.wgsl b/render/wgpu/shaders/gradient/mode/linear.wgsl new file mode 100644 index 000000000..97acd7655 --- /dev/null +++ b/render/wgpu/shaders/gradient/mode/linear.wgsl @@ -0,0 +1,3 @@ +fn find_t(focal_point: f32, uv: vec2) -> f32 { + return uv.x; +} \ No newline at end of file diff --git a/render/wgpu/shaders/gradient/mode/radial.wgsl b/render/wgpu/shaders/gradient/mode/radial.wgsl new file mode 100644 index 000000000..7d8b3e291 --- /dev/null +++ b/render/wgpu/shaders/gradient/mode/radial.wgsl @@ -0,0 +1,3 @@ +fn find_t(focal_point: f32, uv: vec2) -> f32 { + return length(uv * 2.0 - 1.0); +} \ No newline at end of file diff --git a/render/wgpu/shaders/gradient/repeat/clamp.wgsl b/render/wgpu/shaders/gradient/repeat/clamp.wgsl new file mode 100644 index 000000000..305d95d49 --- /dev/null +++ b/render/wgpu/shaders/gradient/repeat/clamp.wgsl @@ -0,0 +1,3 @@ +fn normalize_t(t: f32) -> f32 { + return clamp(t, 0.0, 1.0); +} \ No newline at end of file diff --git a/render/wgpu/shaders/gradient/repeat/mirror.wgsl b/render/wgpu/shaders/gradient/repeat/mirror.wgsl new file mode 100644 index 000000000..2c506bf31 --- /dev/null +++ b/render/wgpu/shaders/gradient/repeat/mirror.wgsl @@ -0,0 +1,13 @@ +fn normalize_t(t: f32) -> f32 { + var result: f32 = t; + if( result < 0.0 ) + { + result = -t; + } + if( (i32(result) & 1) == 0 ) { + result = fract(result); + } else { + result = 1.0 - fract(result); + } + return result; +} \ No newline at end of file diff --git a/render/wgpu/shaders/gradient/repeat/repeat.wgsl b/render/wgpu/shaders/gradient/repeat/repeat.wgsl new file mode 100644 index 000000000..3176289f4 --- /dev/null +++ b/render/wgpu/shaders/gradient/repeat/repeat.wgsl @@ -0,0 +1,3 @@ +fn normalize_t(t: f32) -> f32 { + return fract(t); +} \ No newline at end of file diff --git a/render/wgpu/shaders/gradient_storage.wgsl b/render/wgpu/shaders/gradient_storage.wgsl index 71ded2a0a..26eb228cb 100644 --- a/render/wgpu/shaders/gradient_storage.wgsl +++ b/render/wgpu/shaders/gradient_storage.wgsl @@ -5,7 +5,6 @@ struct Gradient { ratios: array, gradient_type: i32, num_colors: u32, - repeat_mode: i32, interpolation: i32, focal_point: f32, }; diff --git a/render/wgpu/shaders/gradient_uniform.wgsl b/render/wgpu/shaders/gradient_uniform.wgsl index 19e28254e..fa85240b4 100644 --- a/render/wgpu/shaders/gradient_uniform.wgsl +++ b/render/wgpu/shaders/gradient_uniform.wgsl @@ -5,7 +5,6 @@ struct Gradient { ratios: array, 4u>, // secretly array but this let's us squeeze it into alignment gradient_type: i32, num_colors: u32, - repeat_mode: i32, interpolation: i32, focal_point: f32, }; diff --git a/render/wgpu/src/commands.rs b/render/wgpu/src/commands.rs index 56802f580..228d8c024 100644 --- a/render/wgpu/src/commands.rs +++ b/render/wgpu/src/commands.rs @@ -14,9 +14,10 @@ use ruffle_render::backend::ShapeHandle; use ruffle_render::bitmap::BitmapHandle; use ruffle_render::commands::{Command, CommandList}; use ruffle_render::matrix::Matrix; +use ruffle_render::tessellator::GradientType; use ruffle_render::transform::Transform; use std::sync::Arc; -use swf::{BlendMode, Color}; +use swf::{BlendMode, Color, GradientSpread}; pub struct CommandTarget { frame_buffer: FrameBuffer, @@ -520,13 +521,18 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob } } - pub fn prep_gradient(&mut self, bind_group: &'pass wgpu::BindGroup) { + pub fn prep_gradient( + &mut self, + bind_group: &'pass wgpu::BindGroup, + mode: GradientType, + spread: GradientSpread, + ) { if self.needs_depth { self.render_pass - .set_pipeline(self.pipelines.gradient.pipeline_for(self.mask_state)); + .set_pipeline(self.pipelines.gradients[mode][spread].pipeline_for(self.mask_state)); } else { self.render_pass - .set_pipeline(self.pipelines.gradient.depthless_pipeline()); + .set_pipeline(self.pipelines.gradients[mode][spread].depthless_pipeline()); } self.render_pass.set_bind_group(2, bind_group, &[]); @@ -684,8 +690,13 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob DrawType::Color => { self.prep_color(); } - DrawType::Gradient { bind_group, .. } => { - self.prep_gradient(bind_group); + DrawType::Gradient { + bind_group, + spread, + mode, + .. + } => { + self.prep_gradient(bind_group, *mode, *spread); } DrawType::Bitmap { binds, .. } => { self.prep_bitmap(&binds.bind_group, TrivialBlend::Normal); diff --git a/render/wgpu/src/lib.rs b/render/wgpu/src/lib.rs index 2e9c5ee43..01a207dc6 100644 --- a/render/wgpu/src/lib.rs +++ b/render/wgpu/src/lib.rs @@ -111,10 +111,8 @@ struct GradientUniforms { ratios: [f32; 16], gradient_type: i32, num_colors: u32, - repeat_mode: i32, interpolation: i32, focal_point: f32, - _padding: [f32; 3], } impl From for GradientUniforms { @@ -136,14 +134,8 @@ impl From for GradientUniforms { GradientType::Focal => 2, }, num_colors: gradient.num_colors as u32, - repeat_mode: match gradient.repeat_mode { - swf::GradientSpread::Pad => 0, - swf::GradientSpread::Repeat => 1, - swf::GradientSpread::Reflect => 2, - }, interpolation: (gradient.interpolation == swf::GradientInterpolation::LinearRgb) as i32, focal_point: gradient.focal_point.to_f32(), - _padding: Default::default(), } } } @@ -155,10 +147,8 @@ struct GradientStorage { ratios: [f32; 16], gradient_type: i32, num_colors: u32, - repeat_mode: i32, interpolation: i32, focal_point: f32, - _padding: [f32; 3], } impl From for GradientStorage { @@ -177,14 +167,8 @@ impl From for GradientStorage { GradientType::Focal => 2, }, num_colors: gradient.num_colors as u32, - repeat_mode: match gradient.repeat_mode { - swf::GradientSpread::Pad => 0, - swf::GradientSpread::Repeat => 1, - swf::GradientSpread::Reflect => 2, - }, interpolation: (gradient.interpolation == swf::GradientInterpolation::LinearRgb) as i32, focal_point: gradient.focal_point.to_f32(), - _padding: Default::default(), } } } diff --git a/render/wgpu/src/mesh.rs b/render/wgpu/src/mesh.rs index 991eb4774..fbb3eac37 100644 --- a/render/wgpu/src/mesh.rs +++ b/render/wgpu/src/mesh.rs @@ -7,8 +7,10 @@ use crate::{ use ruffle_render::backend::RenderBackend; use ruffle_render::bitmap::BitmapSource; -use ruffle_render::tessellator::{Bitmap, Draw as LyonDraw, DrawType as TessDrawType, Gradient}; -use swf::CharacterId; +use ruffle_render::tessellator::{ + Bitmap, Draw as LyonDraw, DrawType as TessDrawType, Gradient, GradientType, +}; +use swf::{CharacterId, GradientSpread}; #[derive(Debug)] pub struct Mesh { @@ -90,6 +92,8 @@ pub enum DrawType { texture_transforms: wgpu::Buffer, gradient: wgpu::Buffer, bind_group: wgpu::BindGroup, + spread: GradientSpread, + mode: GradientType, }, Bitmap { texture_transforms: wgpu::Buffer, @@ -118,6 +122,9 @@ impl DrawType { ), ); + let spread = gradient.repeat_mode; + let mode = gradient.gradient_type; + let (gradient_ubo, buffer_size) = if descriptors.limits.max_storage_buffers_per_shader_stage > 0 { ( @@ -180,6 +187,8 @@ impl DrawType { DrawType::Gradient { texture_transforms: tex_transforms_ubo, gradient: gradient_ubo, + spread, + mode, bind_group, } } diff --git a/render/wgpu/src/pipelines.rs b/render/wgpu/src/pipelines.rs index e355b6541..6763110d3 100644 --- a/render/wgpu/src/pipelines.rs +++ b/render/wgpu/src/pipelines.rs @@ -3,6 +3,8 @@ use crate::layouts::BindLayouts; use crate::shaders::Shaders; use crate::{MaskState, Vertex}; use enum_map::{enum_map, Enum, EnumMap}; +use ruffle_render::tessellator::GradientType; +use swf::GradientSpread; use wgpu::vertex_attr_array; pub const VERTEX_BUFFERS_DESCRIPTION: [wgpu::VertexBufferLayout; 1] = [wgpu::VertexBufferLayout { @@ -24,7 +26,7 @@ pub struct ShapePipeline { pub struct Pipelines { pub color: ShapePipeline, pub bitmap: EnumMap, - pub gradient: ShapePipeline, + pub gradients: EnumMap>, pub complex_blends: EnumMap, } @@ -78,20 +80,24 @@ impl Pipelines { wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING, ); - let gradient_pipelines = create_shape_pipeline( - "Gradient", - device, - format, - &shaders.gradient_shader, - msaa_sample_count, - &VERTEX_BUFFERS_DESCRIPTION, - &[ - &bind_layouts.globals, - &bind_layouts.transforms, - &bind_layouts.gradient, - ], - wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING, - ); + let gradient_pipelines = enum_map! { + mode => enum_map! { + spread => create_shape_pipeline( + &format!("Gradient - {mode:?} {spread:?}"), + device, + format, + &shaders.gradient_shaders[mode][spread], + msaa_sample_count, + &VERTEX_BUFFERS_DESCRIPTION, + &[ + &bind_layouts.globals, + &bind_layouts.transforms, + &bind_layouts.gradient, + ], + wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING, + ) + } + }; let complex_blend_pipelines = enum_map! { blend => create_shape_pipeline( @@ -136,7 +142,7 @@ impl Pipelines { Self { color: color_pipelines, bitmap: EnumMap::from_array(bitmap_pipelines), - gradient: gradient_pipelines, + gradients: gradient_pipelines, complex_blends: complex_blend_pipelines, } } diff --git a/render/wgpu/src/shaders.rs b/render/wgpu/src/shaders.rs index e273cb570..eebd7537f 100644 --- a/render/wgpu/src/shaders.rs +++ b/render/wgpu/src/shaders.rs @@ -1,11 +1,13 @@ use crate::blend::ComplexBlend; use enum_map::{enum_map, EnumMap}; +use ruffle_render::tessellator::GradientType; +use swf::GradientSpread; #[derive(Debug)] pub struct Shaders { pub color_shader: wgpu::ShaderModule, pub bitmap_shader: wgpu::ShaderModule, - pub gradient_shader: wgpu::ShaderModule, + pub gradient_shaders: EnumMap>, pub copy_srgb_shader: wgpu::ShaderModule, pub copy_shader: wgpu::ShaderModule, pub blend_shaders: EnumMap, @@ -15,12 +17,6 @@ impl Shaders { pub fn new(device: &wgpu::Device) -> Self { let color_shader = create_shader(device, "color", include_str!("../shaders/color.wgsl")); let bitmap_shader = create_shader(device, "bitmap", include_str!("../shaders/bitmap.wgsl")); - let gradient_shader = if device.limits().max_storage_buffers_per_shader_stage > 0 { - include_str!("../shaders/gradient_storage.wgsl") - } else { - include_str!("../shaders/gradient_uniform.wgsl") - }; - let gradient_shader = create_gradient_shader(device, "gradient", gradient_shader); let copy_srgb_shader = create_shader( device, "copy sRGB", @@ -41,10 +37,25 @@ impl Shaders { ComplexBlend::HardLight => create_shader(device, "blend - hardlight", include_str!("../shaders/blend/hardlight.wgsl")), }; + let gradient_shader = if device.limits().max_storage_buffers_per_shader_stage > 0 { + include_str!("../shaders/gradient_storage.wgsl") + } else { + include_str!("../shaders/gradient_uniform.wgsl") + }; + let type_focal = include_str!("../shaders/gradient/mode/focal.wgsl"); + let type_linear = include_str!("../shaders/gradient/mode/linear.wgsl"); + let type_radial = include_str!("../shaders/gradient/mode/radial.wgsl"); + + let gradient_shaders = enum_map! { + GradientType::Focal => create_gradient_shaders(device, "focal", type_focal, gradient_shader), + GradientType::Linear => create_gradient_shaders(device, "linear", type_linear, gradient_shader), + GradientType::Radial => create_gradient_shaders(device, "radial", type_radial, gradient_shader), + }; + Self { color_shader, bitmap_shader, - gradient_shader, + gradient_shaders, copy_srgb_shader, copy_shader, blend_shaders, @@ -67,9 +78,20 @@ fn create_shader(device: &wgpu::Device, name: &str, src: &str) -> wgpu::ShaderMo device.create_shader_module(desc) } -fn create_gradient_shader(device: &wgpu::Device, name: &str, src: &str) -> wgpu::ShaderModule { +fn create_gradient_shaders( + device: &wgpu::Device, + name: &str, + mode: &str, + special: &str, +) -> EnumMap { const COMMON_SRC: &str = include_str!("../shaders/gradient/common.wgsl"); - let src = [src, COMMON_SRC].concat(); + const SPREAD_REFLECT: &str = include_str!("../shaders/gradient/repeat/mirror.wgsl"); + const SPREAD_REPEAT: &str = include_str!("../shaders/gradient/repeat/repeat.wgsl"); + const SPREAD_PAD: &str = include_str!("../shaders/gradient/repeat/clamp.wgsl"); - create_shader(device, name, &src) + enum_map! { + GradientSpread::Reflect => create_shader(device, &format!("gradient - {name} reflect"), &[mode, SPREAD_REFLECT, special, COMMON_SRC].concat()), + GradientSpread::Repeat => create_shader(device, &format!("gradient - {name} repeat"), &[mode, SPREAD_REPEAT, special, COMMON_SRC].concat()), + GradientSpread::Pad => create_shader(device, &format!("gradient - {name} pad"), &[mode, SPREAD_PAD, special, COMMON_SRC].concat()), + } } diff --git a/swf/src/types.rs b/swf/src/types.rs index e4b79fd47..9dd662287 100644 --- a/swf/src/types.rs +++ b/swf/src/types.rs @@ -759,7 +759,7 @@ pub struct Gradient { pub records: Vec, } -#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq, Enum)] pub enum GradientSpread { Pad = 0, Reflect = 1,