Skip to content

Commit 2db8736

Browse files
committed
perf(chat-history): Render the shader directly to bubbles
Rendering big texture into a lot of small bubbles results into bad performance (30fps on my laptop while scrolling). Rendering the shader to small bubbles fixes that issue.
1 parent c5da277 commit 2db8736

File tree

2 files changed

+68
-52
lines changed

2 files changed

+68
-52
lines changed

src/session/content/background.rs

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ uniform vec3 color1;
2121
uniform vec3 color2;
2222
uniform vec3 color3;
2323
uniform vec3 color4;
24-
uniform vec2 p1;
25-
uniform vec2 p2;
26-
uniform vec2 p3;
27-
uniform vec2 p4;
24+
uniform vec4 p12;
25+
uniform vec4 p34;
26+
uniform vec4 gradient_bounds;
2827
2928
void mainImage(out vec4 fragColor,
3029
in vec2 fragCoord,
3130
in vec2 resolution,
3231
in vec2 uv) {
32+
vec2 p1 = p12.xy;
33+
vec2 p2 = p12.zw;
34+
vec2 p3 = p34.xy;
35+
vec2 p4 = p34.zw;
36+
37+
uv = (fragCoord - gradient_bounds.xy) / gradient_bounds.zw;
3338
uv.y = 1.0 - uv.y;
3439
3540
float dp1 = distance(uv, p1);
@@ -56,7 +61,6 @@ mod imp {
5661
#[derive(Default)]
5762
pub(crate) struct Background {
5863
pub(super) background_texture: RefCell<Option<gdk::Texture>>,
59-
pub(super) message_texture: RefCell<Option<gdk::Texture>>,
6064

6165
pub(super) last_size: Cell<(f32, f32)>,
6266

@@ -183,17 +187,16 @@ mod imp {
183187
let texture = match self.background_texture.take() {
184188
Some(texture) if !size_changed => texture,
185189
_ => {
186-
self.render_textures(bounds);
187-
self.background_texture.take().unwrap()
190+
let renderer = self.obj().native().unwrap().renderer();
191+
192+
renderer.render_texture(self.obj().bg_node(bounds, bounds), Some(bounds))
188193
}
189194
};
190195

191196
snapshot.append_texture(&texture, bounds);
192197
self.background_texture.replace(Some(texture));
193198
} else {
194-
self.render_textures(bounds);
195-
let texture = self.background_texture.borrow().as_ref().unwrap().clone();
196-
snapshot.append_texture(&texture, bounds);
199+
snapshot.append_node(&self.obj().bg_node(bounds, bounds));
197200
}
198201
}
199202

@@ -231,22 +234,10 @@ mod imp {
231234
}
232235
}
233236

234-
fn render_textures(&self, bounds: &graphene::Rect) {
235-
let colors = [self.bg_colors.borrow(), self.message_colors.borrow()];
236-
237-
let renderer = self.obj().native().unwrap().renderer();
238-
239-
let mut textures = colors.into_iter().map(|colors| {
240-
renderer.render_texture(self.gradient_shader_node(bounds, &colors), Some(bounds))
241-
});
242-
243-
self.background_texture.replace(textures.next());
244-
self.message_texture.replace(textures.next());
245-
}
246-
247-
fn gradient_shader_node(
237+
pub(super) fn gradient_shader_node(
248238
&self,
249239
bounds: &graphene::Rect,
240+
gradient_bounds: &graphene::Rect,
250241
colors: &[graphene::Vec3],
251242
) -> gsk::GLShaderNode {
252243
let Some(gradient_shader) = &*self.shader.borrow() else {
@@ -267,16 +258,25 @@ mod imp {
267258
args_builder.set_vec3(2, &c3);
268259
args_builder.set_vec3(3, &c4);
269260

270-
let [p1, p2, p3, p4] = Self::calculate_positions(progress, phase);
271-
args_builder.set_vec2(4, &p1);
272-
args_builder.set_vec2(5, &p2);
273-
args_builder.set_vec2(6, &p3);
274-
args_builder.set_vec2(7, &p4);
261+
let [p12, p34] = Self::calculate_positions(progress, phase);
262+
args_builder.set_vec4(4, &p12);
263+
args_builder.set_vec4(5, &p34);
264+
265+
let gradient_bounds = {
266+
graphene::Vec4::new(
267+
gradient_bounds.x(),
268+
gradient_bounds.y(),
269+
gradient_bounds.width(),
270+
gradient_bounds.height(),
271+
)
272+
};
273+
274+
args_builder.set_vec4(6, &gradient_bounds);
275275

276276
gsk::GLShaderNode::new(gradient_shader, bounds, &args_builder.to_args(), &[])
277277
}
278278

279-
fn calculate_positions(progress: f32, phase: usize) -> [graphene::Vec2; 4] {
279+
fn calculate_positions(progress: f32, phase: usize) -> [graphene::Vec4; 2] {
280280
static POSITIONS: [(f32, f32); 8] = [
281281
(0.80, 0.10),
282282
(0.60, 0.20),
@@ -288,7 +288,7 @@ mod imp {
288288
(0.75, 0.40),
289289
];
290290

291-
let mut points = [graphene::Vec2::new(0.0, 0.0); 4];
291+
let mut points = [(0.0, 0.0); 4];
292292

293293
for i in 0..4 {
294294
let start = POSITIONS[(i * 2 + phase) % 8];
@@ -301,10 +301,18 @@ mod imp {
301301
let x = interpolate(start.0, end.0, progress);
302302
let y = interpolate(start.1, end.1, progress);
303303

304-
points[i] = graphene::Vec2::new(x, y);
304+
points[i] = (x, y);
305305
}
306306

307-
points
307+
let points: Vec<_> = points
308+
.chunks(2)
309+
.map(|p| {
310+
let [(x1, y1), (x2, y2)]: [(f32, f32); 2] = p.try_into().unwrap();
311+
graphene::Vec4::from_float([x1, y1, x2, y2])
312+
})
313+
.collect();
314+
315+
points.try_into().unwrap()
308316
}
309317
}
310318
}
@@ -350,27 +358,30 @@ impl Background {
350358
}
351359
}
352360

353-
pub fn subscribe_to_redraw(&self, child: &gtk::Widget) {
361+
pub(crate) fn subscribe_to_redraw(&self, child: &gtk::Widget) {
354362
let animation = self.imp().animation.get().unwrap();
355363
animation.connect_value_notify(clone!(@weak child => move |_| child.queue_draw()));
356364
}
357365

358-
pub fn bg_texture(&self) -> gdk::Texture {
366+
pub(crate) fn bg_node(
367+
&self,
368+
bounds: &graphene::Rect,
369+
gradient_bounds: &graphene::Rect,
370+
) -> gsk::GLShaderNode {
359371
self.imp()
360-
.background_texture
361-
.borrow()
362-
.as_ref()
363-
.unwrap()
364-
.clone()
372+
.gradient_shader_node(bounds, gradient_bounds, &self.imp().bg_colors.borrow())
365373
}
366374

367-
pub fn message_texture(&self) -> gdk::Texture {
368-
self.imp()
369-
.message_texture
370-
.borrow()
371-
.as_ref()
372-
.unwrap()
373-
.clone()
375+
pub(crate) fn message_bg_node(
376+
&self,
377+
bounds: &graphene::Rect,
378+
gradient_bounds: &graphene::Rect,
379+
) -> gsk::GLShaderNode {
380+
self.imp().gradient_shader_node(
381+
bounds,
382+
gradient_bounds,
383+
&self.imp().message_colors.borrow(),
384+
)
374385
}
375386

376387
fn ensure_shader(&self) {

src/session/content/message_row/bubble.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ use std::hash::Hasher;
55

66
use adw::prelude::*;
77
use glib::clone;
8-
use gtk::gdk;
98
use gtk::glib;
10-
use gtk::graphene;
11-
use gtk::gsk;
129
use gtk::subclass::prelude::*;
1310
use gtk::CompositeTemplate;
1411
use once_cell::sync::Lazy;
@@ -162,13 +159,21 @@ mod imp {
162159

163160
if let Some(background) = self.parent_background.borrow().upgrade() {
164161
if !background.has_css_class("fallback") {
162+
let bounds = {
163+
let width = widget.width() as f32;
164+
let height = widget.height() as f32;
165+
166+
gtk::graphene::Rect::new(0.0, 0.0, width, height)
167+
};
168+
165169
let gradient_bounds = background.compute_bounds(self.obj().as_ref()).unwrap();
166170

167171
if widget.has_css_class("outgoing") {
168-
snapshot.append_texture(&background.message_texture(), &gradient_bounds);
172+
snapshot
173+
.append_node(&background.message_bg_node(&bounds, &gradient_bounds));
169174
} else {
170175
snapshot.push_opacity(0.1);
171-
snapshot.append_texture(&background.bg_texture(), &gradient_bounds);
176+
snapshot.append_node(&background.bg_node(&bounds, &gradient_bounds));
172177
snapshot.pop();
173178
};
174179
}

0 commit comments

Comments
 (0)