diff options
author | 2023-05-29 16:44:56 -0700 | |
---|---|---|
committer | 2023-06-06 16:46:20 -0700 | |
commit | ea7f2626b11af249510b27001fb6addd7f9210a9 (patch) | |
tree | b9a685c94c9cd536f74bdf4e20b25de8ac6b5bd8 | |
parent | c15f1b5f6575792cc89bb5fba2e613428397e46a (diff) | |
download | iced-ea7f2626b11af249510b27001fb6addd7f9210a9.tar.gz iced-ea7f2626b11af249510b27001fb6addd7f9210a9.tar.bz2 iced-ea7f2626b11af249510b27001fb6addd7f9210a9.zip |
Optimized gradient data packing.
-rw-r--r-- | core/src/color.rs | 13 | ||||
-rw-r--r-- | graphics/src/gradient.rs | 71 | ||||
-rw-r--r-- | wgpu/src/quad/gradient.rs | 34 | ||||
-rw-r--r-- | wgpu/src/shader/quad.wgsl | 87 | ||||
-rw-r--r-- | wgpu/src/shader/triangle.wgsl | 71 | ||||
-rw-r--r-- | wgpu/src/triangle.rs | 26 |
6 files changed, 144 insertions, 158 deletions
diff --git a/core/src/color.rs b/core/src/color.rs index 1392f28b..e3bbab73 100644 --- a/core/src/color.rs +++ b/core/src/color.rs @@ -145,6 +145,19 @@ impl From<[f32; 4]> for Color { } } +impl Into<u32> for Color { + fn into(self) -> u32 { + let [r, g, b, a] = self.into_rgba8(); + + let r = (r as u32) << 24; + let g = (g as u32) << 16; + let b = (b as u32) << 8; + let a = a as u32; + + r | g | b | a + } +} + /// Creates a [`Color`] with shorter and cleaner syntax. /// /// # Examples diff --git a/graphics/src/gradient.rs b/graphics/src/gradient.rs index d26b5665..57cc007f 100644 --- a/graphics/src/gradient.rs +++ b/graphics/src/gradient.rs @@ -99,61 +99,68 @@ impl Linear { /// Packs the [`Gradient`] for use in shader code. pub fn pack(&self) -> Packed { - let mut data: [f32; 44] = [0.0; 44]; + let mut colors = [0u32; 8]; + let mut offsets = [0.0f32; 8]; for (index, stop) in self.stops.iter().enumerate() { - let [r, g, b, a] = - color::pack(stop.map_or(Color::default(), |s| s.color)) - .components(); - - data[index * 4] = r; - data[(index * 4) + 1] = g; - data[(index * 4) + 2] = b; - data[(index * 4) + 3] = a; - - data[32 + index] = stop.map_or(2.0, |s| s.offset); + let (color, offset) = stop + .map_or((Color::default().into_u32(), 2.0), |s| { + (s.color.into_u32(), s.offset) + }); + colors[index] = color; + offsets[index] = offset; } - data[40] = self.start.x; - data[41] = self.start.y; - data[42] = self.end.x; - data[43] = self.end.y; + let direction = [self.start.x, self.start.y, self.end.x, self.end.y]; - Packed(data) + Packed { + colors, + offsets, + direction, + } } } /// Packed [`Gradient`] data for use in shader code. #[derive(Debug, Copy, Clone, PartialEq)] #[repr(C)] -pub struct Packed([f32; 44]); +pub struct Packed { + // 8 colors, each packed into a u32 + colors: [u32; 8], + offsets: [f32; 8], + direction: [f32; 4], +} /// Creates a new [`Packed`] gradient for use in shader code. pub fn pack(gradient: &core::Gradient, bounds: Rectangle) -> Packed { match gradient { core::Gradient::Linear(linear) => { - let mut data: [f32; 44] = [0.0; 44]; + let mut colors = [0u32; 8]; + let mut offsets = [0.0f32; 8]; for (index, stop) in linear.stops.iter().enumerate() { - let [r, g, b, a] = - color::pack(stop.map_or(Color::default(), |s| s.color)) - .components(); - - data[index * 4] = r; - data[(index * 4) + 1] = g; - data[(index * 4) + 2] = b; - data[(index * 4) + 3] = a; - data[32 + index] = stop.map_or(2.0, |s| s.offset); + // let [r, g, b, a] = + // color::pack(stop.map_or(Color::default(), |s| s.color)) + // .components(); + + let (color, offset) = stop + .map_or((Color::default().into_u32(), 2.0), |s| { + (s.color.into_u32(), s.offset) + }); + + colors[index] = color; + offsets[index] = offset; } let (start, end) = linear.angle.to_distance(&bounds); - data[40] = start.x; - data[41] = start.y; - data[42] = end.x; - data[43] = end.y; + let direction = [start.x, start.y, end.x, end.y]; - Packed(data) + Packed { + colors, + offsets, + direction, + } } } } diff --git a/wgpu/src/quad/gradient.rs b/wgpu/src/quad/gradient.rs index 2b56d594..1b45c9f4 100644 --- a/wgpu/src/quad/gradient.rs +++ b/wgpu/src/quad/gradient.rs @@ -96,36 +96,24 @@ impl Pipeline { as u64, step_mode: wgpu::VertexStepMode::Instance, attributes: &wgpu::vertex_attr_array!( - // Color 1 - 1 => Float32x4, - // Color 2 - 2 => Float32x4, - // Color 3 - 3 => Float32x4, - // Color 4 - 4 => Float32x4, - // Color 5 - 5 => Float32x4, - // Color 6 - 6 => Float32x4, - // Color 7 - 7 => Float32x4, - // Color 8 - 8 => Float32x4, + // Colors 1-4 + 1 => Uint32x4, + // Colors 5-8 + 2 => Uint32x4, // Offsets 1-4 - 9 => Float32x4, + 3 => Float32x4, // Offsets 5-8 - 10 => Float32x4, + 4 => Float32x4, // Direction - 11 => Float32x4, + 5 => Float32x4, // Position & Scale - 12 => Float32x4, + 6 => Float32x4, // Border color - 13 => Float32x4, + 7 => Float32x4, // Border radius - 14 => Float32x4, + 8 => Float32x4, // Border width - 15 => Float32 + 9 => Float32 ), }, ], diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 3232bdbe..fdcc6743 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -38,6 +38,19 @@ fn select_border_radius(radi: vec4<f32>, position: vec2<f32>, center: vec2<f32>) return rx; } +fn l(c: f32) -> f32 { + if (c < 0.04045) { + return c / 12.92; + } else { + return pow(((c + 0.055) / 1.055), 2.4); + }; +} + +fn to_linear(color: u32) -> vec4<f32> { + let c = unpack4x8unorm(color); //unpacks as a b g r + return vec4<f32>(l(c.w), l(c.z), l(c.y), c.x); +} + struct SolidVertexInput { @location(0) v_pos: vec2<f32>, @location(1) color: vec4<f32>, @@ -140,40 +153,28 @@ fn solid_fs_main( struct GradientVertexInput { @location(0) v_pos: vec2<f32>, - @location(1) color_1: vec4<f32>, - @location(2) color_2: vec4<f32>, - @location(3) color_3: vec4<f32>, - @location(4) color_4: vec4<f32>, - @location(5) color_5: vec4<f32>, - @location(6) color_6: vec4<f32>, - @location(7) color_7: vec4<f32>, - @location(8) color_8: vec4<f32>, - @location(9) offsets_1: vec4<f32>, - @location(10) offsets_2: vec4<f32>, - @location(11) direction: vec4<f32>, - @location(12) position_and_scale: vec4<f32>, - @location(13) border_color: vec4<f32>, - @location(14) border_radius: vec4<f32>, - @location(15) border_width: f32 + @location(1) colors_1: vec4<u32>, + @location(2) colors_2: vec4<u32>, + @location(3) offsets_1: vec4<f32>, + @location(4) offsets_2: vec4<f32>, + @location(5) direction: vec4<f32>, + @location(6) position_and_scale: vec4<f32>, + @location(7) border_color: vec4<f32>, + @location(8) border_radius: vec4<f32>, + @location(9) border_width: f32, } struct GradientVertexOutput { @builtin(position) position: vec4<f32>, - @location(1) color_1: vec4<f32>, - @location(2) color_2: vec4<f32>, - @location(3) color_3: vec4<f32>, - @location(4) color_4: vec4<f32>, - @location(5) color_5: vec4<f32>, - @location(6) color_6: vec4<f32>, - @location(7) color_7: vec4<f32>, - @location(8) color_8: vec4<f32>, - @location(9) offsets_1: vec4<f32>, - @location(10) offsets_2: vec4<f32>, - @location(11) direction: vec4<f32>, - @location(12) position_and_scale: vec4<f32>, - @location(13) border_color: vec4<f32>, - @location(14) border_radius: vec4<f32>, - @location(15) border_width: f32 + @location(1) colors_1: vec4<u32>, + @location(2) colors_2: vec4<u32>, + @location(3) offsets_1: vec4<f32>, + @location(4) offsets_2: vec4<f32>, + @location(5) direction: vec4<f32>, + @location(6) position_and_scale: vec4<f32>, + @location(7) border_color: vec4<f32>, + @location(8) border_radius: vec4<f32>, + @location(9) border_width: f32, } @vertex @@ -199,14 +200,8 @@ fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { ); out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); - out.color_1 = input.color_1; - out.color_2 = input.color_2; - out.color_3 = input.color_3; - out.color_4 = input.color_4; - out.color_5 = input.color_5; - out.color_6 = input.color_6; - out.color_7 = input.color_7; - out.color_8 = input.color_8; + out.colors_1 = input.colors_1; + out.colors_2 = input.colors_2; out.offsets_1 = input.offsets_1; out.offsets_2 = input.offsets_2; out.direction = input.direction * globals.scale; @@ -274,14 +269,14 @@ fn gradient( @fragment fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { let colors = array<vec4<f32>, 8>( - input.color_1, - input.color_2, - input.color_3, - input.color_4, - input.color_5, - input.color_6, - input.color_7, - input.color_8, + to_linear(input.colors_1.x), + to_linear(input.colors_1.y), + to_linear(input.colors_1.z), + to_linear(input.colors_1.w), + to_linear(input.colors_2.x), + to_linear(input.colors_2.y), + to_linear(input.colors_2.z), + to_linear(input.colors_2.w), ); var offsets = array<f32, 8>( diff --git a/wgpu/src/shader/triangle.wgsl b/wgpu/src/shader/triangle.wgsl index 625fa46e..5a73a77f 100644 --- a/wgpu/src/shader/triangle.wgsl +++ b/wgpu/src/shader/triangle.wgsl @@ -4,6 +4,19 @@ struct Globals { @group(0) @binding(0) var<uniform> globals: Globals; +fn l(c: f32) -> f32 { + if (c < 0.04045) { + return c / 12.92; + } else { + return pow(((c + 0.055) / 1.055), 2.4); + }; +} + +fn to_linear(color: u32) -> vec4<f32> { + let c = unpack4x8unorm(color); //unpacks as a b g r + return vec4<f32>(l(c.w), l(c.z), l(c.y), c.x); +} + struct SolidVertexInput { @location(0) position: vec2<f32>, @location(1) color: vec4<f32>, @@ -32,46 +45,28 @@ fn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> { struct GradientVertexOutput { @builtin(position) position: vec4<f32>, @location(0) raw_position: vec2<f32>, - @location(1) color_1: vec4<f32>, - @location(2) color_2: vec4<f32>, - @location(3) color_3: vec4<f32>, - @location(4) color_4: vec4<f32>, - @location(5) color_5: vec4<f32>, - @location(6) color_6: vec4<f32>, - @location(7) color_7: vec4<f32>, - @location(8) color_8: vec4<f32>, - @location(9) offsets_1: vec4<f32>, - @location(10) offsets_2: vec4<f32>, - @location(11) direction: vec4<f32>, + @location(1) colors_1: vec4<u32>, + @location(2) colors_2: vec4<u32>, + @location(3) offsets_1: vec4<f32>, + @location(4) offsets_2: vec4<f32>, + @location(5) direction: vec4<f32>, } @vertex fn gradient_vs_main( @location(0) input: vec2<f32>, - @location(1) color_1: vec4<f32>, - @location(2) color_2: vec4<f32>, - @location(3) color_3: vec4<f32>, - @location(4) color_4: vec4<f32>, - @location(5) color_5: vec4<f32>, - @location(6) color_6: vec4<f32>, - @location(7) color_7: vec4<f32>, - @location(8) color_8: vec4<f32>, - @location(9) offsets_1: vec4<f32>, - @location(10) offsets_2: vec4<f32>, - @location(11) direction: vec4<f32>, + @location(1) colors_1: vec4<u32>, + @location(2) colors_2: vec4<u32>, + @location(3) offsets_1: vec4<f32>, + @location(4) offsets_2: vec4<f32>, + @location(5) direction: vec4<f32>, ) -> GradientVertexOutput { var output: GradientVertexOutput; output.position = globals.transform * vec4<f32>(input.xy, 0.0, 1.0); output.raw_position = input; - output.color_1 = color_1; - output.color_2 = color_2; - output.color_3 = color_3; - output.color_4 = color_4; - output.color_5 = color_5; - output.color_6 = color_6; - output.color_7 = color_7; - output.color_8 = color_8; + output.colors_1 = colors_1; + output.colors_2 = colors_2; output.offsets_1 = offsets_1; output.offsets_2 = offsets_2; output.direction = direction; @@ -135,14 +130,14 @@ fn gradient( @fragment fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { let colors = array<vec4<f32>, 8>( - input.color_1, - input.color_2, - input.color_3, - input.color_4, - input.color_5, - input.color_6, - input.color_7, - input.color_8, + to_linear(input.colors_1.x), + to_linear(input.colors_1.y), + to_linear(input.colors_1.z), + to_linear(input.colors_1.w), + to_linear(input.colors_2.x), + to_linear(input.colors_2.y), + to_linear(input.colors_2.z), + to_linear(input.colors_2.w), ); var offsets = array<f32, 8>( diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 6f32f182..3f633e14 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -652,28 +652,16 @@ mod gradient { attributes: &wgpu::vertex_attr_array!( // Position 0 => Float32x2, - // Color 1 - 1 => Float32x4, - // Color 2 - 2 => Float32x4, - // Color 3 - 3 => Float32x4, - // Color 4 - 4 => Float32x4, - // Color 5 - 5 => Float32x4, - // Color 6 - 6 => Float32x4, - // Color 7 - 7 => Float32x4, - // Color 8 - 8 => Float32x4, + // Colors 1-4 + 1 => Uint32x4, + // Colors 5-8, + 2 => Uint32x4, // Offsets 1-4 - 9 => Float32x4, + 3 => Float32x4, // Offsets 5-8 - 10 => Float32x4, + 4 => Float32x4, // Direction - 11 => Float32x4 + 5 => Float32x4 ), }], }, |