#include "config.h"
#include "gskgpuframeprivate.h"
#include "gskgpubufferprivate.h"
#include "gskgpucacheprivate.h"
#include "gskgpudeviceprivate.h"
#include "gskgpudownloadopprivate.h"
#include "gskgpuglobalsopprivate.h"
#include "gskgpuimageprivate.h"
#include "gskgpunodeprocessorprivate.h"
#include "gskgpuopprivate.h"
#include "gskgpurendererprivate.h"
#include "gskgpuuploadopprivate.h"
#include "gskgpuutilsprivate.h"
#include "gskcopypasteutilsprivate.h"
#include "gskdebugprivate.h"
#include "gskrendererprivate.h"
#include "gdk/gdkdmabufdownloaderprivate.h"
#include "gdk/gdkdmabuftextureprivate.h"
#include "gdk/gdkdrawcontextprivate.h"
#include "gdk/gdktexturedownloaderprivate.h"
#define DEFAULT_VERTEX_BUFFER_SIZE 128 * 1024
/* GL_MAX_UNIFORM_BLOCK_SIZE is at 16384 */
#define DEFAULT_STORAGE_BUFFER_SIZE 16 * 1024 * 64
#define DEFAULT_N_GLOBALS_SIZE 16384
#define GDK_ARRAY_NAME gsk_gpu_ops
#define GDK_ARRAY_TYPE_NAME GskGpuOps
#define GDK_ARRAY_ELEMENT_TYPE guchar
#define GDK_ARRAY_BY_VALUE 1
#include "gdk/gdkarrayimpl.c"
typedef struct _GskNodeStackNode GskNodeStackNode;
struct _GskNodeStackNode {
GskRenderNode *node;
guint pos;
};
#define GDK_ARRAY_NAME gsk_node_stack
#define GDK_ARRAY_TYPE_NAME GskNodeStack
#define GDK_ARRAY_ELEMENT_TYPE GskNodeStackNode
#define GDK_ARRAY_BY_VALUE 1
#define GDK_ARRAY_PREALLOC 64
#include "gdk/gdkarrayimpl.c"
typedef struct _GskGpuFramePrivate GskGpuFramePrivate;
struct _GskGpuFramePrivate
{
GskGpuRenderer *renderer;
GskGpuDevice *device;
GskGpuOptimizations optimizations;
gsize texture_vertex_size;
gint64 timestamp;
GskGpuOps ops;
GskGpuOp *first_op;
GskGpuOp *last_op;
GskGpuBuffer *vertex_buffer;
guchar *vertex_buffer_data;
gsize vertex_buffer_used;
GskGpuBuffer *globals_buffer;
guchar *globals_buffer_data;
gsize n_globals;
GskGpuBuffer *storage_buffer;
guchar *storage_buffer_data;
gsize storage_buffer_used;
GskNodeStack node_stack;
};
G_DEFINE_TYPE_WITH_PRIVATE (GskGpuFrame, gsk_gpu_frame, G_TYPE_OBJECT)
static void
gsk_gpu_frame_default_setup (GskGpuFrame *self)
{
}
static void
gsk_gpu_frame_default_cleanup (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuOp *op;
gsize i;
g_assert (gsk_node_stack_get_size (&priv->node_stack) == 0 );
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);
gsk_gpu_op_finish (op);
}
gsk_gpu_ops_set_size (&priv->ops, 0 );
priv->first_op = NULL;
priv->last_op = NULL;
}
static void
gsk_gpu_frame_default_begin (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region,
const graphene_rect_t *opaque)
{
gdk_draw_context_begin_frame_full (context, NULL, depth, region, opaque);
}
static void
gsk_gpu_frame_default_end (GskGpuFrame *self,
GdkDrawContext *context)
{
gdk_draw_context_end_frame_full (context, NULL);
}
static void
gsk_gpu_frame_default_sync (GskGpuFrame *self)
{
}
static gboolean
gsk_gpu_frame_is_clean (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return gsk_gpu_ops_get_size (&priv->ops) == 0 ;
}
static void
gsk_gpu_frame_cleanup (GskGpuFrame *self)
{
if (gsk_gpu_frame_is_clean (self))
return ;
GSK_GPU_FRAME_GET_CLASS (self)->cleanup (self);
}
static GskGpuImage *
gsk_gpu_frame_default_upload_texture (GskGpuFrame *self,
gboolean with_mipmap,
GdkTexture *texture)
{
return NULL;
}
static gpointer
gsk_gpu_frame_default_alloc_op (GskGpuFrame *self,
const GskGpuOpClass *op_class)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuOp *op;
gsize pos;
pos = gsk_gpu_ops_get_size (&priv->ops);
gsk_gpu_ops_splice (&priv->ops,
pos,
0 , FALSE ,
NULL,
op_class->size);
op = (GskGpuOp *) gsk_gpu_ops_index (&priv->ops, pos);
op->op_class = op_class;
priv->last_op = op;
return op;
}
static void
gsk_gpu_frame_default_start_node (GskGpuFrame *self,
GskRenderNode *node,
gsize pos)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsk_node_stack_append (&priv->node_stack, &(GskNodeStackNode) { node, pos });
}
static void
gsk_gpu_frame_default_end_node (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsk_node_stack_set_size (&priv->node_stack, gsk_node_stack_get_size (&priv->node_stack) - 1 );
}
static GskDebugProfile *
gsk_gpu_frame_default_get_profile (GskGpuFrame *self)
{
return NULL;
}
static void
gsk_gpu_frame_dispose (GObject *object)
{
GskGpuFrame *self = GSK_GPU_FRAME (object);
gsk_gpu_frame_cleanup (self);
G_OBJECT_CLASS (gsk_gpu_frame_parent_class)->dispose (object);
}
static void
gsk_gpu_frame_finalize (GObject *object)
{
GskGpuFrame *self = GSK_GPU_FRAME (object);
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsk_gpu_ops_clear (&priv->ops);
gsk_node_stack_clear (&priv->node_stack);
g_clear_object (&priv->vertex_buffer);
g_clear_object (&priv->globals_buffer);
g_clear_object (&priv->storage_buffer);
g_object_unref (priv->device);
G_OBJECT_CLASS (gsk_gpu_frame_parent_class)->finalize (object);
}
static void
gsk_gpu_frame_class_init (GskGpuFrameClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
klass->setup = gsk_gpu_frame_default_setup;
klass->cleanup = gsk_gpu_frame_default_cleanup;
klass->begin = gsk_gpu_frame_default_begin;
klass->end = gsk_gpu_frame_default_end;
klass->sync = gsk_gpu_frame_default_sync;
klass->upload_texture = gsk_gpu_frame_default_upload_texture;
klass->alloc_op = gsk_gpu_frame_default_alloc_op;
klass->start_node = gsk_gpu_frame_default_start_node;
klass->end_node = gsk_gpu_frame_default_end_node;
klass->get_profile = gsk_gpu_frame_default_get_profile;
object_class->dispose = gsk_gpu_frame_dispose;
object_class->finalize = gsk_gpu_frame_finalize;
}
static void
gsk_gpu_frame_init (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsk_gpu_ops_init (&priv->ops);
gsk_node_stack_init (&priv->node_stack);
}
void
gsk_gpu_frame_setup (GskGpuFrame *self,
GskGpuRenderer *renderer,
GskGpuDevice *device,
GskGpuOptimizations optimizations)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
/* no reference, the renderer owns us */
priv->renderer = renderer;
priv->device = g_object_ref (device);
priv->optimizations = optimizations;
GSK_GPU_FRAME_GET_CLASS (self)->setup (self);
}
/*
* gsk_gpu_frame_set_texture_vertex_size :
* @ self : the frame
* @ texture_vertex_size : bytes to reserve in the vertex data per
* texture rendered
*
* Some renderers want to attach vertex data for textures , usually
* for supporting bindless textures . This is the number of bytes
* reserved per texture .
*
* GskGpuFrameClass : : write_texture_vertex_data ( ) is used to write that
* data .
**/
void
gsk_gpu_frame_set_texture_vertex_size (GskGpuFrame *self,
gsize texture_vertex_size)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
priv->texture_vertex_size = texture_vertex_size;
}
void
gsk_gpu_frame_begin (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region,
const graphene_rect_t *opaque)
{
GSK_GPU_FRAME_GET_CLASS (self)->begin (self, context, depth, region, opaque);
}
/* Must do equivalent of gsk_gpu_frame_sync() */
void
gsk_gpu_frame_end (GskGpuFrame *self,
GdkDrawContext *context)
{
GSK_GPU_FRAME_GET_CLASS (self)->end (self, context);
}
/*<private>
* gsk_gpu_frame_sync :
* @ self : the frame that should install a sync point .
*
* Installs a sync point after submit ( ) ing commands .
*
* After the installation of a sync point , the application
* must call gsk_gpu_frame_wait ( ) before it can install a sync
* point again .
*
* Another method to install a sync point is via
* gsk_gpu_frame_end ( ) .
*/
void
gsk_gpu_frame_sync (GskGpuFrame *self)
{
GSK_GPU_FRAME_GET_CLASS (self)->sync (self);
}
GskGpuDevice *
gsk_gpu_frame_get_device (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return priv->device;
}
GdkDrawContext *
gsk_gpu_frame_get_context (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return gsk_gpu_renderer_get_context (priv->renderer);
}
gint64
gsk_gpu_frame_get_timestamp (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return priv->timestamp;
}
gboolean
gsk_gpu_frame_should_optimize (GskGpuFrame *self,
GskGpuOptimizations optimization)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return (priv->optimizations & optimization) == optimization;
}
static void
gsk_gpu_frame_verbose_print (GskGpuFrame *self,
const char *heading)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (priv->renderer), VERBOSE))
{
GskGpuOp *op;
guint indent = 1 ;
GString *string = g_string_new (heading);
g_string_append (string, ":\n" );
for (op = priv->first_op; op; op = op->next)
{
if (op->op_class->stage == GSK_GPU_STAGE_END_PASS)
indent--;
gsk_gpu_op_print (op, self, string, indent);
if (op->op_class->stage == GSK_GPU_STAGE_BEGIN_PASS)
indent++;
}
gdk_debug_message ("%s" , string->str);
g_string_free (string, TRUE );
}
}
static void
gsk_gpu_frame_seal_ops (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuOp *last, *op;
gsize i;
if (gsk_gpu_ops_get_size (&priv->ops) == 0 )
return ;
priv->first_op = (GskGpuOp *) gsk_gpu_ops_index (&priv->ops, 0 );
last = priv->first_op;
for (i = last->op_class->size; i < gsk_gpu_ops_get_size (&priv->ops); i += op->op_class->size)
{
op = (GskGpuOp *) gsk_gpu_ops_index (&priv->ops, i);
last->next = op;
last = op;
}
}
typedef struct
{
struct {
GskGpuOp *first;
GskGpuOp *last;
} upload, command;
} SortData;
static GskGpuOp *
gsk_gpu_frame_sort_render_pass (GskGpuFrame *self,
GskGpuOp *op,
SortData *sort_data)
{
SortData subpasses = { { NULL, NULL }, { NULL, NULL } };
SortData pass = { { NULL, NULL }, { NULL, NULL } };
if (op->op_class->stage == GSK_GPU_STAGE_BEGIN_PASS)
{
pass.command.first = op;
pass.command.last = op;
op = op->next;
}
while (op)
{
switch (op->op_class->stage)
{
case GSK_GPU_STAGE_UPLOAD:
if (pass.upload.first == NULL)
pass.upload.first = op;
else
pass.upload.last->next = op;
pass.upload.last = op;
op = op->next;
break ;
case GSK_GPU_STAGE_COMMAND:
case GSK_GPU_STAGE_SHADER:
if (pass.command.first == NULL)
pass.command.first = op;
else
pass.command.last->next = op;
pass.command.last = op;
op = op->next;
break ;
case GSK_GPU_STAGE_PASS:
if (subpasses.command.first == NULL)
subpasses.command.first = op;
else
subpasses.command.last->next = op;
subpasses.command.last = op;
op = op->next;
break ;
case GSK_GPU_STAGE_BEGIN_PASS:
/* append subpass to existing subpasses */
op = gsk_gpu_frame_sort_render_pass (self, op, &subpasses);
break ;
case GSK_GPU_STAGE_END_PASS:
pass.command.last->next = op;
pass.command.last = op;
op = op->next;
goto out;
default :
g_assert_not_reached ();
break ;
}
}
out:
/* append to the sort data, first the subpasses, then the current pass */
if (subpasses.upload.first)
{
if (sort_data->upload.first != NULL)
sort_data->upload.last->next = subpasses.upload.first;
else
sort_data->upload.first = subpasses.upload.first;
sort_data->upload.last = subpasses.upload.last;
}
if (pass.upload.first)
{
if (sort_data->upload.first != NULL)
sort_data->upload.last->next = pass.upload.first;
else
sort_data->upload.first = pass.upload.first;
sort_data->upload.last = pass.upload.last;
}
if (subpasses.command.first)
{
if (sort_data->command.first != NULL)
sort_data->command.last->next = subpasses.command.first;
else
sort_data->command.first = subpasses.command.first;
sort_data->command.last = subpasses.command.last;
}
if (pass.command.first)
{
if (sort_data->command.first != NULL)
sort_data->command.last->next = pass.command.first;
else
sort_data->command.first = pass.command.first;
sort_data->command.last = pass.command.last;
}
return op;
}
static void
gsk_gpu_frame_sort_ops (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
SortData sort_data = { { NULL, }, };
GskGpuOp *op;
op = priv->first_op;
while (op)
{
op = gsk_gpu_frame_sort_render_pass (self, op, &sort_data);
}
if (sort_data.upload.first)
{
sort_data.upload.last->next = sort_data.command.first;
priv->first_op = sort_data.upload.first;
}
else
priv->first_op = sort_data.command.first;
if (sort_data.command.last)
sort_data.command.last->next = NULL;
priv->last_op = NULL;
}
gpointer
gsk_gpu_frame_alloc_op (GskGpuFrame *self,
const GskGpuOpClass *op_class)
{
return GSK_GPU_FRAME_GET_CLASS (self)->alloc_op (self, op_class);
}
GskGpuOp *
gsk_gpu_frame_get_last_op (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return priv->last_op;
}
static GskGpuImage *
gsk_gpu_frame_do_upload_texture (GskGpuFrame *self,
gboolean dmabuf_import,
gboolean with_mipmap,
GdkTexture *texture)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuImage *image;
image = GSK_GPU_FRAME_GET_CLASS (self)->upload_texture (self, with_mipmap, texture);
if (image == NULL && !dmabuf_import)
image = gsk_gpu_upload_texture_op_try (self, with_mipmap, 0 , GSK_SCALING_FILTER_NEAREST, texture);
if (image)
gsk_gpu_cache_cache_texture_image (gsk_gpu_device_get_cache (priv->device), texture, image, NULL);
return image;
}
GskGpuImage *
gsk_gpu_frame_upload_texture (GskGpuFrame *self,
gboolean with_mipmap,
GdkTexture *texture)
{
return gsk_gpu_frame_do_upload_texture (self, FALSE , with_mipmap, texture);
}
static GskGpuBuffer *
gsk_gpu_frame_create_vertex_buffer (GskGpuFrame *self,
gsize size)
{
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)
{
return GSK_GPU_FRAME_GET_CLASS (self)->create_storage_buffer (self, size);
}
static inline gsize
round_up (gsize number, gsize divisor)
{
return (number + divisor - 1 ) / divisor * divisor;
}
gsize
gsk_gpu_frame_get_texture_vertex_size (GskGpuFrame *self,
gsize n_textures)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
return priv->texture_vertex_size * n_textures;
}
gsize
gsk_gpu_frame_reserve_vertex_data (GskGpuFrame *self,
gsize size)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsize size_needed;
if (priv->vertex_buffer == NULL)
priv->vertex_buffer = gsk_gpu_frame_create_vertex_buffer (self, DEFAULT_VERTEX_BUFFER_SIZE);
size_needed = round_up (priv->vertex_buffer_used, size) + size;
if (gsk_gpu_buffer_get_size (priv->vertex_buffer) < size_needed)
{
gsize old_size = gsk_gpu_buffer_get_size (priv->vertex_buffer);
GskGpuBuffer *new_buffer = gsk_gpu_frame_create_vertex_buffer (self, old_size * 2 );
guchar *new_data = gsk_gpu_buffer_map (new_buffer);
if (priv->vertex_buffer_data)
{
memcpy (new_data, priv->vertex_buffer_data, old_size);
gsk_gpu_buffer_unmap (priv->vertex_buffer, old_size);
}
g_object_unref (priv->vertex_buffer);
priv->vertex_buffer = new_buffer;
priv->vertex_buffer_data = new_data;
}
priv->vertex_buffer_used = size_needed;
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, globals_size, result;
globals_size = gsk_gpu_device_get_globals_aligned_size (priv->device);
if (priv->globals_buffer == NULL)
{
priv->globals_buffer = gsk_gpu_frame_create_globals_buffer (self, DEFAULT_N_GLOBALS_SIZE);
if (priv->globals_buffer == NULL)
return 0 ;
}
if (priv->globals_buffer_data == NULL)
priv->globals_buffer_data = gsk_gpu_buffer_map (priv->globals_buffer);
size_needed = globals_size * (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 );
guchar *new_data = 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;
*((GskGpuGlobalsInstance *) (priv->globals_buffer_data + priv->n_globals * globals_size)) = *globals;
priv->n_globals++;
return result;
}
guchar *
gsk_gpu_frame_get_vertex_data (GskGpuFrame *self,
gsize offset)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
if (priv->vertex_buffer_data == NULL)
priv->vertex_buffer_data = gsk_gpu_buffer_map (priv->vertex_buffer);
return priv->vertex_buffer_data + offset;
}
static void
gsk_gpu_frame_ensure_storage_buffer (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
if (priv->storage_buffer_data != NULL)
return ;
if (priv->storage_buffer == NULL)
priv->storage_buffer = gsk_gpu_frame_create_storage_buffer (self, DEFAULT_STORAGE_BUFFER_SIZE);
priv->storage_buffer_data = gsk_gpu_buffer_map (priv->storage_buffer);
}
void
gsk_gpu_frame_write_texture_vertex_data (GskGpuFrame *self,
guchar *data,
GskGpuImage **images,
GskGpuSampler *samplers,
gsize n_images)
{
GSK_GPU_FRAME_GET_CLASS (self)->write_texture_vertex_data (self, data, images, samplers, n_images);
}
GskGpuBuffer *
gsk_gpu_frame_write_storage_buffer (GskGpuFrame *self,
const guchar *data,
gsize size,
gsize *out_offset)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsize offset;
gsk_gpu_frame_ensure_storage_buffer (self);
offset = priv->storage_buffer_used;
if (offset + size > gsk_gpu_buffer_get_size (priv->storage_buffer))
{
g_assert (offset > 0 );
gsk_gpu_buffer_unmap (priv->storage_buffer, 0 );
g_clear_object (&priv->storage_buffer);
priv->storage_buffer_data = 0 ;
priv->storage_buffer_used = 0 ;
gsk_gpu_frame_ensure_storage_buffer (self);
offset = priv->storage_buffer_used;
}
if (size)
{
memcpy (priv->storage_buffer_data + offset, data, size);
priv->storage_buffer_used += size;
}
*out_offset = offset;
return priv->storage_buffer;
}
gboolean
gsk_gpu_frame_is_busy (GskGpuFrame *self)
{
if (gsk_gpu_frame_is_clean (self))
return FALSE ;
return GSK_GPU_FRAME_GET_CLASS (self)->is_busy (self);
}
void
gsk_gpu_frame_wait (GskGpuFrame *self)
{
if (gsk_gpu_frame_is_clean (self))
return ;
GSK_GPU_FRAME_GET_CLASS (self)->wait (self);
gsk_gpu_frame_cleanup (self);
}
static void
gsk_gpu_frame_record (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
GdkTexture **texture)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskRenderPassType pass_type = texture ? GSK_RENDER_PASS_EXPORT : GSK_RENDER_PASS_PRESENT;
priv->timestamp = timestamp;
gsk_gpu_cache_set_time (gsk_gpu_device_get_cache (priv->device), timestamp);
gsk_gpu_frame_start_node (self, node, 0 );
gsk_gpu_node_processor_process (self, target, target_color_state, clip, node, viewport, pass_type);
gsk_gpu_frame_end_node (self);
if (texture)
gsk_gpu_download_op (self, target, target_color_state, texture);
}
static void
gsk_gpu_frame_submit (GskGpuFrame *self,
GskRenderPassType pass_type)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsk_gpu_frame_seal_ops (self);
gsk_gpu_frame_verbose_print (self, "start of frame" );
gsk_gpu_frame_sort_ops (self);
gsk_gpu_frame_verbose_print (self, "after sort" );
if (priv->vertex_buffer)
{
gsk_gpu_buffer_unmap (priv->vertex_buffer, priv->vertex_buffer_used);
priv->vertex_buffer_data = NULL;
priv->vertex_buffer_used = 0 ;
}
if (priv->globals_buffer)
{
gsize globals_size = gsk_gpu_device_get_globals_aligned_size (gsk_gpu_frame_get_device (self));
gsk_gpu_buffer_unmap (priv->globals_buffer, globals_size * priv->n_globals);
priv->globals_buffer_data = NULL;
}
if (priv->storage_buffer_data)
{
gsk_gpu_buffer_unmap (priv->storage_buffer, priv->storage_buffer_used);
priv->storage_buffer_data = NULL;
priv->storage_buffer_used = 0 ;
}
GSK_GPU_FRAME_GET_CLASS (self)->submit (self,
pass_type,
priv->vertex_buffer,
priv->globals_buffer,
priv->first_op);
}
void
gsk_gpu_frame_render (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
GdkTexture **texture)
{
GskRenderPassType pass_type = texture ? GSK_RENDER_PASS_EXPORT : GSK_RENDER_PASS_PRESENT;
node = gsk_render_node_replace_copy_paste (gsk_render_node_ref (node));
gsk_gpu_frame_cleanup (self);
gsk_gpu_frame_record (self, timestamp, target, target_color_state, clip, node, viewport, texture);
gsk_gpu_frame_submit (self, pass_type);
gsk_render_node_unref (node);
}
static gboolean
image_is_uploaded (GskGpuImage *image)
{
/* If we explicitly uploaded an image, we don't need the toggle ref to
* keep the texture alive, because uploaded images are copies. */
return (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_TOGGLE_REF) == 0 ;
}
gboolean
gsk_gpu_frame_download_texture (GskGpuFrame *self,
gint64 timestamp,
GdkTexture *texture,
guchar *data,
const GdkMemoryLayout *layout,
GdkColorState *color_state)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
const GdkDmabuf *dmabuf;
GdkColorState *image_cs;
GskGpuImage *image;
priv->timestamp = timestamp;
gsk_gpu_cache_set_time (gsk_gpu_device_get_cache (priv->device), timestamp);
image = gsk_gpu_cache_lookup_texture_image (gsk_gpu_device_get_cache (priv->device), texture, NULL);
if (image && image_is_uploaded (image))
g_clear_object (&image);
if (image == NULL)
image = gsk_gpu_frame_do_upload_texture (self, TRUE , FALSE , texture);
if (image == NULL)
return FALSE ;
image_cs = gdk_texture_get_color_state (texture);
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
gsk_gpu_frame_cleanup (self);
if ((gdk_memory_format_get_dmabuf_rgb_fourcc (gsk_gpu_image_get_format (image)) != dmabuf->fourcc &&
gdk_memory_format_get_dmabuf_yuv_fourcc (gsk_gpu_image_get_format (image)) != dmabuf->fourcc) ||
!(gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_DOWNLOADABLE) ||
image_cs != color_state)
{
GskGpuImage *converted;
image_cs = gsk_gpu_color_state_apply_conversion (gdk_texture_get_color_state (texture),
gsk_gpu_image_get_conversion (image));
g_assert (image_cs);
converted = gsk_gpu_node_processor_convert_image (self,
layout->format,
color_state,
image,
image_cs);
gdk_color_state_unref (image_cs);
if (converted == NULL)
{
g_object_unref (image);
return FALSE ;
}
g_object_unref (image);
image = converted;
image_cs = color_state;
}
gsk_gpu_download_into_op (self,
image,
image_cs,
data,
layout,
color_state);
gsk_gpu_frame_submit (self, GSK_RENDER_PASS_EXPORT);
gsk_gpu_frame_sync (self);
g_object_unref (image);
return TRUE ;
}
/*<private>
* gsk_gpu_frame_start_node :
* @ self : the frame
* @ node : the rendernode to track
* @ pos : the position in the parent node
*
* Starts rendering the given node , which is the child of
* the currently rendered node at the given position .
*
* To end rendering that node , call gsk_gpu_frame_end_node ( ) .
**/
void
gsk_gpu_frame_start_node (GskGpuFrame *self,
GskRenderNode *node,
gsize pos)
{
#ifndef G_DISABLE_ASSERT
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
gsize n = gsk_node_stack_get_size (&priv->node_stack);
if (n > 0 )
{
GskNodeStackNode *stack;
GskRenderNode **children;
gsize n_children;
stack = gsk_node_stack_get (&priv->node_stack, n - 1 );
children = gsk_render_node_get_children (stack->node, &n_children);
g_assert (pos < n_children);
g_assert (children[pos] == node);
}
else
{
g_assert (pos == 0 );
}
#endif
GSK_GPU_FRAME_GET_CLASS (self)->start_node (self, node, pos);
}
/*<private>
* gsk_gpu_frame_end_node :
* @ self : the frame
*
* Ends the current node and continues with its parent .
**/
void
gsk_gpu_frame_end_node (GskGpuFrame *self)
{
#ifndef G_DISABLE_ASSERT
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
g_assert (gsk_node_stack_get_size (&priv->node_stack) > 0 );
#endif
GSK_GPU_FRAME_GET_CLASS (self)->end_node (self);
}
GskDebugProfile *
gsk_gpu_frame_get_profile (GskGpuFrame *self)
{
return GSK_GPU_FRAME_GET_CLASS (self)->get_profile (self);
}
Messung V0.5 in Prozent C=99 H=98 G=98
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland