diff --git a/gsk/gpu/gskglbuffer.c b/gsk/gpu/gskglbuffer.c index 461590dd4c..30ec65b32f 100644 --- a/gsk/gpu/gskglbuffer.c +++ b/gsk/gpu/gskglbuffer.c @@ -63,10 +63,16 @@ gsk_gl_buffer_bind (GskGLBuffer *self) } void -gsk_gl_buffer_bind_base (GskGLBuffer *self, - GLuint index) +gsk_gl_buffer_bind_range (GskGLBuffer *self, + GLuint index, + GLintptr offset, + GLsizeiptr size) { - glBindBufferBase (self->target, index, self->buffer_id); + glBindBufferRange (self->target, + index, + self->buffer_id, + offset, + size); } static void diff --git a/gsk/gpu/gskglbufferprivate.h b/gsk/gpu/gskglbufferprivate.h index 359cfa0615..269f9fa34a 100644 --- a/gsk/gpu/gskglbufferprivate.h +++ b/gsk/gpu/gskglbufferprivate.h @@ -20,8 +20,10 @@ GskGpuBuffer * gsk_gl_copied_buffer_new (GLenum gsize size); void gsk_gl_buffer_bind (GskGLBuffer *self); -void gsk_gl_buffer_bind_base (GskGLBuffer *self, - GLuint index); +void gsk_gl_buffer_bind_range (GskGLBuffer *self, + GLuint index, + GLintptr offset, + GLsizeiptr size); G_END_DECLS diff --git a/gsk/gpu/gskglframe.c b/gsk/gpu/gskglframe.c index 2cd2c71112..a85ae5a5e0 100644 --- a/gsk/gpu/gskglframe.c +++ b/gsk/gpu/gskglframe.c @@ -17,7 +17,6 @@ struct _GskGLFrame { GskGpuFrame parent_instance; - GLuint globals_buffer_id; guint next_texture_slot; GLsync sync; @@ -142,6 +141,17 @@ gsk_gl_frame_create_vertex_buffer (GskGpuFrame *frame, return gsk_gl_copied_buffer_new (GL_ARRAY_BUFFER, size); } +static GskGpuBuffer * +gsk_gl_frame_create_globals_buffer (GskGpuFrame *frame, + gsize size) +{ + if (gdk_gl_context_has_feature (GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame)), + GDK_GL_FEATURE_BUFFER_STORAGE)) + return gsk_gl_mapped_buffer_new (GL_UNIFORM_BUFFER, size); + else + return gsk_gl_copied_buffer_new (GL_UNIFORM_BUFFER, size); +} + static GskGpuBuffer * gsk_gl_frame_create_storage_buffer (GskGpuFrame *frame, gsize size) @@ -166,12 +176,14 @@ static void gsk_gl_frame_submit (GskGpuFrame *frame, GskRenderPassType pass_type, GskGpuBuffer *vertex_buffer, + GskGpuBuffer *globals_buffer, GskGpuOp *op) { GskGLFrame *self = GSK_GL_FRAME (frame); GskGLCommandState state = { /* rest is 0 */ - .current_samplers = { GSK_GPU_SAMPLER_N_SAMPLERS, GSK_GPU_SAMPLER_N_SAMPLERS } + .current_samplers = { GSK_GPU_SAMPLER_N_SAMPLERS, GSK_GPU_SAMPLER_N_SAMPLERS }, + .globals = globals_buffer, }; glEnable (GL_SCISSOR_TEST); @@ -182,12 +194,6 @@ gsk_gl_frame_submit (GskGpuFrame *frame, if (vertex_buffer) gsk_gl_buffer_bind (GSK_GL_BUFFER (vertex_buffer)); - gsk_gl_frame_bind_globals (self); - glBufferData (GL_UNIFORM_BUFFER, - sizeof (GskGpuGlobalsInstance), - NULL, - GL_STREAM_DRAW); - while (op) { op = gsk_gpu_op_gl_command (op, frame, &state); @@ -202,8 +208,6 @@ gsk_gl_frame_finalize (GObject *object) GskGLFrame *self = GSK_GL_FRAME (object); g_hash_table_unref (self->vaos); - if (self->globals_buffer_id != 0) - glDeleteBuffers (1, &self->globals_buffer_id); G_OBJECT_CLASS (gsk_gl_frame_parent_class)->finalize (object); } @@ -219,6 +223,7 @@ gsk_gl_frame_class_init (GskGLFrameClass *klass) gpu_frame_class->cleanup = gsk_gl_frame_cleanup; gpu_frame_class->upload_texture = gsk_gl_frame_upload_texture; gpu_frame_class->create_vertex_buffer = gsk_gl_frame_create_vertex_buffer; + gpu_frame_class->create_globals_buffer = gsk_gl_frame_create_globals_buffer; gpu_frame_class->create_storage_buffer = gsk_gl_frame_create_storage_buffer; gpu_frame_class->write_texture_vertex_data = gsk_gl_frame_write_texture_vertex_data; gpu_frame_class->submit = gsk_gl_frame_submit; @@ -266,12 +271,3 @@ gsk_gl_frame_use_program (GskGLFrame *self, g_hash_table_insert (self->vaos, (gpointer) op_class, GUINT_TO_POINTER (vao)); } -void -gsk_gl_frame_bind_globals (GskGLFrame *self) -{ - if (self->globals_buffer_id == 0) - glGenBuffers (1, &self->globals_buffer_id); - - glBindBufferBase (GL_UNIFORM_BUFFER, 0, self->globals_buffer_id); -} - diff --git a/gsk/gpu/gskglframeprivate.h b/gsk/gpu/gskglframeprivate.h index 1cbe7fb50b..8663707a2a 100644 --- a/gsk/gpu/gskglframeprivate.h +++ b/gsk/gpu/gskglframeprivate.h @@ -14,6 +14,4 @@ void gsk_gl_frame_use_program (GskGLFr GskGpuColorStates color_states, guint32 variation); -void gsk_gl_frame_bind_globals (GskGLFrame *self); - G_END_DECLS diff --git a/gsk/gpu/gskgpuframe.c b/gsk/gpu/gskgpuframe.c index 4d91ae700c..a19b1a0214 100644 --- a/gsk/gpu/gskgpuframe.c +++ b/gsk/gpu/gskgpuframe.c @@ -6,6 +6,7 @@ #include "gskgpucacheprivate.h" #include "gskgpudeviceprivate.h" #include "gskgpudownloadopprivate.h" +#include "gskgpuglobalsopprivate.h" #include "gskgpuimageprivate.h" #include "gskgpunodeprocessorprivate.h" #include "gskgpuopprivate.h" @@ -24,6 +25,8 @@ /* GL_MAX_UNIFORM_BLOCK_SIZE is at 16384 */ #define DEFAULT_STORAGE_BUFFER_SIZE 16 * 1024 * 64 +#define DEFAULT_N_GLOBALS (16384 / sizeof (GskGpuGlobalsInstance)) + #define GDK_ARRAY_NAME gsk_gpu_ops #define GDK_ARRAY_TYPE_NAME GskGpuOps #define GDK_ARRAY_ELEMENT_TYPE guchar @@ -47,6 +50,9 @@ struct _GskGpuFramePrivate GskGpuBuffer *vertex_buffer; guchar *vertex_buffer_data; gsize vertex_buffer_used; + GskGpuBuffer *globals_buffer; + GskGpuGlobalsInstance *globals_buffer_data; + gsize n_globals; GskGpuBuffer *storage_buffer; guchar *storage_buffer_data; gsize storage_buffer_used; @@ -66,6 +72,8 @@ gsk_gpu_frame_default_cleanup (GskGpuFrame *self) GskGpuOp *op; gsize i; + priv->n_globals = 0; + for (i = 0; i < gsk_gpu_ops_get_size (&priv->ops); i += op->op_class->size) { op = (GskGpuOp *) gsk_gpu_ops_index (&priv->ops, i); @@ -139,6 +147,7 @@ gsk_gpu_frame_finalize (GObject *object) gsk_gpu_ops_clear (&priv->ops); g_clear_object (&priv->vertex_buffer); + g_clear_object (&priv->globals_buffer); g_clear_object (&priv->storage_buffer); g_object_unref (priv->device); @@ -505,6 +514,13 @@ gsk_gpu_frame_create_vertex_buffer (GskGpuFrame *self, return GSK_GPU_FRAME_GET_CLASS (self)->create_vertex_buffer (self, size); } +static GskGpuBuffer * +gsk_gpu_frame_create_globals_buffer (GskGpuFrame *self, + gsize size) +{ + return GSK_GPU_FRAME_GET_CLASS (self)->create_globals_buffer (self, size); +} + static GskGpuBuffer * gsk_gpu_frame_create_storage_buffer (GskGpuFrame *self, gsize size) @@ -560,6 +576,48 @@ gsk_gpu_frame_reserve_vertex_data (GskGpuFrame *self, return size_needed - size; } +gsize +gsk_gpu_frame_add_globals (GskGpuFrame *self, + const GskGpuGlobalsInstance *globals) +{ + GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self); + gsize size_needed, result; + + if (priv->globals_buffer == NULL) + { + priv->globals_buffer = gsk_gpu_frame_create_globals_buffer (self, sizeof (GskGpuGlobalsInstance) * DEFAULT_N_GLOBALS); + if (priv->globals_buffer == NULL) + return 0; + } + if (priv->globals_buffer_data == NULL) + priv->globals_buffer_data = (GskGpuGlobalsInstance *) gsk_gpu_buffer_map (priv->globals_buffer); + + size_needed = sizeof (GskGpuGlobalsInstance) * (priv->n_globals + 1); + + if (gsk_gpu_buffer_get_size (priv->globals_buffer) < size_needed) + { + gsize old_size = gsk_gpu_buffer_get_size (priv->globals_buffer); + GskGpuBuffer *new_buffer = gsk_gpu_frame_create_globals_buffer (self, old_size * 2); + GskGpuGlobalsInstance *new_data = (GskGpuGlobalsInstance *) gsk_gpu_buffer_map (new_buffer); + + if (priv->globals_buffer_data) + { + memcpy (new_data, priv->globals_buffer_data, old_size); + gsk_gpu_buffer_unmap (priv->globals_buffer, old_size); + } + g_object_unref (priv->globals_buffer); + priv->globals_buffer = new_buffer; + priv->globals_buffer_data = new_data; + } + + result = priv->n_globals; + + priv->globals_buffer_data[priv->n_globals] = *globals; + priv->n_globals++; + + return result; +} + guchar * gsk_gpu_frame_get_vertex_data (GskGpuFrame *self, gsize offset) @@ -691,6 +749,12 @@ gsk_gpu_frame_submit (GskGpuFrame *self, priv->vertex_buffer_used = 0; } + if (priv->globals_buffer) + { + gsk_gpu_buffer_unmap (priv->globals_buffer, sizeof (GskGpuGlobalsInstance) * priv->n_globals); + priv->globals_buffer_data = NULL; + } + if (priv->storage_buffer_data) { gsk_gpu_buffer_unmap (priv->storage_buffer, priv->storage_buffer_used); @@ -701,6 +765,7 @@ gsk_gpu_frame_submit (GskGpuFrame *self, GSK_GPU_FRAME_GET_CLASS (self)->submit (self, pass_type, priv->vertex_buffer, + priv->globals_buffer, priv->first_op); } diff --git a/gsk/gpu/gskgpuframeprivate.h b/gsk/gpu/gskgpuframeprivate.h index c142bafd27..1ec64b1ef7 100644 --- a/gsk/gpu/gskgpuframeprivate.h +++ b/gsk/gpu/gskgpuframeprivate.h @@ -39,6 +39,8 @@ struct _GskGpuFrameClass GdkTexture *texture); GskGpuBuffer * (* create_vertex_buffer) (GskGpuFrame *self, gsize size); + GskGpuBuffer * (* create_globals_buffer) (GskGpuFrame *self, + gsize size); GskGpuBuffer * (* create_storage_buffer) (GskGpuFrame *self, gsize size); void (* write_texture_vertex_data) (GskGpuFrame *self, @@ -49,6 +51,7 @@ struct _GskGpuFrameClass void (* submit) (GskGpuFrame *self, GskRenderPassType pass_type, GskGpuBuffer *vertex_buffer, + GskGpuBuffer *globals_buffer, GskGpuOp *op); }; @@ -92,6 +95,8 @@ void gsk_gpu_frame_write_texture_vertex_data (GskGpuF GskGpuImage **images, GskGpuSampler *samplers, gsize n_images); +gsize gsk_gpu_frame_add_globals (GskGpuFrame *self, + const GskGpuGlobalsInstance *globals); GskGpuBuffer * gsk_gpu_frame_write_storage_buffer (GskGpuFrame *self, const guchar *data, gsize size, diff --git a/gsk/gpu/gskgpuglobalsop.c b/gsk/gpu/gskgpuglobalsop.c index e783d5ec02..6d54e2ee57 100644 --- a/gsk/gpu/gskgpuglobalsop.c +++ b/gsk/gpu/gskgpuglobalsop.c @@ -2,7 +2,7 @@ #include "gskgpuglobalsopprivate.h" -#include "gskglframeprivate.h" +#include "gskglbufferprivate.h" #include "gskgpuframeprivate.h" #include "gskgpuprintprivate.h" #include "gskroundedrectprivate.h" @@ -17,6 +17,7 @@ struct _GskGpuGlobalsOp { GskGpuOp op; + gsize id; GskGpuGlobalsInstance instance; }; @@ -67,13 +68,10 @@ gsk_gpu_globals_op_gl_command (GskGpuOp *op, { GskGpuGlobalsOp *self = (GskGpuGlobalsOp *) op; - gsk_gl_frame_bind_globals (GSK_GL_FRAME (frame)); - - /* FIXME: Does it matter if we glBufferData() or glSubBufferData() here? */ - glBufferSubData (GL_UNIFORM_BUFFER, - 0, - sizeof (self->instance), - &self->instance); + gsk_gl_buffer_bind_range (GSK_GL_BUFFER (state->globals), + 0, + self->id * sizeof (GskGpuGlobalsInstance), + sizeof (GskGpuGlobalsInstance)); return op->next; } @@ -102,4 +100,5 @@ gsk_gpu_globals_op (GskGpuFrame *frame, graphene_matrix_to_float (mvp, self->instance.mvp); gsk_rounded_rect_to_float (clip, graphene_point_zero (), self->instance.clip); graphene_vec2_to_float (scale, self->instance.scale); + self->id = gsk_gpu_frame_add_globals (frame, &self->instance); } diff --git a/gsk/gpu/gskgpuglobalsopprivate.h b/gsk/gpu/gskgpuglobalsopprivate.h index 6dcae7d833..18b785394a 100644 --- a/gsk/gpu/gskgpuglobalsopprivate.h +++ b/gsk/gpu/gskgpuglobalsopprivate.h @@ -7,15 +7,17 @@ G_BEGIN_DECLS -typedef struct _GskGpuGlobalsInstance GskGpuGlobalsInstance; - struct _GskGpuGlobalsInstance { float mvp[16]; float clip[12]; float scale[2]; + float padding[2]; }; +/* GPUs often want 32bit alignment */ +G_STATIC_ASSERT (sizeof (GskGpuGlobalsInstance) % 32 == 0); + void gsk_gpu_globals_op (GskGpuFrame *frame, const graphene_vec2_t *scale, const graphene_matrix_t *mvp, diff --git a/gsk/gpu/gskgpuopprivate.h b/gsk/gpu/gskgpuopprivate.h index ac88840027..47007133f2 100644 --- a/gsk/gpu/gskgpuopprivate.h +++ b/gsk/gpu/gskgpuopprivate.h @@ -29,6 +29,7 @@ struct _GskGLCommandState GskGpuColorStates color_states; guint32 variation; } current_program; + GskGpuBuffer *globals; GskGpuImage *current_images[2]; GskGpuSampler current_samplers[2]; }; diff --git a/gsk/gpu/gskgputypesprivate.h b/gsk/gpu/gskgputypesprivate.h index 46a413f47f..9d2f3878ca 100644 --- a/gsk/gpu/gskgputypesprivate.h +++ b/gsk/gpu/gskgputypesprivate.h @@ -11,6 +11,7 @@ typedef struct _GskGpuClip GskGpuClip; typedef guint32 GskGpuColorStates; typedef struct _GskGpuDevice GskGpuDevice; typedef struct _GskGpuFrame GskGpuFrame; +typedef struct _GskGpuGlobalsInstance GskGpuGlobalsInstance; typedef struct _GskGpuImage GskGpuImage; typedef struct _GskGpuOp GskGpuOp; typedef struct _GskGpuOpClass GskGpuOpClass; diff --git a/gsk/gpu/gskvulkanframe.c b/gsk/gpu/gskvulkanframe.c index cdce76fa46..db65cd97d7 100644 --- a/gsk/gpu/gskvulkanframe.c +++ b/gsk/gpu/gskvulkanframe.c @@ -229,6 +229,13 @@ gsk_vulkan_frame_create_vertex_buffer (GskGpuFrame *frame, return gsk_vulkan_buffer_new_vertex (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)), size); } +static GskGpuBuffer * +gsk_vulkan_frame_create_globals_buffer (GskGpuFrame *frame, + gsize size) +{ + return NULL; +} + static GskGpuBuffer * gsk_vulkan_frame_create_storage_buffer (GskGpuFrame *frame, gsize size) @@ -249,6 +256,7 @@ static void gsk_vulkan_frame_submit (GskGpuFrame *frame, GskRenderPassType pass_type, GskGpuBuffer *vertex_buffer, + GskGpuBuffer *globals_buffer, GskGpuOp *op) { GskVulkanFrame *self = GSK_VULKAN_FRAME (frame); @@ -351,6 +359,7 @@ gsk_vulkan_frame_class_init (GskVulkanFrameClass *klass) gpu_frame_class->begin = gsk_vulkan_frame_begin; gpu_frame_class->upload_texture = gsk_vulkan_frame_upload_texture; gpu_frame_class->create_vertex_buffer = gsk_vulkan_frame_create_vertex_buffer; + gpu_frame_class->create_globals_buffer = gsk_vulkan_frame_create_globals_buffer; gpu_frame_class->create_storage_buffer = gsk_vulkan_frame_create_storage_buffer; gpu_frame_class->write_texture_vertex_data = gsk_vulkan_frame_write_texture_vertex_data; gpu_frame_class->submit = gsk_vulkan_frame_submit;