Skip to content

Commit 810d769

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 f8df112 commit 810d769

File tree

2 files changed

+63
-47
lines changed

2 files changed

+63
-47
lines changed

src/session/content/background.rs

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@ uniform vec3 color1;
1414
uniform vec3 color2;
1515
uniform vec3 color3;
1616
uniform vec3 color4;
17-
uniform vec2 p1;
18-
uniform vec2 p2;
19-
uniform vec2 p3;
20-
uniform vec2 p4;
17+
uniform vec4 p12;
18+
uniform vec4 p34;
19+
uniform vec4 gradient_bounds;
2120
2221
void mainImage(out vec4 fragColor,
2322
in vec2 fragCoord,
2423
in vec2 resolution,
2524
in vec2 uv) {
25+
vec2 p1 = p12.xy;
26+
vec2 p2 = p12.zw;
27+
vec2 p3 = p34.xy;
28+
vec2 p4 = p34.zw;
29+
30+
uv = (fragCoord - gradient_bounds.xy) / gradient_bounds.zw;
2631
uv.y = 1.0 - uv.y;
2732
2833
float dp1 = distance(uv, p1);
@@ -51,7 +56,6 @@ mod imp {
5156
#[derive(Default)]
5257
pub(crate) struct Background {
5358
pub(super) background_texture: RefCell<Option<gdk::Texture>>,
54-
pub(super) message_texture: RefCell<Option<gdk::Texture>>,
5559

5660
pub(super) last_size: Cell<(f32, f32)>,
5761

@@ -178,17 +182,16 @@ mod imp {
178182
let texture = match self.background_texture.take() {
179183
Some(texture) if !size_changed => texture,
180184
_ => {
181-
self.render_textures(bounds);
182-
self.background_texture.take().unwrap()
185+
let renderer = self.obj().native().unwrap().renderer();
186+
187+
renderer.render_texture(self.obj().bg_node(bounds, bounds), Some(bounds))
183188
}
184189
};
185190

186191
snapshot.append_texture(&texture, bounds);
187192
self.background_texture.replace(Some(texture));
188193
} else {
189-
self.render_textures(bounds);
190-
let texture = self.background_texture.borrow().as_ref().unwrap().clone();
191-
snapshot.append_texture(&texture, bounds);
194+
snapshot.append_node(&self.obj().bg_node(bounds, bounds));
192195
}
193196
}
194197

@@ -226,22 +229,10 @@ mod imp {
226229
}
227230
}
228231

229-
fn render_textures(&self, bounds: &graphene::Rect) {
230-
let colors = [self.bg_colors.borrow(), self.message_colors.borrow()];
231-
232-
let renderer = self.obj().native().unwrap().renderer();
233-
234-
let mut textures = colors.into_iter().map(|colors| {
235-
renderer.render_texture(self.gradient_shader_node(bounds, &colors), Some(bounds))
236-
});
237-
238-
self.background_texture.replace(textures.next());
239-
self.message_texture.replace(textures.next());
240-
}
241-
242-
fn gradient_shader_node(
232+
pub(super) fn gradient_shader_node(
243233
&self,
244234
bounds: &graphene::Rect,
235+
gradient_bounds: &graphene::Rect,
245236
colors: &[graphene::Vec3],
246237
) -> gsk::GLShaderNode {
247238
let Some(gradient_shader) = &*self.shader.borrow() else {
@@ -262,16 +253,25 @@ mod imp {
262253
args_builder.set_vec3(2, &c3);
263254
args_builder.set_vec3(3, &c4);
264255

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

271271
gsk::GLShaderNode::new(gradient_shader, bounds, &args_builder.to_args(), &[])
272272
}
273273

274-
fn calculate_positions(progress: f32, phase: usize) -> [graphene::Vec2; 4] {
274+
fn calculate_positions(progress: f32, phase: usize) -> [graphene::Vec4; 2] {
275275
static POSITIONS: [(f32, f32); 8] = [
276276
(0.80, 0.10),
277277
(0.60, 0.20),
@@ -283,7 +283,7 @@ mod imp {
283283
(0.75, 0.40),
284284
];
285285

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

288288
for i in 0..4 {
289289
let start = POSITIONS[(i * 2 + phase) % 8];
@@ -296,10 +296,18 @@ mod imp {
296296
let x = interpolate(start.0, end.0, progress);
297297
let y = interpolate(start.1, end.1, progress);
298298

299-
points[i] = graphene::Vec2::new(x, y);
299+
points[i] = (x, y);
300300
}
301301

302-
points
302+
let points: Vec<_> = points
303+
.chunks(2)
304+
.map(|p| {
305+
let [(x1, y1), (x2, y2)]: [(f32, f32); 2] = p.try_into().unwrap();
306+
graphene::Vec4::from_float([x1, y1, x2, y2])
307+
})
308+
.collect();
309+
310+
points.try_into().unwrap()
303311
}
304312
}
305313
}
@@ -350,22 +358,22 @@ impl Background {
350358
animation.connect_value_notify(clone!(@weak child => move |_| child.queue_draw()));
351359
}
352360

353-
pub fn bg_texture(&self) -> gdk::Texture {
361+
pub fn bg_node(
362+
&self,
363+
bounds: &graphene::Rect,
364+
gradient_bounds: &graphene::Rect,
365+
) -> gsk::GLShaderNode {
354366
self.imp()
355-
.background_texture
356-
.borrow()
357-
.as_ref()
358-
.unwrap()
359-
.clone()
367+
.gradient_shader_node(bounds, gradient_bounds, &*self.imp().bg_colors.borrow())
360368
}
361369

362-
pub fn message_texture(&self) -> gdk::Texture {
370+
pub fn message_bg_node(
371+
&self,
372+
bounds: &graphene::Rect,
373+
gradient_bounds: &graphene::Rect,
374+
) -> gsk::GLShaderNode {
363375
self.imp()
364-
.message_texture
365-
.borrow()
366-
.as_ref()
367-
.unwrap()
368-
.clone()
376+
.gradient_shader_node(bounds, gradient_bounds, &*self.imp().bg_colors.borrow())
369377
}
370378

371379
fn ensure_shader(&self) {

src/session/content/message_row/bubble.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,21 @@ mod imp {
150150

151151
if let Some(background) = self.parent_background.borrow().upgrade() {
152152
if !background.has_css_class("fallback") {
153+
let bounds = {
154+
let width = widget.width() as f32;
155+
let height = widget.height() as f32;
156+
157+
gtk::graphene::Rect::new(0.0, 0.0, width, height)
158+
};
159+
153160
let gradient_bounds = background.compute_bounds(self.obj().as_ref()).unwrap();
154161

155162
if widget.has_css_class("outgoing") {
156-
snapshot.append_texture(&background.message_texture(), &gradient_bounds);
163+
snapshot
164+
.append_node(&background.message_bg_node(&bounds, &gradient_bounds));
157165
} else {
158166
snapshot.push_opacity(0.1);
159-
snapshot.append_texture(&background.bg_texture(), &gradient_bounds);
167+
snapshot.append_node(&background.bg_node(&bounds, &gradient_bounds));
160168
snapshot.pop();
161169
};
162170
}

0 commit comments

Comments
 (0)