I have been trying to make a simple image viewer and noticed that scaling images with Cairo in a DrawingArea is a lot slower in GTK4 in comparison to GTK3. Not only that, but I also face a “Attempt to create texture of size 20250x13182 but max size is 16384. Clipping will occur.” warning pretty quickly, something that doesn’t seem to happen in GTK3. Here is some sample code:
GTK3:
import cairo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
def draw(da, ctx):
global surface
ctx.scale(scale, scale)
ctx.set_source_surface(surface)
ctx.get_source().set_filter(cairo.FILTER_NEAREST)
ctx.paint()
da.set_size_request(surface.get_width() * scale, surface.get_height() * scale)
def clicked(btn):
global scale
scale *= 1.5
da = btn.get_parent().get_children()[1].get_child().get_child()
da.queue_draw()
def main():
global scale
scale = 1
global surface
surface = cairo.ImageSurface.create_from_png("image.png")
win = Gtk.Window()
win.connect('destroy', lambda w: Gtk.main_quit())
win.set_default_size(500, 500)
box = Gtk.Box()
win.add(box)
btn = Gtk.Button()
btn.set_label("Scale")
box.add(btn)
btn.connect('clicked', clicked)
scrolled_win = Gtk.ScrolledWindow()
box.add(scrolled_win)
drawingarea = Gtk.DrawingArea()
drawingarea.set_vexpand(True)
drawingarea.set_hexpand(True)
scrolled_win.add(drawingarea)
drawingarea.connect('draw', draw)
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
GTK4:
#!/usr/bin/env python
import cairo
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def draw(da, ctx, x, y):
global surface
ctx.scale(scale, scale)
ctx.set_source_surface(surface)
ctx.get_source().set_filter(cairo.FILTER_NEAREST)
ctx.paint()
da.set_size_request(surface.get_width() * scale, surface.get_height() * scale)
def clicked(btn):
global scale
scale *= 1.5
da = btn.get_parent().get_last_child().get_child().get_child()
da.queue_draw()
def build_ui(app):
global scale
scale = 1
global surface
surface = cairo.ImageSurface.create_from_png("image.png")
win = Gtk.Window()
win.connect('destroy', lambda w: Gtk.main_quit())
win.set_default_size(500, 500)
win.set_application(app)
box = Gtk.Box()
win.set_child(box)
btn = Gtk.Button()
btn.set_label("Scale")
box.append(btn)
btn.connect('clicked', clicked)
scrolled_win = Gtk.ScrolledWindow()
box.append(scrolled_win)
drawingarea = Gtk.DrawingArea()
drawingarea.set_vexpand(True)
drawingarea.set_hexpand(True)
scrolled_win.set_child(drawingarea)
drawingarea.set_draw_func(draw)
win.present()
def main():
global scale
scale = 1
global surface
surface = cairo.ImageSurface.create_from_png("upscale.png")
app = Gtk.Application()
app.connect("activate", build_ui)
app.run()
if __name__ == '__main__':
main()
So what exactly is going on here? And more importantly, how can I achieve a better performance with GTK4 for a simple image viewer? (scaling PixBuf is unfortunately also on the slower side, and it seems GEGL isn’t easily usable in GTK4 either)
Edit: The slowness seems to be caused by the renderer, as setting GSK_RENDERER to cairo gives pretty much the same speed in GTK4.