mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 14:31:10 +00:00
Merge branch 'wip/otte/big-bigger-oom' into 'main'
Implement tiling for large textures Closes #6324 See merge request GNOME/gtk!7447
This commit is contained in:
commit
2ae345aa8f
@ -260,7 +260,10 @@ gsk_gl_device_get_for_display (GdkDisplay *display,
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||
gsk_gpu_device_setup (GSK_GPU_DEVICE (self), display, max_texture_size);
|
||||
gsk_gpu_device_setup (GSK_GPU_DEVICE (self),
|
||||
display,
|
||||
max_texture_size,
|
||||
GSK_GPU_DEVICE_DEFAULT_TILE_SIZE);
|
||||
|
||||
self->version_string = gdk_gl_context_get_glsl_version_string (context);
|
||||
self->api = gdk_gl_context_get_api (context);
|
||||
|
@ -32,6 +32,7 @@ typedef struct _GskGpuCachedClass GskGpuCachedClass;
|
||||
typedef struct _GskGpuCachedAtlas GskGpuCachedAtlas;
|
||||
typedef struct _GskGpuCachedGlyph GskGpuCachedGlyph;
|
||||
typedef struct _GskGpuCachedTexture GskGpuCachedTexture;
|
||||
typedef struct _GskGpuCachedTile GskGpuCachedTile;
|
||||
|
||||
struct _GskGpuCache
|
||||
{
|
||||
@ -44,6 +45,7 @@ struct _GskGpuCache
|
||||
|
||||
GHashTable *texture_cache;
|
||||
GHashTable *ccs_texture_caches[GDK_COLOR_STATE_N_IDS];
|
||||
GHashTable *tile_cache;
|
||||
GHashTable *glyph_cache;
|
||||
|
||||
GskGpuCachedAtlas *current_atlas;
|
||||
@ -398,6 +400,185 @@ gsk_gpu_cached_texture_new (GskGpuCache *cache,
|
||||
return self;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ CachedTile */
|
||||
|
||||
struct _GskGpuCachedTile
|
||||
{
|
||||
GskGpuCached parent;
|
||||
|
||||
GdkTexture *texture;
|
||||
gsize tile_id;
|
||||
|
||||
/* atomic */ int use_count; /* We count the use by the cache (via the linked
|
||||
* list) and by the texture (via weak ref)
|
||||
*/
|
||||
|
||||
gsize *dead_pixels_counter;
|
||||
|
||||
GskGpuImage *image;
|
||||
GdkColorState *color_state;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_gpu_cached_tile_free (GskGpuCache *cache,
|
||||
GskGpuCached *cached)
|
||||
{
|
||||
GskGpuCachedTile *self = (GskGpuCachedTile *) cached;
|
||||
gpointer key, value;
|
||||
|
||||
g_clear_object (&self->image);
|
||||
g_clear_pointer (&self->color_state, gdk_color_state_unref);
|
||||
|
||||
if (g_hash_table_steal_extended (cache->tile_cache, self, &key, &value))
|
||||
{
|
||||
/* If the texture has been reused already, we put the entry back */
|
||||
if ((GskGpuCached *) value != cached)
|
||||
g_hash_table_insert (cache->tile_cache, key, value);
|
||||
}
|
||||
|
||||
/* If the cached item itself is still in use by the texture, we leave
|
||||
* it to the weak ref or render data to free it.
|
||||
*/
|
||||
if (g_atomic_int_dec_and_test (&self->use_count))
|
||||
{
|
||||
g_free (self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_gpu_cached_tile_is_invalid (GskGpuCachedTile *self)
|
||||
{
|
||||
/* If the use count is less than 2, the orignal texture has died,
|
||||
* and the memory may have been reused for a new texture, so we
|
||||
* can't hand out the image that is for the original texture.
|
||||
*/
|
||||
return g_atomic_int_get (&self->use_count) < 2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_cached_tile_should_collect (GskGpuCache *cache,
|
||||
GskGpuCached *cached,
|
||||
gint64 cache_timeout,
|
||||
gint64 timestamp)
|
||||
{
|
||||
GskGpuCachedTile *self = (GskGpuCachedTile *) cached;
|
||||
|
||||
return gsk_gpu_cached_is_old (cache, cached, cache_timeout, timestamp) ||
|
||||
gsk_gpu_cached_tile_is_invalid (self);
|
||||
}
|
||||
|
||||
static const GskGpuCachedClass GSK_GPU_CACHED_TILE_CLASS =
|
||||
{
|
||||
sizeof (GskGpuCachedTile),
|
||||
gsk_gpu_cached_tile_free,
|
||||
gsk_gpu_cached_tile_should_collect
|
||||
};
|
||||
|
||||
/* Note: this function can run in an arbitrary thread, so it can
|
||||
* only access things atomically
|
||||
*/
|
||||
static void
|
||||
gsk_gpu_cached_tile_destroy_cb (gpointer data)
|
||||
{
|
||||
GskGpuCachedTile *self = data;
|
||||
|
||||
if (!gsk_gpu_cached_tile_is_invalid (self))
|
||||
g_atomic_pointer_add (self->dead_pixels_counter, ((GskGpuCached *) self)->pixels);
|
||||
|
||||
if (g_atomic_int_dec_and_test (&self->use_count))
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
static guint
|
||||
gsk_gpu_cached_tile_hash (gconstpointer data)
|
||||
{
|
||||
const GskGpuCachedTile *self = data;
|
||||
|
||||
return g_direct_hash (self->texture) ^ self->tile_id;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_cached_tile_equal (gconstpointer data_a,
|
||||
gconstpointer data_b)
|
||||
{
|
||||
const GskGpuCachedTile *a = data_a;
|
||||
const GskGpuCachedTile *b = data_b;
|
||||
|
||||
return a->texture == b->texture &&
|
||||
a->tile_id == b->tile_id;
|
||||
}
|
||||
|
||||
static GskGpuCachedTile *
|
||||
gsk_gpu_cached_tile_new (GskGpuCache *cache,
|
||||
GdkTexture *texture,
|
||||
guint tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state)
|
||||
{
|
||||
GskGpuCachedTile *self;
|
||||
|
||||
self = gsk_gpu_cached_new (cache, &GSK_GPU_CACHED_TILE_CLASS, NULL);
|
||||
self->texture = texture;
|
||||
self->tile_id = tile_id;
|
||||
self->image = g_object_ref (image);
|
||||
self->color_state = gdk_color_state_ref (color_state);
|
||||
((GskGpuCached *)self)->pixels = gsk_gpu_image_get_width (image) * gsk_gpu_image_get_height (image);
|
||||
self->dead_pixels_counter = &cache->dead_texture_pixels;
|
||||
self->use_count = 2;
|
||||
|
||||
g_object_weak_ref (G_OBJECT (texture), (GWeakNotify) gsk_gpu_cached_tile_destroy_cb, self);
|
||||
if (cache->tile_cache == NULL)
|
||||
cache->tile_cache = g_hash_table_new (gsk_gpu_cached_tile_hash,
|
||||
gsk_gpu_cached_tile_equal);
|
||||
g_hash_table_add (cache->tile_cache, self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
GskGpuImage *
|
||||
gsk_gpu_cache_lookup_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
gsize tile_id,
|
||||
gint64 timestamp,
|
||||
GdkColorState **out_color_state)
|
||||
{
|
||||
GskGpuCachedTile *tile;
|
||||
GskGpuCachedTile lookup = {
|
||||
.texture = texture,
|
||||
.tile_id = tile_id
|
||||
};
|
||||
|
||||
if (self->tile_cache == NULL)
|
||||
return NULL;
|
||||
|
||||
tile = g_hash_table_lookup (self->tile_cache, &lookup);
|
||||
if (tile == NULL)
|
||||
return NULL;
|
||||
|
||||
gsk_gpu_cached_use (self, (GskGpuCached *) tile, timestamp);
|
||||
|
||||
*out_color_state = tile->color_state;
|
||||
|
||||
return g_object_ref (tile->image);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_cache_cache_tile (GskGpuCache *self,
|
||||
gint64 timestamp,
|
||||
GdkTexture *texture,
|
||||
guint tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state)
|
||||
{
|
||||
GskGpuCachedTile *tile;
|
||||
|
||||
tile = gsk_gpu_cached_tile_new (self, texture, tile_id, image, color_state);
|
||||
|
||||
gsk_gpu_cached_use (self, (GskGpuCached *) tile, timestamp);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ CachedGlyph */
|
||||
|
||||
@ -600,6 +781,7 @@ gsk_gpu_cache_dispose (GObject *object)
|
||||
|
||||
gsk_gpu_cache_clear_cache (self);
|
||||
g_hash_table_unref (self->glyph_cache);
|
||||
g_clear_pointer (&self->tile_cache, g_hash_table_unref);
|
||||
g_hash_table_unref (self->texture_cache);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gpu_cache_parent_class)->dispose (object);
|
||||
|
@ -39,6 +39,17 @@ void gsk_gpu_cache_cache_texture_image (GskGpuC
|
||||
gint64 timestamp,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state);
|
||||
GskGpuImage * gsk_gpu_cache_lookup_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
gsize tile_id,
|
||||
gint64 timestamp,
|
||||
GdkColorState **out_color_state);
|
||||
void gsk_gpu_cache_cache_tile (GskGpuCache *self,
|
||||
gint64 timestamp,
|
||||
GdkTexture *texture,
|
||||
guint tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -22,6 +22,7 @@ struct _GskGpuDevicePrivate
|
||||
{
|
||||
GdkDisplay *display;
|
||||
gsize max_image_size;
|
||||
gsize tile_size;
|
||||
|
||||
GskGpuCache *cache; /* we don't own a ref, but manage the cache */
|
||||
guint cache_gc_source;
|
||||
@ -142,13 +143,15 @@ gsk_gpu_device_init (GskGpuDevice *self)
|
||||
void
|
||||
gsk_gpu_device_setup (GskGpuDevice *self,
|
||||
GdkDisplay *display,
|
||||
gsize max_image_size)
|
||||
gsize max_image_size,
|
||||
gsize tile_size)
|
||||
{
|
||||
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;
|
||||
|
||||
str = g_getenv ("GSK_CACHE_TIMEOUT");
|
||||
@ -200,6 +203,19 @@ gsk_gpu_device_get_cache (GskGpuDevice *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)
|
||||
{
|
||||
@ -208,6 +224,25 @@ gsk_gpu_device_get_max_image_size (GskGpuDevice *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;
|
||||
}
|
||||
|
||||
GskGpuImage *
|
||||
gsk_gpu_device_create_offscreen_image (GskGpuDevice *self,
|
||||
gboolean with_mipmap,
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_GPU_DEVICE_DEFAULT_TILE_SIZE 1024
|
||||
|
||||
#define GSK_TYPE_GPU_DEVICE (gsk_gpu_device_get_type ())
|
||||
#define GSK_GPU_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSK_TYPE_GPU_DEVICE, GskGpuDevice))
|
||||
#define GSK_GPU_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSK_TYPE_GPU_DEVICE, GskGpuDeviceClass))
|
||||
@ -50,12 +52,14 @@ GType gsk_gpu_device_get_type (void) G
|
||||
|
||||
void gsk_gpu_device_setup (GskGpuDevice *self,
|
||||
GdkDisplay *display,
|
||||
gsize max_image_size);
|
||||
gsize max_image_size,
|
||||
gsize tile_size);
|
||||
void gsk_gpu_device_maybe_gc (GskGpuDevice *self);
|
||||
void gsk_gpu_device_queue_gc (GskGpuDevice *self);
|
||||
GdkDisplay * gsk_gpu_device_get_display (GskGpuDevice *self);
|
||||
GskGpuCache * gsk_gpu_device_get_cache (GskGpuDevice *self);
|
||||
gsize gsk_gpu_device_get_max_image_size (GskGpuDevice *self);
|
||||
gsize gsk_gpu_device_get_tile_size (GskGpuDevice *self);
|
||||
|
||||
GskGpuImage * gsk_gpu_device_create_offscreen_image (GskGpuDevice *self,
|
||||
gboolean with_mipmap,
|
||||
|
@ -43,8 +43,10 @@
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include "gdk/gdkcolorstateprivate.h"
|
||||
#include "gdk/gdkmemorytextureprivate.h"
|
||||
#include "gdk/gdkrgbaprivate.h"
|
||||
#include "gdk/gdksubsurfaceprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
|
||||
/* the epsilon we allow pixels to be off due to rounding errors.
|
||||
* Chosen rather randomly.
|
||||
@ -1725,6 +1727,163 @@ gsk_gpu_lookup_texture (GskGpuFrame *frame,
|
||||
return image;
|
||||
}
|
||||
|
||||
static GskGpuSampler
|
||||
gsk_gpu_sampler_for_scaling_filter (GskScalingFilter scaling_filter)
|
||||
{
|
||||
switch (scaling_filter)
|
||||
{
|
||||
case GSK_SCALING_FILTER_LINEAR:
|
||||
return GSK_GPU_SAMPLER_DEFAULT;
|
||||
|
||||
case GSK_SCALING_FILTER_NEAREST:
|
||||
return GSK_GPU_SAMPLER_NEAREST;
|
||||
|
||||
case GSK_SCALING_FILTER_TRILINEAR:
|
||||
return GSK_GPU_SAMPLER_MIPMAP_DEFAULT;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return GSK_GPU_SAMPLER_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
/* must be set up with BLEND_ADD to avoid seams */
|
||||
static void
|
||||
gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
const graphene_rect_t *texture_bounds,
|
||||
GdkTexture *texture,
|
||||
GskScalingFilter scaling_filter)
|
||||
{
|
||||
GskGpuCache *cache;
|
||||
GskGpuDevice *device;
|
||||
gint64 timestamp;
|
||||
GskGpuImage *tile;
|
||||
GdkColorState *tile_cs;
|
||||
GskGpuSampler sampler;
|
||||
gboolean need_mipmap;
|
||||
GdkMemoryTexture *memtex;
|
||||
GdkTexture *subtex;
|
||||
float scaled_tile_width, scaled_tile_height;
|
||||
gsize tile_size, width, height, n_width, n_height, x, y;
|
||||
graphene_rect_t clip_bounds;
|
||||
|
||||
device = gsk_gpu_frame_get_device (self->frame);
|
||||
cache = gsk_gpu_device_get_cache (device);
|
||||
timestamp = gsk_gpu_frame_get_timestamp (self->frame);
|
||||
sampler = gsk_gpu_sampler_for_scaling_filter (scaling_filter);
|
||||
need_mipmap = scaling_filter == GSK_SCALING_FILTER_TRILINEAR;
|
||||
gsk_gpu_node_processor_get_clip_bounds (self, &clip_bounds);
|
||||
tile_size = gsk_gpu_device_get_tile_size (device);
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
n_width = (width + tile_size - 1) / tile_size;
|
||||
n_height = (height + tile_size - 1) / tile_size;
|
||||
scaled_tile_width = texture_bounds->size.width * tile_size / width;
|
||||
scaled_tile_height = texture_bounds->size.height * tile_size / height;
|
||||
|
||||
memtex = NULL;
|
||||
for (y = 0; y < n_height; y++)
|
||||
{
|
||||
for (x = 0; x < n_width; x++)
|
||||
{
|
||||
graphene_rect_t tile_rect = GRAPHENE_RECT_INIT (texture_bounds->origin.x + scaled_tile_width * x,
|
||||
texture_bounds->origin.y + scaled_tile_height * y,
|
||||
scaled_tile_width,
|
||||
scaled_tile_height);
|
||||
if (!gsk_rect_intersection (&tile_rect, texture_bounds, &tile_rect) ||
|
||||
!gsk_rect_intersects (&clip_bounds, &tile_rect))
|
||||
continue;
|
||||
|
||||
tile = gsk_gpu_cache_lookup_tile (cache, texture, y * n_width + x, timestamp, &tile_cs);
|
||||
|
||||
if (tile == NULL)
|
||||
{
|
||||
if (memtex == NULL)
|
||||
memtex = gdk_memory_texture_from_texture (texture);
|
||||
subtex = gdk_memory_texture_new_subtexture (memtex,
|
||||
x * tile_size,
|
||||
y * tile_size,
|
||||
MIN (tile_size, width - x * tile_size),
|
||||
MIN (tile_size, height - y * tile_size));
|
||||
tile = gsk_gpu_upload_texture_op_try (self->frame, need_mipmap, subtex);
|
||||
g_object_unref (subtex);
|
||||
if (tile == NULL)
|
||||
{
|
||||
g_warning ("failed to create %zux%zu tile for %zux%zu texture. Out of memory?",
|
||||
tile_size, tile_size, width, height);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tile_cs = gdk_texture_get_color_state (texture);
|
||||
if (gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_SRGB)
|
||||
{
|
||||
tile_cs = gdk_color_state_get_no_srgb_tf (tile_cs);
|
||||
g_assert (tile_cs);
|
||||
}
|
||||
|
||||
gsk_gpu_cache_cache_tile (cache, timestamp, texture, y * n_width + x, tile, tile_cs);
|
||||
}
|
||||
|
||||
if (need_mipmap &&
|
||||
(gsk_gpu_image_get_flags (tile) & (GSK_GPU_IMAGE_STRAIGHT_ALPHA | GSK_GPU_IMAGE_CAN_MIPMAP)) != GSK_GPU_IMAGE_CAN_MIPMAP)
|
||||
{
|
||||
tile = gsk_gpu_copy_image (self->frame, self->ccs, tile, tile_cs, TRUE);
|
||||
tile_cs = self->ccs;
|
||||
gsk_gpu_cache_cache_tile (cache, timestamp, texture, y * n_width + x, tile, tile_cs);
|
||||
}
|
||||
if (need_mipmap && !(gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_MIPMAP))
|
||||
gsk_gpu_mipmap_op (self->frame, tile);
|
||||
|
||||
gsk_gpu_node_processor_image_op (self,
|
||||
tile,
|
||||
tile_cs,
|
||||
sampler,
|
||||
&tile_rect,
|
||||
&tile_rect);
|
||||
|
||||
g_object_unref (tile);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
g_clear_object (&memtex);
|
||||
}
|
||||
|
||||
static GskGpuImage *
|
||||
gsk_gpu_get_texture_tiles_as_image (GskGpuFrame *frame,
|
||||
GdkColorState *ccs,
|
||||
const graphene_rect_t *clip_bounds,
|
||||
const graphene_vec2_t *scale,
|
||||
const graphene_rect_t *texture_bounds,
|
||||
GdkTexture *texture,
|
||||
GskScalingFilter scaling_filter)
|
||||
{
|
||||
GskGpuNodeProcessor self;
|
||||
GskGpuImage *image;
|
||||
|
||||
image = gsk_gpu_node_processor_init_draw (&self,
|
||||
frame,
|
||||
ccs,
|
||||
gdk_texture_get_depth (texture),
|
||||
scale,
|
||||
clip_bounds);
|
||||
if (image == NULL)
|
||||
return NULL;
|
||||
|
||||
self.blend = GSK_GPU_BLEND_ADD;
|
||||
self.pending_globals |= GSK_GPU_GLOBAL_BLEND;
|
||||
gsk_gpu_node_processor_sync_globals (&self, 0);
|
||||
|
||||
gsk_gpu_node_processor_draw_texture_tiles (&self,
|
||||
texture_bounds,
|
||||
texture,
|
||||
scaling_filter);
|
||||
|
||||
gsk_gpu_node_processor_finish_draw (&self, image);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
@ -1741,11 +1900,26 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
|
||||
|
||||
if (image == NULL)
|
||||
{
|
||||
GSK_DEBUG (FALLBACK, "Unsupported texture format %u for size %dx%d",
|
||||
gdk_texture_get_format (texture),
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
gsk_gpu_node_processor_add_cairo_node (self, node);
|
||||
graphene_rect_t clip, rounded_clip;
|
||||
|
||||
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip))
|
||||
return;
|
||||
rect_round_to_pixels (&clip, &self->scale, &self->offset, &rounded_clip);
|
||||
|
||||
image = gsk_gpu_get_texture_tiles_as_image (self->frame,
|
||||
self->ccs,
|
||||
&rounded_clip,
|
||||
&self->scale,
|
||||
&node->bounds,
|
||||
texture,
|
||||
should_mipmap ? GSK_SCALING_FILTER_TRILINEAR : GSK_SCALING_FILTER_LINEAR);
|
||||
gsk_gpu_node_processor_image_op (self,
|
||||
image,
|
||||
self->ccs,
|
||||
GSK_GPU_SAMPLER_DEFAULT,
|
||||
&clip,
|
||||
&rounded_clip);
|
||||
g_object_unref (image);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1797,14 +1971,25 @@ gsk_gpu_get_texture_node_as_image (GskGpuFrame *frame,
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
||||
GdkColorState *image_cs;
|
||||
GskGpuImage *image;
|
||||
gboolean should_mipmap;
|
||||
|
||||
if (texture_node_should_mipmap (node, frame, scale))
|
||||
return gsk_gpu_get_node_as_image_via_offscreen (frame, ccs, clip_bounds, scale, node, out_bounds);
|
||||
|
||||
should_mipmap = texture_node_should_mipmap (node, frame, scale);
|
||||
image = gsk_gpu_lookup_texture (frame, ccs, texture, FALSE, &image_cs);
|
||||
|
||||
/* Happens ie for oversized textures */
|
||||
if (image == NULL)
|
||||
{
|
||||
image = gsk_gpu_get_texture_tiles_as_image (frame,
|
||||
ccs,
|
||||
clip_bounds,
|
||||
scale,
|
||||
&node->bounds,
|
||||
gsk_texture_node_get_texture (node),
|
||||
should_mipmap ? GSK_SCALING_FILTER_TRILINEAR : GSK_SCALING_FILTER_LINEAR);
|
||||
*out_bounds = *clip_bounds;
|
||||
return image;
|
||||
}
|
||||
|
||||
if (should_mipmap)
|
||||
return gsk_gpu_get_node_as_image_via_offscreen (frame, ccs, clip_bounds, scale, node, out_bounds);
|
||||
|
||||
if (!gdk_color_state_equal (ccs, image_cs) ||
|
||||
@ -1833,8 +2018,15 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
|
||||
guint32 descriptor;
|
||||
gboolean need_mipmap, need_offscreen;
|
||||
|
||||
need_offscreen = self->modelview != NULL ||
|
||||
!graphene_vec2_equal (&self->scale, graphene_vec2_one ());
|
||||
texture = gsk_texture_scale_node_get_texture (node);
|
||||
scaling_filter = gsk_texture_scale_node_get_filter (node);
|
||||
need_mipmap = scaling_filter == GSK_SCALING_FILTER_TRILINEAR;
|
||||
image = gsk_gpu_lookup_texture (self->frame, self->ccs, texture, need_mipmap, &image_cs);
|
||||
|
||||
need_offscreen = image == NULL ||
|
||||
self->modelview != NULL ||
|
||||
!graphene_vec2_equal (&self->scale, graphene_vec2_one ());
|
||||
|
||||
if (need_offscreen)
|
||||
{
|
||||
GskGpuImage *offscreen;
|
||||
@ -1853,11 +2045,20 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
|
||||
return;
|
||||
clip_bounds.size.width = ceilf (clip_bounds.size.width);
|
||||
clip_bounds.size.height = ceilf (clip_bounds.size.height);
|
||||
offscreen = gsk_gpu_node_processor_create_offscreen (self->frame,
|
||||
self->ccs,
|
||||
graphene_vec2_one (),
|
||||
&clip_bounds,
|
||||
node);
|
||||
if (image == NULL)
|
||||
offscreen = gsk_gpu_get_texture_tiles_as_image (self->frame,
|
||||
self->ccs,
|
||||
&clip_bounds,
|
||||
graphene_vec2_one (),
|
||||
&node->bounds,
|
||||
texture,
|
||||
scaling_filter);
|
||||
else
|
||||
offscreen = gsk_gpu_node_processor_create_offscreen (self->frame,
|
||||
self->ccs,
|
||||
graphene_vec2_one (),
|
||||
&clip_bounds,
|
||||
node);
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, offscreen, GSK_GPU_SAMPLER_DEFAULT);
|
||||
gsk_gpu_texture_op (self->frame,
|
||||
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
|
||||
@ -1870,22 +2071,6 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
|
||||
return;
|
||||
}
|
||||
|
||||
texture = gsk_texture_scale_node_get_texture (node);
|
||||
scaling_filter = gsk_texture_scale_node_get_filter (node);
|
||||
need_mipmap = scaling_filter == GSK_SCALING_FILTER_TRILINEAR;
|
||||
|
||||
image = gsk_gpu_lookup_texture (self->frame, self->ccs, texture, need_mipmap, &image_cs);
|
||||
|
||||
if (image == NULL)
|
||||
{
|
||||
GSK_DEBUG (FALLBACK, "Unsupported texture format %u for size %dx%d",
|
||||
gdk_texture_get_format (texture),
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
gsk_gpu_node_processor_add_cairo_node (self, node);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA) ||
|
||||
(need_mipmap && !(gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_CAN_MIPMAP)) ||
|
||||
!gdk_color_state_equal (image_cs, self->ccs))
|
||||
@ -1902,24 +2087,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
|
||||
if (need_mipmap && !(gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_MIPMAP))
|
||||
gsk_gpu_mipmap_op (self->frame, image);
|
||||
|
||||
switch (scaling_filter)
|
||||
{
|
||||
case GSK_SCALING_FILTER_LINEAR:
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
|
||||
break;
|
||||
|
||||
case GSK_SCALING_FILTER_NEAREST:
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_NEAREST);
|
||||
break;
|
||||
|
||||
case GSK_SCALING_FILTER_TRILINEAR:
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_MIPMAP_DEFAULT);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return;
|
||||
}
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, gsk_gpu_sampler_for_scaling_filter (scaling_filter));
|
||||
|
||||
gsk_gpu_texture_op (self->frame,
|
||||
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
|
||||
|
@ -575,7 +575,8 @@ gsk_vulkan_device_setup (GskVulkanDevice *self,
|
||||
self->max_immutable_samplers = MIN (self->max_samplers / 3, 32);
|
||||
gsk_gpu_device_setup (GSK_GPU_DEVICE (self),
|
||||
display,
|
||||
vk_props.properties.limits.maxImageDimension2D);
|
||||
vk_props.properties.limits.maxImageDimension2D,
|
||||
GSK_GPU_DEVICE_DEFAULT_TILE_SIZE);
|
||||
}
|
||||
|
||||
GskGpuDevice *
|
||||
|
Loading…
Reference in New Issue
Block a user