From 01108d4148b9d4a227c0c48854c58ab27d69410f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 1 Apr 2023 22:48:38 -0400 Subject: [PATCH 1/4] gsk: Pass scale as float to the command queue --- gsk/gl/gskglcommandqueue.c | 12 ++++++------ gsk/gl/gskglcommandqueueprivate.h | 2 +- gsk/gl/gskglrenderjob.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index 3d2998e43d..f186c79fb8 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -993,7 +993,7 @@ gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self) * gsk_gl_command_queue_execute: * @self: a `GskGLCommandQueue` * @surface_height: the height of the backing surface - * @scale_factor: the scale factor of the backing surface + * @scale: the scale of the backing surface * @scissor: (nullable): the scissor clip if any * @default_framebuffer: the default framebuffer id if not zero * @@ -1009,7 +1009,7 @@ gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self) void gsk_gl_command_queue_execute (GskGLCommandQueue *self, guint surface_height, - guint scale_factor, + float scale, const cairo_region_t *scissor, guint default_framebuffer) { @@ -1097,10 +1097,10 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self, g_assert (cairo_region_num_rectangles (scissor) == 1); cairo_region_get_rectangle (scissor, 0, &r); - scissor_test.origin.x = r.x * scale_factor; - scissor_test.origin.y = surface_height - (r.height * scale_factor) - (r.y * scale_factor); - scissor_test.size.width = r.width * scale_factor; - scissor_test.size.height = r.height * scale_factor; + scissor_test.origin.x = (int) floor (r.x * scale); + scissor_test.origin.y = (int) floor (surface_height - (r.height * scale) - (r.y * scale)); + scissor_test.size.width = (int) ceil (r.width * scale); + scissor_test.size.height = (int) ceil (r.height * scale); } next_batch_index = self->head_batch_index; diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h index c946eb9803..fd72f68aff 100644 --- a/gsk/gl/gskglcommandqueueprivate.h +++ b/gsk/gl/gskglcommandqueueprivate.h @@ -288,7 +288,7 @@ void gsk_gl_command_queue_begin_frame (GskGLCommandQueue void gsk_gl_command_queue_end_frame (GskGLCommandQueue *self); void gsk_gl_command_queue_execute (GskGLCommandQueue *self, guint surface_height, - guint scale_factor, + float scale, const cairo_region_t *scissor, guint default_framebuffer); int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index b68a8278aa..48a30f8143 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -4322,14 +4322,14 @@ gsk_gl_render_job_render (GskGLRenderJob *job, GskRenderNode *root) { G_GNUC_UNUSED gint64 start_time; - guint scale_factor; + float scale; guint surface_height; g_return_if_fail (job != NULL); g_return_if_fail (root != NULL); g_return_if_fail (GSK_IS_GL_DRIVER (job->driver)); - scale_factor = MAX (job->scale_x, job->scale_y); + scale = MAX (job->scale_x, job->scale_y); surface_height = job->viewport.size.height; gsk_gl_command_queue_make_current (job->command_queue); @@ -4360,7 +4360,7 @@ gsk_gl_render_job_render (GskGLRenderJob *job, start_time = GDK_PROFILER_CURRENT_TIME; gsk_gl_command_queue_make_current (job->command_queue); gdk_gl_context_push_debug_group (job->command_queue->context, "Executing command queue"); - gsk_gl_command_queue_execute (job->command_queue, surface_height, scale_factor, job->region, job->default_framebuffer); + gsk_gl_command_queue_execute (job->command_queue, surface_height, scale, job->region, job->default_framebuffer); gdk_gl_context_pop_debug_group (job->command_queue->context); gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Execute GL command queue", ""); } From 519cde95f0a02ab9ff9bc96bad89747a7bda6a3f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 1 Apr 2023 22:54:19 -0400 Subject: [PATCH 2/4] gsk: Cosmetics Rename scale_factor to scale in various places, now that it is no longer an int but a float. --- gsk/gl/gskglrenderer.c | 10 +++++----- gsk/gl/gskglrenderjob.c | 10 +++++----- gsk/gl/gskglrenderjobprivate.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index d43a4edfa7..ffd3a0f27b 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -282,18 +282,18 @@ gsk_gl_renderer_render (GskRenderer *renderer, GskGLRenderJob *job; GdkSurface *surface; gboolean clear_framebuffer; - float scale_factor; + float scale; g_assert (GSK_IS_GL_RENDERER (renderer)); g_assert (root != NULL); surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self->context)); - scale_factor = gdk_surface_get_scale_factor (surface); + scale = gdk_surface_get_scale_factor (surface); viewport.origin.x = 0; viewport.origin.y = 0; - viewport.size.width = gdk_surface_get_width (surface) * scale_factor; - viewport.size.height = gdk_surface_get_height (surface) * scale_factor; + viewport.size.width = gdk_surface_get_width (surface) * scale; + viewport.size.height = gdk_surface_get_height (surface) * scale; gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context), gsk_render_node_prefers_high_depth (root), @@ -306,7 +306,7 @@ gsk_gl_renderer_render (GskRenderer *renderer, clear_framebuffer = update_area_requires_clear (surface, render_region); gsk_gl_driver_begin_frame (self->driver, self->command_queue); - job = gsk_gl_render_job_new (self->driver, &viewport, scale_factor, render_region, 0, clear_framebuffer); + job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, clear_framebuffer); #ifdef G_ENABLE_DEBUG if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK)) gsk_gl_render_job_set_debug_fallback (job, TRUE); diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 48a30f8143..ecc78e6a4a 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -4401,7 +4401,7 @@ get_framebuffer_format (GdkGLContext *context, GskGLRenderJob * gsk_gl_render_job_new (GskGLDriver *driver, const graphene_rect_t *viewport, - float scale_factor, + float scale, const cairo_region_t *region, guint framebuffer, gboolean clear_framebuffer) @@ -4414,7 +4414,7 @@ gsk_gl_render_job_new (GskGLDriver *driver, g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); g_return_val_if_fail (viewport != NULL, NULL); - g_return_val_if_fail (scale_factor > 0, NULL); + g_return_val_if_fail (scale > 0, NULL); /* Check for non-standard framebuffer binding as we might not be using * the default framebuffer on systems like macOS where we've bound an @@ -4436,14 +4436,14 @@ gsk_gl_render_job_new (GskGLDriver *driver, job->default_framebuffer = default_framebuffer; job->offset_x = 0; job->offset_y = 0; - job->scale_x = scale_factor; - job->scale_y = scale_factor; + job->scale_x = scale; + job->scale_y = scale; job->viewport = *viewport; job->target_format = get_framebuffer_format (job->command_queue->context, framebuffer); gsk_gl_render_job_set_alpha (job, 1.0f); gsk_gl_render_job_set_projection_from_rect (job, viewport, NULL); - gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor)); + gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale, scale)); /* Setup our initial clip. If region is NULL then we are drawing the * whole viewport. Otherwise, we need to convert the region to a diff --git a/gsk/gl/gskglrenderjobprivate.h b/gsk/gl/gskglrenderjobprivate.h index c340bf1490..32edae12a3 100644 --- a/gsk/gl/gskglrenderjobprivate.h +++ b/gsk/gl/gskglrenderjobprivate.h @@ -24,7 +24,7 @@ GskGLRenderJob *gsk_gl_render_job_new (GskGLDriver *driver, const graphene_rect_t *viewport, - float scale_factor, + float scale, const cairo_region_t *region, guint framebuffer, gboolean clear_framebuffer); From fa58dd9256cfe5775718a311e1785ca3df46bddc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 1 Apr 2023 22:52:13 -0400 Subject: [PATCH 3/4] Use fractional scale for the GL renderer This commit combines changes in the Wayland backend, the GL context frontend, and the GL renderer to switch them all to use the fractional scale. In the Wayland backend, we now use the fractional scale to size the EGL window. In the GL frontend code, we use the fractional scale to scale the damage region and surface in begin/end_frame. And in the GL renderer, we replace gdk_surface_get_scale_factor() with gdk_surface_get_scale(). --- gdk/gdkglcontext.c | 16 +++++++++------- gdk/wayland/gdksurface-wayland.c | 9 +++++---- gsk/gl/gskglrenderer.c | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 5f6047378b..b8972e57f8 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -94,6 +94,8 @@ #include #endif +#include + #define DEFAULT_ALLOWED_APIS GDK_GL_API_GL | GDK_GL_API_GLES typedef struct { @@ -586,8 +588,8 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, cairo_region_union (region, damage); cairo_region_destroy (damage); - ww = gdk_surface_get_width (surface) * gdk_surface_get_scale_factor (surface); - wh = gdk_surface_get_height (surface) * gdk_surface_get_scale_factor (surface); + ww = (int) ceil (gdk_surface_get_width (surface) * gdk_surface_get_scale (surface)); + wh = (int) ceil (gdk_surface_get_height (surface) * gdk_surface_get_scale (surface)); gdk_gl_context_make_current (context); @@ -631,7 +633,7 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context, EGLint *heap_rects = NULL; int i, j, n_rects = cairo_region_num_rectangles (painted); int surface_height = gdk_surface_get_height (surface); - int scale = gdk_surface_get_scale_factor (surface); + double scale = gdk_surface_get_scale (surface); EGLint *rects; if (n_rects < G_N_ELEMENTS (stack_rects) / 4) @@ -644,10 +646,10 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context, cairo_rectangle_int_t rect; cairo_region_get_rectangle (painted, i, &rect); - rects[j++] = rect.x * scale; - rects[j++] = (surface_height - rect.height - rect.y) * scale; - rects[j++] = rect.width * scale; - rects[j++] = rect.height * scale; + rects[j++] = (int) floor (rect.x * scale); + rects[j++] = (int) floor ((surface_height - rect.height - rect.y) * scale); + rects[j++] = (int) ceil (rect.width * scale); + rects[j++] = (int) ceil (rect.height * scale); } priv->eglSwapBuffersWithDamage (gdk_display_get_egl_display (display), egl_surface, rects, n_rects); g_free (heap_rects); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 76112b8256..f51f081a43 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -259,8 +259,9 @@ gdk_wayland_surface_update_size (GdkSurface *surface, if (impl->display_server.egl_window) wl_egl_window_resize (impl->display_server.egl_window, - width * gdk_fractional_scale_to_int (scale), - height * gdk_fractional_scale_to_int (scale), 0, 0); + gdk_fractional_scale_scale (scale, width), + gdk_fractional_scale_scale (scale, height), + 0, 0); gdk_surface_invalidate_rect (surface, NULL); @@ -1364,8 +1365,8 @@ gdk_wayland_surface_ensure_wl_egl_window (GdkSurface *surface) { impl->display_server.egl_window = wl_egl_window_create (impl->display_server.wl_surface, - surface->width * gdk_fractional_scale_to_int (&impl->scale), - surface->height * gdk_fractional_scale_to_int (&impl->scale)); + gdk_fractional_scale_scale (&impl->scale, surface->width), + gdk_fractional_scale_scale (&impl->scale, surface->height)); gdk_surface_set_egl_native_window (surface, impl->display_server.egl_window); } } diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index ffd3a0f27b..eb3c77c72f 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -288,7 +288,7 @@ gsk_gl_renderer_render (GskRenderer *renderer, g_assert (root != NULL); surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self->context)); - scale = gdk_surface_get_scale_factor (surface); + scale = gdk_surface_get_scale (surface); viewport.origin.x = 0; viewport.origin.y = 0; From 4746ffc4eb8ca399e260958ef43fa58d653dd108 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 2 Apr 2023 10:24:37 -0400 Subject: [PATCH 4/4] Make fractional scaling for GL opt-in Fractional scaling with the GL renderer is experimental for now, so we disable it unless GDK_DEBUG=gl-fractional is set. This will give us time to work out the kinks. --- gdk/gdk.c | 1 + gdk/gdkdebugprivate.h | 1 + gdk/gdkglcontext.c | 25 +++++++++++++++++--- gdk/gdkglcontextprivate.h | 2 ++ gdk/wayland/gdksurface-wayland.c | 40 ++++++++++++++++++++++++++------ gsk/gl/gskglrenderer.c | 2 +- 6 files changed, 60 insertions(+), 11 deletions(-) diff --git a/gdk/gdk.c b/gdk/gdk.c index 3d1457e075..8c0bdaff00 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -121,6 +121,7 @@ static const GdkDebugKey gdk_debug_keys[] = { { "portals", GDK_DEBUG_PORTALS, "Force use of portals", TRUE }, { "no-portals", GDK_DEBUG_NO_PORTALS, "Disable use of portals", TRUE }, { "gl-disable", GDK_DEBUG_GL_DISABLE, "Disable OpenGL support", TRUE }, + { "gl-fractional", GDK_DEBUG_GL_FRACTIONAL, "Enable fractional scaling for OpenGL (experimental)", TRUE }, { "gl-debug", GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL", TRUE }, { "gl-legacy", GDK_DEBUG_GL_LEGACY, "Use a legacy OpenGL context", TRUE }, { "gl-gles", GDK_DEBUG_GL_GLES, "Only allow OpenGL GLES API", TRUE }, diff --git a/gdk/gdkdebugprivate.h b/gdk/gdkdebugprivate.h index bbcf2d4630..d41cf3178f 100644 --- a/gdk/gdkdebugprivate.h +++ b/gdk/gdkdebugprivate.h @@ -41,6 +41,7 @@ typedef enum { GDK_DEBUG_PORTALS = 1 << 12, GDK_DEBUG_NO_PORTALS = 1 << 13, GDK_DEBUG_GL_DISABLE = 1 << 14, + GDK_DEBUG_GL_FRACTIONAL = 1 << 15, GDK_DEBUG_GL_LEGACY = 1 << 16, GDK_DEBUG_GL_GLES = 1 << 17, GDK_DEBUG_GL_DEBUG = 1 << 18, diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index b8972e57f8..8614ec3e83 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -560,6 +560,23 @@ gdk_gl_context_real_make_current (GdkGLContext *context, #endif } +double +gdk_gl_context_get_scale (GdkGLContext *self) +{ + GdkDisplay *display; + GdkSurface *surface; + double scale; + + surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self)); + scale = gdk_surface_get_scale (surface); + + display = gdk_gl_context_get_display (self); + if (!(gdk_display_get_debug_flags (display) & GDK_DEBUG_GL_FRACTIONAL)) + scale = ceil (scale); + + return scale; +} + static void gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, gboolean prefers_high_depth, @@ -569,9 +586,11 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, G_GNUC_UNUSED GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); GdkSurface *surface; cairo_region_t *damage; + double scale; int ww, wh; surface = gdk_draw_context_get_surface (draw_context); + scale = gdk_gl_context_get_scale (context); #ifdef HAVE_EGL if (priv->egl_context) @@ -588,8 +607,8 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, cairo_region_union (region, damage); cairo_region_destroy (damage); - ww = (int) ceil (gdk_surface_get_width (surface) * gdk_surface_get_scale (surface)); - wh = (int) ceil (gdk_surface_get_height (surface) * gdk_surface_get_scale (surface)); + ww = (int) ceil (gdk_surface_get_width (surface) * scale); + wh = (int) ceil (gdk_surface_get_height (surface) * scale); gdk_gl_context_make_current (context); @@ -633,7 +652,7 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context, EGLint *heap_rects = NULL; int i, j, n_rects = cairo_region_num_rectangles (painted); int surface_height = gdk_surface_get_height (surface); - double scale = gdk_surface_get_scale (surface); + double scale = gdk_gl_context_get_scale (context); EGLint *rects; if (n_rects < G_N_ELEMENTS (stack_rects) / 4) diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h index 2f19e96b1c..847b1c54a0 100644 --- a/gdk/gdkglcontextprivate.h +++ b/gdk/gdkglcontextprivate.h @@ -167,5 +167,7 @@ gboolean gdk_gl_context_use_es_bgra (GdkGLContext gboolean gdk_gl_context_has_vertex_half_float (GdkGLContext *self) G_GNUC_PURE; +double gdk_gl_context_get_scale (GdkGLContext *self); + G_END_DECLS diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index f51f081a43..ca27f65373 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -230,6 +230,30 @@ gdk_wayland_surface_maybe_resize (GdkSurface *surface, gdk_wayland_surface_create_wl_surface (surface); } +static inline void +get_egl_window_size (GdkSurface *surface, + int *width, + int *height) +{ + GdkDisplay *display = gdk_surface_get_display (surface); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + if (gdk_display_get_debug_flags (display) & GDK_DEBUG_GL_FRACTIONAL) + { + GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window", gdk_fractional_scale_to_double (&impl->scale)); + + *width = gdk_fractional_scale_scale (&impl->scale, surface->width), + *height = gdk_fractional_scale_scale (&impl->scale, surface->height); + } + else + { + GDK_DISPLAY_DEBUG (display, OPENGL, "Using integer scale %d for EGL window", gdk_fractional_scale_to_int (&impl->scale)); + + *width = surface->width * gdk_fractional_scale_to_int (&impl->scale); + *height = surface->height * gdk_fractional_scale_to_int (&impl->scale); + } +} + void gdk_wayland_surface_update_size (GdkSurface *surface, int32_t width, @@ -258,10 +282,11 @@ gdk_wayland_surface_update_size (GdkSurface *surface, impl->viewport_dirty = TRUE; if (impl->display_server.egl_window) - wl_egl_window_resize (impl->display_server.egl_window, - gdk_fractional_scale_scale (scale, width), - gdk_fractional_scale_scale (scale, height), - 0, 0); + { + int w, h; + get_egl_window_size (surface, &w, &h); + wl_egl_window_resize (impl->display_server.egl_window, w, h, 0, 0); + } gdk_surface_invalidate_rect (surface, NULL); @@ -1363,10 +1388,11 @@ gdk_wayland_surface_ensure_wl_egl_window (GdkSurface *surface) if (impl->display_server.egl_window == NULL) { + int width, height; + + get_egl_window_size (surface, &width, &height); impl->display_server.egl_window = - wl_egl_window_create (impl->display_server.wl_surface, - gdk_fractional_scale_scale (&impl->scale, surface->width), - gdk_fractional_scale_scale (&impl->scale, surface->height)); + wl_egl_window_create (impl->display_server.wl_surface, width, height); gdk_surface_set_egl_native_window (surface, impl->display_server.egl_window); } } diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index eb3c77c72f..8451ad9563 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -288,7 +288,7 @@ gsk_gl_renderer_render (GskRenderer *renderer, g_assert (root != NULL); surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self->context)); - scale = gdk_surface_get_scale (surface); + scale = gdk_gl_context_get_scale (self->context); viewport.origin.x = 0; viewport.origin.y = 0;