Skip to content

Commit b45db4e

Browse files
committed
perf: offload drag and layer resize processing to the GPU
after a week of some of the most math intensive shit I have ever done we now have smoother dragging thx to the GdkPaintable and some fucking algorithm's I have made(or recreated?). I express my gratitude to my data structures and alorithm's professor for the lessons.
1 parent 167511d commit b45db4e

4 files changed

Lines changed: 80 additions & 4 deletions

File tree

‎src/meme-canvas.c‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ void on_drag_begin (GtkGestureDrag *gesture, double x, double y, MemeWindow *sel
197197
self->selected_layer = layer;
198198
self->drag_obj_start_scale = layer->scale;
199199
self->drag_start_x = ix * img_w; self->drag_start_y = iy * img_h;
200-
sync_ui_with_layer(self); render_meme(self); return;
200+
sync_ui_with_layer(self);
201+
if (!meme_window_begin_layer_drag(self)) render_meme(self);
202+
return;
201203
}
202204

203205
if (ix >= l_left && ix <= l_right && iy >= l_top && iy <= l_bot) {
@@ -207,7 +209,9 @@ void on_drag_begin (GtkGestureDrag *gesture, double x, double y, MemeWindow *sel
207209
self->drag_obj_start_x = layer->x; self->drag_obj_start_y = layer->y;
208210
self->drag_start_x = ix; self->drag_start_y = iy;
209211
self->snap_guide_v_active = FALSE; self->snap_guide_h_active = FALSE;
210-
sync_ui_with_layer(self); render_meme(self); return;
212+
sync_ui_with_layer(self);
213+
if (!meme_window_begin_layer_drag(self)) render_meme(self);
214+
return;
211215
}
212216
}
213217
if (self->selected_layer) { self->selected_layer = NULL; sync_ui_with_layer(self); render_meme(self); }
@@ -261,8 +265,8 @@ void on_drag_update (GtkGestureDrag *gesture, double offset_x, double offset_y,
261265
double cdx = (self->drag_start_x + offset_x/s) - cx, cdy = (self->drag_start_y + offset_y/s) - cy;
262266
double dist_s = sqrt(sdx*sdx + sdy*sdy), dist_c = sqrt(cdx*cdx + cdy*cdy);
263267
if (dist_s > 5.0) self->selected_layer->scale = CLAMP(self->drag_obj_start_scale * (dist_c/dist_s), 0.1, 5.0);
264-
if (self->selected_layer->type == LAYER_TYPE_TEXT) {
265-
self->selected_layer->pixbuf = NULL;
268+
if (self->selected_layer->type == LAYER_TYPE_TEXT && !self->drag_preview) {
269+
g_clear_object (&self->selected_layer->pixbuf);
266270
}
267271
} else if (self->drag_type == DRAG_TYPE_DRAW_STROKE && self->draw_points) {
268272
double start_x, start_y, wx, wy, pix, piy;
@@ -279,6 +283,10 @@ void on_drag_update (GtkGestureDrag *gesture, double offset_x, double offset_y,
279283
if (self->drag_type == DRAG_TYPE_CROP_MOVE || self->drag_type == DRAG_TYPE_CROP_RESIZE ||
280284
self->drag_type == DRAG_TYPE_DRAW_STROKE) {
281285
gtk_widget_queue_draw(GTK_WIDGET(self->crop_overlay_area));
286+
} else if (self->drag_preview) {
287+
meme_window_update_layer_drag(self);
288+
if (self->drag_type == DRAG_TYPE_IMAGE_MOVE)
289+
gtk_widget_queue_draw(GTK_WIDGET(self->crop_overlay_area));
282290
} else {
283291
render_meme(self);
284292
if (self->drag_type == DRAG_TYPE_IMAGE_MOVE)
@@ -319,6 +327,11 @@ void on_drag_end (GtkGestureDrag *g, double x, double y, MemeWindow *self) {
319327
g_array_free (self->draw_points, TRUE);
320328
self->draw_points = NULL;
321329
}
330+
if (self->drag_preview && self->drag_type == DRAG_TYPE_IMAGE_RESIZE &&
331+
self->selected_layer && self->selected_layer->type == LAYER_TYPE_TEXT) {
332+
g_clear_object (&self->selected_layer->pixbuf);
333+
}
334+
meme_window_end_layer_drag(self);
322335
self->drag_type = DRAG_TYPE_NONE;
323336
render_meme(self);
324337
}

‎src/meme-window-canvas.c‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,68 @@
2323
#include "meme-window-private.h"
2424
#include "meme-canvas.h"
2525

26+
gboolean meme_window_begin_layer_drag (MemeWindow *self) {
27+
ImageLayer *layer = self->selected_layer;
28+
GdkTexture *below = NULL, *above = NULL, *layer_tex = NULL;
29+
MemeDragLayerState state;
30+
gboolean cinematic, deepfry, bw, reduce_quality_on_drag;
31+
32+
g_clear_object (&self->drag_preview);
33+
34+
if (!layer || !self->template_image) return FALSE;
35+
if (self->drag_type != DRAG_TYPE_IMAGE_MOVE &&
36+
self->drag_type != DRAG_TYPE_IMAGE_RESIZE) return FALSE;
37+
38+
cinematic = gtk_toggle_button_get_active (self->cinematic_button);
39+
deepfry = gtk_toggle_button_get_active (self->deep_fry_button);
40+
bw = gtk_toggle_button_get_active (self->bw_button);
41+
reduce_quality_on_drag = g_settings_get_boolean (self->template_settings, "reduce-quality-on-drag");
42+
43+
if (bw) return FALSE;
44+
45+
if ((cinematic || deepfry) && !reduce_quality_on_drag) return FALSE;
46+
47+
if (!meme_render_drag_split (self->template_image, self->layers, layer,
48+
&below, &above, &layer_tex))
49+
return FALSE;
50+
51+
self->drag_preview = meme_drag_preview_new (below, above, layer_tex);
52+
g_clear_object (&below);
53+
g_clear_object (&above);
54+
g_clear_object (&layer_tex);
55+
56+
meme_drag_preview_state_from_layer (&state, layer);
57+
meme_drag_preview_set_state (self->drag_preview, &state);
58+
gtk_picture_set_paintable (self->meme_preview, GDK_PAINTABLE (self->drag_preview));
59+
return TRUE;
60+
}
61+
62+
void meme_window_update_layer_drag (MemeWindow *self) {
63+
MemeDragLayerState state;
64+
65+
if (!self->drag_preview || !self->selected_layer) return;
66+
meme_drag_preview_state_from_layer (&state, self->selected_layer);
67+
meme_drag_preview_set_state (self->drag_preview, &state);
68+
}
69+
70+
void meme_window_end_layer_drag (MemeWindow *self) {
71+
g_clear_object (&self->drag_preview);
72+
}
73+
2674
void render_meme (MemeWindow *self) {
2775
gboolean is_dragging, is_crop_drag, crop_active, cinematic, deepfry, bw_button;
2876
gboolean reduce_quality_on_drag, use_fast_preview;
2977
GdkTexture *tex;
3078

79+
if (self->drag_preview) {
80+
if (self->drag_type == DRAG_TYPE_IMAGE_MOVE ||
81+
self->drag_type == DRAG_TYPE_IMAGE_RESIZE) {
82+
meme_window_update_layer_drag (self);
83+
return;
84+
}
85+
g_clear_object (&self->drag_preview);
86+
}
87+
3188
if (!self->template_image) return;
3289

3390
is_dragging = (self->drag_type != DRAG_TYPE_NONE);

‎src/meme-window-private.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <adwaita.h>
44
#include "meme-core.h"
55
#include "meme-renderer.h"
6+
#include "meme-drag-preview.h"
67

78
typedef struct {
89
GdkPixbuf *pixbuf;
@@ -51,6 +52,7 @@ struct _MemeWindow {
5152
GtkWidget *margin_color_btn;
5253
GtkButton *save_project_button, *load_project_button;
5354
GdkPixbuf *template_image, *final_meme;
55+
MemeDragPreview *drag_preview; /* non-NULL while a layer is dragged on the GPU */
5456
GList *layers, *undo_stack, *redo_stack;
5557
ImageLayer *selected_layer;
5658
DragType drag_type;
@@ -116,6 +118,9 @@ struct _MemeWindow {
116118

117119
void sync_ui_with_layer(MemeWindow *self);
118120
void render_meme(MemeWindow *self);
121+
gboolean meme_window_begin_layer_drag(MemeWindow *self);
122+
void meme_window_update_layer_drag(MemeWindow *self);
123+
void meme_window_end_layer_drag(MemeWindow *self);
119124
void on_clear_clicked(MemeWindow *self);
120125
void apply_zoom(MemeWindow *self);
121126
void update_template_image(MemeWindow *self, GdkPixbuf *new_pixbuf);

‎src/meme-window.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ void on_clear_clicked (MemeWindow *self) {
3737
gtk_stack_set_visible_child_name (self->content_stack, "empty");
3838
g_clear_object (&self->template_image);
3939
g_clear_object (&self->final_meme);
40+
g_clear_object (&self->drag_preview);
4041
g_clear_object (&self->crop_session_template_snapshot);
4142
if (self->layers) { meme_layer_list_free (self->layers); self->layers = NULL; }
4243
free_history_stack (&self->undo_stack); free_history_stack (&self->redo_stack);

0 commit comments

Comments
 (0)