[gtk/wip/chergert/glproto] add render target abstraction
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/glproto] add render target abstraction
- Date: Wed, 13 Jan 2021 19:07:27 +0000 (UTC)
commit 9e1eca9b06aed8f1b8c536471e5eddf4dc11c70e
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 13 11:05:43 2021 -0800
add render target abstraction
this will make things a bit easier to manage and release without so much
manual control over texture/framebuffer management
gsk/next/gskgldriver.c | 172 +++++++++++++++++++++++++++++++++---------
gsk/next/gskgldriverprivate.h | 17 ++++-
gsk/next/gskglrenderer.c | 12 +--
gsk/next/gskglrenderjob.c | 77 ++++++++++---------
gsk/next/gskgltypesprivate.h | 2 +-
5 files changed, 195 insertions(+), 85 deletions(-)
---
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 64cb9894d4..4e9a2d7ddb 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -163,6 +163,7 @@ gsk_next_driver_dispose (GObject *object)
g_clear_pointer (&self->textures, g_hash_table_unref);
g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref);
g_clear_pointer (&self->texture_id_to_key, g_hash_table_unref);
+ g_clear_pointer (&self->render_targets, g_ptr_array_unref);
G_OBJECT_CLASS (gsk_next_driver_parent_class)->dispose (object);
}
@@ -186,6 +187,7 @@ gsk_next_driver_init (GskNextDriver *self)
g_free,
NULL);
gsk_gl_texture_pool_init (&self->texture_pool);
+ self->render_targets = g_ptr_array_new ();
}
static gboolean
@@ -351,12 +353,23 @@ gsk_next_driver_end_frame (GskNextDriver *self)
g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
g_return_if_fail (self->in_frame == TRUE);
+ gdk_gl_context_make_current (self->command_queue->context);
+
gsk_gl_command_queue_end_frame (self->command_queue);
gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->icons));
gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs));
gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->shadows));
+ for (guint i = 0; i < self->render_targets->len; i++)
+ {
+ GskGLRenderTarget *render_target = g_ptr_array_index (self->render_targets, i);
+
+ gsk_next_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
+ glDeleteTextures (1, &render_target->texture_id);
+ g_slice_free (GskGLRenderTarget, render_target);
+ }
+
if (self->autorelease_framebuffers->len > 0)
{
glDeleteFramebuffers (self->autorelease_framebuffers->len,
@@ -378,43 +391,6 @@ gsk_next_driver_get_context (GskNextDriver *self)
return gsk_gl_command_queue_get_context (self->command_queue);
}
-/**
- * gsk_next_driver_create_render_target:
- * @self: a #GskNextDriver
- * @width: the width for the render target
- * @height: the height for the render target
- * @min_filter: the min filter to use for the texture
- * @mag_filter: the mag filter to use for the texture
- * @out_fbo_id: (out): location for framebuffer id
- * @out_texture_id: (out): location for texture id
- *
- * Creates a new render target where @out_texture_id is bound
- * to the framebuffer @out_fbo_id using glFramebufferTexture2D().
- *
- * Returns: %TRUE if successful; otherwise %FALSE and @out_fbo_id and
- * @out_texture_id are undefined.
- */
-gboolean
-gsk_next_driver_create_render_target (GskNextDriver *self,
- int width,
- int height,
- int min_filter,
- int mag_filter,
- guint *out_fbo_id,
- guint *out_texture_id)
-{
- g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), FALSE);
- g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->command_queue), FALSE);
-
- return gsk_gl_command_queue_create_render_target (self->command_queue,
- width,
- height,
- min_filter,
- mag_filter,
- out_fbo_id,
- out_texture_id);
-}
-
/**
* gsk_next_driver_lookup_texture:
* @self: a #GskNextDriver
@@ -682,3 +658,125 @@ gsk_next_driver_release_texture (GskNextDriver *self,
gsk_gl_texture_pool_put (&self->texture_pool, texture);
}
+
+/**
+ * gsk_next_driver_create_render_target:
+ * @self: a #GskNextDriver
+ * @width: the width for the render target
+ * @height: the height for the render target
+ * @min_filter: the min filter to use for the texture
+ * @mag_filter: the mag filter to use for the texture
+ * @out_render_target: (out): a location for the render target
+ *
+ * Creates a new render target which contains a framebuffer and a texture
+ * bound to that framebuffer of the size @width x @height and using the
+ * appropriate filters.
+ *
+ * Use gsk_next_driver_release_render_target() when you are finished with
+ * the render target to release it. You may steal the texture from the
+ * render target when releasing it.
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @out_fbo_id and
+ * @out_texture_id are undefined.
+ */
+gboolean
+gsk_next_driver_create_render_target (GskNextDriver *self,
+ int width,
+ int height,
+ int min_filter,
+ int mag_filter,
+ GskGLRenderTarget **out_render_target)
+{
+ guint framebuffer_id;
+ guint texture_id;
+
+ g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), FALSE);
+ g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->command_queue), FALSE);
+ g_return_val_if_fail (out_render_target != NULL, FALSE);
+
+ if (self->render_targets->len > 0)
+ {
+ for (guint i = self->render_targets->len; i > 0; i--)
+ {
+ GskGLRenderTarget *render_target = g_ptr_array_index (self->render_targets, i-1);
+
+ if (render_target->width == width &&
+ render_target->height == height &&
+ render_target->min_filter == min_filter &&
+ render_target->mag_filter == mag_filter)
+ {
+ *out_render_target = g_ptr_array_steal_index_fast (self->render_targets, i-1);
+ return TRUE;
+ }
+ }
+ }
+
+ if (gsk_gl_command_queue_create_render_target (self->command_queue,
+ width, height,
+ min_filter, mag_filter,
+ &framebuffer_id, &texture_id))
+ {
+ GskGLRenderTarget *render_target;
+
+ render_target = g_slice_new0 (GskGLRenderTarget);
+ render_target->min_filter = min_filter;
+ render_target->mag_filter = mag_filter;
+ render_target->width = width;
+ render_target->height = height;
+ render_target->framebuffer_id = framebuffer_id;
+ render_target->texture_id = texture_id;
+
+ *out_render_target = render_target;
+
+ return TRUE;
+ }
+
+ *out_render_target = NULL;
+
+ return FALSE;
+}
+
+/**
+ * gsk_next_driver_release_render_target:
+ * @self: a #GskNextDriver
+ * @render_target: a #GskGLRenderTarget created with
+ * gsk_next_driver_create_render_target().
+ * @release_texture: if the texture should also be released
+ *
+ * Releases a render target that was previously created. An attempt may
+ * be made to cache the render target so that future creations of render
+ * targets are performed faster.
+ *
+ * If @release_texture is %FALSE, the backing texture id is returned and
+ * the framebuffer is released. Otherwise, both the texture and framebuffer
+ * are released or cached until the end of the frame.
+ *
+ * This may be called when building the render job as the texture or
+ * framebuffer will not be removed immediately.
+ *
+ * Returns: a texture id if @release_texture is %FALSE, otherwise zero.
+ */
+guint
+gsk_next_driver_release_render_target (GskNextDriver *self,
+ GskGLRenderTarget *render_target,
+ gboolean release_texture)
+{
+ guint texture_id;
+
+ g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), 0);
+ g_return_val_if_fail (render_target != NULL, 0);
+
+ if (release_texture)
+ {
+ texture_id = 0;
+ g_ptr_array_add (self->render_targets, render_target);
+ }
+ else
+ {
+ texture_id = render_target->texture_id;
+ gsk_next_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
+ g_slice_free (GskGLRenderTarget, render_target);
+ }
+
+ return texture_id;
+}
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index 587c3d1e42..13f4429891 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -59,6 +59,16 @@ typedef struct {
G_DECLARE_FINAL_TYPE (GskNextDriver, gsk_next_driver, GSK, NEXT_DRIVER, GObject)
+struct _GskGLRenderTarget
+{
+ guint framebuffer_id;
+ guint texture_id;
+ int min_filter;
+ int mag_filter;
+ int width;
+ int height;
+};
+
struct _GskNextDriver
{
GObject parent_instance;
@@ -77,6 +87,7 @@ struct _GskNextDriver
GHashTable *texture_id_to_key;
GArray *autorelease_framebuffers;
+ GPtrArray *render_targets;
#define GSK_GL_NO_UNIFORMS
#define GSK_GL_ADD_UNIFORM(pos, KEY, name)
@@ -103,8 +114,10 @@ gboolean gsk_next_driver_create_render_target (GskNextDriver *se
int height,
int min_filter,
int mag_filter,
- guint *out_fbo_id,
- guint *out_texture_id);
+ GskGLRenderTarget **render_target);
+guint gsk_next_driver_release_render_target (GskNextDriver *self,
+ GskGLRenderTarget *render_target,
+ gboolean release_texture);
void gsk_next_driver_begin_frame (GskNextDriver *self);
void gsk_next_driver_end_frame (GskNextDriver *self);
guint gsk_next_driver_lookup_texture (GskNextDriver *self,
diff --git a/gsk/next/gskglrenderer.c b/gsk/next/gskglrenderer.c
index b7b1b13811..430c92ddbc 100644
--- a/gsk/next/gskglrenderer.c
+++ b/gsk/next/gskglrenderer.c
@@ -244,10 +244,10 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
const graphene_rect_t *viewport)
{
GskNextRenderer *self = (GskNextRenderer *)renderer;
+ GskGLRenderTarget *render_target;
GskGLRenderJob *job;
GdkGLContext *context;
- GLuint fbo_id;
- GLuint texture_id;
+ guint texture_id;
int width;
int height;
@@ -263,15 +263,15 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
if (!gsk_next_driver_create_render_target (self->driver,
width, height,
GL_NEAREST, GL_NEAREST,
- &fbo_id, &texture_id))
+ &render_target))
return NULL;
- gsk_next_driver_autorelease_framebuffer (self->driver, fbo_id);
-
- job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, fbo_id);
+ job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id);
gsk_gl_render_job_render_flipped (job, root);
gsk_gl_render_job_free (job);
+ texture_id = gsk_next_driver_release_render_target (self->driver, render_target, FALSE);
+
return create_texture_from_texture (context, texture_id, width, height);
}
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index e8e9baacec..87527a3688 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -1799,8 +1799,8 @@ blur_offscreen (GskGLRenderJob *job,
float blur_radius_y)
{
const GskRoundedRect new_clip = GSK_ROUNDED_RECT_INIT (0, 0, texture_to_blur_width,
texture_to_blur_height);
- guint pass1_texture_id, pass1_framebuffer_id;
- guint pass2_texture_id, pass2_framebuffer_id;
+ GskGLRenderTarget *pass1;
+ GskGLRenderTarget *pass2;
GskGLRenderState state;
g_assert (blur_radius_x > 0);
@@ -1809,26 +1809,22 @@ blur_offscreen (GskGLRenderJob *job,
g_assert (offscreen->area.size.width > 0);
g_assert (offscreen->area.size.height > 0);
- gsk_next_driver_create_render_target (job->driver,
- MAX (texture_to_blur_width, 1),
- MAX (texture_to_blur_height, 1),
- GL_NEAREST, GL_NEAREST,
- &pass1_framebuffer_id,
- &pass1_texture_id);
-
- gsk_next_driver_autorelease_framebuffer (job->driver, pass1_framebuffer_id);
+ if (!gsk_next_driver_create_render_target (job->driver,
+ MAX (texture_to_blur_width, 1),
+ MAX (texture_to_blur_height, 1),
+ GL_NEAREST, GL_NEAREST,
+ &pass1))
+ return 0;
if (texture_to_blur_width <= 0 || texture_to_blur_height <= 0)
- return pass1_texture_id;
-
- gsk_next_driver_create_render_target (job->driver,
- texture_to_blur_width,
- texture_to_blur_height,
- GL_NEAREST, GL_NEAREST,
- &pass2_framebuffer_id,
- &pass2_texture_id);
+ return gsk_next_driver_release_render_target (job->driver, pass1, FALSE);
- gsk_next_driver_autorelease_framebuffer (job->driver, pass2_framebuffer_id);
+ if (!gsk_next_driver_create_render_target (job->driver,
+ texture_to_blur_width,
+ texture_to_blur_height,
+ GL_NEAREST, GL_NEAREST,
+ &pass2))
+ return gsk_next_driver_release_render_target (job->driver, pass1, FALSE);
gsk_gl_render_state_save (&state, job);
@@ -1838,7 +1834,7 @@ blur_offscreen (GskGLRenderJob *job,
gsk_gl_render_job_push_clip (job, &new_clip);
/* Bind new framebuffer and clear it */
- gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass1_framebuffer_id);
+ gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass1->framebuffer_id);
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
/* Begin drawing the first horizontal pass, using offscreen as the
@@ -1869,7 +1865,7 @@ blur_offscreen (GskGLRenderJob *job,
gsk_gl_program_end_draw (job->driver->blur);
/* Bind second pass framebuffer and clear it */
- gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass2_framebuffer_id);
+ gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass2->framebuffer_id);
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
/* Draw using blur program with first pass as source texture */
@@ -1883,7 +1879,7 @@ blur_offscreen (GskGLRenderJob *job,
UNIFORM_SHARED_SOURCE,
GL_TEXTURE_2D,
GL_TEXTURE0,
- pass1_texture_id);
+ pass1->texture_id);
gsk_gl_program_set_uniform1f (job->driver->blur,
UNIFORM_BLUR_RADIUS,
blur_radius_y);
@@ -1902,9 +1898,9 @@ blur_offscreen (GskGLRenderJob *job,
gsk_gl_render_state_restore (&state, job);
- /* TODO: Release bound fbo/texture pair */
+ gsk_next_driver_release_render_target (job->driver, pass1, TRUE);
- return pass2_texture_id;
+ return gsk_next_driver_release_render_target (job->driver, pass2, FALSE);
}
static void
@@ -2441,29 +2437,31 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
}
}
- guint framebuffer_id;
- guint texture_id;
+ GskGLRenderTarget *render_target;
GskGLRenderState state;
gsk_gl_render_state_save (&state, job);
- gsk_next_driver_create_render_target (job->driver,
- width, height,
- filter, filter,
- &texture_id, &framebuffer_id);
+ if (!gsk_next_driver_create_render_target (job->driver,
+ width, height,
+ filter, filter,
+ &render_target))
+ g_assert_not_reached ();
if (gdk_gl_context_has_debug (job->command_queue->context))
{
gdk_gl_context_label_object_printf (job->command_queue->context,
- GL_TEXTURE, texture_id,
+ GL_TEXTURE,
+ render_target->texture_id,
"Offscreen<%s> %d",
g_type_name_from_instance ((GTypeInstance *) node),
- texture_id);
+ render_target->texture_id);
gdk_gl_context_label_object_printf (job->command_queue->context,
- GL_FRAMEBUFFER, framebuffer_id,
+ GL_FRAMEBUFFER,
+ render_target->framebuffer_id,
"Offscreen<%s> FB %d",
g_type_name_from_instance ((GTypeInstance *) node),
- framebuffer_id);
+ render_target->framebuffer_id);
}
job->viewport.origin.x = offscreen->bounds->origin.x * scale_x;
@@ -2471,7 +2469,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
job->viewport.size.width = width;
job->viewport.size.height = height;
- gsk_gl_command_queue_bind_framebuffer (job->command_queue, framebuffer_id);
+ gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
init_projection_matrix (&job->projection, &job->viewport);
@@ -2493,13 +2491,14 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
gsk_gl_render_state_restore (&state, job);
offscreen->was_offscreen = TRUE;
- offscreen->texture_id = texture_id;
- init_full_texture_region (&offscreen->area);
+ offscreen->texture_id = gsk_next_driver_release_render_target (job->driver,
+ render_target,
+ FALSE);
- gsk_next_driver_autorelease_framebuffer (job->driver, framebuffer_id);
+ init_full_texture_region (&offscreen->area);
if (!offscreen->do_not_cache)
- gsk_next_driver_cache_texture (job->driver, &key, texture_id);
+ gsk_next_driver_cache_texture (job->driver, &key, offscreen->texture_id);
return TRUE;
}
diff --git a/gsk/next/gskgltypesprivate.h b/gsk/next/gskgltypesprivate.h
index f29f457cff..03aa07383a 100644
--- a/gsk/next/gskgltypesprivate.h
+++ b/gsk/next/gskgltypesprivate.h
@@ -35,7 +35,7 @@ typedef struct _GskGLBuffer GskGLBuffer;
typedef struct _GskGLCommandQueue GskGLCommandQueue;
typedef struct _GskGLCompiler GskGLCompiler;
typedef struct _GskGLDrawVertex GskGLDrawVertex;
-typedef struct _GskGLFramebuffer GskGLFramebuffer;
+typedef struct _GskGLRenderTarget GskGLRenderTarget;
typedef struct _GskGLGlyphLibrary GskGLGlyphLibrary;
typedef struct _GskGLIconLibrary GskGLIconLibrary;
typedef struct _GskGLProgram GskGLProgram;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]