Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/gsk/gpu/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 10 kB image not shown  

Quelle  gskgpudevice.c

  Sprache: C
 

#include "config.h"

#include "gskgpudeviceprivate.h"

#include "gskgpucacheprivate.h"
#include "gskgpuglobalsopprivate.h"

#include "gdk/gdkprofilerprivate.h"

#include "gsk/gskdebugprivate.h"

#define CACHE_TIMEOUT 15  /* seconds */

typedef struct _GskGpuDevicePrivate GskGpuDevicePrivate;

struct _GskGpuDevicePrivate
{
  GdkDisplay *display;
  gsize max_image_size;
  gsize tile_size;
  gsize globals_aligned_size;

  GskGpuCache *cache; /* we don't own a ref, but manage the cache */
  guint cache_gc_source;
  int cache_timeout;  /* in seconds, or -1 to disable gc */
};

G_DEFINE_TYPE_WITH_PRIVATE (GskGpuDevice, gsk_gpu_device, G_TYPE_OBJECT)

/* Returns TRUE if everything was GC'ed */
static gboolean
gsk_gpu_device_gc (GskGpuDevice *self,
                   gint64        timestamp)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
  gboolean result;

  if (priv->cache == NULL)
    return TRUE;

  gsk_gpu_device_make_current (self);

  gsk_gpu_cache_set_time (priv->cache, timestamp);

  result = gsk_gpu_cache_gc (priv->cache,
                             priv->cache_timeout >= 0 ? priv->cache_timeout * G_TIME_SPAN_SECOND : -1);
  if (result)
    g_clear_object (&priv->cache);

  return result;
}

static gboolean
cache_gc_cb (gpointer data)
{
  GskGpuDevice *self = data;
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
  gint64 timestamp;
  gboolean result = G_SOURCE_CONTINUE;

  timestamp = g_get_monotonic_time ();
  GSK_DEBUG (CACHE, "Periodic %s GC (timestamp %lld)", G_OBJECT_TYPE_NAME (self), (long long) timestamp);

  /* gc can collect the device if all windows are closed and only
   * the cache is keeping it alive */

  g_object_ref (self);

  if (gsk_gpu_device_gc (self, timestamp))
    {
      priv->cache_gc_source = 0;
      result = G_SOURCE_REMOVE;
    }

  g_object_unref (self);

  return result;
}

void
gsk_gpu_device_maybe_gc (GskGpuDevice *self,
                         gint64        timestamp)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
  gsize dead_texture_pixels, dead_textures;

  if (priv->cache_timeout < 0)
    return;

  if (priv->cache == NULL)
    return;

  dead_textures = gsk_gpu_cache_get_dead_textures (priv->cache);
  dead_texture_pixels = gsk_gpu_cache_get_dead_texture_pixels (priv->cache);

  if (priv->cache_timeout == 0 || dead_textures > 50 || dead_texture_pixels > 1000 * 1000)
    {
      GSK_DEBUG (CACHE, "Pre-frame %s GC (%" G_GSIZE_FORMAT " dead textures, %" G_GSIZE_FORMAT " dead pixels)",
                 G_OBJECT_TYPE_NAME (self),
                 dead_textures, dead_texture_pixels);
      gsk_gpu_device_gc (self, timestamp);
    }
}

void
gsk_gpu_device_queue_gc (GskGpuDevice *self)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  if (priv->cache_timeout > 0 && !priv->cache_gc_source)
    priv->cache_gc_source = g_timeout_add_seconds (priv->cache_timeout, cache_gc_cb, self);
}

static void
gsk_gpu_device_dispose (GObject *object)
{
  GskGpuDevice *self = GSK_GPU_DEVICE (object);
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  g_clear_handle_id (&priv->cache_gc_source, g_source_remove);

  G_OBJECT_CLASS (gsk_gpu_device_parent_class)->dispose (object);
}

static void
gsk_gpu_device_finalize (GObject *object)
{
  GskGpuDevice *self = GSK_GPU_DEVICE (object);
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  g_object_unref (priv->display);

  G_OBJECT_CLASS (gsk_gpu_device_parent_class)->finalize (object);
}

static void
gsk_gpu_device_class_init (GskGpuDeviceClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = gsk_gpu_device_dispose;
  object_class->finalize = gsk_gpu_device_finalize;
}

static void
gsk_gpu_device_init (GskGpuDevice *self)
{
}

static inline gsize
round_up (gsize number, gsize divisor)
{
  return (number + divisor - 1) / divisor * divisor;
}

void
gsk_gpu_device_setup (GskGpuDevice *self,
                      GdkDisplay   *display,
                      gsize         max_image_size,
                      gsize         tile_size,
                      gsize         globals_alignment)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
  const char *str;

  priv->display = g_object_ref (display);
  priv->max_image_size = max_image_size;
  priv->tile_size = tile_size;
  priv->cache_timeout = CACHE_TIMEOUT;
  priv->globals_aligned_size = round_up (sizeof (GskGpuGlobalsInstance), globals_alignment);

  str = g_getenv ("GSK_CACHE_TIMEOUT");
  if (str != NULL)
    {
      gint64 value;
      GError *error = NULL;

      if (!g_ascii_string_to_signed (str, 10, -1, G_MAXINT, &value, &error))
        {
          g_warning ("Failed to parse GSK_CACHE_TIMEOUT: %s", error->message);
          g_error_free (error);
        }
      else
        {
          priv->cache_timeout = (int) value;
        }
    }

  if (GSK_DEBUG_CHECK (CACHE))
    {
      if (priv->cache_timeout < 0)
        gdk_debug_message ("Cache GC disabled");
      else if (priv->cache_timeout == 0)
        gdk_debug_message ("Cache GC before every frame");
      else
        gdk_debug_message ("Cache GC timeout: %d seconds", priv->cache_timeout);
    }
}

