wgpu: Split up gradient shader based on type and repeat

This commit is contained in:
Nathan Adams 2022-12-25 01:20:57 +01:00
parent a79e73fb12
commit cb6d72b49b
18 changed files with 122 additions and 109 deletions

1
Cargo.lock generated
View File

@ -3448,6 +3448,7 @@ version = "0.1.0"
dependencies = [
"approx",
"downcast-rs",
"enum-map",
"flate2",
"gc-arena",
"gif 0.12.0",

View File

@ -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"

View File

@ -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<Vertex> for RuffleVertexCtor {
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Enum)]
pub enum GradientType {
Linear,
Radial,

View File

@ -5,58 +5,6 @@ struct VertexOutput {
@group(2) @binding(0) var<uniform> textureTransforms: TextureTransforms;
fn find_t(gradient_type: i32, focal_point: f32, uv: vec2<f32>) -> 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<f32> = vec2<f32>(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<f32> {
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.

View File

@ -0,0 +1,7 @@
fn find_t(focal_point: f32, uv: vec2<f32>) -> f32 {
let uv = uv * 2.0 - 1.0;
var d: vec2<f32> = vec2<f32>(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);
}

View File

@ -0,0 +1,3 @@
fn find_t(focal_point: f32, uv: vec2<f32>) -> f32 {
return uv.x;
}

View File

@ -0,0 +1,3 @@
fn find_t(focal_point: f32, uv: vec2<f32>) -> f32 {
return length(uv * 2.0 - 1.0);
}

View File

@ -0,0 +1,3 @@
fn normalize_t(t: f32) -> f32 {
return clamp(t, 0.0, 1.0);
}

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
fn normalize_t(t: f32) -> f32 {
return fract(t);
}

View File

@ -5,7 +5,6 @@ struct Gradient {
ratios: array<f32,16u>,
gradient_type: i32,
num_colors: u32,
repeat_mode: i32,
interpolation: i32,
focal_point: f32,
};

View File

@ -5,7 +5,6 @@ struct Gradient {
ratios: array<vec4<f32>, 4u>, // secretly array<f32; 16> but this let's us squeeze it into alignment
gradient_type: i32,
num_colors: u32,
repeat_mode: i32,
interpolation: i32,
focal_point: f32,
};

View File

@ -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);

View File

@ -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<TessGradient> for GradientUniforms {
@ -136,14 +134,8 @@ impl From<TessGradient> 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<TessGradient> for GradientStorage {
@ -177,14 +167,8 @@ impl From<TessGradient> 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(),
}
}
}

View File

@ -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,
}
}

View File

@ -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<TrivialBlend, ShapePipeline>,
pub gradient: ShapePipeline,
pub gradients: EnumMap<GradientType, EnumMap<GradientSpread, ShapePipeline>>,
pub complex_blends: EnumMap<ComplexBlend, ShapePipeline>,
}
@ -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,
}
}

View File

@ -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<GradientType, EnumMap<GradientSpread, wgpu::ShaderModule>>,
pub copy_srgb_shader: wgpu::ShaderModule,
pub copy_shader: wgpu::ShaderModule,
pub blend_shaders: EnumMap<ComplexBlend, wgpu::ShaderModule>,
@ -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<GradientSpread, wgpu::ShaderModule> {
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()),
}
}

View File

@ -759,7 +759,7 @@ pub struct Gradient {
pub records: Vec<GradientRecord>,
}
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq, Enum)]
pub enum GradientSpread {
Pad = 0,
Reflect = 1,