summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Bingus <shankern@protonmail.com>2023-05-29 16:44:56 -0700
committerLibravatar Bingus <shankern@protonmail.com>2023-06-06 16:46:20 -0700
commitea7f2626b11af249510b27001fb6addd7f9210a9 (patch)
treeb9a685c94c9cd536f74bdf4e20b25de8ac6b5bd8
parentc15f1b5f6575792cc89bb5fba2e613428397e46a (diff)
downloadiced-ea7f2626b11af249510b27001fb6addd7f9210a9.tar.gz
iced-ea7f2626b11af249510b27001fb6addd7f9210a9.tar.bz2
iced-ea7f2626b11af249510b27001fb6addd7f9210a9.zip
Optimized gradient data packing.
-rw-r--r--core/src/color.rs13
-rw-r--r--graphics/src/gradient.rs71
-rw-r--r--wgpu/src/quad/gradient.rs34
-rw-r--r--wgpu/src/shader/quad.wgsl87
-rw-r--r--wgpu/src/shader/triangle.wgsl71
-rw-r--r--wgpu/src/triangle.rs26
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
),
}],
},