Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gskgpuframe.c

  Sprache: C
 

#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,
                      0FALSE,
                      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, TRUEFALSE, 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.12 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik