glrenderer: Handle filters differently
authorBenjamin Otte <otte@redhat.com>
Fri, 17 Mar 2023 05:14:53 +0000 (06:14 +0100)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 19 Mar 2023 01:33:17 +0000 (21:33 -0400)
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.

12 files changed:
gsk/gl/gskglattachmentstate.c
gsk/gl/gskglattachmentstateprivate.h
gsk/gl/gskglcommandqueue.c
gsk/gl/gskglcommandqueueprivate.h
gsk/gl/gskgldriver.c
gsk/gl/gskgldriverprivate.h
gsk/gl/gskglprogramprivate.h
gsk/gl/gskglrenderer.c
gsk/gl/gskglrenderjob.c
gsk/gl/gskgltexture.c
gsk/gl/gskgltexturelibrary.c
gsk/gl/gskgltextureprivate.h

index b05cc975a1bacba31884567d6280a51974322fc0..f3f62cb21048c26cca305b35ff6c822a3058f84d 100644 (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)
         {
index 4052fa22c2a5cb70f541d34f03a3009ad3b996fb..e2fdb621c6c4d10d9211d4756765b50e83f21f21 100644 (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);
 
index 39917877ad9b4150c58f780752ed37e973ac5da2..4352ec29dadbb299c8e983cac7f2e31602099e5a 100644 (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,
index 48911305a8ba8c3f5936c28a24238fecd2c67c22..d10d25a66150a674b12bbe629fe9bd2be927e53c 100644 (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,
index 39b987a9cdb3823260b811e0d9f823b3345f282a..da97f301671e442f9654b595fa4d03246379660b 100644 (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 ((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!
index 11cfbe4d52684df9ef63899ef51bff5ca2345555..25f1ff6399374ae1eed7f767618abfd23ce9ab54 100644 (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
index 7693ed9a62c2662dd9fdfb992bcd0b335cc8f911..4947fb1a321ded28c7942c916c0cfa5a58e28903 100644 (file)
@@ -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,
index 9ed6a655bcf84acff7d49f44a1fe4700fcb20386..d43a4edfa70aa3b35ef9e53909cdd8830adbf109 100644 (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);
index 8fbc06ab358aff3da7a1eef5aee9495ade67ab39..343365b8a63058e99ba0cdeb2cc1d03801170cb5 100644 (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;
 
index c6dfa98ba79ee6f3a7e048d7b781a5d4a054f5fa..a578e80358501145ac2b576ec9b49f5364960c55 100644 (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;
index a1cf4c1b121002ace1d82e32f70ab79d47616c75..45ac94692e39fb77c48ba9cb63fdccae0b261b76 100644 (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,
index c8605cec27b8b7a7c49d2d3e5f4631c4fe9d65cd..c3813f5e29bb43902bf7d087a02666ddf6d44443 100644 (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,