forked from AuroraMiddleware/gtk
bfe4aea981
Count how often we change programs during a frame.
361 lines
14 KiB
C
361 lines
14 KiB
C
/* gsknglcommandqueueprivate.h
|
|
*
|
|
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
*/
|
|
|
|
#ifndef __GSK_NGL_COMMAND_QUEUE_PRIVATE_H__
|
|
#define __GSK_NGL_COMMAND_QUEUE_PRIVATE_H__
|
|
|
|
#include <gsk/gskprofilerprivate.h>
|
|
|
|
#include "gskngltypesprivate.h"
|
|
#include "gsknglbufferprivate.h"
|
|
#include "gsknglattachmentstateprivate.h"
|
|
#include "gskngluniformstateprivate.h"
|
|
|
|
#include "inlinearray.h"
|
|
|
|
#include "../gl/gskglprofilerprivate.h"
|
|
|
|
G_BEGIN_DECLS
|
|
|
|
#define GSK_TYPE_GL_COMMAND_QUEUE (gsk_ngl_command_queue_get_type())
|
|
|
|
G_DECLARE_FINAL_TYPE (GskNglCommandQueue, gsk_ngl_command_queue, GSK, NGL_COMMAND_QUEUE, GObject)
|
|
|
|
typedef enum _GskNglCommandKind
|
|
{
|
|
/* The batch will perform a glClear() */
|
|
GSK_NGL_COMMAND_KIND_CLEAR,
|
|
|
|
/* The batch will perform a glDrawArrays() */
|
|
GSK_NGL_COMMAND_KIND_DRAW,
|
|
} GskNglCommandKind;
|
|
|
|
typedef struct _GskNglCommandBind
|
|
{
|
|
/* @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;
|
|
|
|
/* The identifier for the texture created with glGenTextures(). */
|
|
guint id : 27;
|
|
} GskNglCommandBind;
|
|
|
|
G_STATIC_ASSERT (sizeof (GskNglCommandBind) == 4);
|
|
|
|
typedef struct _GskNglCommandBatchAny
|
|
{
|
|
/* A GskNglCommandKind indicating what the batch will do */
|
|
guint kind : 8;
|
|
|
|
/* 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 GskNglCommandDraw so that we can use the extra
|
|
* bits here without making the structure larger.
|
|
*/
|
|
guint program : 24;
|
|
|
|
/* 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.
|
|
*/
|
|
gint16 next_batch_index;
|
|
|
|
/* Same but for reverse direction as we sort in reverse to get the
|
|
* batches ordered by framebuffer.
|
|
*/
|
|
gint16 prev_batch_index;
|
|
|
|
/* The viewport size of the batch. We check this as we process
|
|
* batches to determine if we need to resize the viewport.
|
|
*/
|
|
struct {
|
|
guint16 width;
|
|
guint16 height;
|
|
} viewport;
|
|
} GskNglCommandBatchAny;
|
|
|
|
G_STATIC_ASSERT (sizeof (GskNglCommandBatchAny) == 12);
|
|
|
|
typedef struct _GskNglCommandDraw
|
|
{
|
|
GskNglCommandBatchAny head;
|
|
|
|
/* 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;
|
|
|
|
/* 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 number of textures to bind, which is only guaranteed up to 16
|
|
* by the OpenGL specification to be conformant.
|
|
*/
|
|
guint bind_count : 5;
|
|
|
|
/* 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;
|
|
|
|
/* The offset within the VBO containing @vbo_count vertices to send with
|
|
* glDrawArrays().
|
|
*/
|
|
guint vbo_offset;
|
|
|
|
/* The offset within the array of uniform changes to be made containing
|
|
* @uniform_count #GskNglCommandUniform elements to apply.
|
|
*/
|
|
guint uniform_offset;
|
|
|
|
/* The offset within the array of bind changes to be made containing
|
|
* @bind_count #GskNglCommandBind elements to apply.
|
|
*/
|
|
guint bind_offset;
|
|
} GskNglCommandDraw;
|
|
|
|
G_STATIC_ASSERT (sizeof (GskNglCommandDraw) == 32);
|
|
|
|
typedef struct _GskNglCommandClear
|
|
{
|
|
GskNglCommandBatchAny any;
|
|
guint bits;
|
|
guint framebuffer;
|
|
} GskNglCommandClear;
|
|
|
|
G_STATIC_ASSERT (sizeof (GskNglCommandClear) == 20);
|
|
|
|
typedef struct _GskNglCommandUniform
|
|
{
|
|
GskNglUniformInfo info;
|
|
guint location;
|
|
} GskNglCommandUniform;
|
|
|
|
G_STATIC_ASSERT (sizeof (GskNglCommandUniform) == 8);
|
|
|
|
typedef union _GskNglCommandBatch
|
|
{
|
|
GskNglCommandBatchAny any;
|
|
GskNglCommandDraw draw;
|
|
GskNglCommandClear clear;
|
|
} GskNglCommandBatch;
|
|
|
|
G_STATIC_ASSERT (sizeof (GskNglCommandBatch) == 32);
|
|
|
|
DEFINE_INLINE_ARRAY (GskNglCommandBatches, gsk_ngl_command_batches, GskNglCommandBatch)
|
|
DEFINE_INLINE_ARRAY (GskNglCommandBinds, gsk_ngl_command_binds, GskNglCommandBind)
|
|
DEFINE_INLINE_ARRAY (GskNglCommandUniforms, gsk_ngl_command_uniforms, GskNglCommandUniform)
|
|
|
|
struct _GskNglCommandQueue
|
|
{
|
|
GObject parent_instance;
|
|
|
|
/* The GdkGLContext we make current before executing GL commands. */
|
|
GdkGLContext *context;
|
|
|
|
/* Array of GskNglCommandBatch 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.
|
|
*/
|
|
GskNglCommandBatches batches;
|
|
|
|
/* 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.
|
|
*/
|
|
GskNglBuffer vertices;
|
|
|
|
/* The GskNglAttachmentState contains information about our FBO and texture
|
|
* attachments as we process incoming operations. We snapshot them into
|
|
* various batches so that we can compare differences between merge
|
|
* candidates.
|
|
*/
|
|
GskNglAttachmentState *attachments;
|
|
|
|
/* The uniform state across all programs. We snapshot this into batches so
|
|
* that we can compare uniform state between batches to give us more
|
|
* chances at merging draw commands.
|
|
*/
|
|
GskNglUniformState *uniforms;
|
|
|
|
/* Current program if we are in a draw so that we can send commands
|
|
* to the uniform state as needed.
|
|
*/
|
|
GskNglUniformProgram *program_info;
|
|
|
|
/* The profiler instance to deliver timing/etc data */
|
|
GskProfiler *profiler;
|
|
GskGLProfiler *gl_profiler;
|
|
|
|
/* Array of GskNglCommandBind which denote what textures need to be attached
|
|
* to which slot. GskNglCommandDraw.bind_offset and bind_count reference this
|
|
* array to determine what to attach.
|
|
*/
|
|
GskNglCommandBinds batch_binds;
|
|
|
|
/* Array of GskNglCommandUniform denoting which uniforms must be updated
|
|
* before the glDrawArrays() may be called. These are referenced from the
|
|
* GskNglCommandDraw.uniform_offset and uniform_count fields.
|
|
*/
|
|
GskNglCommandUniforms batch_uniforms;
|
|
|
|
/* 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.
|
|
*/
|
|
gint16 tail_batch_index;
|
|
gint16 head_batch_index;
|
|
|
|
/* Max framebuffer we used, so we can sort items faster */
|
|
guint fbo_max;
|
|
|
|
/* Various GSK and GDK metric counter ids */
|
|
struct {
|
|
GQuark n_frames;
|
|
GQuark cpu_time;
|
|
GQuark gpu_time;
|
|
guint n_binds;
|
|
guint n_fbos;
|
|
guint n_uniforms;
|
|
guint n_uploads;
|
|
guint n_programs;
|
|
guint queue_depth;
|
|
} metrics;
|
|
|
|
/* Counter for uploads on the frame */
|
|
guint n_uploads;
|
|
|
|
/* If we're inside a begin/end_frame pair */
|
|
guint in_frame : 1;
|
|
|
|
/* If we're inside of a begin_draw()/end_draw() pair. */
|
|
guint in_draw : 1;
|
|
|
|
/* If we've warned about truncating batches */
|
|
guint have_truncated : 1;
|
|
};
|
|
|
|
GskNglCommandQueue *gsk_ngl_command_queue_new (GdkGLContext *context,
|
|
GskNglUniformState *uniforms);
|
|
void gsk_ngl_command_queue_set_profiler (GskNglCommandQueue *self,
|
|
GskProfiler *profiler);
|
|
GdkGLContext *gsk_ngl_command_queue_get_context (GskNglCommandQueue *self);
|
|
void gsk_ngl_command_queue_make_current (GskNglCommandQueue *self);
|
|
void gsk_ngl_command_queue_begin_frame (GskNglCommandQueue *self);
|
|
void gsk_ngl_command_queue_end_frame (GskNglCommandQueue *self);
|
|
void gsk_ngl_command_queue_execute (GskNglCommandQueue *self,
|
|
guint surface_height,
|
|
guint scale_factor,
|
|
const cairo_region_t *scissor);
|
|
int gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
|
|
GdkTexture *texture,
|
|
guint x_offset,
|
|
guint y_offset,
|
|
guint width,
|
|
guint height,
|
|
int min_filter,
|
|
int mag_filter);
|
|
int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
|
|
int width,
|
|
int height,
|
|
int min_filter,
|
|
int mag_filter);
|
|
guint gsk_ngl_command_queue_create_framebuffer (GskNglCommandQueue *self);
|
|
gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
|
|
int width,
|
|
int height,
|
|
int min_filter,
|
|
int mag_filter,
|
|
guint *out_fbo_id,
|
|
guint *out_texture_id);
|
|
void gsk_ngl_command_queue_delete_program (GskNglCommandQueue *self,
|
|
guint program_id);
|
|
void gsk_ngl_command_queue_clear (GskNglCommandQueue *self,
|
|
guint clear_bits,
|
|
const graphene_rect_t *viewport);
|
|
void gsk_ngl_command_queue_begin_draw (GskNglCommandQueue *self,
|
|
GskNglUniformProgram *program_info,
|
|
guint width,
|
|
guint height);
|
|
void gsk_ngl_command_queue_end_draw (GskNglCommandQueue *self);
|
|
void gsk_ngl_command_queue_split_draw (GskNglCommandQueue *self);
|
|
|
|
static inline GskNglCommandBatch *
|
|
gsk_ngl_command_queue_get_batch (GskNglCommandQueue *self)
|
|
{
|
|
return gsk_ngl_command_batches_tail (&self->batches);
|
|
}
|
|
|
|
static inline GskNglDrawVertex *
|
|
gsk_ngl_command_queue_add_vertices (GskNglCommandQueue *self)
|
|
{
|
|
gsk_ngl_command_queue_get_batch (self)->draw.vbo_count += GSK_NGL_N_VERTICES;
|
|
return gsk_ngl_buffer_advance (&self->vertices, GSK_NGL_N_VERTICES);
|
|
}
|
|
|
|
static inline GskNglDrawVertex *
|
|
gsk_ngl_command_queue_add_n_vertices (GskNglCommandQueue *self,
|
|
guint count)
|
|
{
|
|
/* This is a batch form of gsk_ngl_command_queue_add_vertices(). Note that
|
|
* it does *not* add the count to .draw.vbo_count as the caller is responsible
|
|
* for that.
|
|
*/
|
|
return gsk_ngl_buffer_advance (&self->vertices, GSK_NGL_N_VERTICES * count);
|
|
}
|
|
|
|
static inline void
|
|
gsk_ngl_command_queue_retract_n_vertices (GskNglCommandQueue *self,
|
|
guint count)
|
|
{
|
|
/* Like gsk_ngl_command_queue_add_n_vertices(), this does not tweak
|
|
* the draw vbo_count.
|
|
*/
|
|
gsk_ngl_buffer_retract (&self->vertices, GSK_NGL_N_VERTICES * count);
|
|
}
|
|
|
|
static inline guint
|
|
gsk_ngl_command_queue_bind_framebuffer (GskNglCommandQueue *self,
|
|
guint framebuffer)
|
|
{
|
|
guint ret = self->attachments->fbo.id;
|
|
gsk_ngl_attachment_state_bind_framebuffer (self->attachments, framebuffer);
|
|
return ret;
|
|
}
|
|
|
|
G_END_DECLS
|
|
|
|
#endif /* __GSK_NGL_COMMAND_QUEUE_PRIVATE_H__ */
|