mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
Merge branch 'wip/otte/cpu-mipmap' into 'main'
gpu: Allow uploading of mipmap levels when tiling See merge request GNOME/gtk!7657
This commit is contained in:
commit
0274294a6f
@ -454,6 +454,9 @@
|
||||
<file>icons/16x16/categories/applications-other.png</file>
|
||||
<file>icons/48x48/status/starred.png</file>
|
||||
<file alias="icons/scalable/apps/org.gtk.Demo4.svg">data/scalable/apps/org.gtk.Demo4.svg</file>
|
||||
<file>portland-rose-thumbnail.png</file>
|
||||
<file>large-image-thumbnail.png</file>
|
||||
<file compressed="true">large-image.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/Demo4/gtk">
|
||||
<file preprocess="xml-stripblanks">help-overlay.ui</file>
|
||||
|
@ -14,6 +14,103 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include "demo3widget.h"
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GCancellable *cancellable = NULL;
|
||||
|
||||
static void
|
||||
load_texture (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cable)
|
||||
{
|
||||
GFile *file = task_data;
|
||||
GdkTexture *texture;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = gdk_texture_new_from_file (file, &error);
|
||||
|
||||
if (texture)
|
||||
g_task_return_pointer (task, texture, g_object_unref);
|
||||
else
|
||||
g_task_return_error (task, error);
|
||||
}
|
||||
|
||||
static void
|
||||
set_wait_cursor (GtkWidget *widget)
|
||||
{
|
||||
gtk_widget_set_cursor_from_name (GTK_WIDGET (gtk_widget_get_root (widget)), "wait");
|
||||
}
|
||||
|
||||
static void
|
||||
unset_wait_cursor (GtkWidget *widget)
|
||||
{
|
||||
gtk_widget_set_cursor (GTK_WIDGET (gtk_widget_get_root (widget)), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
texture_loaded (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = g_task_propagate_pointer (G_TASK (result), &error);
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window)
|
||||
{
|
||||
g_object_unref (texture);
|
||||
return;
|
||||
}
|
||||
|
||||
unset_wait_cursor (GTK_WIDGET (data));
|
||||
|
||||
g_object_set (G_OBJECT (data), "texture", texture, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
open_file_async (GFile *file,
|
||||
GtkWidget *demo)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
set_wait_cursor (demo);
|
||||
|
||||
task = g_task_new (demo, cancellable, texture_loaded, demo);
|
||||
g_task_set_task_data (task, g_object_ref (file), g_object_unref);
|
||||
g_task_run_in_thread (task, load_texture);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
open_portland_rose (GtkWidget *button,
|
||||
GtkWidget *demo)
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_uri ("resource:///transparent/portland-rose.jpg");
|
||||
open_file_async (file, demo);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
static void
|
||||
open_large_image (GtkWidget *button,
|
||||
GtkWidget *demo)
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_uri ("resource:///org/gtk/Demo4/large-image.png");
|
||||
open_file_async (file, demo);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
static void
|
||||
file_opened (GObject *source,
|
||||
GAsyncResult *result,
|
||||
@ -21,7 +118,6 @@ file_opened (GObject *source,
|
||||
{
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
GdkTexture *texture;
|
||||
|
||||
file = gtk_file_dialog_open_finish (GTK_FILE_DIALOG (source), result, &error);
|
||||
|
||||
@ -32,17 +128,9 @@ file_opened (GObject *source,
|
||||
return;
|
||||
}
|
||||
|
||||
texture = gdk_texture_new_from_file (file, &error);
|
||||
g_object_unref (file);
|
||||
if (!texture)
|
||||
{
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
open_file_async (file, data);
|
||||
|
||||
g_object_set (G_OBJECT (data), "texture", texture, NULL);
|
||||
g_object_unref (texture);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -116,11 +204,26 @@ transform_from (GBinding *binding,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
free_cancellable (gpointer data)
|
||||
{
|
||||
g_cancellable_cancel (cancellable);
|
||||
g_clear_object (&cancellable);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cancel_load (GtkWidget *widget,
|
||||
GVariant *args,
|
||||
gpointer data)
|
||||
{
|
||||
unset_wait_cursor (widget);
|
||||
g_cancellable_cancel (G_CANCELLABLE (data));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_image_scaling (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *box;
|
||||
@ -130,6 +233,7 @@ do_image_scaling (GtkWidget *do_widget)
|
||||
GtkWidget *scale;
|
||||
GtkWidget *dropdown;
|
||||
GtkWidget *button;
|
||||
GtkEventController *controller;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Image Scaling");
|
||||
@ -138,6 +242,20 @@ do_image_scaling (GtkWidget *do_widget)
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
cancellable = g_cancellable_new ();
|
||||
g_object_set_data_full (G_OBJECT (window), "cancellable",
|
||||
cancellable, free_cancellable);
|
||||
|
||||
controller = gtk_shortcut_controller_new ();
|
||||
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
|
||||
gtk_shortcut_new (
|
||||
gtk_keyval_trigger_new (GDK_KEY_Escape, 0),
|
||||
gtk_callback_action_new (cancel_load, cancellable, NULL)
|
||||
));
|
||||
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
|
||||
GTK_SHORTCUT_SCOPE_GLOBAL);
|
||||
gtk_widget_add_controller (window, controller);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
@ -156,6 +274,22 @@ do_image_scaling (GtkWidget *do_widget)
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (open_file), widget);
|
||||
gtk_box_append (GTK_BOX (box2), button);
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_button_set_child (GTK_BUTTON (button),
|
||||
gtk_image_new_from_resource ("/org/gtk/Demo4/portland-rose-thumbnail.png"));
|
||||
gtk_widget_add_css_class (button, "image-button");
|
||||
gtk_widget_set_tooltip_text (button, "Portland Rose");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (open_portland_rose), widget);
|
||||
gtk_box_append (GTK_BOX (box2), button);
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_button_set_child (GTK_BUTTON (button),
|
||||
gtk_image_new_from_resource ("/org/gtk/Demo4/large-image-thumbnail.png"));
|
||||
gtk_widget_add_css_class (button, "image-button");
|
||||
gtk_widget_set_tooltip_text (button, "Large image");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (open_large_image), widget);
|
||||
gtk_box_append (GTK_BOX (box2), button);
|
||||
|
||||
button = gtk_button_new_from_icon_name ("object-rotate-right-symbolic");
|
||||
gtk_widget_set_tooltip_text (button, "Rotate");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (rotate), widget);
|
||||
@ -191,7 +325,9 @@ do_image_scaling (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
{
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
BIN
demos/gtk-demo/large-image-thumbnail.png
Normal file
BIN
demos/gtk-demo/large-image-thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
demos/gtk-demo/large-image.png
Normal file
BIN
demos/gtk-demo/large-image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 622 KiB |
BIN
demos/gtk-demo/portland-rose-thumbnail.png
Normal file
BIN
demos/gtk-demo/portland-rose-thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
File diff suppressed because it is too large
Load Diff
@ -110,6 +110,16 @@ void gdk_memory_convert_color_state (guchar
|
||||
GdkColorState *dest_color_state,
|
||||
gsize width,
|
||||
gsize height);
|
||||
void gdk_memory_mipmap (guchar *dest,
|
||||
gsize dest_stride,
|
||||
GdkMemoryFormat dest_format,
|
||||
const guchar *src,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
gsize src_width,
|
||||
gsize src_height,
|
||||
guint lod_level,
|
||||
gboolean linear);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
86
gdk/gdkparalleltask.c
Normal file
86
gdk/gdkparalleltask.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright © 2024 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkparalleltaskprivate.h"
|
||||
|
||||
typedef struct _TaskData TaskData;
|
||||
|
||||
struct _TaskData
|
||||
{
|
||||
GdkTaskFunc task_func;
|
||||
gpointer task_data;
|
||||
int n_running_tasks;
|
||||
};
|
||||
|
||||
static void
|
||||
gdk_parallel_task_thread_func (gpointer data,
|
||||
gpointer unused)
|
||||
{
|
||||
TaskData *task = data;
|
||||
|
||||
task->task_func (task->task_data);
|
||||
|
||||
g_atomic_int_add (&task->n_running_tasks, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_parallel_task_run:
|
||||
* @task_func: the function to spawn
|
||||
* @task_data: data to pass to the function
|
||||
*
|
||||
* Spawns the given function in many threads.
|
||||
* Once all functions have exited, this function returns.
|
||||
**/
|
||||
void
|
||||
gdk_parallel_task_run (GdkTaskFunc task_func,
|
||||
gpointer task_data)
|
||||
{
|
||||
static GThreadPool *pool;
|
||||
TaskData task = {
|
||||
.task_func = task_func,
|
||||
.task_data = task_data,
|
||||
};
|
||||
int i, n_tasks;
|
||||
|
||||
if (g_once_init_enter (&pool))
|
||||
{
|
||||
GThreadPool *the_pool = g_thread_pool_new (gdk_parallel_task_thread_func,
|
||||
NULL,
|
||||
MAX (2, g_get_num_processors ()) - 1,
|
||||
FALSE,
|
||||
NULL);
|
||||
g_once_init_leave (&pool, the_pool);
|
||||
}
|
||||
|
||||
n_tasks = g_get_num_processors ();
|
||||
task.n_running_tasks = n_tasks;
|
||||
/* Start with 1 because we run 1 task ourselves */
|
||||
for (i = 1; i < n_tasks; i++)
|
||||
{
|
||||
g_thread_pool_push (pool, &task, NULL);
|
||||
}
|
||||
|
||||
gdk_parallel_task_thread_func (&task, NULL);
|
||||
|
||||
while (g_atomic_int_get (&task.n_running_tasks) > 0)
|
||||
g_thread_yield ();
|
||||
}
|
||||
|
32
gdk/gdkparalleltaskprivate.h
Normal file
32
gdk/gdkparalleltaskprivate.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright © 2024 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef void (* GdkTaskFunc) (gpointer user_data);
|
||||
|
||||
void gdk_parallel_task_run (GdkTaskFunc task_func,
|
||||
gpointer task_data);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -33,7 +33,18 @@
|
||||
*
|
||||
* `GdkTexture` is an immutable object: That means you cannot change
|
||||
* anything about it other than increasing the reference count via
|
||||
* [method@GObject.Object.ref], and consequently, it is a thread-safe object.
|
||||
* [method@GObject.Object.ref], and consequently, it is a threadsafe object.
|
||||
*
|
||||
* GDK provides a number of threadsafe texture loading functions:
|
||||
* [ctor@Gdk.Texture.new_from_resource],
|
||||
* [ctor@Gdk.Texture.new_from_bytes],
|
||||
* [ctor@Gdk.Texture.new_from_file],
|
||||
* [ctor@Gdk.Texture.new_from_filename],
|
||||
* [ctor@Gdk.Texture.new_for_pixbuf]. Note that these are meant for loading
|
||||
* icons and resources that are shipped with the toolkit or application. It
|
||||
* is recommended that you use a dedicated image loading framework such as
|
||||
* [glycin](https://lib.rs/crates/glycin), if you need to load untrusted image
|
||||
* data.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -52,23 +52,24 @@ gdk_public_sources = files([
|
||||
'gdkmonitor.c',
|
||||
'gdkpaintable.c',
|
||||
'gdkpango.c',
|
||||
'gdkparalleltask.c',
|
||||
'gdkpipeiostream.c',
|
||||
'gdkpopup.c',
|
||||
'gdkpopuplayout.c',
|
||||
'gdkprofiler.c',
|
||||
'gdkrectangle.c',
|
||||
'gdkrgba.c',
|
||||
'gdkseat.c',
|
||||
'gdkseatdefault.c',
|
||||
'gdksnapshot.c',
|
||||
'gdktexture.c',
|
||||
'gdktexturedownloader.c',
|
||||
'gdkvulkancontext.c',
|
||||
'gdksubsurface.c',
|
||||
'gdksurface.c',
|
||||
'gdkpopuplayout.c',
|
||||
'gdkprofiler.c',
|
||||
'gdkpopup.c',
|
||||
'gdktexture.c',
|
||||
'gdktexturedownloader.c',
|
||||
'gdktoplevellayout.c',
|
||||
'gdktoplevelsize.c',
|
||||
'gdktoplevel.c',
|
||||
'gdkvulkancontext.c',
|
||||
'loaders/gdkpng.c',
|
||||
'loaders/gdktiff.c',
|
||||
'loaders/gdkjpeg.c',
|
||||
|
@ -537,6 +537,8 @@ struct _GskGpuCachedTile
|
||||
GskGpuCached parent;
|
||||
|
||||
GdkTexture *texture;
|
||||
guint lod_level;
|
||||
gboolean lod_linear;
|
||||
gsize tile_id;
|
||||
|
||||
/* atomic */ int use_count; /* We count the use by the cache (via the linked
|
||||
@ -630,7 +632,10 @@ gsk_gpu_cached_tile_hash (gconstpointer data)
|
||||
{
|
||||
const GskGpuCachedTile *self = data;
|
||||
|
||||
return g_direct_hash (self->texture) ^ self->tile_id;
|
||||
return g_direct_hash (self->texture) ^
|
||||
self->tile_id ^
|
||||
(self->lod_level << 24) ^
|
||||
(self->lod_linear << 31);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -641,12 +646,16 @@ gsk_gpu_cached_tile_equal (gconstpointer data_a,
|
||||
const GskGpuCachedTile *b = data_b;
|
||||
|
||||
return a->texture == b->texture &&
|
||||
a->lod_level == b->lod_level &&
|
||||
a->lod_linear == b->lod_linear &&
|
||||
a->tile_id == b->tile_id;
|
||||
}
|
||||
|
||||
static GskGpuCachedTile *
|
||||
gsk_gpu_cached_tile_new (GskGpuCache *cache,
|
||||
GdkTexture *texture,
|
||||
guint lod_level,
|
||||
gboolean lod_linear,
|
||||
guint tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state)
|
||||
@ -655,6 +664,8 @@ gsk_gpu_cached_tile_new (GskGpuCache *cache,
|
||||
|
||||
self = gsk_gpu_cached_new (cache, &GSK_GPU_CACHED_TILE_CLASS);
|
||||
self->texture = texture;
|
||||
self->lod_level = lod_level;
|
||||
self->lod_linear = lod_linear;
|
||||
self->tile_id = tile_id;
|
||||
self->image = g_object_ref (image);
|
||||
self->color_state = gdk_color_state_ref (color_state);
|
||||
@ -673,14 +684,18 @@ gsk_gpu_cached_tile_new (GskGpuCache *cache,
|
||||
}
|
||||
|
||||
GskGpuImage *
|
||||
gsk_gpu_cache_lookup_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
gsize tile_id,
|
||||
GdkColorState **out_color_state)
|
||||
gsk_gpu_cache_lookup_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
guint lod_level,
|
||||
GskScalingFilter lod_filter,
|
||||
gsize tile_id,
|
||||
GdkColorState **out_color_state)
|
||||
{
|
||||
GskGpuCachedTile *tile;
|
||||
GskGpuCachedTile lookup = {
|
||||
.texture = texture,
|
||||
.lod_level = lod_level,
|
||||
.lod_linear = lod_filter == GSK_SCALING_FILTER_TRILINEAR,
|
||||
.tile_id = tile_id
|
||||
};
|
||||
|
||||
@ -699,15 +714,23 @@ gsk_gpu_cache_lookup_tile (GskGpuCache *self,
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_cache_cache_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
guint tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state)
|
||||
gsk_gpu_cache_cache_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
guint lod_level,
|
||||
GskScalingFilter lod_filter,
|
||||
gsize tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state)
|
||||
{
|
||||
GskGpuCachedTile *tile;
|
||||
|
||||
tile = gsk_gpu_cached_tile_new (self, texture, tile_id, image, color_state);
|
||||
tile = gsk_gpu_cached_tile_new (self,
|
||||
texture,
|
||||
lod_level,
|
||||
lod_filter == GSK_SCALING_FILTER_TRILINEAR,
|
||||
tile_id,
|
||||
image,
|
||||
color_state);
|
||||
|
||||
gsk_gpu_cached_use (self, (GskGpuCached *) tile);
|
||||
}
|
||||
|
@ -77,11 +77,15 @@ void gsk_gpu_cache_cache_texture_image (GskGpuC
|
||||
GdkColorState *color_state);
|
||||
GskGpuImage * gsk_gpu_cache_lookup_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
guint lod_level,
|
||||
GskScalingFilter lod_filter,
|
||||
gsize tile_id,
|
||||
GdkColorState **out_color_state);
|
||||
void gsk_gpu_cache_cache_tile (GskGpuCache *self,
|
||||
GdkTexture *texture,
|
||||
guint tile_id,
|
||||
guint lod_level,
|
||||
GskScalingFilter lod_filter,
|
||||
gsize tile_id,
|
||||
GskGpuImage *image,
|
||||
GdkColorState *color_state);
|
||||
|
||||
|
@ -107,7 +107,7 @@ gsk_gpu_frame_default_upload_texture (GskGpuFrame *self,
|
||||
{
|
||||
GskGpuImage *image;
|
||||
|
||||
image = gsk_gpu_upload_texture_op_try (self, with_mipmap, texture);
|
||||
image = gsk_gpu_upload_texture_op_try (self, with_mipmap, 0, GSK_SCALING_FILTER_NEAREST, texture);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
@ -1964,18 +1964,26 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
gboolean need_mipmap;
|
||||
GdkMemoryTexture *memtex;
|
||||
GdkTexture *subtex;
|
||||
float scaled_tile_width, scaled_tile_height;
|
||||
float scale_factor, scaled_tile_width, scaled_tile_height;
|
||||
gsize tile_size, width, height, n_width, n_height, x, y;
|
||||
graphene_rect_t clip_bounds;
|
||||
guint lod_level;
|
||||
|
||||
device = gsk_gpu_frame_get_device (self->frame);
|
||||
cache = gsk_gpu_device_get_cache (device);
|
||||
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);
|
||||
tile_size = gsk_gpu_device_get_tile_size (device);
|
||||
scale_factor = MIN (width / MAX (tile_size, texture_bounds->size.width),
|
||||
height / MAX (tile_size, texture_bounds->size.height));
|
||||
if (scale_factor <= 1.0)
|
||||
lod_level = 0;
|
||||
else
|
||||
lod_level = floor (log2f (scale_factor));
|
||||
tile_size <<= lod_level;
|
||||
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;
|
||||
@ -1994,7 +2002,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
!gsk_rect_intersects (&clip_bounds, &tile_rect))
|
||||
continue;
|
||||
|
||||
tile = gsk_gpu_cache_lookup_tile (cache, texture, y * n_width + x, &tile_cs);
|
||||
tile = gsk_gpu_cache_lookup_tile (cache, texture, lod_level, scaling_filter, y * n_width + x, &tile_cs);
|
||||
|
||||
if (tile == NULL)
|
||||
{
|
||||
@ -2005,7 +2013,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
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);
|
||||
tile = gsk_gpu_upload_texture_op_try (self->frame, need_mipmap, lod_level, scaling_filter, subtex);
|
||||
g_object_unref (subtex);
|
||||
if (tile == NULL)
|
||||
{
|
||||
@ -2021,7 +2029,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
g_assert (tile_cs);
|
||||
}
|
||||
|
||||
gsk_gpu_cache_cache_tile (cache, texture, y * n_width + x, tile, tile_cs);
|
||||
gsk_gpu_cache_cache_tile (cache, texture, lod_level, scaling_filter, y * n_width + x, tile, tile_cs);
|
||||
}
|
||||
|
||||
if (need_mipmap &&
|
||||
@ -2029,7 +2037,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
{
|
||||
tile = gsk_gpu_copy_image (self->frame, self->ccs, tile, tile_cs, TRUE);
|
||||
tile_cs = self->ccs;
|
||||
gsk_gpu_cache_cache_tile (cache, texture, y * n_width + x, tile, tile_cs);
|
||||
gsk_gpu_cache_cache_tile (cache, texture, lod_level, scaling_filter, 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);
|
||||
|
@ -214,6 +214,8 @@ struct _GskGpuUploadTextureOp
|
||||
GskGpuImage *image;
|
||||
GskGpuBuffer *buffer;
|
||||
GdkTexture *texture;
|
||||
guint lod_level;
|
||||
GskScalingFilter lod_filter;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -236,6 +238,10 @@ gsk_gpu_upload_texture_op_print (GskGpuOp *op,
|
||||
|
||||
gsk_gpu_print_op (string, indent, "upload-texture");
|
||||
gsk_gpu_print_image (string, self->image);
|
||||
if (self->lod_level > 0)
|
||||
g_string_append_printf (string, " @%ux %s",
|
||||
1 << self->lod_level,
|
||||
self->lod_filter == GSK_SCALING_FILTER_TRILINEAR ? "linear" : "nearest");
|
||||
gsk_gpu_print_newline (string);
|
||||
}
|
||||
|
||||
@ -248,9 +254,31 @@ gsk_gpu_upload_texture_op_draw (GskGpuOp *op,
|
||||
GdkTextureDownloader *downloader;
|
||||
|
||||
downloader = gdk_texture_downloader_new (self->texture);
|
||||
gdk_texture_downloader_set_format (downloader, gsk_gpu_image_get_format (self->image));
|
||||
gdk_texture_downloader_set_color_state (downloader, gdk_texture_get_color_state (self->texture));
|
||||
gdk_texture_downloader_download_into (downloader, data, stride);
|
||||
if (self->lod_level == 0)
|
||||
{
|
||||
gdk_texture_downloader_set_format (downloader, gsk_gpu_image_get_format (self->image));
|
||||
gdk_texture_downloader_download_into (downloader, data, stride);
|
||||
}
|
||||
else
|
||||
{
|
||||
GBytes *bytes;
|
||||
gsize src_stride;
|
||||
|
||||
gdk_texture_downloader_set_format (downloader, gdk_texture_get_format (self->texture));
|
||||
bytes = gdk_texture_downloader_download_bytes (downloader, &src_stride);
|
||||
gdk_memory_mipmap (data,
|
||||
stride,
|
||||
gsk_gpu_image_get_format (self->image),
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
src_stride,
|
||||
gdk_texture_get_format (self->texture),
|
||||
gdk_texture_get_width (self->texture),
|
||||
gdk_texture_get_height (self->texture),
|
||||
self->lod_level,
|
||||
self->lod_filter == GSK_SCALING_FILTER_TRILINEAR ? TRUE : FALSE);
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
gdk_texture_downloader_free (downloader);
|
||||
}
|
||||
|
||||
@ -296,9 +324,11 @@ static const GskGpuOpClass GSK_GPU_UPLOAD_TEXTURE_OP_CLASS = {
|
||||
};
|
||||
|
||||
GskGpuImage *
|
||||
gsk_gpu_upload_texture_op_try (GskGpuFrame *frame,
|
||||
gboolean with_mipmap,
|
||||
GdkTexture *texture)
|
||||
gsk_gpu_upload_texture_op_try (GskGpuFrame *frame,
|
||||
gboolean with_mipmap,
|
||||
guint lod_level,
|
||||
GskScalingFilter lod_filter,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
GskGpuUploadTextureOp *self;
|
||||
GskGpuImage *image;
|
||||
@ -311,8 +341,8 @@ gsk_gpu_upload_texture_op_try (GskGpuFrame *frame,
|
||||
format,
|
||||
gdk_memory_format_alpha (format) != GDK_MEMORY_ALPHA_PREMULTIPLIED &&
|
||||
gdk_color_state_get_no_srgb_tf (gdk_texture_get_color_state (texture)) != NULL,
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
(gdk_texture_get_width (texture) + (1 << lod_level) - 1) >> lod_level,
|
||||
(gdk_texture_get_height (texture) + (1 << lod_level) - 1) >> lod_level);
|
||||
if (image == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -343,6 +373,8 @@ gsk_gpu_upload_texture_op_try (GskGpuFrame *frame,
|
||||
self = (GskGpuUploadTextureOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_UPLOAD_TEXTURE_OP_CLASS);
|
||||
|
||||
self->texture = g_object_ref (texture);
|
||||
self->lod_level = lod_level;
|
||||
self->lod_filter = lod_filter;
|
||||
self->image = image;
|
||||
|
||||
return g_object_ref (self->image);
|
||||
|
@ -11,6 +11,8 @@ typedef void (* GskGpuCairoFunc) (gpointe
|
||||
|
||||
GskGpuImage * gsk_gpu_upload_texture_op_try (GskGpuFrame *frame,
|
||||
gboolean with_mipmap,
|
||||
guint lod_level,
|
||||
GskScalingFilter lod_filter,
|
||||
GdkTexture *texture);
|
||||
|
||||
GskGpuImage * gsk_gpu_upload_cairo_op (GskGpuFrame *frame,
|
||||
|
Loading…
Reference in New Issue
Block a user