From 5baa48a9ece21f51f97357e82e4c9a98dd81feed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Fri, 12 Nov 2021 13:45:22 +0100 Subject: 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. --- fiv-view.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ meson.build | 1 + 2 files changed, 138 insertions(+) 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 + +// 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'), -- cgit v1.2.3