GdkDisplay *
gsk_gpu_device_get_display (GskGpuDevice *self)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  return priv->display;
}

GskGpuCache *
gsk_gpu_device_get_cache (GskGpuDevice *self)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  if (G_LIKELY (priv->cache))
    return priv->cache;

  priv->cache = gsk_gpu_cache_new (self);

  return priv->cache;
}

/*<private>
 * gsk_gpu_device_get_max_image_size:
 * @self: a device
 *
 * Returns the max image size supported by this device.
 *
 * This maps to `GL_MAX_TEXTURE_SIZE` on GL, but Vulkan is more flexible with
 * per-format size limits, so this is an estimate and code should still handle
 * failures of image creation at smaller sizes. (Besides handling them anyway
 * in case of OOM.)
 *
 * Returns: The maximum size in pixels for creating a GskGpuImage
 **/

gsize
gsk_gpu_device_get_max_image_size (GskGpuDevice *self)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  return priv->max_image_size;
}

/*<private>
 * gsk_gpu_device_get_tile_size:
 * @self: a device
 *
 * The suggested size for tiling images.
 *
 * This value will be small enough so that image creation never fails
 * due to size constraints. It should also not be too large to allow
 * efficient caching of tiles and evictions of unused tiles (think of
 * an image editor showing only a section of a large image).
 *
 * Returns: The suggested size of tiles when tiling images.
 **/

gsize
gsk_gpu_device_get_tile_size (GskGpuDevice *self)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  return priv->tile_size;
}

/*<private>
 * gsk_gpu_device_get_globals_aligned_size:
 * @self: a device
 *
 * The required size for allocating arrays of globals.
 *
 * This value will be at least `sizeof (GskGpuGlobalsInstance)` but due to constraints
 * of how buffers are mapped, it might be larger to allow a single buffer to hold
 * all the globals instances.
 *
 * Returns: The minimum aligned size for a GskGpuGlobalsInstance
 **/

gsize
gsk_gpu_device_get_globals_aligned_size (GskGpuDevice *self)
{
  GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);

  return priv->globals_aligned_size;
}

/*<private>
 * gsk_gpu_device_create_offscreen_image:
 * @self: the device to create the offscreen in
 * @with_mipmap: whether to allocate memory for mipmap levels
 * @format: the desired format
 * @is_srgb: if the format should be srgb
 * @width: width of the image
 * @height: height of the image
 *
 * Creates an image suitable for offscreen rendering.
 *
 * Note that the format is a hint and the device may choose a different
 * format if the desired format is not be renderable on the device.
 *
 * If width/height is too large or the device is out of memory,
 * `NULL` may be returned.
 *
 * Returns: (nullable): The created image or `NULL` on error.
 **/

GskGpuImage *
gsk_gpu_device_create_offscreen_image (GskGpuDevice    *self,
                                       gboolean         with_mipmap,
                                       GdkMemoryFormat  format,
                                       gboolean         is_srgb,
                                       gsize            width,
                                       gsize            height)
{
  return GSK_GPU_DEVICE_GET_CLASS (self)->create_offscreen_image (self, with_mipmap, format, is_srgb, width, height);
}

GskGpuImage *
gsk_gpu_device_create_atlas_image (GskGpuDevice *self,
                                   gsize         width,
                                   gsize         height)
{
  return GSK_GPU_DEVICE_GET_CLASS (self)->create_atlas_image (self, width, height);
}

/*<private>
 * gsk_gpu_device_create_upload_image:
 * @self: the device to create the offscreen in
 * @with_mipmap: whether to try to allocate memory for mipmap levels
 * @format: the desired format
 * @conv: the desired builtin conversion
 * @width: width of the image
 * @height: height of the image
 *
 * Creates an image suitable for uploading data into.
 *
 * Note that the with_mipmap, format, and conv arguments are all hints and
 * the device may choose a different format if those are not supported.
 * The device will choose the most suitable format and the uploading code
 * should convert on the CPU to that format.
 *
 * Returns: (nullable): The created image or `NULL` if the image size was
 *   too large.
 **/

GskGpuImage *
gsk_gpu_device_create_upload_image (GskGpuDevice     *self,
                                    gboolean          with_mipmap,
                                    GdkMemoryFormat   format,
                                    GskGpuConversion  conv,
                                    gsize             width,
                                    gsize             height)
{
  return GSK_GPU_DEVICE_GET_CLASS (self)->create_upload_image (self, with_mipmap, format, conv, width, height);
}

GskGpuImage *
gsk_gpu_device_create_download_image (GskGpuDevice   *self,
                                      GdkMemoryDepth  depth,
                                      gsize           width,
                                      gsize           height)
{
  return GSK_GPU_DEVICE_GET_CLASS (self)->create_download_image (self, depth, width, height);
}

void
gsk_gpu_device_make_current (GskGpuDevice *self)
{
  GSK_GPU_DEVICE_GET_CLASS (self)->make_current (self);
}

/* }}} */
/* vim:set foldmethod=marker: */

Messung V0.5 in Prozent
C=99 H=94 G=96

¤ Dauer der Verarbeitung: 0.11 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.