aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2021-11-12 13:45:22 +0100
committerPřemysl Eric Janouch <p@janouch.name>2024-01-26 21:58:39 +0100
commit5baa48a9ece21f51f97357e82e4c9a98dd81feed (patch)
treeb50c9e3458cf8565f69125476e3ff7009260f933
parent370f5062241de4ede2cc41d57c1e622d917ad050 (diff)
downloadfiv-5baa48a9ece21f51f97357e82e4c9a98dd81feed.tar.gz
fiv-5baa48a9ece21f51f97357e82e4c9a98dd81feed.tar.xz
fiv-5baa48a9ece21f51f97357e82e4c9a98dd81feed.zip
WIP: Try to scale pictures using OpenGL
WIP: Need to learn scaling. WIP: Will it work with the native GDK window? WIP: Find out what in the name of fuck is Quartz doing.
-rw-r--r--fiv-view.c137
-rw-r--r--meson.build1
2 files changed, 138 insertions, 0 deletions
diff --git a/fiv-view.c b/fiv-view.c
index 0025d47..b39adab 100644
--- a/fiv-view.c
+++ b/fiv-view.c
@@ -584,6 +584,137 @@ fiv_view_realize(GtkWidget *widget)
reload_screen_cms_profile(FIV_VIEW(widget), window);
}
+#include <epoxy/gl.h>
+
+// TODO(p): Try to use OpenGL/epoxy to scale a surface weirdly, for starters.
+static bool
+try_gl(FivView *self, cairo_t *cr)
+{
+ GError *error = NULL;
+ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(self));
+ GdkGLContext *ctx = gdk_window_create_gl_context(window, &error);
+ if (!ctx) {
+ g_debug("%s", error->message);
+ g_error_free(error);
+ return false;
+ }
+
+ // TODO(p): Need at least OpenGL 2.1 for sRGB textures.
+ // - GDK uses 1.1/1.5/3.3 in its shaders.
+ // - This means OpenGL 2.0, 3.2, 3.3...
+ // - Shaders have been introduced in core OpenGL 2.0:
+ // https://www.khronos.org/opengl/wiki/History_of_OpenGL
+ // - Apple gives at most 4.1 and has deprecated OpenGL completely,
+ // so that's the practical ceiling.
+ // - Apple does not support OpenGL ES directly.
+ // - libepoxy doesn't have EGL support on macOS, may have GLX support.
+ // - There are epoxy_gl_version() and epoxy_has_gl_extension().
+ if (!gdk_gl_context_realize(ctx, &error)) {
+ g_warning("%s", error->message);
+ g_error_free(error);
+ return false;
+ }
+
+ // TODO(p): Use glGetError() != GL_NO_ERROR (0), at least at the end,
+ // and possibly use that clue as a hint to use fallback rendering.
+ // It should actually be a queue.
+ //
+ // Alternatively, ARB_debug_output/KHR_debug are a bit too new.
+
+ gdk_gl_context_make_current(ctx);
+ int width = 200;
+ int height = 200;
+
+ // NOTE: I get 16384, quite decent.
+ // https://feedback.wildfiregames.com/report/opengl/feature/GL_MAX_TEXTURE_SIZE
+ GLint max;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+
+ // TODO(p): Create a texture for the source, and for the destination,
+ // and rescale the picture with a bi-cubic algorithm in sRGB.
+ // TODO(p): Pre-scale the texture, create the context externally.
+ // TODO(p): Check GL_MAX_TEXTURE_SIZE, it may not make sense to prescale
+ // if the result is truly huge, though I can use Cairo as a fallback.
+ // I can also, naturally, scale ad-hoc.
+ // I may not be even able to load the source texture...
+ enum { SRC, DEST };
+ GLuint textures[2];
+ glGenTextures(2, textures);
+
+ // https://stackoverflow.com/questions/25157306 0..1
+ // GL_TEXTURE_RECTANGLE seems very useful, OpenGL 3.1
+ glBindTexture(GL_TEXTURE_2D, textures[SRC]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ // TODO(p): Figure out how to do bi-cubic in OpenGL.
+ // - IMG_texture_filter_cubic is somehow related to OpenGL ES,
+ // and I do not have it on my system.
+ // - Some shaders: https://www.shadertoy.com/view/MllSzX
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ // TODO(p): What is a framebuffer?
+ // - FBOs are in core since OpenGL 3.0.
+ // - glCheckFramebufferStatus() is not required to call.
+ // TODO(p): How do we get sRGB?
+ // - GL_SRGB8_ALPHA8
+ // - But see: https://stackoverflow.com/a/43333704/76313
+ // - Is texture sampling (there should be any filtering)
+ // done before or after fragment (i.e., pixel) shaders?
+ // - Is GL_FRAMEBUFFER_SRGB necessary?
+ // - GL_RGB10_A2 and GL_RGB10 don't have sRGB versions,
+ // need to do it ourselves.
+ // - GL_UNSIGNED_INT_10_10_10_2 + GL_UNSIGNED_INT_2_10_10_10_REV
+ // - GL_RGB10_A2UI vs GL_RGB10_A2?
+ // - The former isn't translated to 0..1, do not want.
+ // - pixman can also only do ARGB32 for sRGB.
+ // - Cairo doesn't support have transparency with RGB30.
+ // - GL_RGB{,A}{,16F,32F} look better
+ // - https://developer.apple.com/library/archive/releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_11_2.html
+ // They want GL_RGB{,A}16 on macOS. But maybe others will work, too.
+
+ // https://www.khronos.org/opengl/wiki/Texture#Swizzle_mask
+ // since OpenGL 3.3.
+ // - I guess this won't work with RGB30.
+#if 0
+ glGenFramebuffers(1, &priv->frame_buffer);
+
+ // GL_UNSIGNED_INT_8_8_8_8 stands for native-endian, so to speak.
+ // GL_UNSIGNED_BYTE is big-endian.
+ //
+ // https://mail.gnome.org/archives/commits-list/2016-April/msg06169.html
+ // and other thread messages show how GDK tackles ARGB -> RGBA on ES.
+ //
+ // I actually only care about alpha placement...
+ // I also don't care all that much about vertical flipping.
+ //
+ // TODO(p): Test whether GTK+ OpenGL is broken on big-endian.
+ if (gdk_gl_context_get_use_es(priv->context))
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA,
+ GL_UNSIGNED_BYTE, NULL);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, priv->frame_buffer);
+ glFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[DEST], 0);
+#endif
+
+ // ...
+
+ // TODO(p): Find out what scales here, if it's Cairo or GL.
+ gdk_cairo_draw_from_gl(
+ cr, window, textures[DEST], GL_TEXTURE, 1, 0, 0, width, height);
+ gdk_gl_context_make_current(ctx);
+
+ glDeleteTextures(2, textures);
+
+ gdk_gl_context_clear_current();
+ g_object_unref(ctx);
+ return true;
+}
+
static gboolean
fiv_view_draw(GtkWidget *widget, cairo_t *cr)
{
@@ -661,6 +792,12 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr)
#endif // GDK_WINDOWING_QUARTZ
cairo_paint(cr);
+
+ // XXX: GL would benefit from excluding the image area from
+ // gtk_render_background(), but then translucency wouldn't work.
+ // The naïve solution for that is rendering the background offscreen
+ // and recombining later (i.e., custom double-buffering).
+ try_gl(self, cr);
return TRUE;
}
diff --git a/meson.build b/meson.build
index 2d854e7..6a1bb61 100644
--- a/meson.build
+++ b/meson.build
@@ -36,6 +36,7 @@ gdkpixbuf = dependency('gdk-pixbuf-2.0', required : get_option('gdk-pixbuf'))
dependencies = [
dependency('gtk+-3.0'),
dependency('pixman-1'),
+ dependency('epoxy'),
dependency('libjpeg'),
dependency('libturbojpeg'),