[gtk/wip/chergert/glproto] start on more memory friendly version of command queue
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/glproto] start on more memory friendly version of command queue
- Date: Wed, 23 Dec 2020 01:08:40 +0000 (UTC)
commit 82e253fe402d9b1357c4f1c917856afdbc96860c
Author: Christian Hergert <chergert redhat com>
Date: Tue Dec 22 17:08:20 2020 -0800
start on more memory friendly version of command queue
This avoids the pointers (and therefore using slice allocations w/ reuse)
by keeping fixed sized structs for most things and multiple arrays for
the in-flight changes.
To avoid memmove of batches we have a next_batch_index int that can be
changed as we append batches to the end of the array to reorder.
I'm still thinking about what we can do to track rects as we do reordering
as well as what operations are barriers. Will probably keep a window by
program as we go which gets reset as we hit barriers.
gsk/next/gskglbuffer.c | 8 +
gsk/next/gskglbufferprivate.h | 15 +-
gsk/next/gskglcommandqueue.c | 1064 ++++++++++++++---------------------
gsk/next/gskglcommandqueueprivate.h | 22 +-
gsk/next/gskglprogram.c | 51 +-
gsk/next/gskglprogramprivate.h | 116 ++--
gsk/next/gskglrenderjob.c | 75 ++-
gsk/next/gskgltypes.h | 2 +
8 files changed, 585 insertions(+), 768 deletions(-)
---
diff --git a/gsk/next/gskglbuffer.c b/gsk/next/gskglbuffer.c
index 913f5ebc8e..c9ee140ec0 100644
--- a/gsk/next/gskglbuffer.c
+++ b/gsk/next/gskglbuffer.c
@@ -169,3 +169,11 @@ gsk_gl_buffer_advance (GskGLBuffer *buffer,
g_array_set_size (buffer->buffer, buffer->buffer->len + count);
return (guint8 *)buffer->buffer->data + (*offset * g_array_get_element_size (buffer->buffer));
}
+
+guint
+gsk_gl_buffer_get_offset (GskGLBuffer *buffer)
+{
+ g_return_val_if_fail (buffer != NULL, 0);
+
+ return buffer->buffer->len;
+}
diff --git a/gsk/next/gskglbufferprivate.h b/gsk/next/gskglbufferprivate.h
index 2d88bb4995..3150dd7eeb 100644
--- a/gsk/next/gskglbufferprivate.h
+++ b/gsk/next/gskglbufferprivate.h
@@ -28,13 +28,14 @@ G_BEGIN_DECLS
typedef struct _GskGLBuffer GskGLBuffer;
-GskGLBuffer *gsk_gl_buffer_new (GLenum target,
- guint element_size);
-void gsk_gl_buffer_free (GskGLBuffer *buffer);
-void gsk_gl_buffer_submit (GskGLBuffer *buffer);
-gpointer gsk_gl_buffer_advance (GskGLBuffer *buffer,
- guint count,
- guint *offset);
+GskGLBuffer *gsk_gl_buffer_new (GLenum target,
+ guint element_size);
+void gsk_gl_buffer_free (GskGLBuffer *buffer);
+void gsk_gl_buffer_submit (GskGLBuffer *buffer);
+guint gsk_gl_buffer_get_offset (GskGLBuffer *buffer);
+gpointer gsk_gl_buffer_advance (GskGLBuffer *buffer,
+ guint count,
+ guint *offset);
G_END_DECLS
diff --git a/gsk/next/gskglcommandqueue.c b/gsk/next/gskglcommandqueue.c
index 1dd1dfa009..f7286dcbd9 100644
--- a/gsk/next/gskglcommandqueue.c
+++ b/gsk/next/gskglcommandqueue.c
@@ -20,6 +20,7 @@
#include "config.h"
+#include <gdk/gdkglcontextprivate.h>
#include <gsk/gskdebugprivate.h>
#include <epoxy/gl.h>
@@ -28,44 +29,25 @@
#include "gskglcommandqueueprivate.h"
#include "gskgluniformstateprivate.h"
-/* The MAX_MERGE_DISTANCE is used to reduce how far back we'll look for
- * programs to merge a batch with. This number is specific to batches using
- * the same program as a secondary index (See program_link field) is used
- * for tracking those.
- */
-#define MAX_MERGE_DISTANCE 5
-
struct _GskGLCommandQueue
{
GObject parent_instance;
+ /* The GdkGLContext we make current before executing GL commands. */
GdkGLContext *context;
- /* Queue containing a linked list of all the GskGLCommandBatch that have
- * been allocated so that we can reuse them on the next frame without
- * allocating additional memory. Using stable pointers instead of offsets
- * into an array makes this a bit easier to manage from a life-cycle
- * standpoint as well as reordering using the links instead of memmove()s
- * in an array.
- */
- GQueue unused_batches;
-
- /* As we build the real command queue, we place the batches into this
- * queue by pushing onto the tail. Executing commands will result in
- * walking this queue from head to tail.
+ /* Array of GskGLCommandBatch which is a fixed size structure that will
+ * point into offsets of other arrays so that all similar data is stored
+ * together. The idea here is that we reduce the need for pointers so that
+ * using g_realloc()'d arrays is fine.
*/
- GQueue all_batches;
+ GArray *batches;
- /* When merging batches we want to skip all items between the merge
- * candidate and the previous within it's program. To do this we keep an
- * index of commands by program to avoid iteration overhead. This array
- * contains a GQueue for each program which will point into the statically
- * allocated @program_link in GskGLCommandBatch.
- *
- * After we find a merge candidate, we check for clipping and other
- * changes which might make them unacceptable to merge.
+ /* Contains array of vertices and some wrapper code to help upload them
+ * to the GL driver. We can also tweak this to use double buffered arrays
+ * if we find that to be faster on some hardware and/or drivers.
*/
- GArray *program_batches;
+ GskGLBuffer *vertices;
/* The GskGLAttachmentState contains information about our FBO and texture
* attachments as we process incoming operations. We snapshot them into
@@ -80,11 +62,24 @@ struct _GskGLCommandQueue
*/
GskGLUniformState *uniforms;
- /* Our VBO containing all the vertices to upload to the GPU before calling
- * glDrawArrays() to draw. Each drawing operation contains 6 vec4 with the
- * positions necessary to draw with glDrawArrays().
+ /* Array of GskGLCommandDraw which allows us to have a static size field
+ * in GskGLCommandBatch to coalesce draws. Multiple GskGLCommandDraw may
+ * be processed together (and out-of-order) to reduce the number of state
+ * changes when submitting commands.
*/
- GskGLBuffer *vertices;
+ GArray *batch_draws;
+
+ /* Array of GskGLCommandBind which denote what textures need to be attached
+ * to which slot. GskGLCommandDraw.bind_offset and bind_count reference this
+ * array to determine what to attach.
+ */
+ GArray *batch_binds;
+
+ /* Array of GskGLCommandUniform denoting which uniforms must be updated
+ * before the glDrawArrays() may be called. These are referenced from the
+ * GskGLCommandDraw.uniform_offset and uniform_count fields.
+ */
+ GArray *batch_uniforms;
/* Sometimes we want to save attachment state so that operations we do
* cannot affect anything that is known to the command queue. We call
@@ -103,575 +98,411 @@ struct _GskGLCommandQueue
GArray *autorelease_framebuffers;
GArray *autorelease_textures;
+ /* String storage for debug groups */
+ GStringChunk *debug_groups;
+
+ /* Discovered max texture size when loading the command queue so that we
+ * can either scale down or slice textures to fit within this size. Assumed
+ * to be both height and width.
+ */
int max_texture_size;
+
+ /* The index of the last batch in @batches, which may not be the element
+ * at the end of the array, as batches can be reordered. This is used to
+ * update the "next" index when adding a new batch.
+ */
+ int tail_batch_index;
+
+ /* If we're inside of a begin_draw()/end_draw() pair. */
+ guint in_draw : 1;
};
-typedef struct _GskGLCommandDraw
+typedef enum _GskGLCommandKind
{
- guint vao_offset;
- guint vao_count;
-} GskGLCommandDraw;
+ /* The batch will perform a glClear() */
+ GSK_GL_COMMAND_KIND_CLEAR,
-G_STATIC_ASSERT (sizeof (GskGLCommandDraw) == 8);
+ /* THe batch represents a new debug group */
+ GSK_GL_COMMAND_KIND_PUSH_DEBUG_GROUP,
-typedef struct _GskGLCommandUniform
-{
- guint offset;
- guint array_count : 16;
- guint location : 7;
- guint format : 5;
- guint flags : 4;
-} GskGLCommandUniform;
+ /* The batch represents the end of a debug group */
+ GSK_GL_COMMAND_KIND_POP_DEBUG_GROUP,
-G_STATIC_ASSERT (sizeof (GskGLCommandUniform) == 8);
+ /* The batch will perform a glDrawArrays() */
+ GSK_GL_COMMAND_KIND_DRAW,
+} GskGLCommandKind;
-typedef struct _GskGLCommandBatch
+typedef struct _GskGLCommandBind
{
- /* An index into GskGLCommandQueue.all_batches */
- GList all_link;
+ /* @texture is the value passed to glActiveTexture(), the "slot" the
+ * texture will be placed into. We always use GL_TEXTURE_2D so we don't
+ * waste any bits here to indicate that.
+ */
+ guint texture : 5;
- /* An index into GskGLCommandBatch.program_batches */
- GList program_link;
+ /* The identifier for the texture created with glGenTextures(). */
+ guint id : 27;
+} GskGLCommandBind;
- union {
- GskGLBindTexture bind;
- GskGLBindTexture *binds;
- };
+G_STATIC_ASSERT (sizeof (GskGLCommandBind) == 4);
- union {
- GskGLCommandDraw draw;
- GskGLCommandDraw *draws;
- };
-
- union {
- GskGLCommandUniform uniform;
- GskGLCommandUniform *uniforms;
- };
+typedef struct _GskGLCommandDraw
+{
+ /* There doesn't seem to be a limit on the framebuffer identifier that
+ * can be returned, so we have to use a whole unsigned for the framebuffer
+ * we are drawing to. When processing batches, we check to see if this
+ * changes and adjust the render target accordingly. Some sorting is
+ * performed to reduce the amount we change framebuffers.
+ */
+ guint framebuffer;
- guint is_clear : 1;
- guint program_changed : 1;
- guint program : 14;
- guint n_draws : 16;
- guint n_binds : 16;
- guint n_uniforms : 16;
+ /* The number of uniforms to change. This must be less than or equal to
+ * GL_MAX_UNIFORM_LOCATIONS but only guaranteed up to 1024 by any OpenGL
+ * implementation to be conformant.
+ */
+ guint uniform_count : 11;
- /* The framebuffer to use and if it has changed */
- GskGLBindFramebuffer framebuffer;
-} GskGLCommandBatch;
+ /* The number of textures to bind, which is only guaranteed up to 16
+ * by the OpenGL specification to be conformant.
+ */
+ guint bind_count : 5;
-G_DEFINE_TYPE (GskGLCommandQueue, gsk_gl_command_queue, G_TYPE_OBJECT)
+ /* GL_MAX_ELEMENTS_VERTICES specifies 33000 for this which requires 16-bit
+ * to address all possible counts <= GL_MAX_ELEMENTS_VERTICES.
+ */
+ guint vbo_count : 16;
-static inline gboolean
-ispow2 (guint n)
-{
- return !(n & (n-1));
-}
+ /* The offset within the VBO containing @vbo_count vertices to send with
+ * glDrawArrays().
+ */
+ guint vbo_offset;
-static GskGLCommandBatch *
-gsk_gl_command_queue_alloc_batch (GskGLCommandQueue *self)
-{
- GskGLCommandBatch *batch;
+ /* The offset within the array of uniform changes to be made containing
+ * @uniform_count #GskGLCommandUniform elements to apply.
+ */
+ guint uniform_offset;
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
+ /* The offset within the array of bind changes to be made containing
+ * @bind_count #GskGLCommandBind elements to apply.
+ */
+ guint bind_offset;
+} GskGLCommandDraw;
- if G_LIKELY (self->unused_batches.length > 0)
- return g_queue_pop_head_link (&self->unused_batches)->data;
+G_STATIC_ASSERT (sizeof (GskGLCommandDraw) == 20);
- batch = g_slice_new0 (GskGLCommandBatch);
- batch->all_link.data = batch;
- batch->program_link.data = batch;
+typedef struct _GskGLCommandUniform
+{
+ GskGLUniformInfo info;
+ guint location;
+} GskGLCommandUniform;
- return batch;
-}
+G_STATIC_ASSERT (sizeof (GskGLCommandUniform) == 8);
-static void
-gsk_gl_command_queue_release_batch (GskGLCommandQueue *self,
- GskGLCommandBatch *batch)
+typedef struct _GskGLCommandBatch
{
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
- g_assert (batch != NULL);
-
- g_queue_unlink (&self->all_batches, &batch->all_link);
+ /* The index of the next batch following this one. This is used
+ * as a sort of integer-based linked list to simplify out-of-order
+ * batching without moving memory around. -1 indicates last batch.
+ */
+ int next_batch_index;
- g_assert (batch->program ||
- (batch->program_link.prev == NULL &&
- batch->program_link.next == NULL));
+ /* A GskGLCommandKind indicating what the batch will do */
+ guint kind : 8;
- if (batch->program_link.prev || batch->program_link.next)
- {
- GQueue *queue = &g_array_index (self->program_batches, GQueue, batch->program);
- g_queue_unlink (queue, &batch->program_link);
- }
+ /* The program's identifier to use for determining if we can merge two
+ * batches together into a single set of draw operations. We put this
+ * here instead of the GskGLCommandDraw so that we can use the extra
+ * bits here without making the structure larger.
+ */
+ guint program : 24;
- if (batch->n_draws > 1)
- g_free (batch->draws);
+ union {
+ /* Information about what to draw */
+ GskGLCommandDraw draw;
- if (batch->n_binds > 1)
- g_free (batch->binds);
+ /* The message to apply when pushing a debug group */
+ const char *debug_group;
- batch->n_binds = 0;
- batch->n_draws = 0;
- batch->binds = NULL;
- batch->draws = NULL;
- batch->framebuffer.id = 0;
- batch->framebuffer.changed = FALSE;
- batch->program = 0;
- batch->program_changed = FALSE;
+ /* The bits to glClear() */
+ struct {
+ guint bits;
+ guint framebuffer;
+ } clear;
+ };
+} GskGLCommandBatch;
- g_assert (batch->program_link.prev == NULL);
- g_assert (batch->program_link.next == NULL);
- g_assert (batch->program_link.data == batch);
- g_assert (batch->all_link.prev == NULL);
- g_assert (batch->all_link.next == NULL);
- g_assert (batch->all_link.data == batch);
+G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32);
- g_queue_push_head_link (&self->unused_batches, &batch->all_link);
-}
+G_DEFINE_TYPE (GskGLCommandQueue, gsk_gl_command_queue, G_TYPE_OBJECT)
static void
-gsk_gl_command_batch_apply_uniform (GskGLCommandBatch *batch,
- GskGLUniformState *state,
- const GskGLCommandUniform *uniform)
+gsk_gl_command_queue_save (GskGLCommandQueue *self)
{
- const union {
- graphene_matrix_t matrix[0];
- GskRoundedRect rounded_rect[0];
- float fval[0];
- int ival[0];
- } *data;
-
- g_assert (batch != NULL);
- g_assert (uniform != NULL);
-
- data = gsk_gl_uniform_state_get_uniform_data (state, uniform->offset);
-
- switch (uniform->format)
- {
- case GSK_GL_UNIFORM_FORMAT_1F:
- glUniform1f (uniform->location, data->fval[0]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_2F:
- glUniform2f (uniform->location, data->fval[0], data->fval[1]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_3F:
- glUniform3f (uniform->location, data->fval[0], data->fval[1], data->fval[2]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_4F:
- glUniform4f (uniform->location, data->fval[0], data->fval[1], data->fval[2], data->fval[3]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_1FV:
- glUniform1fv (uniform->location, uniform->array_count, data->fval);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_2FV:
- glUniform2fv (uniform->location, uniform->array_count, data->fval);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_3FV:
- glUniform3fv (uniform->location, uniform->array_count, data->fval);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_4FV:
- glUniform4fv (uniform->location, uniform->array_count, data->fval);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_1I:
- case GSK_GL_UNIFORM_FORMAT_TEXTURE:
- glUniform1i (uniform->location, data->ival[0]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_2I:
- glUniform2i (uniform->location, data->ival[0], data->ival[1]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_3I:
- glUniform3i (uniform->location, data->ival[0], data->ival[1], data->ival[2]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_4I:
- glUniform4i (uniform->location, data->ival[0], data->ival[1], data->ival[2], data->ival[3]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_MATRIX: {
- float mat[16];
- graphene_matrix_to_float (&data->matrix[0], mat);
- glUniformMatrix4fv (uniform->location, 1, GL_FALSE, mat);
- break;
- }
-
- case GSK_GL_UNIFORM_FORMAT_COLOR:
- glUniform4fv (uniform->location, 1, &data->fval[0]);
- break;
-
- case GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT:
- if (uniform->flags & GSK_GL_UNIFORM_FLAGS_SEND_CORNERS)
- glUniform4fv (uniform->location, 3, (const float *)&data->rounded_rect[0]);
- else
- glUniform4fv (uniform->location, 1, (const float *)&data->rounded_rect[0]);
- break;
+ g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
- default:
- break;
- }
+ g_ptr_array_add (self->saved_state,
+ gsk_gl_attachment_state_save (self->attachments));
}
static void
-gsk_gl_command_batch_draw (GskGLCommandBatch *batch,
- guint vao_offset,
- guint vao_count)
+gsk_gl_command_queue_restore (GskGLCommandQueue *self)
{
- GskGLCommandDraw *last;
-
- g_assert (batch != NULL);
-
- if (batch->n_draws == 0)
- {
- batch->draw.vao_offset = vao_offset;
- batch->draw.vao_count = vao_count;
- batch->n_draws = 1;
- return;
- }
-
- last = batch->n_draws == 1 ? &batch->draw : &batch->draws[batch->n_draws-1];
-
- if (last->vao_offset + last->vao_count == vao_offset)
- {
- batch->draw.vao_count += vao_count;
- }
- else if (batch->n_draws == 1)
- {
- GskGLCommandDraw *draws = g_new (GskGLCommandDraw, 16);
+ GskGLAttachmentState *saved;
- draws[0].vao_offset = batch->draw.vao_offset;
- draws[0].vao_count = batch->draw.vao_count;
- draws[1].vao_offset = vao_offset;
- draws[1].vao_count = vao_count;
+ g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_assert (self->saved_state->len > 0);
- batch->draws = draws;
- batch->n_draws = 2;
- }
- else
- {
- if G_UNLIKELY (batch->n_draws >= 16 && ispow2 (batch->n_draws))
- batch->draws = g_realloc (batch->draws, sizeof (GskGLCommandDraw) * batch->n_draws * 2);
+ saved = g_ptr_array_steal_index (self->saved_state,
+ self->saved_state->len - 1);
- batch->draws[batch->n_draws].vao_count = vao_count;
- batch->draws[batch->n_draws].vao_offset = vao_offset;
- batch->n_draws++;
- }
+ gsk_gl_attachment_state_restore (saved);
}
static void
-gsk_gl_command_batch_execute (GskGLCommandBatch *batch,
- GskGLUniformState *uniforms)
+gsk_gl_command_queue_dispose (GObject *object)
{
- g_assert (batch != NULL);
- g_assert (batch->n_draws > 0);
-
- if (batch->framebuffer.changed)
- glBindFramebuffer (GL_FRAMEBUFFER, batch->framebuffer.id);
-
- if (batch->program_changed)
- glUseProgram (batch->program);
-
- if (batch->n_binds == 1)
- {
- g_assert (batch->bind.changed);
-
- glActiveTexture (batch->bind.texture);
- glBindTexture (batch->bind.target, batch->bind.id);
- }
- else if (batch->n_binds > 1)
- {
- for (guint i = 0; i < batch->n_binds; i++)
- {
- const GskGLBindTexture *bind = &batch->binds[i];
-
- g_assert (bind->changed);
-
- glActiveTexture (bind->texture);
- glBindTexture (bind->target, bind->id);
- }
- }
-
- if (batch->n_uniforms == 1)
- {
- gsk_gl_command_batch_apply_uniform (batch, uniforms, &batch->uniform);
- }
- else if (batch->n_uniforms > 0)
- {
- for (guint i = 0; i < batch->n_uniforms; i++)
- {
- const GskGLCommandUniform *uniform = &batch->uniforms[i];
- gsk_gl_command_batch_apply_uniform (batch, uniforms, uniform);
- }
- }
+ GskGLCommandQueue *self = (GskGLCommandQueue *)object;
- if (batch->is_clear)
- {
- glClearColor (0, 0, 0, 0);
- glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- }
- else if (batch->n_draws == 1)
- {
- glDrawArrays (GL_TRIANGLES, batch->draw.vao_offset, batch->draw.vao_count);
- }
- else if (batch->n_draws > 1)
- {
- for (guint i = 0; i < batch->n_draws; i++)
- {
- const GskGLCommandDraw *draw = &batch->draws[i];
+ g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
- g_assert (draw->vao_count > 0);
+ g_clear_object (&self->context);
+ g_clear_pointer (&self->batches, g_array_unref);
+ g_clear_pointer (&self->attachments, gsk_gl_attachment_state_free);
+ g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_free);
+ g_clear_pointer (&self->vertices, gsk_gl_buffer_free);
+ g_clear_pointer (&self->batch_draws, g_array_unref);
+ g_clear_pointer (&self->batch_binds, g_array_unref);
+ g_clear_pointer (&self->batch_uniforms, g_array_unref);
+ g_clear_pointer (&self->saved_state, g_ptr_array_unref);
+ g_clear_pointer (&self->autorelease_framebuffers, g_array_unref);
+ g_clear_pointer (&self->autorelease_textures, g_array_unref);
- glDrawArrays (GL_TRIANGLES, draw->vao_offset, draw->vao_count);
- }
- }
+ G_OBJECT_CLASS (gsk_gl_command_queue_parent_class)->dispose (object);
}
static void
-gsk_gl_command_batch_uniform_cb (const GskGLUniformInfo *info,
- guint location,
- gpointer user_data)
+gsk_gl_command_queue_class_init (GskGLCommandQueueClass *klass)
{
- GskGLCommandBatch *batch = user_data;
- GskGLCommandUniform *u;
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- g_assert (batch != NULL);
- g_assert (info != NULL);
+ object_class->dispose = gsk_gl_command_queue_dispose;
+}
- if (batch->n_uniforms == 0)
- {
- u = &batch->uniform;
- batch->n_uniforms = 1;
- }
- else if (batch->n_uniforms == 1)
- {
- u = g_new (GskGLCommandUniform, 2);
- u[0] = batch->uniform;
- batch->uniforms = u;
- batch->n_uniforms = 2;
- u = &u[1];
- }
- else
- {
- u = g_realloc_n (batch->uniforms, batch->n_uniforms+1, sizeof (GskGLCommandUniform));
- batch->uniforms = u;
- u = &u[batch->n_uniforms];
- batch->n_uniforms++;
- }
+static void
+gsk_gl_command_queue_init (GskGLCommandQueue *self)
+{
+ self->max_texture_size = -1;
- u->format = info->format;
- u->flags = info->flags;
- u->array_count = info->array_count;
- u->location = location;
- u->offset = info->offset;
+ self->batches = g_array_new (FALSE, TRUE, sizeof (GskGLCommandBatch));
+ self->batch_draws = g_array_new (FALSE, FALSE, sizeof (GskGLCommandDraw));
+ self->batch_binds = g_array_new (FALSE, FALSE, sizeof (GskGLCommandBind));
+ self->batch_uniforms = g_array_new (FALSE, FALSE, sizeof (GskGLCommandUniform));
+ self->attachments = gsk_gl_attachment_state_new ();
+ self->vertices = gsk_gl_buffer_new (GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
+ self->uniforms = gsk_gl_uniform_state_new ();
+ self->saved_state = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_attachment_state_free);
+ self->autorelease_textures = g_array_new (FALSE, FALSE, sizeof (GLuint));
+ self->autorelease_framebuffers = g_array_new (FALSE, FALSE, sizeof (GLuint));
+ self->debug_groups = g_string_chunk_new (4096);
}
-static gboolean
-gsk_gl_command_batch_mergeable (GskGLCommandBatch *batch,
- GskGLCommandBatch *other)
+GskGLCommandQueue *
+gsk_gl_command_queue_new (GdkGLContext *context)
{
- g_assert (batch != NULL);
- g_assert (other != NULL);
- g_assert (batch != other);
+ GskGLCommandQueue *self;
- if (batch->program != other->program)
- return FALSE;
+ g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
- return FALSE;
+ self = g_object_new (GSK_TYPE_GL_COMMAND_QUEUE, NULL);
+ self->context = g_object_ref (context);
+
+ return g_steal_pointer (&self);
}
-static void
-gsk_gl_command_queue_try_merge (GskGLCommandQueue *self,
- GskGLCommandBatch *batch)
+void
+gsk_gl_command_queue_begin_draw (GskGLCommandQueue *self,
+ guint program)
{
- guint count = 0;
-
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
- g_assert (batch != NULL);
- g_assert (batch->program != 0);
+ GskGLCommandBatch *batch;
- /* We probably only want to look at the past couple by program to
- * avoid pathological situations. In most cases, they will naturally
- * come within the last few submissions.
- */
+ g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (self->in_draw == FALSE);
- for (const GList *iter = batch->program_link.prev;
- iter != NULL && count < MAX_MERGE_DISTANCE;
- iter = iter->prev, count++)
- {
- GskGLCommandBatch *predecessor = iter->data;
+ g_array_set_size (self->batches, self->batches->len + 1);
- if (gsk_gl_command_batch_mergeable (predecessor, batch))
- {
- /* We need to check all the intermediates for overdrawing. */
- }
- }
+ batch = &g_array_index (self->batches, GskGLCommandBatch, self->batches->len - 1);
+ batch->kind = GSK_GL_COMMAND_KIND_DRAW;
+ batch->program = program;
+ batch->next_batch_index = -1;
+ batch->draw.framebuffer = 0;
+ batch->draw.uniform_count = 0;
+ batch->draw.uniform_offset = self->batch_uniforms->len;
+ batch->draw.bind_count = 0;
+ batch->draw.bind_offset = self->batch_binds->len;
+ batch->draw.vbo_count = 0;
+ batch->draw.vbo_offset = gsk_gl_buffer_get_offset (self->vertices);
}
-static inline GskGLCommandBatch *
-gsk_gl_command_queue_get_batch (GskGLCommandQueue *self)
+static void
+gsk_gl_command_queue_uniform_snapshot_cb (const GskGLUniformInfo *info,
+ guint location,
+ gpointer user_data)
{
+ GskGLCommandQueue *self = user_data;
+ GskGLCommandUniform uniform;
+
+ g_assert (info != NULL);
g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
- return self->all_batches.tail->data;
+ uniform.location = location;
+ uniform.info = *info;
+
+ g_array_append_val (self->batch_uniforms, uniform);
}
-static GskGLCommandBatch *
-gsk_gl_command_queue_advance (GskGLCommandQueue *self,
- guint new_program)
+void
+gsk_gl_command_queue_end_draw (GskGLCommandQueue *self)
{
- GskGLCommandBatch *last_batch = NULL;
GskGLCommandBatch *batch;
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-
- if (self->all_batches.length > 0)
+ g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (self->batches->len > 0);
+ g_return_if_fail (self->in_draw == TRUE);
+
+ batch = &g_array_index (self->batches, GskGLCommandBatch, self->batches->len - 1);
+
+ g_assert (batch->kind == GSK_GL_COMMAND_KIND_DRAW);
+
+ /* Track the destination framebuffer in case it changed */
+ batch->draw.framebuffer = self->attachments->fbo.id;
+ self->attachments->fbo.changed = FALSE;
+
+ /* Track the list of uniforms that changed */
+ batch->draw.uniform_offset = self->batch_uniforms->len;
+ gsk_gl_uniform_state_snapshot (self->uniforms,
+ batch->program,
+ gsk_gl_command_queue_uniform_snapshot_cb,
+ self);
+ batch->draw.uniform_count = self->batch_uniforms->len - batch->draw.uniform_offset;
+
+ /* Track the bind attachments that changed */
+ batch->draw.bind_offset = self->batch_binds->len;
+ batch->draw.bind_count = 0;
+ for (guint i = 0; i < G_N_ELEMENTS (self->attachments->textures); i++)
{
- last_batch = self->all_batches.tail->data;
-
- gsk_gl_uniform_state_snapshot (self->uniforms,
- last_batch->program,
- gsk_gl_command_batch_uniform_cb,
- last_batch);
- }
+ GskGLBindTexture *texture = &self->attachments->textures[i];
- batch = gsk_gl_command_queue_alloc_batch (self);
+ if (texture->changed)
+ {
+ GskGLCommandBind bind;
- if G_LIKELY (last_batch != NULL)
- {
- batch->program = new_program ? new_program : last_batch->program;
- batch->program_changed = batch->program != last_batch->program;
- batch->framebuffer = last_batch->framebuffer;
- batch->framebuffer.changed = FALSE;
- }
- else
- {
- batch->program = new_program;
- batch->program_changed = TRUE;
- batch->framebuffer.id = 0;
- batch->framebuffer.changed = FALSE;
- }
+ texture->changed = FALSE;
- g_queue_push_tail_link (&self->all_batches, &batch->all_link);
+ bind.texture = texture->texture;
+ bind.id = texture->id;
- if (batch->program)
- {
- GQueue *q;
+ g_array_append_val (self->batch_binds, bind);
- if (self->program_batches->len <= batch->program)
- g_array_set_size (self->program_batches, batch->program + 1);
+ batch->draw.bind_count++;
+ }
+ }
- q = &g_array_index (self->program_batches, GQueue, batch->program);
- g_queue_push_tail_link (q, &batch->program_link);
+ if (self->tail_batch_index > -1)
+ {
+ GskGLCommandBatch *last_batch = &g_array_index (self->batches, GskGLCommandBatch,
self->tail_batch_index);
+ last_batch->next_batch_index = self->batches->len - 1;
}
- if (last_batch != NULL)
- gsk_gl_command_queue_try_merge (self, last_batch);
+ self->tail_batch_index = self->batches->len - 1;
- return g_steal_pointer (&batch);
+ self->in_draw = FALSE;
}
-static inline gboolean
-gsk_gl_command_queue_batch_is_complete (GskGLCommandQueue *self)
+GskGLDrawVertex *
+gsk_gl_command_queue_add_vertices (GskGLCommandQueue *self,
+ const GskGLDrawVertex vertices[GSK_GL_N_VERTICES])
{
- GskGLCommandBatch *batch = gsk_gl_command_queue_get_batch (self);
+ GskGLCommandBatch *batch;
+ GskGLDrawVertex *dest;
+ guint offset;
- return batch->is_clear || (batch->program && batch->n_draws > 0);
-}
+ g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), NULL);
+ g_return_val_if_fail (self->in_draw == TRUE, NULL);
-static void
-gsk_gl_command_queue_dispose (GObject *object)
-{
- GskGLCommandQueue *self = (GskGLCommandQueue *)object;
+ batch = &g_array_index (self->batches, GskGLCommandBatch, self->batches->len - 1);
+ batch->draw.vbo_count += GSK_GL_N_VERTICES;
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
+ dest = gsk_gl_buffer_advance (self->vertices, GSK_GL_N_VERTICES, &offset);
- while (self->all_batches.length > 0)
+ if (vertices != NULL)
{
- GskGLCommandBatch *batch = self->all_batches.head->data;
-
- gsk_gl_command_queue_release_batch (self, batch);
+ memcpy (dest, vertices, sizeof (GskGLDrawVertex) * GSK_GL_N_VERTICES);
+ return NULL;
}
- while (self->unused_batches.length > 0)
- {
- GskGLCommandBatch *batch = self->unused_batches.head->data;
+ return dest;
+}
- g_queue_unlink (&self->unused_batches, self->unused_batches.head->data);
- g_slice_free (GskGLCommandBatch, batch);
- }
+void
+gsk_gl_command_queue_clear (GskGLCommandQueue *self,
+ guint clear_bits)
+{
+ GskGLCommandBatch *batch;
-#ifndef G_DISABLE_DEBUG
- g_assert (self->unused_batches.length == 0);
- g_assert (self->all_batches.length == 0);
+ g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (self->in_draw == FALSE);
+ g_return_if_fail (self->batches->len < G_MAXINT);
- for (guint i = 0; i < self->program_batches->len; i++)
- {
- GQueue *q = &g_array_index (self->program_batches, GQueue, i);
- g_assert (q->length == 0);
- }
-#endif
+ if (clear_bits == 0)
+ clear_bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- g_clear_pointer (&self->saved_state, g_ptr_array_unref);
- g_clear_pointer (&self->attachments, gsk_gl_attachment_state_free);
- g_clear_object (&self->context);
- g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_free);
- g_clear_pointer (&self->vertices, gsk_gl_buffer_free);
- g_clear_pointer (&self->program_batches, g_array_unref);
- g_clear_pointer (&self->autorelease_framebuffers, g_array_unref);
- g_clear_pointer (&self->autorelease_textures, g_array_unref);
-
- G_OBJECT_CLASS (gsk_gl_command_queue_parent_class)->dispose (object);
-}
+ g_array_set_size (self->batches, self->batches->len + 1);
-static void
-gsk_gl_command_queue_class_init (GskGLCommandQueueClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ batch = &g_array_index (self->batches, GskGLCommandBatch, self->batches->len - 1);
+ batch->kind = GSK_GL_COMMAND_KIND_CLEAR;
+ batch->clear.bits = clear_bits;
+ batch->clear.framebuffer = self->attachments->fbo.id;
+ batch->next_batch_index = -1;
+ batch->program = 0;
- object_class->dispose = gsk_gl_command_queue_dispose;
+ self->attachments->fbo.changed = FALSE;
}
-static void
-gsk_gl_command_queue_init (GskGLCommandQueue *self)
+void
+gsk_gl_command_queue_push_debug_group (GskGLCommandQueue *self,
+ const char *debug_group)
{
- self->max_texture_size = -1;
+ GskGLCommandBatch *batch;
- self->attachments = gsk_gl_attachment_state_new ();
- self->vertices = gsk_gl_buffer_new (GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
- self->uniforms = gsk_gl_uniform_state_new ();
- self->program_batches = g_array_new (FALSE, TRUE, sizeof (GQueue));
- self->saved_state = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_attachment_state_free);
- self->autorelease_textures = g_array_new (FALSE, FALSE, sizeof (GLuint));
- self->autorelease_framebuffers = g_array_new (FALSE, FALSE, sizeof (GLuint));
+ g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (self->in_draw == FALSE);
+ g_return_if_fail (self->batches->len < G_MAXINT);
- gsk_gl_command_queue_advance (self, 0);
+ g_array_set_size (self->batches, self->batches->len + 1);
+
+ batch = &g_array_index (self->batches, GskGLCommandBatch, self->batches->len - 1);
+ batch->kind = GSK_GL_COMMAND_KIND_PUSH_DEBUG_GROUP;
+ batch->debug_group = g_string_chunk_insert (self->debug_groups, debug_group);
+ batch->next_batch_index = -1;
+ batch->program = 0;
}
-GskGLCommandQueue *
-gsk_gl_command_queue_new (GdkGLContext *context)
+void
+gsk_gl_command_queue_pop_debug_group (GskGLCommandQueue *self)
{
- GskGLCommandQueue *self;
-
- g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+ GskGLCommandBatch *batch;
- self = g_object_new (GSK_TYPE_GL_COMMAND_QUEUE, NULL);
- self->context = g_object_ref (context);
+ g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (self->in_draw == FALSE);
+ g_return_if_fail (self->batches->len < G_MAXINT);
- if (self->max_texture_size < 0)
- {
- gdk_gl_context_make_current (context);
- glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint *)&self->max_texture_size);
- GSK_NOTE (OPENGL, g_message ("GL max texture size: %d", self->max_texture_size));
- }
+ g_array_set_size (self->batches, self->batches->len + 1);
- return g_steal_pointer (&self);
+ batch = &g_array_index (self->batches, GskGLCommandBatch, self->batches->len - 1);
+ batch->kind = GSK_GL_COMMAND_KIND_POP_DEBUG_GROUP;
+ batch->debug_group = NULL;
+ batch->next_batch_index = -1;
+ batch->program = 0;
}
GdkGLContext *
@@ -691,30 +522,6 @@ gsk_gl_command_queue_make_current (GskGLCommandQueue *self)
gdk_gl_context_make_current (self->context);
}
-void
-gsk_gl_command_queue_use_program (GskGLCommandQueue *self,
- guint program)
-{
- GskGLCommandBatch *batch;
-
- g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
-
- batch = gsk_gl_command_queue_get_batch (self);
-
- if (batch->program == program || program == 0)
- return;
-
- if (batch->n_draws == 0)
- {
- batch->program = program;
- return;
- }
-
- batch = gsk_gl_command_queue_advance (self, program);
- batch->program = program;
- batch->program_changed = TRUE;
-}
-
void
gsk_gl_command_queue_delete_program (GskGLCommandQueue *self,
guint program)
@@ -725,30 +532,6 @@ gsk_gl_command_queue_delete_program (GskGLCommandQueue *self,
gsk_gl_uniform_state_clear_program (self->uniforms, program);
}
-GskGLDrawVertex *
-gsk_gl_command_queue_draw (GskGLCommandQueue *self,
- const GskGLDrawVertex vertices[6])
-{
- GskGLCommandBatch *batch;
- GskGLDrawVertex *dest;
- guint offset;
-
- g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), NULL);
-
- batch = gsk_gl_command_queue_get_batch (self);
- dest = gsk_gl_buffer_advance (self->vertices, 6, &offset);
-
- gsk_gl_command_batch_draw (batch, offset, 6);
-
- if (vertices != NULL)
- {
- memcpy (dest, vertices, sizeof (GskGLDrawVertex) * 6);
- return NULL;
- }
-
- return dest;
-}
-
void
gsk_gl_command_queue_set_uniform1i (GskGLCommandQueue *self,
guint program,
@@ -982,21 +765,15 @@ gsk_gl_command_queue_set_uniform_rounded_rect (GskGLCommandQueue *self,
void
gsk_gl_command_queue_execute (GskGLCommandQueue *self)
{
- GskGLCommandBatch *last_batch;
GLuint vao_id;
+ int next_batch_index;
g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (self->in_draw == FALSE);
- if (self->all_batches.length == 0)
+ if (self->batches->len == 0)
return;
- /* First advance the queue to ensure that we have stashed all the
- * state we need and possibly merged the final batch.
- */
- last_batch = gsk_gl_command_queue_get_batch (self);
- if (last_batch->program != 0 && last_batch->n_draws > 0)
- gsk_gl_command_queue_advance (self, 0);
-
gsk_gl_command_queue_make_current (self);
glEnable (GL_DEPTH_TEST);
@@ -1024,12 +801,34 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self)
sizeof (GskGLDrawVertex),
(void *) G_STRUCT_OFFSET (GskGLDrawVertex, uv));
- for (const GList *iter = self->all_batches.head; iter != NULL; iter = iter->next)
+ next_batch_index = 0;
+
+ while (next_batch_index >= 0)
{
- GskGLCommandBatch *batch = self->all_batches.head->data;
+ const GskGLCommandBatch *batch = &g_array_index (self->batches, GskGLCommandBatch, next_batch_index);
+
+ switch (batch->kind)
+ {
+ case GSK_GL_COMMAND_KIND_CLEAR:
+ glClear (batch->clear.bits);
+ break;
- if (batch->n_draws > 0)
- gsk_gl_command_batch_execute (batch, self->uniforms);
+ case GSK_GL_COMMAND_KIND_PUSH_DEBUG_GROUP:
+ gdk_gl_context_push_debug_group (self->context, batch->debug_group);
+ break;
+
+ case GSK_GL_COMMAND_KIND_POP_DEBUG_GROUP:
+ gdk_gl_context_pop_debug_group (self->context);
+ break;
+
+ case GSK_GL_COMMAND_KIND_DRAW:
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ next_batch_index = batch->next_batch_index;
}
glDeleteVertexArrays (1, &vao_id);
@@ -1040,6 +839,8 @@ gsk_gl_command_queue_begin_frame (GskGLCommandQueue *self)
{
g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ self->tail_batch_index = -1;
+
glBindFramebuffer (GL_FRAMEBUFFER, 0);
for (guint i = 0; i < 8; i++)
@@ -1069,14 +870,10 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
{
g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
- while (self->all_batches.length > 0)
- {
- GskGLCommandBatch *batch = self->all_batches.head->data;
- gsk_gl_command_queue_release_batch (self, batch);
- }
-
gsk_gl_uniform_state_end_frame (self->uniforms);
+ self->batches->len = 0;
+
/* Release autoreleased framebuffers */
if (self->autorelease_framebuffers->len > 0)
glDeleteFramebuffers (self->autorelease_framebuffers->len,
@@ -1087,100 +884,17 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
glDeleteTextures (self->autorelease_textures->len,
(GLuint *)(gpointer)self->autorelease_textures->data);
- /* Allocate first batch for next round so we never have an empty
- * GskGLCommandQueue.all_batches array to check for elsewhere.
- */
- gsk_gl_command_queue_advance (self, 0);
-}
-
-void
-gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self,
- guint framebuffer)
-{
- g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
-
- gsk_gl_attachment_state_bind_framebuffer (self->attachments, framebuffer);
+ g_string_chunk_clear (self->debug_groups);
}
void
-gsk_gl_command_queue_set_viewport (GskGLCommandQueue *self,
- const graphene_rect_t *viewport)
+gsk_gl_command_queue_change_viewport (GskGLCommandQueue *self,
+ const graphene_rect_t *viewport)
{
g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_if_fail (viewport != NULL);
- /* TODO: Set viewport as part of batch */
-}
-
-static void
-gsk_gl_command_queue_save (GskGLCommandQueue *self)
-{
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-
- g_ptr_array_add (self->saved_state,
- gsk_gl_attachment_state_save (self->attachments));
-}
-
-static void
-gsk_gl_command_queue_restore (GskGLCommandQueue *self)
-{
- GskGLAttachmentState *saved;
-
- g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
- g_assert (self->saved_state->len > 0);
-
- saved = g_ptr_array_steal_index (self->saved_state,
- self->saved_state->len - 1);
-
- gsk_gl_attachment_state_restore (saved);
-}
-
-int
-gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
- int width,
- int height,
- int min_filter,
- int mag_filter)
-{
- GLuint texture_id;
-
- g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), -1);
-
- if (width > self->max_texture_size || height > self->max_texture_size)
- return -1;
-
- gsk_gl_command_queue_save (self);
- gsk_gl_command_queue_make_current (self);
-
- glGenTextures (1, &texture_id);
-
- glActiveTexture (GL_TEXTURE0);
- glBindTexture (GL_TEXTURE_2D, texture_id);
-
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- if (gdk_gl_context_get_use_es (self->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);
-
- gsk_gl_command_queue_restore (self);
-
- return (int)texture_id;
-}
-
-guint
-gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self)
-{
- GLuint fbo_id;
-
- g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), -1);
-
- gsk_gl_command_queue_make_current (self);
- glGenFramebuffers (1, &fbo_id);
- return fbo_id;
+
}
gboolean
@@ -1245,20 +959,62 @@ gsk_gl_command_queue_autorelease_texture (GskGLCommandQueue *self,
g_array_append_val (self->autorelease_textures, texture_id);
}
-void
-gsk_gl_command_queue_clear (GskGLCommandQueue *self)
+int
+gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
+ int width,
+ int height,
+ int min_filter,
+ int mag_filter)
{
- GskGLCommandBatch *batch;
+ GLuint texture_id;
- g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
+ g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), -1);
- batch = gsk_gl_command_queue_get_batch (self);
+ if (width > self->max_texture_size || height > self->max_texture_size)
+ return -1;
- if (batch->is_clear)
- return;
+ gsk_gl_command_queue_save (self);
+ gsk_gl_command_queue_make_current (self);
+
+ glGenTextures (1, &texture_id);
+
+ glActiveTexture (GL_TEXTURE0);
+ glBindTexture (GL_TEXTURE_2D, texture_id);
+
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ if (gdk_gl_context_get_use_es (self->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);
+
+ gsk_gl_command_queue_restore (self);
+
+ return (int)texture_id;
+}
+
+guint
+gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self)
+{
+ GLuint fbo_id;
+
+ g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), -1);
+
+ gsk_gl_command_queue_make_current (self);
+
+ glGenFramebuffers (1, &fbo_id);
+
+ return fbo_id;
+}
- if (gsk_gl_command_queue_batch_is_complete (self))
- batch = gsk_gl_command_queue_advance (self, 0);
+void
+gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self,
+ guint framebuffer)
+{
+ g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (self));
- batch->is_clear = TRUE;
+ gsk_gl_attachment_state_bind_framebuffer (self->attachments, framebuffer);
}
diff --git a/gsk/next/gskglcommandqueueprivate.h b/gsk/next/gskglcommandqueueprivate.h
index 8759041a90..1a5ccae8e2 100644
--- a/gsk/next/gskglcommandqueueprivate.h
+++ b/gsk/next/gskglcommandqueueprivate.h
@@ -35,13 +35,8 @@ void gsk_gl_command_queue_make_current (GskGLCommandQu
void gsk_gl_command_queue_begin_frame (GskGLCommandQueue *self);
void gsk_gl_command_queue_end_frame (GskGLCommandQueue *self);
void gsk_gl_command_queue_execute (GskGLCommandQueue *self);
-void gsk_gl_command_queue_set_viewport (GskGLCommandQueue *self,
+void gsk_gl_command_queue_change_viewport (GskGLCommandQueue *self,
const graphene_rect_t *viewport);
-GdkTexture *gsk_gl_command_queue_download (GskGLCommandQueue *self,
- GError **error);
-GdkMemoryTexture *gsk_gl_command_queue_download_texture (GskGLCommandQueue *self,
- guint texture_id,
- GError **error);
guint gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture,
GError **error);
@@ -58,11 +53,10 @@ gboolean gsk_gl_command_queue_create_render_target (GskGLCommandQu
guint *out_texture_id);
void gsk_gl_command_queue_delete_program (GskGLCommandQueue *self,
guint program_id);
-void gsk_gl_command_queue_use_program (GskGLCommandQueue *self,
- guint program_id);
void gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self,
guint framebuffer);
-void gsk_gl_command_queue_clear (GskGLCommandQueue *self);
+void gsk_gl_command_queue_clear (GskGLCommandQueue *self,
+ guint clear_bits);
void gsk_gl_command_queue_set_uniform1i (GskGLCommandQueue *self,
guint program,
guint location,
@@ -140,12 +134,18 @@ void gsk_gl_command_queue_set_uniform_rounded_rect (GskGLCommandQu
guint program,
guint location,
const GskRoundedRect *rounded_rect);
+void gsk_gl_command_queue_push_debug_group (GskGLCommandQueue *self,
+ const char *message);
+void gsk_gl_command_queue_pop_debug_group (GskGLCommandQueue *self);
void gsk_gl_command_queue_autorelease_framebuffer (GskGLCommandQueue *self,
guint framebuffer_id);
void gsk_gl_command_queue_autorelease_texture (GskGLCommandQueue *self,
guint texture_id);
-GskGLDrawVertex *gsk_gl_command_queue_draw (GskGLCommandQueue *self,
- const GskGLDrawVertex vertices[6]);
+void gsk_gl_command_queue_begin_draw (GskGLCommandQueue *self,
+ guint program);
+void gsk_gl_command_queue_end_draw (GskGLCommandQueue *self);
+GskGLDrawVertex *gsk_gl_command_queue_add_vertices (GskGLCommandQueue *self,
+ const GskGLDrawVertex
vertices[GSK_GL_N_VERTICES]);
G_END_DECLS
diff --git a/gsk/next/gskglprogram.c b/gsk/next/gskglprogram.c
index 2c13bb0b65..e6280c6574 100644
--- a/gsk/next/gskglprogram.c
+++ b/gsk/next/gskglprogram.c
@@ -84,35 +84,6 @@ gsk_gl_program_init (GskGLProgram *self)
self->uniform_locations = g_array_new (FALSE, TRUE, sizeof (GLint));
}
-/**
- * gsk_gl_program_use:
- * @self: a #GskGLProgram
- *
- * Sets @self as the current program.
- */
-void
-gsk_gl_program_use (GskGLProgram *self)
-{
- g_return_if_fail (GSK_IS_GL_PROGRAM (self));
- g_return_if_fail (self->command_queue != NULL);
-
- gsk_gl_command_queue_use_program (self->command_queue, self->id);
-}
-
-/**
- * gsk_gl_program_unuse:
- * @self: a #GskGLProgram
- *
- * Changes the program to 0 and cleans up any necessary state.
- */
-void
-gsk_gl_program_unuse (GskGLProgram *self)
-{
- g_return_if_fail (GSK_IS_GL_PROGRAM (self));
-
- gsk_gl_command_queue_use_program (self->command_queue, 0);
-}
-
/**
* gsk_gl_program_add_uniform:
* @self: a #GskGLProgram
@@ -351,11 +322,27 @@ gsk_gl_program_set_uniform_rounded_rect (GskGLProgram *self,
rounded_rect);
}
+void
+gsk_gl_program_begin_draw (GskGLProgram *self)
+{
+ g_assert (GSK_IS_GL_PROGRAM (self));
+
+ return gsk_gl_command_queue_begin_draw (self->command_queue, self->id);
+}
+
+void
+gsk_gl_program_end_draw (GskGLProgram *self)
+{
+ g_assert (GSK_IS_GL_PROGRAM (self));
+
+ return gsk_gl_command_queue_end_draw (self->command_queue);
+}
+
GskGLDrawVertex *
-gsk_gl_program_draw (GskGLProgram *self,
- const GskGLDrawVertex vertices[6])
+gsk_gl_program_add_vertices (GskGLProgram *self,
+ const GskGLDrawVertex vertices[GSK_GL_N_VERTICES])
{
g_assert (GSK_IS_GL_PROGRAM (self));
- return gsk_gl_command_queue_draw (self->command_queue, vertices);
+ return gsk_gl_command_queue_add_vertices (self->command_queue, vertices);
}
diff --git a/gsk/next/gskglprogramprivate.h b/gsk/next/gskglprogramprivate.h
index e223a5263a..42c41e2850 100644
--- a/gsk/next/gskglprogramprivate.h
+++ b/gsk/next/gskglprogramprivate.h
@@ -29,64 +29,64 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GskGLProgram, gsk_gl_program, GSK, GL_PROGRAM, GObject)
-GskGLProgram *gsk_gl_program_new (GskGLCommandQueue *command_queue,
- const char *name,
- int program_id);
-gboolean gsk_gl_program_add_uniform (GskGLProgram *self,
- const char *name,
- guint key);
-void gsk_gl_program_use (GskGLProgram *self);
-void gsk_gl_program_unuse (GskGLProgram *self);
-void gsk_gl_program_delete (GskGLProgram *self);
-void gsk_gl_program_set_uniform1i (GskGLProgram *self,
- guint key,
- int value0);
-void gsk_gl_program_set_uniform2i (GskGLProgram *self,
- guint key,
- int value0,
- int value1);
-void gsk_gl_program_set_uniform3i (GskGLProgram *self,
- guint key,
- int value0,
- int value1,
- int value2);
-void gsk_gl_program_set_uniform4i (GskGLProgram *self,
- guint key,
- int value0,
- int value1,
- int value2,
- int value3);
-void gsk_gl_program_set_uniform1f (GskGLProgram *self,
- guint key,
- float value0);
-void gsk_gl_program_set_uniform2f (GskGLProgram *self,
- guint key,
- float value0,
- float value1);
-void gsk_gl_program_set_uniform3f (GskGLProgram *self,
- guint key,
- float value0,
- float value1,
- float value2);
-void gsk_gl_program_set_uniform4f (GskGLProgram *self,
- guint key,
- float value0,
- float value1,
- float value2,
- float value3);
-void gsk_gl_program_set_uniform_color (GskGLProgram *self,
- guint key,
- const GdkRGBA *color);
-void gsk_gl_program_set_uniform_texture (GskGLProgram *self,
- guint key,
- GLenum texture_target,
- GLenum texture_slot,
- guint texture_id);
-void gsk_gl_program_set_uniform_rounded_rect (GskGLProgram *self,
- guint key,
- const GskRoundedRect *rounded_rect);
-GskGLDrawVertex *gsk_gl_program_draw (GskGLProgram *self,
- const GskGLDrawVertex vertices[6]);
+GskGLProgram *gsk_gl_program_new (GskGLCommandQueue *command_queue,
+ const char *name,
+ int program_id);
+gboolean gsk_gl_program_add_uniform (GskGLProgram *self,
+ const char *name,
+ guint key);
+void gsk_gl_program_delete (GskGLProgram *self);
+void gsk_gl_program_set_uniform1i (GskGLProgram *self,
+ guint key,
+ int value0);
+void gsk_gl_program_set_uniform2i (GskGLProgram *self,
+ guint key,
+ int value0,
+ int value1);
+void gsk_gl_program_set_uniform3i (GskGLProgram *self,
+ guint key,
+ int value0,
+ int value1,
+ int value2);
+void gsk_gl_program_set_uniform4i (GskGLProgram *self,
+ guint key,
+ int value0,
+ int value1,
+ int value2,
+ int value3);
+void gsk_gl_program_set_uniform1f (GskGLProgram *self,
+ guint key,
+ float value0);
+void gsk_gl_program_set_uniform2f (GskGLProgram *self,
+ guint key,
+ float value0,
+ float value1);
+void gsk_gl_program_set_uniform3f (GskGLProgram *self,
+ guint key,
+ float value0,
+ float value1,
+ float value2);
+void gsk_gl_program_set_uniform4f (GskGLProgram *self,
+ guint key,
+ float value0,
+ float value1,
+ float value2,
+ float value3);
+void gsk_gl_program_set_uniform_color (GskGLProgram *self,
+ guint key,
+ const GdkRGBA *color);
+void gsk_gl_program_set_uniform_texture (GskGLProgram *self,
+ guint key,
+ GLenum texture_target,
+ GLenum texture_slot,
+ guint texture_id);
+void gsk_gl_program_set_uniform_rounded_rect (GskGLProgram *self,
+ guint key,
+ const GskRoundedRect *rounded_rect);
+void gsk_gl_program_begin_draw (GskGLProgram *self);
+void gsk_gl_program_end_draw (GskGLProgram *self);
+GskGLDrawVertex *gsk_gl_program_add_vertices (GskGLProgram *self,
+ const GskGLDrawVertex
vertices[GSK_GL_N_VERTICES]);
G_END_DECLS
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index 021865dc93..9694be4538 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -38,6 +38,7 @@
struct _GskGLRenderJob
{
GskNextDriver *driver;
+ GskGLCommandQueue *command_queue;
cairo_region_t *region;
guint framebuffer;
graphene_rect_t viewport;
@@ -334,6 +335,7 @@ gsk_gl_render_job_new (GskNextDriver *driver,
job = g_slice_new0 (GskGLRenderJob);
job->driver = g_object_ref (driver);
+ job->command_queue = driver->command_queue;
job->clip = g_array_new (FALSE, FALSE, sizeof (GskGLRenderClip));
job->modelview = g_array_new (FALSE, FALSE, sizeof (GskGLRenderModelview));
job->framebuffer = framebuffer;
@@ -442,11 +444,74 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
{
g_assert (job != NULL);
g_assert (node != NULL);
+ g_assert (GSK_IS_NEXT_DRIVER (job->driver));
+ g_assert (GSK_IS_GL_COMMAND_QUEUE (job->command_queue));
if (node_is_invisible (node) ||
!gsk_gl_render_job_node_overlaps_clip (job, node))
return;
+ switch (gsk_render_node_get_node_type (node))
+ {
+ case GSK_CONTAINER_NODE:
+ {
+ guint i;
+ guint p;
+
+ for (i = 0, p = gsk_container_node_get_n_children (node);
+ i < p;
+ i ++)
+ {
+ GskRenderNode *child = gsk_container_node_get_child (node, i);
+ gsk_gl_render_job_visit_node (job, child);
+ }
+ }
+ break;
+
+ case GSK_DEBUG_NODE:
+ {
+ const char *message = gsk_debug_node_get_message (node);
+
+ if (message != NULL)
+ gsk_gl_command_queue_push_debug_group (job->command_queue, message);
+
+ gsk_gl_render_job_visit_node (job, gsk_debug_node_get_child (node));
+
+ if (message != NULL)
+ gsk_gl_command_queue_pop_debug_group (job->command_queue);
+ }
+ break;
+
+ case GSK_CAIRO_NODE:
+ case GSK_COLOR_NODE:
+ case GSK_LINEAR_GRADIENT_NODE:
+ case GSK_REPEATING_LINEAR_GRADIENT_NODE:
+ case GSK_RADIAL_GRADIENT_NODE:
+ case GSK_REPEATING_RADIAL_GRADIENT_NODE:
+ case GSK_CONIC_GRADIENT_NODE:
+ case GSK_BORDER_NODE:
+ case GSK_TEXTURE_NODE:
+ case GSK_INSET_SHADOW_NODE:
+ case GSK_OUTSET_SHADOW_NODE:
+ case GSK_TRANSFORM_NODE:
+ case GSK_OPACITY_NODE:
+ case GSK_COLOR_MATRIX_NODE:
+ case GSK_REPEAT_NODE:
+ case GSK_CLIP_NODE:
+ case GSK_ROUNDED_CLIP_NODE:
+ case GSK_SHADOW_NODE:
+ case GSK_BLEND_NODE:
+ case GSK_CROSS_FADE_NODE:
+ case GSK_TEXT_NODE:
+ case GSK_BLUR_NODE:
+ case GSK_GL_SHADER_NODE:
+ break;
+
+ case GSK_NOT_A_RENDER_NODE:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
}
@@ -455,7 +520,6 @@ void
gsk_gl_render_job_prepare (GskGLRenderJob *job,
GskRenderNode *root)
{
- GskGLCommandQueue *command_queue;
GdkGLContext *context;
g_return_if_fail (job != NULL);
@@ -463,13 +527,12 @@ gsk_gl_render_job_prepare (GskGLRenderJob *job,
g_return_if_fail (GSK_IS_NEXT_DRIVER (job->driver));
context = gsk_next_driver_get_context (job->driver);
- command_queue = job->driver->command_queue;
gdk_gl_context_push_debug_group (context, "Adding render ops");
- gsk_gl_command_queue_bind_framebuffer (command_queue, job->framebuffer);
- gsk_gl_command_queue_set_viewport (command_queue, &job->viewport);
- gsk_gl_command_queue_clear (command_queue);
+ gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
+ gsk_gl_command_queue_change_viewport (job->command_queue, &job->viewport);
+ gsk_gl_command_queue_clear (job->command_queue, 0);
gsk_gl_render_job_visit_node (job, root);
@@ -483,6 +546,6 @@ gsk_gl_render_job_render (GskGLRenderJob *job)
g_return_if_fail (GSK_IS_NEXT_DRIVER (job->driver));
gsk_next_driver_begin_frame (job->driver);
- gsk_gl_command_queue_execute (job->driver->command_queue);
+ gsk_gl_command_queue_execute (job->command_queue);
gsk_next_driver_end_frame (job->driver);
}
diff --git a/gsk/next/gskgltypes.h b/gsk/next/gskgltypes.h
index 232786438e..d4d48e74d4 100644
--- a/gsk/next/gskgltypes.h
+++ b/gsk/next/gskgltypes.h
@@ -28,6 +28,8 @@
G_BEGIN_DECLS
+#define GSK_GL_N_VERTICES 6
+
typedef struct _GskGLAttachmentState GskGLAttachmentState;
typedef struct _GskGLCommandQueue GskGLCommandQueue;
typedef struct _GskGLCompiler GskGLCompiler;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]