Reduced memory transfer of OpenGL gradient uniform upload. Rearranged gradient uniforms on OpenGL side to be more performant.
This commit is contained in:
parent
f7ce7244d0
commit
1eb8d972ba
7 changed files with 83 additions and 128 deletions
|
|
@ -91,7 +91,7 @@ fn generate_box(frame: &mut Frame, bounds: Size) -> bool {
|
||||||
|
|
||||||
let gradient = |top_left: Point, bottom_right: Point| -> Gradient {
|
let gradient = |top_left: Point, bottom_right: Point| -> Gradient {
|
||||||
let mut builder = Gradient::linear(top_left, bottom_right);
|
let mut builder = Gradient::linear(top_left, bottom_right);
|
||||||
let stops = thread_rng().gen_range(1..10u32);
|
let stops = thread_rng().gen_range(1..15u32);
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i <= stops {
|
while i <= stops {
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,10 @@ impl Pipeline {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.use_program(Some(program));
|
gl.use_program(Some(program));
|
||||||
|
|
||||||
let matrix: [f32; 16] = Transformation::identity().into();
|
|
||||||
gl.uniform_matrix_4_f32_slice(
|
gl.uniform_matrix_4_f32_slice(
|
||||||
Some(&transform_location),
|
Some(&transform_location),
|
||||||
false,
|
false,
|
||||||
&matrix,
|
Transformation::identity().as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
gl.uniform_1_f32(Some(&scale_location), 1.0);
|
gl.uniform_1_f32(Some(&scale_location), 1.0);
|
||||||
|
|
@ -139,11 +138,10 @@ impl Pipeline {
|
||||||
|
|
||||||
if transformation != self.current_transform {
|
if transformation != self.current_transform {
|
||||||
unsafe {
|
unsafe {
|
||||||
let matrix: [f32; 16] = transformation.into();
|
|
||||||
gl.uniform_matrix_4_f32_slice(
|
gl.uniform_matrix_4_f32_slice(
|
||||||
Some(&self.transform_location),
|
Some(&self.transform_location),
|
||||||
false,
|
false,
|
||||||
&matrix,
|
transformation.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.current_transform = transformation;
|
self.current_transform = transformation;
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,10 @@ impl Pipeline {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.use_program(Some(program));
|
gl.use_program(Some(program));
|
||||||
|
|
||||||
let matrix: [f32; 16] = Transformation::identity().into();
|
|
||||||
gl.uniform_matrix_4_f32_slice(
|
gl.uniform_matrix_4_f32_slice(
|
||||||
Some(&transform_location),
|
Some(&transform_location),
|
||||||
false,
|
false,
|
||||||
&matrix,
|
Transformation::identity().as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
gl.uniform_1_f32(Some(&scale_location), 1.0);
|
gl.uniform_1_f32(Some(&scale_location), 1.0);
|
||||||
|
|
@ -119,11 +118,10 @@ impl Pipeline {
|
||||||
|
|
||||||
if transformation != self.current_transform {
|
if transformation != self.current_transform {
|
||||||
unsafe {
|
unsafe {
|
||||||
let matrix: [f32; 16] = transformation.into();
|
|
||||||
gl.uniform_matrix_4_f32_slice(
|
gl.uniform_matrix_4_f32_slice(
|
||||||
Some(&self.transform_location),
|
Some(&self.transform_location),
|
||||||
false,
|
false,
|
||||||
&matrix,
|
transformation.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.current_transform = transformation;
|
self.current_transform = transformation;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
// GLSL does not support dynamically sized arrays without SSBOs
|
|
||||||
#define MAX_STOPS 64
|
|
||||||
|
|
||||||
#ifdef GL_ES
|
#ifdef GL_ES
|
||||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
@ -16,34 +13,38 @@ layout (location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
in vec2 raw_position;
|
in vec2 raw_position;
|
||||||
|
|
||||||
uniform vec2 gradient_start;
|
uniform vec4 gradient_direction;
|
||||||
uniform vec2 gradient_end;
|
|
||||||
|
|
||||||
uniform uint color_stops_size;
|
uniform uint color_stops_size;
|
||||||
uniform float color_stop_offsets[MAX_STOPS];
|
// GLSL does not support dynamically sized arrays without SSBOs so this is capped to 16 stops
|
||||||
uniform vec4 color_stop_colors[MAX_STOPS];
|
//stored as color(vec4) -> offset(vec4) sequentially;
|
||||||
|
uniform vec4 color_stops[32];
|
||||||
|
|
||||||
//TODO: rewrite without branching to make ALUs happy
|
//TODO: rewrite without branching to make ALUs happy
|
||||||
void main() {
|
void main() {
|
||||||
vec2 gradient_vec = vec2(gradient_end - gradient_start);
|
vec2 start = gradient_direction.xy;
|
||||||
vec2 current_vec = vec2(raw_position.xy - gradient_start);
|
vec2 end = gradient_direction.zw;
|
||||||
|
vec2 gradient_vec = vec2(end - start);
|
||||||
|
vec2 current_vec = vec2(raw_position.xy - start);
|
||||||
vec2 unit = normalize(gradient_vec);
|
vec2 unit = normalize(gradient_vec);
|
||||||
float coord_offset = dot(unit, current_vec) / length(gradient_vec);
|
float coord_offset = dot(unit, current_vec) / length(gradient_vec);
|
||||||
|
|
||||||
for (uint i = 0; i < color_stops_size - 1; i++) {
|
for (uint i = 0; i < color_stops_size - 2; i += 2) {
|
||||||
float stop_offset = color_stop_offsets[i];
|
vec4 color = color_stops[i];
|
||||||
float next_stop_offset = color_stop_offsets[i + 1];
|
float offset = color_stops[i+1].x;
|
||||||
|
|
||||||
if (stop_offset <= coord_offset && coord_offset <= next_stop_offset) {
|
vec4 next_color = color_stops[i+2];
|
||||||
fragColor = mix(color_stop_colors[i], color_stop_colors[i+1], smoothstep(
|
float next_offset = color_stops[i+3].x;
|
||||||
stop_offset,
|
|
||||||
next_stop_offset,
|
if (offset <= coord_offset && coord_offset <= next_offset) {
|
||||||
|
fragColor = mix(color, next_color, smoothstep(
|
||||||
|
offset,
|
||||||
|
next_offset,
|
||||||
coord_offset
|
coord_offset
|
||||||
));
|
));
|
||||||
} else if (coord_offset < color_stop_offsets[0]) {
|
} else if (coord_offset < color_stops[1].x) {
|
||||||
fragColor = color_stop_colors[0];
|
fragColor = color_stops[0];
|
||||||
} else if (coord_offset > color_stop_offsets[color_stops_size - 1]) {
|
} else if (coord_offset > color_stops[color_stops_size - 1].x) {
|
||||||
fragColor = color_stop_colors[color_stops_size - 1];
|
fragColor = color_stops[color_stops_size - 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::program::Version;
|
use crate::program::Version;
|
||||||
use crate::triangle::{simple_triangle_program, set_transform};
|
use crate::triangle::{set_transform, simple_triangle_program};
|
||||||
use glow::{Context, HasContext, NativeProgram};
|
use glow::{Context, HasContext, NativeProgram};
|
||||||
use iced_graphics::gradient::Linear;
|
|
||||||
use iced_graphics::gradient::Gradient;
|
use iced_graphics::gradient::Gradient;
|
||||||
|
use iced_graphics::gradient::Linear;
|
||||||
use iced_graphics::Transformation;
|
use iced_graphics::Transformation;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -20,21 +20,14 @@ pub struct GradientUniformData {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct GradientUniformLocations {
|
struct GradientUniformLocations {
|
||||||
gradient_start_location: <Context as HasContext>::UniformLocation,
|
gradient_direction_location: <Context as HasContext>::UniformLocation,
|
||||||
gradient_end_location: <Context as HasContext>::UniformLocation,
|
|
||||||
color_stops_size_location: <Context as HasContext>::UniformLocation,
|
color_stops_size_location: <Context as HasContext>::UniformLocation,
|
||||||
//currently the maximum number of stops is 64 due to needing to allocate the
|
//currently the maximum number of stops is 64 due to needing to allocate the
|
||||||
//memory for the array of stops with a const value in GLSL
|
//memory for the array of stops with a const value in GLSL
|
||||||
color_stops_locations: [ColorStopLocation; 64],
|
color_stops_location: <Context as HasContext>::UniformLocation,
|
||||||
transform_location: <Context as HasContext>::UniformLocation,
|
transform_location: <Context as HasContext>::UniformLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Debug, Clone)]
|
|
||||||
struct ColorStopLocation {
|
|
||||||
color: <Context as HasContext>::UniformLocation,
|
|
||||||
offset: <Context as HasContext>::UniformLocation,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GradientProgram {
|
impl GradientProgram {
|
||||||
pub fn new(gl: &Context, shader_version: &Version) -> Self {
|
pub fn new(gl: &Context, shader_version: &Version) -> Self {
|
||||||
let program = simple_triangle_program(
|
let program = simple_triangle_program(
|
||||||
|
|
@ -56,36 +49,25 @@ impl GradientProgram {
|
||||||
transform: &Transformation,
|
transform: &Transformation,
|
||||||
) {
|
) {
|
||||||
if transform != &self.uniform_data.transform {
|
if transform != &self.uniform_data.transform {
|
||||||
set_transform(gl, self.uniform_data.uniform_locations.transform_location, *transform);
|
set_transform(
|
||||||
|
gl,
|
||||||
|
self.uniform_data.uniform_locations.transform_location,
|
||||||
|
*transform,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if &self.uniform_data.gradient != gradient {
|
if &self.uniform_data.gradient != gradient {
|
||||||
match gradient {
|
match gradient {
|
||||||
Gradient::Linear(linear) => {
|
Gradient::Linear(linear) => {
|
||||||
let gradient_start: [f32; 2] = (linear.start).into();
|
|
||||||
let gradient_end: [f32; 2] = (linear.end).into();
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.uniform_2_f32(
|
gl.uniform_4_f32(
|
||||||
Some(
|
Some(
|
||||||
&self
|
&self.uniform_data.uniform_locations.gradient_direction_location
|
||||||
.uniform_data
|
|
||||||
.uniform_locations
|
|
||||||
.gradient_start_location,
|
|
||||||
),
|
),
|
||||||
gradient_start[0],
|
linear.start.x,
|
||||||
gradient_start[1],
|
linear.start.y,
|
||||||
);
|
linear.end.x,
|
||||||
|
linear.end.y
|
||||||
gl.uniform_2_f32(
|
|
||||||
Some(
|
|
||||||
&self
|
|
||||||
.uniform_data
|
|
||||||
.uniform_locations
|
|
||||||
.gradient_end_location,
|
|
||||||
),
|
|
||||||
gradient_end[0],
|
|
||||||
gradient_end[1],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
gl.uniform_1_u32(
|
gl.uniform_1_u32(
|
||||||
|
|
@ -95,37 +77,32 @@ impl GradientProgram {
|
||||||
.uniform_locations
|
.uniform_locations
|
||||||
.color_stops_size_location,
|
.color_stops_size_location,
|
||||||
),
|
),
|
||||||
linear.color_stops.len() as u32,
|
(linear.color_stops.len() * 2) as u32,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (index, stop) in
|
let mut stops = [0.0; 128];
|
||||||
linear.color_stops.iter().enumerate()
|
|
||||||
{
|
|
||||||
gl.uniform_1_f32(
|
|
||||||
Some(
|
|
||||||
&self
|
|
||||||
.uniform_data
|
|
||||||
.uniform_locations
|
|
||||||
.color_stops_locations[index]
|
|
||||||
.offset,
|
|
||||||
),
|
|
||||||
stop.offset,
|
|
||||||
);
|
|
||||||
|
|
||||||
gl.uniform_4_f32(
|
for (index, stop) in linear.color_stops.iter().enumerate() {
|
||||||
Some(
|
if index == 16 { break; }
|
||||||
&self
|
stops[index*8] = stop.color.r;
|
||||||
.uniform_data
|
stops[(index*8)+1] = stop.color.g;
|
||||||
.uniform_locations
|
stops[(index*8)+2] = stop.color.b;
|
||||||
.color_stops_locations[index]
|
stops[(index*8)+3] = stop.color.a;
|
||||||
.color,
|
stops[(index*8)+4] = stop.offset;
|
||||||
),
|
stops[(index*8)+5] = 0.;
|
||||||
stop.color.r,
|
stops[(index*8)+6] = 0.;
|
||||||
stop.color.g,
|
stops[(index*8)+7] = 0.;
|
||||||
stop.color.b,
|
|
||||||
stop.color.a,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gl.uniform_4_f32_slice(
|
||||||
|
Some(
|
||||||
|
&self
|
||||||
|
.uniform_data
|
||||||
|
.uniform_locations
|
||||||
|
.color_stops_location,
|
||||||
|
),
|
||||||
|
&stops,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,10 +111,13 @@ impl GradientProgram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_program(&mut self, gl: &glow::Context, gradient: &Gradient, transform: &Transformation) {
|
pub fn use_program(
|
||||||
unsafe {
|
&mut self,
|
||||||
gl.use_program(Some(self.program))
|
gl: &Context,
|
||||||
}
|
gradient: &Gradient,
|
||||||
|
transform: &Transformation,
|
||||||
|
) {
|
||||||
|
unsafe { gl.use_program(Some(self.program)) }
|
||||||
|
|
||||||
self.write_uniforms(gl, gradient, transform);
|
self.write_uniforms(gl, gradient, transform);
|
||||||
}
|
}
|
||||||
|
|
@ -145,38 +125,18 @@ impl GradientProgram {
|
||||||
|
|
||||||
impl GradientUniformData {
|
impl GradientUniformData {
|
||||||
fn new(gl: &Context, program: NativeProgram) -> Self {
|
fn new(gl: &Context, program: NativeProgram) -> Self {
|
||||||
let gradient_start_location =
|
let gradient_direction_location =
|
||||||
unsafe { gl.get_uniform_location(program, "gradient_start") }
|
unsafe { gl.get_uniform_location(program, "gradient_direction") }
|
||||||
.expect("Gradient - Get gradient_start.");
|
.expect("Gradient - Get gradient_direction.");
|
||||||
|
|
||||||
let gradient_end_location =
|
|
||||||
unsafe { gl.get_uniform_location(program, "gradient_end") }
|
|
||||||
.expect("Gradient - Get gradient_end.");
|
|
||||||
|
|
||||||
let color_stops_size_location =
|
let color_stops_size_location =
|
||||||
unsafe { gl.get_uniform_location(program, "color_stops_size") }
|
unsafe { gl.get_uniform_location(program, "color_stops_size") }
|
||||||
.expect("Gradient - Get color_stops_size.");
|
.expect("Gradient - Get color_stops_size.");
|
||||||
|
|
||||||
let color_stops_locations: [ColorStopLocation; 64] =
|
let color_stops_location = unsafe {
|
||||||
core::array::from_fn(|index| {
|
gl.get_uniform_location(program, "color_stops")
|
||||||
let offset = unsafe {
|
.expect("Gradient - Get color_stops.")
|
||||||
gl.get_uniform_location(
|
};
|
||||||
program,
|
|
||||||
&format!("color_stop_offsets[{}]", index),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.expect("Gradient - Color stop offset location.");
|
|
||||||
|
|
||||||
let color = unsafe {
|
|
||||||
gl.get_uniform_location(
|
|
||||||
program,
|
|
||||||
&format!("color_stop_colors[{}]", index),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.expect("Gradient - Color stop color location.");
|
|
||||||
|
|
||||||
ColorStopLocation { color, offset }
|
|
||||||
});
|
|
||||||
|
|
||||||
let transform_location =
|
let transform_location =
|
||||||
unsafe { gl.get_uniform_location(program, "u_Transform") }
|
unsafe { gl.get_uniform_location(program, "u_Transform") }
|
||||||
|
|
@ -190,10 +150,9 @@ impl GradientUniformData {
|
||||||
}),
|
}),
|
||||||
transform: Transformation::identity(),
|
transform: Transformation::identity(),
|
||||||
uniform_locations: GradientUniformLocations {
|
uniform_locations: GradientUniformLocations {
|
||||||
gradient_start_location,
|
gradient_direction_location,
|
||||||
gradient_end_location,
|
|
||||||
color_stops_size_location,
|
color_stops_size_location,
|
||||||
color_stops_locations,
|
color_stops_location,
|
||||||
transform_location,
|
transform_location,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ pub use stroke::{LineCap, LineDash, LineJoin, Stroke};
|
||||||
pub use text::Text;
|
pub use text::Text;
|
||||||
|
|
||||||
use crate::{Backend, Primitive, Renderer};
|
use crate::{Backend, Primitive, Renderer};
|
||||||
|
pub use crate::gradient::Gradient;
|
||||||
|
|
||||||
use iced_native::layout::{self, Layout};
|
use iced_native::layout::{self, Layout};
|
||||||
use iced_native::mouse;
|
use iced_native::mouse;
|
||||||
|
|
@ -37,8 +38,6 @@ use iced_native::{
|
||||||
Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector, Widget,
|
Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::gradient::Gradient;
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// A widget capable of drawing 2D graphics.
|
/// A widget capable of drawing 2D graphics.
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ impl GradientPipeline {
|
||||||
"iced_wgpu::triangle [GRADIENT] uniforms",
|
"iced_wgpu::triangle [GRADIENT] uniforms",
|
||||||
);
|
);
|
||||||
|
|
||||||
//TODO: With a WASM target storage buffers are not supported. Will need to use UBOs & static
|
//Note: with a WASM target storage buffers are not supported. Will need to use UBOs & static
|
||||||
// sized array (64 on OpenGL side right now) to make gradients work
|
// sized array (eg like the 64-sized array on OpenGL side right now) to make gradients work
|
||||||
let storage_buffer = DynamicBuffer::storage(
|
let storage_buffer = DynamicBuffer::storage(
|
||||||
device,
|
device,
|
||||||
"iced_wgpu::triangle [GRADIENT] storage",
|
"iced_wgpu::triangle [GRADIENT] storage",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue