glrenderer: Handle filters differently

Instead of uploading a texture once per filter, ensure textures are
uploaded as little as possible and use samplers instead to switch
different filters.

Sometimes we have to reupload a texture unfortunately, when it is an
external one and we want to create mipmaps.
This commit is contained in:
Benjamin Otte 2023-03-17 06:14:53 +01:00 committed by Matthias Clasen
parent b59d45c5c7
commit b5345b7f25
12 changed files with 221 additions and 195 deletions

View File

@ -44,6 +44,7 @@ gsk_gl_attachment_state_new (void)
self->textures[i].id = 0;
self->textures[i].changed = FALSE;
self->textures[i].initial = TRUE;
self->textures[i].sampler = sampler_index (GL_LINEAR, GL_LINEAR);
}
return self;
@ -65,9 +66,12 @@ void
gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self,
GLenum target,
GLenum texture,
guint id)
guint id,
GLint min_filter,
GLint mag_filter)
{
GskGLBindTexture *attach;
unsigned int sampler;
g_assert (self != NULL);
g_assert (target == GL_TEXTURE_1D ||
@ -77,12 +81,16 @@ gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self,
attach = &self->textures[texture - GL_TEXTURE0];
if (attach->target != target || attach->texture != texture || attach->id != id)
sampler = sampler_index (min_filter, mag_filter);
if (attach->target != target || attach->texture != texture || attach->id != id ||
attach->sampler != sampler)
{
attach->target = target;
attach->texture = texture;
attach->id = id;
attach->initial = FALSE;
attach->sampler = sampler;
if (attach->changed == FALSE)
{

View File

@ -29,11 +29,37 @@ typedef struct _GskGLAttachmentState GskGLAttachmentState;
typedef struct _GskGLBindFramebuffer GskGLBindFramebuffer;
typedef struct _GskGLBindTexture GskGLBindTexture;
#define GSK_GL_N_FILTERS 3
static inline guint
filter_index (GLint filter)
{
switch (filter)
{
case GL_LINEAR:
return 0;
case GL_NEAREST:
return 1;
case GL_LINEAR_MIPMAP_LINEAR:
return 2;
default:
g_assert_not_reached ();
}
}
static inline guint
sampler_index (GLint min_filter,
GLint mag_filter)
{
return filter_index (min_filter) * GSK_GL_N_FILTERS + filter_index (mag_filter);
}
struct _GskGLBindTexture
{
guint changed : 1;
guint initial : 1;
GLenum target : 30;
GLenum target : 26;
guint sampler : 4;
GLenum texture;
guint id;
};
@ -62,7 +88,9 @@ void gsk_gl_attachment_state_unref (GskGLAttachmentS
void gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self,
GLenum target,
GLenum texture,
guint id);
guint id,
GLint min_filter,
GLint mag_filter);
void gsk_gl_attachment_state_bind_framebuffer (GskGLAttachmentState *self,
guint id);

View File

@ -247,6 +247,16 @@ will_ignore_batch (GskGLCommandQueue *self)
return TRUE;
}
static inline GLint
filter_from_index (guint index)
{
GLint filters[3] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR };
g_assert (index < GSK_GL_N_FILTERS);
return filters[index];
}
static inline guint
snapshot_attachments (const GskGLAttachmentState *state,
GskGLCommandBinds *array)
@ -260,6 +270,7 @@ snapshot_attachments (const GskGLAttachmentState *state,
{
bind[count].id = state->textures[i].id;
bind[count].texture = state->textures[i].texture;
bind[count].sampler = state->textures[i].sampler;
count++;
}
}
@ -400,6 +411,8 @@ gsk_gl_command_queue_dispose (GObject *object)
g_clear_pointer (&self->attachments, gsk_gl_attachment_state_unref);
g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_unref);
glDeleteSamplers (G_N_ELEMENTS (self->samplers), self->samplers);
gsk_gl_command_batches_clear (&self->batches);
gsk_gl_command_binds_clear (&self->batch_binds);
gsk_gl_command_uniforms_clear (&self->batch_uniforms);
@ -434,6 +447,7 @@ gsk_gl_command_queue_new (GdkGLContext *context,
GskGLUniformState *uniforms)
{
GskGLCommandQueue *self;
guint i;
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
@ -466,6 +480,16 @@ gsk_gl_command_queue_new (GdkGLContext *context,
}
}
/* create the samplers */
glGenSamplers (G_N_ELEMENTS (self->samplers), self->samplers);
for (i = 0; i < G_N_ELEMENTS (self->samplers); i++)
{
glSamplerParameteri (self->samplers[i], GL_TEXTURE_MIN_FILTER, filter_from_index(i / GSK_GL_N_FILTERS));
glSamplerParameteri (self->samplers[i], GL_TEXTURE_MAG_FILTER, filter_from_index(i % GSK_GL_N_FILTERS));
glSamplerParameteri (self->samplers[i], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri (self->samplers[i], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
return g_steal_pointer (&self);
}
@ -987,6 +1011,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
guint vao_id;
guint vbo_id;
int textures[4];
int samplers[4];
int framebuffer = -1;
int next_batch_index;
int active = -1;
@ -999,6 +1024,8 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
for (guint i = 0; i < G_N_ELEMENTS (textures); i++)
textures[i] = -1;
for (guint i = 0; i < G_N_ELEMENTS (samplers); i++)
samplers[i] = -1;
gsk_gl_command_queue_sort_batches (self);
@ -1128,6 +1155,12 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
textures[bind->texture] = bind->id;
}
if (samplers[bind->texture] != bind->sampler)
{
glBindSampler (bind->texture, self->samplers[bind->sampler]);
samplers[bind->texture] = bind->sampler;
}
bind++;
}
@ -1261,8 +1294,6 @@ gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
guint *out_fbo_id,
guint *out_texture_id)
{
@ -1276,9 +1307,8 @@ gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self,
g_assert (out_texture_id != NULL);
texture_id = gsk_gl_command_queue_create_texture (self,
width, height,
format,
min_filter, mag_filter);
width, height,
format);
if (texture_id == -1)
{
@ -1303,9 +1333,7 @@ int
gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter)
int format)
{
GLuint texture_id = 0;
@ -1321,9 +1349,9 @@ gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture_id);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@ -1449,9 +1477,7 @@ gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self,
int
gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture,
int min_filter,
int mag_filter)
GdkTexture *texture)
{
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
cairo_surface_t *surface = NULL;
@ -1460,7 +1486,6 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
g_assert (!GDK_IS_GL_TEXTURE (texture));
g_assert (mag_filter == GL_LINEAR || mag_filter == GL_NEAREST);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
@ -1472,7 +1497,7 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
width = MIN (width, self->max_texture_size);
height = MIN (height, self->max_texture_size);
}
texture_id = gsk_gl_command_queue_create_texture (self, width, height, GL_RGBA8, min_filter, mag_filter);
texture_id = gsk_gl_command_queue_create_texture (self, width, height, GL_RGBA8);
if (texture_id == -1)
return texture_id;
@ -1484,9 +1509,6 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
gsk_gl_command_queue_do_upload_texture (self, texture);
if (min_filter == GL_LINEAR_MIPMAP_LINEAR)
glGenerateMipmap (GL_TEXTURE_2D);
/* Restore previous texture state if any */
if (self->attachments->textures[0].id > 0)
glBindTexture (self->attachments->textures[0].target,

View File

@ -53,10 +53,12 @@ typedef struct _GskGLCommandBind
* texture will be placed into. We always use GL_TEXTURE_2D so we don't
* waste any bits here to indicate that.
*/
guint texture : 5;
guint texture : 4;
guint sampler : 4;
/* The identifier for the texture created with glGenTextures(). */
guint id : 27;
guint id: 24;
} GskGLCommandBind;
G_STATIC_ASSERT (sizeof (GskGLCommandBind) == 4);
@ -225,6 +227,13 @@ struct _GskGLCommandQueue
*/
GskGLCommandUniforms batch_uniforms;
/* Array of samplers that we use for mag/min filter handling. It is indexed
* by the sampler_index() function.
* Note that when samplers are not supported (hello GLES), we fall back to
* setting the texture filter, but that needs to be done for every texture.
*/
GLuint samplers[GSK_GL_N_FILTERS * GSK_GL_N_FILTERS];
/* Discovered max texture size when loading the command queue so that we
* can either scale down or slice textures to fit within this size. Assumed
* to be both height and width.
@ -281,22 +290,16 @@ void gsk_gl_command_queue_execute (GskGLCommandQueue
const cairo_region_t *scissor,
guint default_framebuffer);
int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture,
int min_filter,
int mag_filter);
GdkTexture *texture);
int gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter);
int format);
guint gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self);
gboolean gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
guint *out_fbo_id,
guint *out_texture_id);
void gsk_gl_command_queue_delete_program (GskGLCommandQueue *self,

View File

@ -59,8 +59,7 @@ texture_key_hash (gconstpointer v)
return GPOINTER_TO_SIZE (k->pointer) ^
((scale_x << 8) |
(scale_y << 6) |
(k->filter << 1) |
(scale_y << 4) |
k->pointer_is_child);
}
@ -74,7 +73,6 @@ texture_key_equal (gconstpointer v1,
return k1->pointer == k2->pointer &&
k1->scale_x == k2->scale_x &&
k1->scale_y == k2->scale_y &&
k1->filter == k2->filter &&
k1->pointer_is_child == k2->pointer_is_child &&
(!k1->pointer_is_child || memcmp (&k1->parent_rect, &k2->parent_rect, sizeof k1->parent_rect) == 0);
}
@ -692,8 +690,7 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
* gsk_gl_driver_load_texture:
* @self: a `GdkTexture`
* @texture: a `GdkTexture`
* @min_filter: GL_NEAREST or GL_LINEAR
* @mag_filter: GL_NEAREST or GL_LINEAR
* @ensure_mipmap: Mipmaps for this texture must exist for downscaling
*
* Loads a `GdkTexture` by uploading the contents to the GPU when
* necessary. If @texture is a `GdkGLTexture`, it can be used without
@ -714,8 +711,7 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
guint
gsk_gl_driver_load_texture (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter)
gboolean ensure_mipmap)
{
GdkGLContext *context;
GdkMemoryTexture *downloaded_texture;
@ -723,7 +719,6 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
guint texture_id;
int height;
int width;
int format;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
@ -731,9 +726,23 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
context = self->command_queue->context;
format = GL_RGBA8;
texture_id = 0;
downloaded_texture = NULL;
if (GDK_IS_GL_TEXTURE (texture) && min_filter == GL_LINEAR && mag_filter == GL_LINEAR)
t = gdk_texture_get_render_data (texture, self);
if (t && t->texture_id)
{
if (ensure_mipmap & !t->has_mipmap)
{
glBindTexture (GL_TEXTURE_2D, t->texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
t->has_mipmap = TRUE;
}
return t->texture_id;
}
if (GDK_IS_GL_TEXTURE (texture) && !ensure_mipmap)
{
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
@ -743,42 +752,35 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
/* A GL texture from the same GL context is a simple task... */
return gdk_gl_texture_get_id (gl_texture);
}
else
{
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
}
}
else
if (texture_id == 0)
{
if ((t = gdk_texture_get_render_data (texture, self)))
{
if (t->min_filter == min_filter && t->mag_filter == mag_filter && t->texture_id)
return t->texture_id;
}
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
}
/* The download_texture() call may have switched the GL context. Make sure
* the right context is at work again.
*/
gdk_gl_context_make_current (context);
/* The download_texture() call may have switched the GL context. Make sure
* the right context is at work again.
*/
gdk_gl_context_make_current (context);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, GDK_TEXTURE (downloaded_texture));
}
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
GDK_TEXTURE (downloaded_texture),
min_filter,
mag_filter);
t = gsk_gl_texture_new (texture_id,
width, height, format, min_filter, mag_filter,
self->current_frame_id);
width, height,
self->current_frame_id);
if (ensure_mipmap)
{
glBindTexture (GL_TEXTURE_2D, t->texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
t->has_mipmap = TRUE;
}
g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t);
gdk_texture_clear_render_data (texture);
if (gdk_texture_set_render_data (texture, self, t, gsk_gl_texture_destroyed))
t->user = texture;
@ -787,7 +789,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
g_clear_object (&downloaded_texture);
return texture_id;
return t->texture_id;
}
/**
@ -796,8 +798,6 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
* @width: the width of the texture
* @height: the height of the texture
* @format: format for the texture
* @min_filter: GL_NEAREST or GL_LINEAR
* @mag_filter: GL_NEAREST or GL_FILTER
*
* Creates a new texture immediately that can be used by the caller
* to upload data, map to a framebuffer, or other uses which may
@ -815,9 +815,7 @@ GskGLTexture *
gsk_gl_driver_create_texture (GskGLDriver *self,
float width,
float height,
int format,
int min_filter,
int mag_filter)
int format)
{
GskGLTexture *texture;
guint texture_id;
@ -825,14 +823,11 @@ gsk_gl_driver_create_texture (GskGLDriver *self,
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL);
texture_id = gsk_gl_command_queue_create_texture (self->command_queue,
width, height,
format,
min_filter, mag_filter);
width, height,
format);
texture = gsk_gl_texture_new (texture_id,
width, height,
format,
min_filter, mag_filter,
self->current_frame_id);
width, height,
self->current_frame_id);
g_hash_table_insert (self->textures,
GUINT_TO_POINTER (texture->texture_id),
texture);
@ -878,8 +873,6 @@ gsk_gl_driver_release_texture (GskGLDriver *self,
* @width: the width for the render target
* @height: the height for the render target
* @format: the format to use
* @min_filter: the min filter to use for the texture
* @mag_filter: the mag filter to use for the texture
* @out_render_target: (out): a location for the render target
*
* Creates a new render target which contains a framebuffer and a texture
@ -900,8 +893,6 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
GskGLRenderTarget **out_render_target)
{
guint framebuffer_id;
@ -919,9 +910,7 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
GskGLRenderTarget *render_target = g_ptr_array_index (self->render_targets, i-1);
if (render_target->width == width &&
render_target->height == height &&
render_target->min_filter == min_filter &&
render_target->mag_filter == mag_filter)
render_target->height == height)
{
*out_render_target = g_ptr_array_steal_index_fast (self->render_targets, i-1);
return TRUE;
@ -933,14 +922,11 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
if (gsk_gl_command_queue_create_render_target (self->command_queue,
width, height,
format,
min_filter, mag_filter,
&framebuffer_id, &texture_id))
{
GskGLRenderTarget *render_target;
render_target = g_new0 (GskGLRenderTarget, 1);
render_target->min_filter = min_filter;
render_target->mag_filter = mag_filter;
render_target->format = format;
render_target->width = width;
render_target->height = height;
@ -1001,9 +987,6 @@ gsk_gl_driver_release_render_target (GskGLDriver *self,
texture = gsk_gl_texture_new (render_target->texture_id,
render_target->width,
render_target->height,
render_target->format,
render_target->min_filter,
render_target->mag_filter,
self->current_frame_id);
g_hash_table_insert (self->textures,
GUINT_TO_POINTER (texture_id),
@ -1197,8 +1180,7 @@ gsk_gl_driver_create_command_queue (GskGLDriver *self,
void
gsk_gl_driver_add_texture_slices (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter,
gboolean ensure_mipmap,
guint min_cols,
guint min_rows,
GskGLTextureSlice **out_slices,
@ -1235,8 +1217,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
if (t)
{
if (t->n_slices == n_slices &&
t->min_filter == min_filter &&
t->mag_filter == mag_filter)
(t->has_mipmap || !ensure_mipmap))
{
*out_slices = t->slices;
*out_n_slices = t->n_slices;
@ -1264,10 +1245,13 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
subtex = gdk_memory_texture_new_subtexture (memtex,
x, y,
slice_width, slice_height);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
subtex,
min_filter, mag_filter);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, subtex);
g_object_unref (subtex);
if (ensure_mipmap)
{
glBindTexture (GL_TEXTURE_2D, texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
}
slices[slice_index].rect.x = x;
slices[slice_index].rect.y = y;
@ -1287,9 +1271,8 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
/* Allocate one Texture for the entire thing. */
t = gsk_gl_texture_new (0,
tex_width, tex_height,
GL_RGBA8,
min_filter, mag_filter,
self->current_frame_id);
t->has_mipmap = ensure_mipmap;
/* Use gsk_gl_texture_free() as destroy notify here since we are
* not inserting this GskGLTexture into self->textures!

View File

@ -61,7 +61,6 @@ typedef struct {
gconstpointer pointer;
float scale_x;
float scale_y;
int filter;
int pointer_is_child;
graphene_rect_t parent_rect; /* Valid when pointer_is_child */
} GskTextureKey;
@ -86,8 +85,6 @@ struct _GskGLRenderTarget
{
guint framebuffer_id;
guint texture_id;
int min_filter;
int mag_filter;
int format;
int width;
int height;
@ -144,8 +141,6 @@ gboolean gsk_gl_driver_create_render_target (GskGLDriver *s
int width,
int height,
int format,
int min_filter,
int mag_filter,
GskGLRenderTarget **render_target);
guint gsk_gl_driver_release_render_target (GskGLDriver *self,
GskGLRenderTarget *render_target,
@ -161,14 +156,11 @@ void gsk_gl_driver_cache_texture (GskGLDriver *s
guint texture_id);
guint gsk_gl_driver_load_texture (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter);
gboolean ensure_mipmap);
GskGLTexture * gsk_gl_driver_create_texture (GskGLDriver *self,
float width,
float height,
int format,
int min_filter,
int mag_filter);
int format);
void gsk_gl_driver_release_texture (GskGLDriver *self,
GskGLTexture *texture);
void gsk_gl_driver_release_texture_by_id (GskGLDriver *self,
@ -177,8 +169,7 @@ GskGLTexture * gsk_gl_driver_mark_texture_permanent (GskGLDriver *s
guint texture_id);
void gsk_gl_driver_add_texture_slices (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter,
gboolean ensure_mipmap,
guint min_cols,
guint min_rows,
GskGLTextureSlice **out_slices,
@ -232,8 +223,7 @@ gsk_gl_driver_lookup_texture (GskGLDriver *self,
static inline void
gsk_gl_driver_slice_texture (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter,
gboolean ensure_mipmap,
guint min_cols,
guint min_rows,
GskGLTextureSlice **out_slices,
@ -244,8 +234,7 @@ gsk_gl_driver_slice_texture (GskGLDriver *self,
t = gdk_texture_get_render_data (texture, self);
if (t && t->slices &&
t->min_filter == min_filter &&
t->mag_filter == mag_filter &&
(t->has_mipmap || !ensure_mipmap) &&
min_cols == 0 && min_rows == 0)
{
*out_slices = t->slices;
@ -253,7 +242,7 @@ gsk_gl_driver_slice_texture (GskGLDriver *self,
return;
}
gsk_gl_driver_add_texture_slices (self, texture, min_filter, mag_filter, min_cols, min_rows, out_slices, out_n_slices);
gsk_gl_driver_add_texture_slices (self, texture, ensure_mipmap, min_cols, min_rows, out_slices, out_n_slices);
}
G_END_DECLS

View File

@ -245,6 +245,29 @@ gsk_gl_program_set_uniform_color (GskGLProgram *self,
color);
}
static inline void
gsk_gl_program_set_uniform_texture_with_filter (GskGLProgram *self,
guint key,
guint stamp,
GLenum texture_target,
GLenum texture_slot,
guint texture_id,
GLint min_filter,
GLint mag_filter)
{
gsk_gl_attachment_state_bind_texture (self->driver->command_queue->attachments,
texture_target,
texture_slot,
texture_id,
min_filter,
mag_filter);
gsk_gl_uniform_state_set_texture (self->uniforms,
self->program_info,
key,
stamp,
texture_slot);
}
static inline void
gsk_gl_program_set_uniform_texture (GskGLProgram *self,
guint key,
@ -253,15 +276,14 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
GLenum texture_slot,
guint texture_id)
{
gsk_gl_attachment_state_bind_texture (self->driver->command_queue->attachments,
texture_target,
texture_slot,
texture_id);
gsk_gl_uniform_state_set_texture (self->uniforms,
self->program_info,
key,
stamp,
texture_slot);
gsk_gl_program_set_uniform_texture_with_filter (self,
key,
stamp,
texture_target,
texture_slot,
texture_id,
GL_LINEAR,
GL_LINEAR);
}
static inline void

View File

@ -379,7 +379,6 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
if (gsk_gl_driver_create_render_target (self->driver,
width, height,
format,
GL_NEAREST, GL_NEAREST,
&render_target))
{
gsk_gl_driver_begin_frame (self->driver, self->command_queue);

View File

@ -198,7 +198,6 @@ typedef struct _GskGLRenderOffscreen
guint force_offscreen : 1;
guint reset_clip : 1;
guint do_not_cache : 1;
guint linear_filter : 1;
/* Return location for whether we created a texture */
guint was_offscreen : 1;
@ -1221,7 +1220,6 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
key.pointer_is_child = FALSE;
key.scale_x = scale_x;
key.scale_y = scale_y;
key.filter = GL_NEAREST;
cached_id = gsk_gl_driver_lookup_texture (job->driver, &key);
@ -1291,8 +1289,7 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
/* Create texture to upload */
texture = gdk_texture_new_for_surface (surface);
texture_id = gsk_gl_driver_load_texture (job->driver, texture,
GL_NEAREST, GL_NEAREST);
texture_id = gsk_gl_driver_load_texture (job->driver, texture, FALSE);
if (gdk_gl_context_has_debug (job->command_queue->context))
gdk_gl_context_label_object_printf (job->command_queue->context, GL_TEXTURE, texture_id,
@ -1341,7 +1338,6 @@ blur_offscreen (GskGLRenderJob *job,
MAX (texture_to_blur_width, 1),
MAX (texture_to_blur_height, 1),
job->target_format,
GL_NEAREST, GL_NEAREST,
&pass1))
return 0;
@ -1352,7 +1348,6 @@ blur_offscreen (GskGLRenderJob *job,
texture_to_blur_width,
texture_to_blur_height,
job->target_format,
GL_NEAREST, GL_NEAREST,
&pass2))
return gsk_gl_driver_release_render_target (job->driver, pass1, FALSE);
@ -2105,13 +2100,14 @@ gsk_gl_render_job_visit_transform_node (GskGLRenderJob *job,
{
GskGLRenderOffscreen offscreen = {0};
float sx = 1, sy = 1;
gboolean linear_filter = FALSE;
offscreen.bounds = &child->bounds;
offscreen.force_offscreen = FALSE;
offscreen.reset_clip = TRUE;
if (!result_is_axis_aligned (transform, &child->bounds))
offscreen.linear_filter = TRUE;
linear_filter = TRUE;
if (category == GSK_TRANSFORM_CATEGORY_2D)
{
@ -2141,16 +2137,19 @@ gsk_gl_render_job_visit_transform_node (GskGLRenderJob *job,
if (gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen))
{
/* For non-trivial transforms, we draw everything on a texture and then
* draw the texture transformed. */
* draw the texture transformed.
*/
if (transform)
gsk_gl_render_job_push_modelview (job, transform);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id,
linear_filter ? GL_LINEAR : GL_NEAREST,
linear_filter ? GL_LINEAR : GL_NEAREST);
gsk_gl_render_job_draw_offscreen (job, &child->bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
@ -2228,7 +2227,6 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
key.pointer_is_child = FALSE;
key.scale_x = scale_x;
key.scale_y = scale_y;
key.filter = GL_NEAREST;
blurred_texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
@ -2272,7 +2270,6 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
if (!gsk_gl_driver_create_render_target (job->driver,
texture_width, texture_height,
get_target_format (job, node),
GL_NEAREST, GL_NEAREST,
&render_target))
g_assert_not_reached ();
@ -2545,7 +2542,6 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
gsk_gl_driver_create_render_target (job->driver,
texture_width, texture_height,
get_target_format (job, node),
GL_NEAREST, GL_NEAREST,
&render_target);
if (gdk_gl_context_has_debug (context))
@ -3206,7 +3202,6 @@ gsk_gl_render_job_visit_blur_node (GskGLRenderJob *job,
key.pointer_is_child = FALSE;
key.scale_x = job->scale_x;
key.scale_y = job->scale_y;
key.filter = GL_NEAREST;
offscreen.texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
cache_texture = offscreen.texture_id == 0;
@ -3515,12 +3510,10 @@ gsk_gl_render_job_visit_gl_shader_node (GskGLRenderJob *job,
static void
gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
GdkTexture *texture,
int min_filter,
int mag_filter,
gboolean ensure_mipmap,
GskGLRenderOffscreen *offscreen)
{
if (min_filter == GL_LINEAR &&
mag_filter == GL_LINEAR &&
if (!ensure_mipmap &&
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
texture->width,
texture->height) &&
@ -3534,7 +3527,7 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
}
else
{
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, min_filter, mag_filter);
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
init_full_texture_region (offscreen);
}
}
@ -3551,7 +3544,7 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
{
GskGLRenderOffscreen offscreen = {0};
gsk_gl_render_job_upload_texture (job, texture, GL_LINEAR, GL_LINEAR, &offscreen);
gsk_gl_render_job_upload_texture (job, texture, FALSE, &offscreen);
g_assert (offscreen.texture_id);
g_assert (offscreen.was_offscreen == FALSE);
@ -3576,7 +3569,7 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
GskGLTextureSlice *slices = NULL;
guint n_slices = 0;
gsk_gl_driver_slice_texture (job->driver, texture, GL_LINEAR, GL_LINEAR, 0, 0, &slices, &n_slices);
gsk_gl_driver_slice_texture (job->driver, texture, FALSE, 0, 0, &slices, &n_slices);
g_assert (slices != NULL);
g_assert (n_slices > 0);
@ -3635,7 +3628,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
int max_texture_size = job->command_queue->max_texture_size;
graphene_rect_t clip_rect;
GskGLRenderTarget *render_target;
GskGLRenderOffscreen offscreen = {0};
graphene_rect_t viewport;
graphene_rect_t prev_viewport;
graphene_matrix_t prev_projection;
@ -3661,7 +3653,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
key.parent_rect = clip_rect;
key.scale_x = 1.;
key.scale_y = 1.;
key.filter = min_filter;
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
@ -3676,7 +3667,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
(int) ceilf (clip_rect.size.width),
(int) ceilf (clip_rect.size.height),
get_target_format (job, node),
GL_LINEAR, GL_LINEAR,
&render_target))
{
gsk_gl_render_job_visit_texture (job, texture, bounds);
@ -3695,10 +3685,7 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
if G_LIKELY (texture->width <= max_texture_size &&
texture->height <= max_texture_size)
{
gsk_gl_render_job_upload_texture (job, texture, min_filter, mag_filter, &offscreen);
g_assert (offscreen.texture_id);
g_assert (offscreen.was_offscreen == FALSE);
texture_id = gsk_gl_driver_load_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR);
u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width;
v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height;
@ -3706,11 +3693,13 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height;
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id,
min_filter,
mag_filter);
gsk_gl_render_job_draw_coords (job,
0, 0, clip_rect.size.width, clip_rect.size.height,
u0, v0, u1, v1,
@ -3724,7 +3713,7 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
GskGLTextureSlice *slices = NULL;
guint n_slices = 0;
gsk_gl_driver_slice_texture (job->driver, texture, min_filter, mag_filter, 0, 0, &slices, &n_slices);
gsk_gl_driver_slice_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR, 0, 0, &slices, &n_slices);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
@ -3744,11 +3733,13 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
if (i > 0)
gsk_gl_render_job_split_draw (job);
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
slice->texture_id);
gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
slice->texture_id,
min_filter,
mag_filter);
gsk_gl_render_job_draw_coords (job,
slice_bounds.origin.x,
slice_bounds.origin.y,
@ -4049,7 +4040,6 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
{
GskTextureKey key;
guint cached_id;
int filter;
g_assert (job != NULL);
g_assert (node != NULL);
@ -4070,19 +4060,15 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
offscreen->force_offscreen == FALSE)
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
gsk_gl_render_job_upload_texture (job, texture, GL_LINEAR, GL_LINEAR, offscreen);
g_assert (offscreen->was_offscreen == FALSE);
gsk_gl_render_job_upload_texture (job, texture, FALSE, offscreen);
return TRUE;
}
filter = offscreen->linear_filter ? GL_LINEAR : GL_NEAREST;
key.pointer = node;
key.pointer_is_child = TRUE; /* Don't conflict with the child using the cache too */
key.parent_rect = *offscreen->bounds;
key.scale_x = job->scale_x;
key.scale_y = job->scale_y;
key.filter = filter;
float offset_x = job->offset_x;
float offset_y = job->offset_y;
@ -4190,7 +4176,6 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
if (!gsk_gl_driver_create_render_target (job->driver,
texture_width, texture_height,
get_target_format (job, node),
filter, filter,
&render_target))
g_assert_not_reached ();
@ -4278,7 +4263,6 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
MAX (1, job->viewport.size.width),
MAX (1, job->viewport.size.height),
job->target_format,
GL_NEAREST, GL_NEAREST,
&framebuffer_id, &texture_id))
return;

View File

@ -59,9 +59,6 @@ GskGLTexture *
gsk_gl_texture_new (guint texture_id,
int width,
int height,
int format,
int min_filter,
int mag_filter,
gint64 frame_id)
{
GskGLTexture *texture;
@ -69,9 +66,6 @@ gsk_gl_texture_new (guint texture_id,
texture = g_new0 (GskGLTexture, 1);
texture->texture_id = texture_id;
texture->link.data = texture;
texture->min_filter = min_filter;
texture->mag_filter = mag_filter;
texture->format = format;
texture->width = width;
texture->height = height;
texture->last_used_in_frame = frame_id;

View File

@ -320,7 +320,7 @@ gsk_gl_texture_library_pack_one (GskGLTextureLibrary *self,
height = MIN (height, self->driver->command_queue->max_texture_size);
}
texture = gsk_gl_driver_create_texture (self->driver, width, height, GL_RGBA8, GL_LINEAR, GL_LINEAR);
texture = gsk_gl_driver_create_texture (self->driver, width, height, GL_RGBA8);
texture->permanent = TRUE;
return texture;
@ -552,9 +552,7 @@ gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self)
atlas->texture_id = gsk_gl_command_queue_create_texture (self->driver->command_queue,
atlas->width,
atlas->height,
GL_RGBA8,
GL_LINEAR,
GL_LINEAR);
GL_RGBA8);
gdk_gl_context_label_object_printf (gdk_gl_context_get_current (),
GL_TEXTURE, atlas->texture_id,

View File

@ -65,20 +65,16 @@ struct _GskGLTexture
int width;
int height;
int min_filter;
int mag_filter;
int format;
/* Set when used by an atlas so we don't drop the texture */
guint permanent : 1;
/* we called glGenerateMipmap() for this texture */
guint has_mipmap : 1;
};
GskGLTexture * gsk_gl_texture_new (guint texture_id,
int width,
int height,
int format,
int min_filter,
int mag_filter,
gint64 frame_id);
const GskGLTextureNineSlice * gsk_gl_texture_get_nine_slice (GskGLTexture *texture,
const GskRoundedRect *outline,