Sync with nip4 - #64
Conversation
|
I've got a big nip4 PR about to land which adds simple MSpaint-style image editing:
Maybe we should get that in vipsdisp as well? It could be useful. I think it should go in pretty easily (hopefully). https://github.com/libvips/nip4/tree/paintbox Only the first two tools are done (brush and line draw), but the others should be easy now the framework is there. edit: it needs this libvips branch, I forgot https://github.com/libvips/libvips/tree/draw_line-add-draw-point I've not made a PR yet because the API might need tweaking to improve performance. |
|
I merged the paintbox into nip4, so that could potentially go into vipsdisp. Perhaps we should merge this PR first, then look at ways to make it easier to keep the two in sync in the future (eg. add some ifdefs to nip4 etc.). |
|
I added the last 4 of your commits back into nip4, so at least they won't need doing again. I also removed nip4's autoptr definition for vipsrect and added that to the libvips branch for nip4's paintbox, since nip4 now needs that new API anyway. |
|
Great! Re-synced with libvips/nip4@2ae4c31, but it still needs some testing.
This looks like an OpenJPEG issue. I can work around it in a few ways:
(1) is probably the most acceptable, while (3) is the safest. |
|
That's great!
Ahhhh I remember this bug, I seem to remember it's been fixed in openjpeg now, but of course it'll be a long while before we can deprecate |
|
Off topic, but have you tried the paintbox in nip4? It's integrated with recomp, so you can do (for example):
It's fun! It does need undo / redo implementing though, someone needs to port over the system from nip2. |
|
Ah, let me try OpenJPEG from its master branch. The weird thing is that it only happens with palette JP2 images, which isn't what we originally added the |
|
I think I've pushed most of your changes back into nip4, so this ought to be less painful next time. Thanks! I added a NIP4 #define (set in meson.build) around some stuff. |
|
I made a libvips PR for that extra draw_line callback. We should probably tag nip4 and vipsdisp as depending on libvips 8.19. |
|
I'm getting what look like double unref errors from the vipsdisp paintbox, eg: But I've not yet found a way to trigger them on demand, nor a backtrace :( I'll keep poking it. |
|
Got a backtrace! So there's somehow a dangling pointer from an unreffed image in the pipeline dependency graph. I've not seen this from nip4, maybe some change in this PR has done it. |
|
Re-synced with libvips/nip4@4796411. Hopefully, that will fix the dangling pointer issue. (I noticed that the previous changeset did |
|
Ah, I was able to reproduce it. I'll investigate it further tomorrow. |
|
I got this backtrace with ASan. Details(vipsdisp:303639): GLib-GObject-CRITICAL **: 11:20:12.040: object_ref: assertion '!object_already_finalized' failed
AddressSanitizer:DEADLYSIGNAL
=================================================================
==303639==ERROR: AddressSanitizer: SEGV on unknown address 0x00fe0003b2e2 (pc 0x7f2ed39c0e5d bp 0x7fff8c5f8090 sp 0x7fff8c5f8090 T0)
==303639==The signal is caused by a READ memory access.
#0 0x7f2ed39c0e5d in g_type_check_instance (/lib64/libgobject-2.0.so.0+0x2fe5d) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#1 0x7f2ed39b7804 (/lib64/libgobject-2.0.so.0+0x26804) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#2 0x7f2ed39b8c77 in g_signal_emit_valist (/lib64/libgobject-2.0.so.0+0x27c77) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#3 0x7f2ed39b8d32 in g_signal_emit (/lib64/libgobject-2.0.so.0+0x27d32) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#4 0x7f2ed0da8b78 in vips_image_invalidate /home/kleisauke/libvips/build/../libvips/iofuncs/image.c:1397:2
#5 0x7f2ed0da8a48 in vips_image_invalidate_all_cb /home/kleisauke/libvips/build/../libvips/iofuncs/image.c:1403:2
#6 0x7f2ed0ed9132 in vips_slist_map2 /home/kleisauke/libvips/build/../libvips/iofuncs/util.c:122:33
#7 0x7f2ed0dc7697 in vips__link_map /home/kleisauke/libvips/build/../libvips/iofuncs/generate.c:263:11
#8 0x7f2ed0da89d1 in vips_image_invalidate_all /home/kleisauke/libvips/build/../libvips/iofuncs/image.c:1429:9
#9 0x7f2ed0db9300 in vips_image_inplace /home/kleisauke/libvips/build/../libvips/iofuncs/image.c:3635:2
#10 0x000000403861 in draw_mask /home/kleisauke/vipsdisp/build/../src/draw_mask.c:48:3
#11 0x7f2ed0cf9e71 in vips__draw_line_direct /home/kleisauke/libvips/build/../libvips/draw/draw_line.c:206:4
#12 0x7f2ed0cf763d in vips_draw_line_build /home/kleisauke/libvips/build/../libvips/draw/draw_line.c:265:2
#13 0x7f2ed0d7a40e in vips_object_build /home/kleisauke/libvips/build/../libvips/iofuncs/object.c:372:6
#14 0x7f2ed0ddb390 in vips_cache_operation_buildp /home/kleisauke/libvips/build/../libvips/iofuncs/cache.c:1062:7
#15 0x7f2ed0e1e1bd in vips_call_required_optional /home/kleisauke/libvips/build/../libvips/iofuncs/operation.c:974:6
#16 0x7f2ed0e273e2 in vips_call_by_name /home/kleisauke/libvips/build/../libvips/iofuncs/operation.c:1014:11
#17 0x7f2ed0e2767e in vips_call_split /home/kleisauke/libvips/build/../libvips/iofuncs/operation.c:1121:11
#18 0x7f2ed0cfa41b in vips_draw_linev /home/kleisauke/libvips/build/../libvips/draw/draw_line.c:339:11
#19 0x7f2ed0cfa2bd in vips_draw_line /home/kleisauke/libvips/build/../libvips/draw/draw_line.c:390:11
#20 0x000000413783 in tilesource_draw_line /home/kleisauke/vipsdisp/build/../src/tilesource.c:2169:3
#21 0x00000040d216 in paintbox_update_brush_draw /home/kleisauke/vipsdisp/build/../src/paintbox.c:372:3
#22 0x00000040c9c2 in paintbox_drag_update /home/kleisauke/vipsdisp/build/../src/paintbox.c:417:4
#23 0x000000402426 in vipsdisp_BOOLEAN__DOUBLE_DOUBLE_OBJECT /home/kleisauke/vipsdisp/build/src/vipsdispmarshal.c:123:14
#24 0x7f2ed3997ebb in g_closure_invoke (/lib64/libgobject-2.0.so.0+0x6ebb) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#25 0x7f2ed39b6808 (/lib64/libgobject-2.0.so.0+0x25808) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#26 0x7f2ed39b8260 (/lib64/libgobject-2.0.so.0+0x27260) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#27 0x7f2ed39b8c77 in g_signal_emit_valist (/lib64/libgobject-2.0.so.0+0x27c77) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#28 0x7f2ed39b8d32 in g_signal_emit (/lib64/libgobject-2.0.so.0+0x27d32) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#29 0x000000407453 in imageui_drag_update /home/kleisauke/vipsdisp/build/../src/imageui.c:390:2
#30 0x7f2ecee1cd37 (/lib64/libgtk-4.so.1+0x1cd37) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#31 0x7f2ed39b8b25 (/lib64/libgobject-2.0.so.0+0x27b25) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#32 0x7f2ed39b8c77 in g_signal_emit_valist (/lib64/libgobject-2.0.so.0+0x27c77) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#33 0x7f2ed39b8d32 in g_signal_emit (/lib64/libgobject-2.0.so.0+0x27d32) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#34 0x7f2ed399c012 in g_cclosure_marshal_VOID__BOXEDv (/lib64/libgobject-2.0.so.0+0xb012) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#35 0x7f2ed39b8b25 (/lib64/libgobject-2.0.so.0+0x27b25) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#36 0x7f2ed39b8c77 in g_signal_emit_valist (/lib64/libgobject-2.0.so.0+0x27c77) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#37 0x7f2ed39b8d32 in g_signal_emit (/lib64/libgobject-2.0.so.0+0x27d32) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#38 0x7f2eceee10ca (/lib64/libgtk-4.so.1+0xe10ca) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#39 0x7f2eceee2111 (/lib64/libgtk-4.so.1+0xe2111) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#40 0x7f2ecf06103b (/lib64/libgtk-4.so.1+0x26103b) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#41 0x7f2ecef287c9 (/lib64/libgtk-4.so.1+0x1287c9) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#42 0x7f2ecef2961a (/lib64/libgtk-4.so.1+0x12961a) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#43 0x7f2ecf234c67 (/lib64/libgtk-4.so.1+0x434c67) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#44 0x7f2ecf2e02e9 (/lib64/libgtk-4.so.1+0x4e02e9) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#45 0x7f2ed39b8b25 (/lib64/libgobject-2.0.so.0+0x27b25) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#46 0x7f2ed39b8c77 in g_signal_emit_valist (/lib64/libgobject-2.0.so.0+0x27c77) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#47 0x7f2ed39b8d32 in g_signal_emit (/lib64/libgobject-2.0.so.0+0x27d32) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#48 0x7f2ecf2e24c5 (/lib64/libgtk-4.so.1+0x4e24c5) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#49 0x7f2ecf2e28c8 (/lib64/libgtk-4.so.1+0x4e28c8) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#50 0x7f2ed39b8b25 (/lib64/libgobject-2.0.so.0+0x27b25) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#51 0x7f2ed39b8c77 in g_signal_emit_valist (/lib64/libgobject-2.0.so.0+0x27c77) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#52 0x7f2ed39b8d32 in g_signal_emit (/lib64/libgobject-2.0.so.0+0x27d32) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4)
#53 0x7f2ecf2b4039 (/lib64/libgtk-4.so.1+0x4b4039) (BuildId: f8c1968c415dee5548b27461f475993aa1a92865)
#54 0x7f2ecfb05021 (/lib64/libglib-2.0.so.0+0x47021) (BuildId: a55397c41cae330fee603dd8a00cf8cd2ac399ca)
#55 0x7f2ecfb01f23 (/lib64/libglib-2.0.so.0+0x43f23) (BuildId: a55397c41cae330fee603dd8a00cf8cd2ac399ca)
#56 0x7f2ecfb06037 (/lib64/libglib-2.0.so.0+0x48037) (BuildId: a55397c41cae330fee603dd8a00cf8cd2ac399ca)
#57 0x7f2ecfb061e2 in g_main_context_iteration (/lib64/libglib-2.0.so.0+0x481e2) (BuildId: a55397c41cae330fee603dd8a00cf8cd2ac399ca)
#58 0x7f2ecfcdd02c in g_application_run (/lib64/libgio-2.0.so.0+0xbd02c) (BuildId: 00cd86f4a9b73cecf6e2d43069359410cdc95433)
#59 0x00000040d416 in main /home/kleisauke/vipsdisp/build/../src/main.c:39:15
#60 0x7f2ecec0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6)
#61 0x7f2ecec0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6)
#62 0x000000402174 in _start (/usr/bin/vipsdisp+0x402174) (BuildId: 2569ed18f59712e895e736cf35e72f842cfd5576)
==303639==Register values:
rax = 0x000000fe0003b2e2 rbx = 0x00007fff8c5f8300 rcx = 0x00007fff8c5f8300 rdx = 0x0000000000000000
rdi = 0x00007c6ec68de840 rsi = 0x0000000000000184 rbp = 0x00007fff8c5f8090 rsp = 0x00007fff8c5f8090
r8 = 0x00007fff8c5f7fd0 r9 = 0x00007f2ed0da5d30 r10 = 0x0000000000000000 r11 = 0x0000000000000001
r12 = 0x0000000000000184 r13 = 0x0000000000000a03 r14 = 0x00007c6ec68de840 r15 = 0x00007c6ec694c040
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib64/libgobject-2.0.so.0+0x2fe5d) (BuildId: e04a34a9d2ebbca4ef8791440a31ca2bef837aa4) in g_type_check_instance
==303639==ABORTING
Aborted LD_PRELOAD=$ASAN_DSO vipsdisp |
|
... it looks like disabling the operation cache makes this easier to reproduce: --- a/src/main.c
+++ b/src/main.c
@@ -20,6 +20,8 @@ main(int argc, char **argv)
if (VIPS_INIT(argv[0]))
vips_error_exit("unable to start libvips");
+ vips_cache_set_max(0);
+
#ifdef DEBUG
printf("DEBUG on in main.c\n");
vips_leak_set(TRUE);but I haven't been able to reproduce the same crash in nip4. |
|
I added most of your new commits back into nip4 (no need to sync again, just to make it easier next time). |
|
I've not been able to make vipsdisp fall over! But maybe I've not tried hard enough. Nice job! |
|
I can still provoke a crash (and disabling the operation cache makes it even easier to reproduce). :( It's very weird, there must be something I've overlooked, since I can't reproduce it in nip4. |
|
You're right :( diff --git a/src/main.c b/src/main.c
index 69c2d4c..1b11eae 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,6 +1,6 @@
/*
-#define DEBUG
*/
+#define DEBUG
#include "package.h"
@@ -23,6 +23,7 @@ main(int argc, char **argv)
#ifdef DEBUG
printf("DEBUG on in main.c\n");
vips_leak_set(TRUE);
+ vips_cache_set_max(0);
g_log_set_always_fatal(
G_LOG_FLAG_RECURSION |Makes it quite easy to trigger. I tried a few things (moving eval, moving invalidate) and didn't manage to fix it, I'll keep looking. |
|
The good news is that I can no longer reproduce the issue when closing the "Info bar" view. The bad news is that this explains why I couldn't reproduce it in nip4: opening that view in nip4 causes the same crash. 😅 |
|
Oh no! |
|
I've finished the nip4 paintbox, for now anyway. Shall we merge this PR, then I can make another PR for the paintbox? I've not looked into the infobar crash :( I should do that. |
|
Re-synced with libvips/nip4@e73b551, removed the draft status and added a TODO list for the remaining crashes in the PR description. |
|
Sure, that'd be great! |
|
Oh wait, I just noticed the |
|
I'm OK leaving at one big commit. vipsdisp feels like a subsidiary project now, so I don't think the merge history needs to be especially readable. I think the paintbox might be quite handy for vipsdisp! It looks great! I noticed ^Z / ^Y aren't working, I think you maybe need to add to app.c: { "win.undo", { "<Primary>z", NULL } },
{ "win.redo", { "<Primary>y", NULL } }, |
* Add missing nip4 guards * Prevent unconditional use of nip4 symbols * Fix `-Wmaybe-uninitialized` warning * Fix `-Wc23-extensions` Clang warning
In line with commit libvips/nip4@5762dec.
In line with commit libvips/nip4@3aeeac7.
Good catch, I forgot to re-sync |
|
Nice! I got the "!object_already_finalized" crash one time, and an object leak from (I think?) the undo system another time, so this probably isn't good enough for release. Let's merge anyway, I'll be more likely to use it and fix it if it's in master. |
|
Great! Merging this would also fix the build failure on master when building against libvips master (since we moved the VipsRect autoptr cleanup there). Just wondering, did you get the |
|
Yes, I had the infobar + paintbox open :( I don't get crashes in nip4 with them both open though, I'm not sure I understand what's going on. |
|
Thank you for doing this work! |
|
No problem!
Ah, I was testing with this change in nip4: --- a/src/main.c
+++ b/src/main.c
@@ -421,9 +421,7 @@ main_startup(int argc, char **argv)
*
* FIXME .. link this to prefs?
*/
- vips_cache_set_max(10000);
- vips_cache_set_max_mem(1000 * 1024 * 1024);
- vips_cache_set_max_files(1000);
+ vips_cache_set_max(0);
}
void(IIRC, I also wasn't able to reproduce it without this) |
|
I've been trying to track the infobar problem down and found something strange. I patched libvips with this: diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h
index 7854f29d8..43f352070 100644
--- a/libvips/include/vips/internal.h
+++ b/libvips/include/vips/internal.h
@@ -435,6 +435,8 @@ char *vips__get_iso8601(void);
gboolean vips__image_is_cicp_hdr(VipsImage *image);
+int vips__object_n_objects(void);
+
#ifdef __cplusplus
}
#endif /*__cplusplus*/
diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c
index 0d6711df3..20ed929f8 100644
--- a/libvips/iofuncs/init.c
+++ b/libvips/iofuncs/init.c
@@ -390,6 +390,8 @@ vips_verbose(void)
static int
vips_leak(void)
{
+ printf("vips_leak: n_objects = %d\n", vips__object_n_objects());
+
char txt[1024];
VipsBuf buf = VIPS_BUF_STATIC(txt);
int n_leaks;
diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c
index 1a414b023..339861603 100644
--- a/libvips/iofuncs/object.c
+++ b/libvips/iofuncs/object.c
@@ -3172,6 +3172,12 @@ vips_object_print_all_cb(VipsObject *object, int *n, void *b)
return NULL;
}
+int
+vips__object_n_objects(void)
+{
+ return g_hash_table_size(vips__object_all);
+}
+
int
vips__object_leak(void)
{
diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c
index 9288f4a69..3a2acf1f7 100644
--- a/libvips/iofuncs/operation.c
+++ b/libvips/iofuncs/operation.c
@@ -595,6 +595,8 @@ vips_operation_build(VipsObject *object)
printf("\n");
#endif /*VIPS_DEBUG*/
+ printf("vips_operation_build: n_objects = %d\n", vips__object_n_objects());
+
if (class->flags & VIPS_OPERATION_BLOCKED) {
vips_error(VIPS_OBJECT_CLASS(class)->nickname,
"%s", _("operation is blocked"));ie. print the total number of active objects on operation build and on shutdown. I disabled the operation cache in nip4 with The I'm unsure where the refs are being held. I tried a standalone program: /* compile with
* gcc -g -Wall point.c `pkg-config vips --cflags --libs`
*/
#include <vips/vips.h>
int
main(int argc, char **argv)
{
if (VIPS_INIT(argv[0]))
vips_error_exit(NULL);
vips_cache_set_max(0);
VipsImage *image;
if (!(image = vips_image_new_from_file(argv[1], NULL)))
vips_error_exit(NULL);
for (int i = 0; i < 1000; i++) {
int x = i % image->Xsize;
int y = i / image->Xsize;
double *v;
int n;
if (vips_getpoint(image, &v, &n, x, y,
"unpack_complex", TRUE,
NULL))
vips_error_exit(NULL);
}
VIPS_UNREF(image);
return 0;
}But it behaves as you'd expect, with a low and steady number of objects. |
|
I reworked |

Context: #63 (comment).
Follow-up TODO items:
test/test-suite/images/palette.jp2(see workarounds in Sync with nip4 #64 (comment)).