[gtk/wip/chergert/glproto: 295/526] start on sharing driver instance across renderers
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/glproto: 295/526] start on sharing driver instance across renderers
- Date: Tue, 16 Feb 2021 01:14:32 +0000 (UTC)
commit c177fa6aec808081205e02603c4075bd8df7d87b
Author: Christian Hergert <chergert redhat com>
Date: Thu Jan 21 16:31:51 2021 -0800
start on sharing driver instance across renderers
this isn't fully working yet (popup windows seem to start with a black
screen) but eventually they start to look closer to correct. More
troubleshooting necessary but this is a start.
gsk/next/gskglcommandqueue.c | 2 --
gsk/next/gskgldriver.c | 55 +++++++++++++++++++++++++++++++--
gsk/next/gskgldriverprivate.h | 4 +--
gsk/next/gskglrenderer.c | 67 ++++++++++++++++++++++------------------
gsk/next/gskglrenderjob.c | 30 ++++++++++++++----
gsk/next/gskglrenderjobprivate.h | 1 +
6 files changed, 116 insertions(+), 43 deletions(-)
---
diff --git a/gsk/next/gskglcommandqueue.c b/gsk/next/gskglcommandqueue.c
index bd80a296c6..765484ea70 100644
--- a/gsk/next/gskglcommandqueue.c
+++ b/gsk/next/gskglcommandqueue.c
@@ -716,8 +716,6 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
if (self->batches->len == 0)
return;
- gsk_gl_command_queue_make_current (self);
-
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL);
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 6162480830..77bde80552 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -393,9 +393,9 @@ gsk_next_driver_autorelease_framebuffer (GskNextDriver *self,
g_array_append_val (self->autorelease_framebuffers, framebuffer_id);
}
-GskNextDriver *
+static GskNextDriver *
gsk_next_driver_new (GskGLCommandQueue *command_queue,
- gboolean debug,
+ gboolean debug_shaders,
GError **error)
{
GskNextDriver *self;
@@ -409,7 +409,7 @@ gsk_next_driver_new (GskGLCommandQueue *command_queue,
self = g_object_new (GSK_TYPE_NEXT_DRIVER, NULL);
self->command_queue = g_object_ref (command_queue);
- self->debug = !!debug;
+ self->debug = !!debug_shaders;
if (!gsk_next_driver_load_programs (self, error))
{
@@ -424,6 +424,49 @@ gsk_next_driver_new (GskGLCommandQueue *command_queue,
return g_steal_pointer (&self);
}
+/**
+ * gsk_next_driver_from_shared_context:
+ * @context: a shared #GdkGLContext retrieved with gdk_gl_context_get_shared_context()
+ * @debug_shaders: if debug information for shaders should be displayed
+ * @error: location for error information
+ *
+ * Retrieves a driver for a shared context. Generally this is shared across all GL
+ * contexts for a display so that fewer programs are necessary for driving output.
+ *
+ * Returns: (transfer full): a #GskNextDriver if successful; otherwise %NULL and
+ * @error is set.
+ */
+GskNextDriver *
+gsk_next_driver_from_shared_context (GdkGLContext *context,
+ gboolean debug_shaders,
+ GError **error)
+{
+ GskGLCommandQueue *command_queue = NULL;
+ GskNextDriver *driver;
+
+ g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+ if ((driver = g_object_get_data (G_OBJECT (context), "GSK_NEXT_DRIVER")))
+ return g_object_ref (driver);
+
+ gdk_gl_context_make_current (context);
+
+ command_queue = gsk_gl_command_queue_new (context);
+
+ if (!(driver = gsk_next_driver_new (command_queue, debug_shaders, error)))
+ goto failure;
+
+ g_object_set_data_full (G_OBJECT (context),
+ "GSK_NEXT_DRIVER",
+ g_object_ref (driver),
+ g_object_unref);
+
+failure:
+ g_clear_object (&command_queue);
+
+ return g_steal_pointer (&driver);
+}
+
/**
* gsk_next_driver_begin_frame:
* @self: a #GskNextDriver
@@ -604,6 +647,7 @@ gsk_next_driver_load_texture (GskNextDriver *self,
int min_filter,
int mag_filter)
{
+ GdkGLContext *previous_context = NULL;
GdkGLContext *context;
GdkTexture *downloaded_texture = NULL;
GdkTexture *source_texture;
@@ -632,6 +676,8 @@ gsk_next_driver_load_texture (GskNextDriver *self,
{
cairo_surface_t *surface;
+ previous_context = gdk_gl_context_get_current ();
+
/* In this case, we have to temporarily make the texture's
* context the current one, download its data into our context
* and then create a texture from it. */
@@ -681,6 +727,9 @@ gsk_next_driver_load_texture (GskNextDriver *self,
g_clear_object (&downloaded_texture);
+ if (previous_context)
+ gdk_gl_context_make_current (previous_context);
+
return t->texture_id;
}
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index c73181bb27..18b10a66be 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -116,8 +116,8 @@ struct _GskNextDriver
guint in_frame : 1;
};
-GskNextDriver *gsk_next_driver_new (GskGLCommandQueue *command_queue,
- gboolean debug,
+GskNextDriver *gsk_next_driver_from_shared_context (GdkGLContext *context,
+ gboolean debug_shaders,
GError **error);
GdkGLContext *gsk_next_driver_get_context (GskNextDriver *self);
gboolean gsk_next_driver_create_render_target (GskNextDriver *self,
diff --git a/gsk/next/gskglrenderer.c b/gsk/next/gskglrenderer.c
index 2ec2477e16..59db1fea46 100644
--- a/gsk/next/gskglrenderer.c
+++ b/gsk/next/gskglrenderer.c
@@ -20,6 +20,7 @@
#include "config.h"
+#include <gdk/gdksurfaceprivate.h>
#include <gsk/gskdebugprivate.h>
#include <gsk/gskrendererprivate.h>
@@ -38,20 +39,15 @@ struct _GskNextRenderer
{
GskRenderer parent_instance;
- /* The GskGLCommandQueue manages how we send all drawing operations,
- * uniform changes, and other texture related operations to the GPU.
- * It maintains a cache of state to help reduce the number of state
- * changes we send to the GPU. Furthermore, it can reorder batches so
- * that we switch programs and uniforms less frequently by verifying
- * what batches can be reordered based on clipping and stacking.
+ /* This context is used to swap buffers when we are rendering directly
+ * to a GDK surface. It is also used to locate the shared driver for
+ * the display that we use to drive the command queue.
*/
- GskGLCommandQueue *command_queue;
+ GdkGLContext *context;
- /* The driver manages our program state and command queues. It gives
- * us a single place to manage loading all the programs as well which
- * unfortunately cannot be shared across all renderers for a display.
- * (Context sharing explicitly does not name program/uniform state as
- * shareable even though on some implementations it is).
+ /* The driver manages our program state and command queues. It also
+ * deals with caching textures, shaders, shadows, glyph, and icon
+ * caches through various helpers.
*/
GskNextDriver *driver;
};
@@ -70,8 +66,8 @@ gsk_next_renderer_realize (GskRenderer *renderer,
GError **error)
{
GskNextRenderer *self = (GskNextRenderer *)renderer;
- GskGLCommandQueue *command_queue = NULL;
GdkGLContext *context = NULL;
+ GdkGLContext *shared_context;
GskNextDriver *driver = NULL;
gboolean ret = FALSE;
gboolean debug_shaders = FALSE;
@@ -79,23 +75,34 @@ gsk_next_renderer_realize (GskRenderer *renderer,
g_assert (GSK_IS_NEXT_RENDERER (self));
g_assert (GDK_IS_SURFACE (surface));
+ if (self->context != NULL)
+ return TRUE;
+
+ g_assert (self->driver == NULL);
+ g_assert (self->context == NULL);
+
if (!(context = gdk_surface_create_gl_context (surface, error)) ||
!gdk_gl_context_realize (context, error))
goto failure;
- gdk_gl_context_make_current (context);
-
- command_queue = gsk_gl_command_queue_new (context);
+ if (!(shared_context = gdk_surface_get_shared_data_gl_context (surface)))
+ {
+ g_set_error (error,
+ GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ "Failed to locate shared GL context for driver");
+ goto failure;
+ }
#ifdef G_ENABLE_DEBUG
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS))
debug_shaders = TRUE;
#endif
- if (!(driver = gsk_next_driver_new (command_queue, debug_shaders, error)))
+ if (!(driver = gsk_next_driver_from_shared_context (shared_context, debug_shaders, error)))
goto failure;
- self->command_queue = g_steal_pointer (&command_queue);
+ self->context = g_steal_pointer (&context);
self->driver = g_steal_pointer (&driver);
ret = TRUE;
@@ -103,7 +110,6 @@ gsk_next_renderer_realize (GskRenderer *renderer,
failure:
g_clear_object (&driver);
g_clear_object (&context);
- g_clear_object (&command_queue);
return ret;
}
@@ -116,7 +122,6 @@ gsk_next_renderer_unrealize (GskRenderer *renderer)
g_assert (GSK_IS_NEXT_RENDERER (renderer));
g_clear_object (&self->driver);
- g_clear_object (&self->command_queue);
}
typedef struct _GskGLTextureState
@@ -207,32 +212,35 @@ gsk_gl_renderer_render (GskRenderer *renderer,
cairo_region_t *render_region;
graphene_rect_t viewport;
GskGLRenderJob *job;
- GdkGLContext *context;
GdkSurface *surface;
float scale_factor;
g_assert (GSK_IS_NEXT_RENDERER (renderer));
g_assert (root != NULL);
- context = gsk_gl_command_queue_get_context (self->command_queue);
- surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
+ surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self->context));
scale_factor = gdk_surface_get_scale_factor (surface);
- render_region = get_render_region (surface, context);
+ render_region = get_render_region (surface, self->context);
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;
- gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (context), update_area);
- job = gsk_gl_render_job_new (self->driver, &viewport, scale_factor, render_region, 0);
+ gdk_gl_context_make_current (self->context);
+ gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->context), update_area);
+
+ job = gsk_gl_render_job_new (self->driver, &viewport, scale_factor, render_region, self->context, 0);
+
#ifdef G_ENABLE_DEBUG
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
gsk_gl_render_job_set_debug_fallback (job, TRUE);
#endif
gsk_gl_render_job_render (job, root);
- gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (context));
+
+ gdk_gl_context_make_current (self->context);
+ gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->context));
gsk_gl_render_job_free (job);
@@ -255,7 +263,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
g_assert (GSK_IS_NEXT_RENDERER (renderer));
g_assert (root != NULL);
- context = gsk_gl_command_queue_get_context (self->command_queue);
+ context = gsk_gl_command_queue_get_context (self->driver->command_queue);
width = ceilf (viewport->size.width);
height = ceilf (viewport->size.height);
@@ -267,7 +275,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
&render_target))
return NULL;
- job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id);
+ job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, context, render_target->framebuffer_id);
gsk_gl_render_job_render_flipped (job, root);
gsk_gl_render_job_free (job);
@@ -282,7 +290,6 @@ gsk_next_renderer_dispose (GObject *object)
#ifdef G_ENABLE_DEBUG
GskNextRenderer *self = (GskNextRenderer *)object;
- g_assert (self->command_queue == NULL);
g_assert (self->driver == NULL);
#endif
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index c1e6fd615c..a88f411082 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -74,6 +74,12 @@
struct _GskGLRenderJob
{
+ /* The context containing the framebuffer we are drawing to. Generally this
+ * is the context of the surface but may be a shared context if rendering to
+ * an offscreen texture such as gsk_gl_renderer_render_texture().
+ */
+ GdkGLContext *context;
+
/* The driver to be used. This is shared among all the renderers on a given
* GdkDisplay and uses the shared GL context to send commands.
*/
@@ -3578,18 +3584,20 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
g_return_if_fail (root != NULL);
g_return_if_fail (GSK_IS_NEXT_DRIVER (job->driver));
- context = gsk_next_driver_get_context (job->driver);
+ context = gsk_gl_command_queue_get_context (job->command_queue);
scale_factor = MAX (job->scale_x, job->scale_y);
surface_height = job->viewport.size.height;
+ /* Do initial frame setup using shared GL context */
gsk_next_driver_begin_frame (job->driver);
+ /* Build the command queue using the shared GL context for all renderers
+ * on the same display.
+ */
+ gdk_gl_context_push_debug_group (context, "Building command queue");
if (job->framebuffer != 0)
gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
-
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
-
- gdk_gl_context_push_debug_group (context, "Building command queue");
gsk_gl_render_job_visit_node (job, root);
gdk_gl_context_pop_debug_group (context);
@@ -3600,10 +3608,16 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
gsk_next_driver_save_atlases_to_png (job->driver, NULL);
#endif
- gdk_gl_context_push_debug_group (context, "Executing command queue");
+ /* But now for executing the command queue, we want to use the context
+ * that was provided to us when creating the render job as framebuffer 0
+ * is bound to that context.
+ */
+ gdk_gl_context_make_current (job->context);
+ gdk_gl_context_push_debug_group (job->context, "Executing command queue");
gsk_gl_command_queue_execute (job->command_queue, surface_height, scale_factor, job->region);
- gdk_gl_context_pop_debug_group (context);
+ gdk_gl_context_pop_debug_group (job->context);
+ /* Do frame cleanup using shared GL context */
gsk_next_driver_end_frame (job->driver);
}
@@ -3621,6 +3635,7 @@ gsk_gl_render_job_new (GskNextDriver *driver,
const graphene_rect_t *viewport,
float scale_factor,
const cairo_region_t *region,
+ GdkGLContext *context,
guint framebuffer)
{
const graphene_rect_t *clip_rect = viewport;
@@ -3628,12 +3643,14 @@ gsk_gl_render_job_new (GskNextDriver *driver,
GskGLRenderJob *job;
g_return_val_if_fail (GSK_IS_NEXT_DRIVER (driver), NULL);
+ g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
g_return_val_if_fail (viewport != NULL, NULL);
g_return_val_if_fail (scale_factor > 0, NULL);
job = g_slice_new0 (GskGLRenderJob);
job->driver = g_object_ref (driver);
job->command_queue = driver->command_queue;
+ job->context = g_object_ref (context);
job->clip = g_array_new (FALSE, FALSE, sizeof (GskGLRenderClip));
job->modelview = g_array_new (FALSE, FALSE, sizeof (GskGLRenderModelview));
job->framebuffer = framebuffer;
@@ -3687,6 +3704,7 @@ gsk_gl_render_job_free (GskGLRenderJob *job)
}
g_clear_object (&job->driver);
+ g_clear_object (&job->context);
g_clear_pointer (&job->region, cairo_region_destroy);
g_clear_pointer (&job->modelview, g_array_unref);
g_clear_pointer (&job->clip, g_array_unref);
diff --git a/gsk/next/gskglrenderjobprivate.h b/gsk/next/gskglrenderjobprivate.h
index 2a8c01fa71..02cfee5737 100644
--- a/gsk/next/gskglrenderjobprivate.h
+++ b/gsk/next/gskglrenderjobprivate.h
@@ -27,6 +27,7 @@ GskGLRenderJob *gsk_gl_render_job_new (GskNextDriver *dr
const graphene_rect_t *viewport,
float scale_factor,
const cairo_region_t *region,
+ GdkGLContext *context,
guint framebuffer);
void gsk_gl_render_job_free (GskGLRenderJob *job);
void gsk_gl_render_job_render (GskGLRenderJob *job,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]