From b5345b7f25d3a721a396c8bb032c1bb8ca595ede Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 17 Mar 2023 06:14:53 +0100 Subject: [PATCH] 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. --- gsk/gl/gskglattachmentstate.c | 12 ++- gsk/gl/gskglattachmentstateprivate.h | 32 ++++++- gsk/gl/gskglcommandqueue.c | 60 ++++++++----- gsk/gl/gskglcommandqueueprivate.h | 23 ++--- gsk/gl/gskgldriver.c | 121 ++++++++++++--------------- gsk/gl/gskgldriverprivate.h | 23 ++--- gsk/gl/gskglprogramprivate.h | 36 ++++++-- gsk/gl/gskglrenderer.c | 1 - gsk/gl/gskglrenderjob.c | 84 ++++++++----------- gsk/gl/gskgltexture.c | 6 -- gsk/gl/gskgltexturelibrary.c | 6 +- gsk/gl/gskgltextureprivate.h | 8 +- 12 files changed, 219 insertions(+), 193 deletions(-) diff --git a/gsk/gl/gskglattachmentstate.c b/gsk/gl/gskglattachmentstate.c index b05cc975a1..f3f62cb210 100644 --- a/gsk/gl/gskglattachmentstate.c +++ b/gsk/gl/gskglattachmentstate.c @@ -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) { diff --git a/gsk/gl/gskglattachmentstateprivate.h b/gsk/gl/gskglattachmentstateprivate.h index 4052fa22c2..e2fdb621c6 100644 --- a/gsk/gl/gskglattachmentstateprivate.h +++ b/gsk/gl/gskglattachmentstateprivate.h @@ -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); diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index 39917877ad..4352ec29da 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -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, diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h index 48911305a8..d10d25a661 100644 --- a/gsk/gl/gskglcommandqueueprivate.h +++ b/gsk/gl/gskglcommandqueueprivate.h @@ -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, diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c index 39b987a9cd..da97f30167 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -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 ((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; - } + if (texture_id == 0) + { 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! diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h index 11cfbe4d52..25f1ff6399 100644 --- a/gsk/gl/gskgldriverprivate.h +++ b/gsk/gl/gskgldriverprivate.h @@ -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 diff --git a/gsk/gl/gskglprogramprivate.h b/gsk/gl/gskglprogramprivate.h index 7693ed9a62..4947fb1a32 100644 --- a/gsk/gl/gskglprogramprivate.h +++ b/gsk/gl/gskglprogramprivate.h @@ -246,17 +246,21 @@ gsk_gl_program_set_uniform_color (GskGLProgram *self, } static inline void -gsk_gl_program_set_uniform_texture (GskGLProgram *self, - guint key, - guint stamp, - GLenum texture_target, - GLenum texture_slot, - guint texture_id) +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); + texture_id, + min_filter, + mag_filter); gsk_gl_uniform_state_set_texture (self->uniforms, self->program_info, key, @@ -264,6 +268,24 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self, texture_slot); } +static inline void +gsk_gl_program_set_uniform_texture (GskGLProgram *self, + guint key, + guint stamp, + GLenum texture_target, + GLenum texture_slot, + guint texture_id) +{ + gsk_gl_program_set_uniform_texture_with_filter (self, + key, + stamp, + texture_target, + texture_slot, + texture_id, + GL_LINEAR, + GL_LINEAR); +} + static inline void gsk_gl_program_set_uniform_matrix (GskGLProgram *self, guint key, diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 9ed6a655bc..d43a4edfa7 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -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); diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 8fbc06ab35..343365b8a6 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -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; diff --git a/gsk/gl/gskgltexture.c b/gsk/gl/gskgltexture.c index c6dfa98ba7..a578e80358 100644 --- a/gsk/gl/gskgltexture.c +++ b/gsk/gl/gskgltexture.c @@ -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; diff --git a/gsk/gl/gskgltexturelibrary.c b/gsk/gl/gskgltexturelibrary.c index a1cf4c1b12..45ac94692e 100644 --- a/gsk/gl/gskgltexturelibrary.c +++ b/gsk/gl/gskgltexturelibrary.c @@ -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, diff --git a/gsk/gl/gskgltextureprivate.h b/gsk/gl/gskgltextureprivate.h index c8605cec27..c3813f5e29 100644 --- a/gsk/gl/gskgltextureprivate.h +++ b/gsk/gl/gskgltextureprivate.h @@ -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, -- 2.30.2