1 #include "config.h"
2 
3 #include "gskgldriverprivate.h"
4 
5 #include "gskdebugprivate.h"
6 #include "gskprofilerprivate.h"
7 #include "gdk/gdkglcontextprivate.h"
8 #include "gdk/gdktextureprivate.h"
9 #include "gdk/gdkgltextureprivate.h"
10 #include "gdkmemorytextureprivate.h"
11 
12 #include <gdk/gdk.h>
13 #include <epoxy/gl.h>
14 
15  typedef struct {
16   GLuint fbo_id;
17   GLuint depth_stencil_id;
18 } Fbo;
19 
20 typedef struct {
21   GLuint texture_id;
22   int width;
23   int height;
24   GLuint min_filter;
25   GLuint mag_filter;
26   Fbo fbo;
27   GdkTexture *user;
28   guint in_use : 1;
29   guint permanent : 1;
30 
31   /* TODO: Make this optional and not for every texture... */
32   TextureSlice *slices;
33   guint n_slices;
34 } Texture;
35 
36 struct _GskGLDriver
37 {
38   GObject parent_instance;
39 
40   GdkGLContext *gl_context;
41   GskProfiler *profiler;
42   struct {
43     GQuark created_textures;
44     GQuark reused_textures;
45     GQuark surface_uploads;
46   } counters;
47 
48   Fbo default_fbo;
49 
50   GHashTable *textures;         /* texture_id -> Texture */
51   GHashTable *pointer_textures; /* pointer -> texture_id */
52 
53   const Texture *bound_source_texture;
54 
55   int max_texture_size;
56 
57   gboolean in_frame : 1;
58 };
59 
G_DEFINE_TYPE(GskGLDriver,gsk_gl_driver,G_TYPE_OBJECT)60 G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
61 
62 static void
63 upload_gdk_texture (GdkTexture      *source_texture,
64                     int              target,
65                     int              x_offset,
66                     int              y_offset,
67                     int              width,
68                     int              height)
69 {
70   cairo_surface_t *surface = NULL;
71   GdkMemoryFormat data_format;
72   const guchar *data;
73   gsize data_stride;
74   gsize bpp;
75 
76   g_return_if_fail (source_texture != NULL);
77   g_return_if_fail (x_offset + width <= gdk_texture_get_width (source_texture));
78   g_return_if_fail (y_offset + height <= gdk_texture_get_height (source_texture));
79 
80   /* Note: GdkGLTextures are already handled before we reach this and reused as-is */
81 
82   if (GDK_IS_MEMORY_TEXTURE (source_texture))
83     {
84       GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (source_texture);
85       data = gdk_memory_texture_get_data (memory_texture);
86       data_format = gdk_memory_texture_get_format (memory_texture);
87       data_stride = gdk_memory_texture_get_stride (memory_texture);
88     }
89   else
90     {
91       /* Fall back to downloading to a surface */
92       surface = gdk_texture_download_surface (source_texture);
93       cairo_surface_flush (surface);
94       data = cairo_image_surface_get_data (surface);
95       data_format = GDK_MEMORY_DEFAULT;
96       data_stride = cairo_image_surface_get_stride (surface);
97     }
98 
99   bpp = gdk_memory_format_bytes_per_pixel (data_format);
100 
101   gdk_gl_context_upload_texture (gdk_gl_context_get_current (),
102                                  data + x_offset * bpp + y_offset * data_stride,
103                                  width, height, data_stride,
104                                  data_format, target);
105 
106   if (surface)
107     cairo_surface_destroy (surface);
108 }
109 
110 static Texture *
texture_new(void)111 texture_new (void)
112 {
113   return g_slice_new0 (Texture);
114 }
115 
116 static inline void
fbo_clear(const Fbo * f)117 fbo_clear (const Fbo *f)
118 {
119   if (f->depth_stencil_id != 0)
120     glDeleteRenderbuffers (1, &f->depth_stencil_id);
121 
122   glDeleteFramebuffers (1, &f->fbo_id);
123 }
124 
125 static void
texture_free(gpointer data)126 texture_free (gpointer data)
127 {
128   Texture *t = data;
129   guint i;
130 
131   if (t->user)
132     gdk_texture_clear_render_data (t->user);
133 
134   if (t->fbo.fbo_id != 0)
135     fbo_clear (&t->fbo);
136 
137   if (t->texture_id != 0)
138     {
139       glDeleteTextures (1, &t->texture_id);
140     }
141   else
142     {
143       g_assert_cmpint (t->n_slices, >, 0);
144 
145       for (i = 0; i < t->n_slices; i ++)
146         glDeleteTextures (1, &t->slices[i].texture_id);
147     }
148 
149   g_slice_free (Texture, t);
150 }
151 
152 static void
gsk_gl_driver_set_texture_parameters(GskGLDriver * self,int min_filter,int mag_filter)153 gsk_gl_driver_set_texture_parameters (GskGLDriver *self,
154                                       int          min_filter,
155                                       int          mag_filter)
156 {
157   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
158   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
159 
160   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
161   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
162 }
163 
164 static void
gsk_gl_driver_finalize(GObject * gobject)165 gsk_gl_driver_finalize (GObject *gobject)
166 {
167   GskGLDriver *self = GSK_GL_DRIVER (gobject);
168 
169   gdk_gl_context_make_current (self->gl_context);
170 
171   g_clear_pointer (&self->textures, g_hash_table_unref);
172   g_clear_pointer (&self->pointer_textures, g_hash_table_unref);
173   g_clear_object (&self->profiler);
174 
175   if (self->gl_context == gdk_gl_context_get_current ())
176     gdk_gl_context_clear_current ();
177 
178   G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
179 }
180 
181 static void
gsk_gl_driver_class_init(GskGLDriverClass * klass)182 gsk_gl_driver_class_init (GskGLDriverClass *klass)
183 {
184   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
185 
186   gobject_class->finalize = gsk_gl_driver_finalize;
187 }
188 
189 static void
gsk_gl_driver_init(GskGLDriver * self)190 gsk_gl_driver_init (GskGLDriver *self)
191 {
192   self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
193 
194   self->max_texture_size = -1;
195 
196 #ifdef G_ENABLE_DEBUG
197   self->profiler = gsk_profiler_new ();
198   self->counters.created_textures = gsk_profiler_add_counter (self->profiler,
199                                                               "created_textures",
200                                                               "Textures created this frame",
201                                                               TRUE);
202   self->counters.reused_textures = gsk_profiler_add_counter (self->profiler,
203                                                              "reused_textures",
204                                                              "Textures reused this frame",
205                                                              TRUE);
206   self->counters.surface_uploads = gsk_profiler_add_counter (self->profiler,
207                                                              "surface_uploads",
208                                                              "Texture uploads from surfaces this frame",
209                                                              TRUE);
210 #endif
211 }
212 
213 GskGLDriver *
gsk_gl_driver_new(GdkGLContext * context)214 gsk_gl_driver_new (GdkGLContext *context)
215 {
216   GskGLDriver *self;
217   g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
218 
219   self = (GskGLDriver *) g_object_new (GSK_TYPE_GL_DRIVER, NULL);
220   self->gl_context = context;
221 
222   return self;
223 }
224 
225 void
gsk_gl_driver_begin_frame(GskGLDriver * self)226 gsk_gl_driver_begin_frame (GskGLDriver *self)
227 {
228   g_return_if_fail (GSK_IS_GL_DRIVER (self));
229   g_return_if_fail (!self->in_frame);
230 
231   self->in_frame = TRUE;
232 
233   if (self->max_texture_size < 0)
234     {
235       glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint *) &self->max_texture_size);
236       GSK_NOTE (OPENGL, g_message ("GL max texture size: %d", self->max_texture_size));
237     }
238 
239   glBindFramebuffer (GL_FRAMEBUFFER, 0);
240 
241   glActiveTexture (GL_TEXTURE0);
242   glBindTexture (GL_TEXTURE_2D, 0);
243 
244   glActiveTexture (GL_TEXTURE0 + 1);
245   glBindTexture (GL_TEXTURE_2D, 0);
246 
247   glBindVertexArray (0);
248   glUseProgram (0);
249 
250   glActiveTexture (GL_TEXTURE0);
251 
252 #ifdef G_ENABLE_DEBUG
253   gsk_profiler_reset (self->profiler);
254 #endif
255 }
256 
257 gboolean
gsk_gl_driver_in_frame(GskGLDriver * self)258 gsk_gl_driver_in_frame (GskGLDriver *self)
259 {
260   return self->in_frame;
261 }
262 
263 void
gsk_gl_driver_end_frame(GskGLDriver * self)264 gsk_gl_driver_end_frame (GskGLDriver *self)
265 {
266   g_return_if_fail (GSK_IS_GL_DRIVER (self));
267   g_return_if_fail (self->in_frame);
268 
269   self->bound_source_texture = NULL;
270 
271   self->default_fbo.fbo_id = 0;
272 
273 #ifdef G_ENABLE_DEBUG
274   GSK_NOTE (OPENGL,
275             g_message ("Textures created: %" G_GINT64_FORMAT "\n"
276                      " Textures reused: %" G_GINT64_FORMAT "\n"
277                      " Surface uploads: %" G_GINT64_FORMAT,
278                      gsk_profiler_counter_get (self->profiler, self->counters.created_textures),
279                      gsk_profiler_counter_get (self->profiler, self->counters.reused_textures),
280                      gsk_profiler_counter_get (self->profiler, self->counters.surface_uploads)));
281 #endif
282 
283   GSK_NOTE (OPENGL,
284             g_message ("*** Frame end: textures=%d",
285                      g_hash_table_size (self->textures)));
286 
287   self->in_frame = FALSE;
288 }
289 
290 int
gsk_gl_driver_collect_textures(GskGLDriver * self)291 gsk_gl_driver_collect_textures (GskGLDriver *self)
292 {
293   GHashTableIter iter;
294   gpointer value_p = NULL;
295   int old_size;
296 
297   g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
298   g_return_val_if_fail (!self->in_frame, 0);
299 
300   old_size = g_hash_table_size (self->textures);
301 
302   g_hash_table_iter_init (&iter, self->textures);
303   while (g_hash_table_iter_next (&iter, NULL, &value_p))
304     {
305       Texture *t = value_p;
306 
307       if (t->user || t->permanent)
308         continue;
309 
310       if (t->in_use)
311         {
312           t->in_use = FALSE;
313 
314           if (t->fbo.fbo_id != 0)
315             {
316               fbo_clear (&t->fbo);
317               t->fbo.fbo_id = 0;
318             }
319         }
320       else
321         {
322           /* Remove from self->pointer_textures. */
323           /* TODO: Is there a better way for this? */
324           if (self->pointer_textures)
325             {
326               GHashTableIter pointer_iter;
327               gpointer value;
328               gpointer p;
329 
330               g_hash_table_iter_init (&pointer_iter, self->pointer_textures);
331               while (g_hash_table_iter_next (&pointer_iter, &p, &value))
332                 {
333                   if (GPOINTER_TO_INT (value) == t->texture_id)
334                     {
335                       g_hash_table_iter_remove (&pointer_iter);
336                       break;
337                     }
338                 }
339             }
340 
341           g_hash_table_iter_remove (&iter);
342         }
343     }
344 
345   return old_size - g_hash_table_size (self->textures);
346 }
347 
348 
349 GdkGLContext *
gsk_gl_driver_get_gl_context(GskGLDriver * self)350 gsk_gl_driver_get_gl_context (GskGLDriver *self)
351 {
352   return self->gl_context;
353 }
354 
355 int
gsk_gl_driver_get_max_texture_size(GskGLDriver * self)356 gsk_gl_driver_get_max_texture_size (GskGLDriver *self)
357 {
358   if (self->max_texture_size < 0)
359     {
360       if (gdk_gl_context_get_use_es (self->gl_context))
361         return 2048;
362 
363       return 1024;
364     }
365 
366   return self->max_texture_size;
367 }
368 
369 static Texture *
gsk_gl_driver_get_texture(GskGLDriver * self,int texture_id)370 gsk_gl_driver_get_texture (GskGLDriver *self,
371                            int          texture_id)
372 {
373   Texture *t;
374 
375   if (g_hash_table_lookup_extended (self->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
376     return t;
377 
378   return NULL;
379 }
380 
381 static Texture *
create_texture(GskGLDriver * self,float fwidth,float fheight)382 create_texture (GskGLDriver *self,
383                 float        fwidth,
384                 float        fheight)
385 {
386   guint texture_id;
387   Texture *t;
388   int width = ceilf (fwidth);
389   int height = ceilf (fheight);
390 
391   g_assert (width > 0);
392   g_assert (height > 0);
393 
394   if (width > self->max_texture_size ||
395       height > self->max_texture_size)
396     {
397       g_critical ("Texture %d x %d is bigger than supported texture limit of %d; clipping...",
398                   width, height,
399                   self->max_texture_size);
400 
401       width = MIN (width, self->max_texture_size);
402       height = MIN (height, self->max_texture_size);
403     }
404 
405   glGenTextures (1, &texture_id);
406   t = texture_new ();
407   t->texture_id = texture_id;
408   t->width = width;
409   t->height = height;
410   t->min_filter = GL_NEAREST;
411   t->mag_filter = GL_NEAREST;
412   t->in_use = TRUE;
413   g_hash_table_insert (self->textures, GINT_TO_POINTER (texture_id), t);
414 #ifdef G_ENABLE_DEBUG
415   gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
416 #endif
417 
418   return t;
419 }
420 
421 static void
gsk_gl_driver_release_texture(gpointer data)422 gsk_gl_driver_release_texture (gpointer data)
423 {
424   Texture *t = data;
425 
426   t->user = NULL;
427 }
428 
429 void
gsk_gl_driver_slice_texture(GskGLDriver * self,GdkTexture * texture,TextureSlice ** out_slices,guint * out_n_slices)430 gsk_gl_driver_slice_texture (GskGLDriver   *self,
431                              GdkTexture    *texture,
432                              TextureSlice **out_slices,
433                              guint         *out_n_slices)
434 {
435   const int max_texture_size = gsk_gl_driver_get_max_texture_size (self) / 4; // XXX Too much?
436   const int cols = (texture->width / max_texture_size) + 1;
437   const int rows = (texture->height / max_texture_size) + 1;
438   int col, row;
439   int x = 0, y = 0; /* Position in the texture */
440   TextureSlice *slices;
441   Texture *tex;
442 
443   g_assert (texture->width > max_texture_size || texture->height > max_texture_size);
444 
445 
446   tex = gdk_texture_get_render_data (texture, self);
447 
448   if (tex != NULL)
449     {
450       g_assert (tex->n_slices > 0);
451       *out_slices = tex->slices;
452       *out_n_slices = tex->n_slices;
453       return;
454     }
455 
456   slices = g_new0 (TextureSlice, cols * rows);
457 
458   for (col = 0; col < cols; col ++)
459     {
460       const int slice_width = MIN (max_texture_size, texture->width - x);
461 
462       for (row = 0; row < rows; row ++)
463         {
464           const int slice_height = MIN (max_texture_size, texture->height - y);
465           const int slice_index = (col * rows) + row;
466           guint texture_id;
467 
468           glGenTextures (1, &texture_id);
469 
470 #ifdef G_ENABLE_DEBUG
471           gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
472 #endif
473           glBindTexture (GL_TEXTURE_2D, texture_id);
474           gsk_gl_driver_set_texture_parameters (self, GL_NEAREST, GL_NEAREST);
475           upload_gdk_texture (texture, GL_TEXTURE_2D, x, y, slice_width, slice_height);
476 
477 #ifdef G_ENABLE_DEBUG
478           gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
479 #endif
480 
481           slices[slice_index].rect = (GdkRectangle){x, y, slice_width, slice_height};
482           slices[slice_index].texture_id = texture_id;
483 
484           y += slice_height;
485         }
486 
487       y = 0;
488       x += slice_width;
489     }
490 
491   /* Allocate one Texture for the entire thing. */
492   tex = texture_new ();
493   tex->width = texture->width;
494   tex->height = texture->height;
495   tex->min_filter = GL_NEAREST;
496   tex->mag_filter = GL_NEAREST;
497   tex->in_use = TRUE;
498   tex->slices = slices;
499   tex->n_slices = cols * rows;
500 
501   /* Use texture_free as destroy notify here since we are not inserting this Texture
502    * into self->textures! */
503   gdk_texture_set_render_data (texture, self, tex, texture_free);
504 
505   *out_slices = slices;
506   *out_n_slices = cols * rows;
507 }
508 
509 int
gsk_gl_driver_get_texture_for_texture(GskGLDriver * self,GdkTexture * texture,int min_filter,int mag_filter)510 gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
511                                        GdkTexture  *texture,
512                                        int          min_filter,
513                                        int          mag_filter)
514 {
515   Texture *t;
516   GdkTexture *downloaded_texture = NULL;
517   GdkTexture *source_texture;
518 
519   if (GDK_IS_GL_TEXTURE (texture))
520     {
521       GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
522       GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
523 
524       if (gdk_gl_context_is_shared (self->gl_context, texture_context))
525         {
526           /* A GL texture from the same GL context is a simple task... */
527           return gdk_gl_texture_get_id (gl_texture);
528         }
529       else
530         {
531           cairo_surface_t *surface;
532 
533           /* In this case, we have to temporarily make the texture's context the current one,
534            * download its data into our context and then create a texture from it. */
535           if (texture_context)
536             gdk_gl_context_make_current (texture_context);
537 
538           surface = gdk_texture_download_surface (texture);
539           downloaded_texture = gdk_texture_new_for_surface (surface);
540           cairo_surface_destroy (surface);
541 
542           gdk_gl_context_make_current (self->gl_context);
543 
544           source_texture = downloaded_texture;
545         }
546     }
547   else
548     {
549       t = gdk_texture_get_render_data (texture, self);
550 
551       if (t)
552         {
553           if (t->min_filter == min_filter && t->mag_filter == mag_filter)
554             return t->texture_id;
555         }
556 
557       source_texture = texture;
558     }
559 
560   t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
561 
562   if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
563     t->user = texture;
564 
565   gsk_gl_driver_bind_source_texture (self, t->texture_id);
566   gsk_gl_driver_init_texture (self,
567                               t->texture_id,
568                               source_texture,
569                               min_filter,
570                               mag_filter);
571   gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
572                                       "GdkTexture<%p> %d", texture, t->texture_id);
573 
574   if (downloaded_texture)
575     g_object_unref (downloaded_texture);
576 
577   return t->texture_id;
578 }
579 
580 static guint
texture_key_hash(gconstpointer v)581 texture_key_hash (gconstpointer v)
582 {
583   const GskTextureKey *k = (GskTextureKey *)v;
584 
585   return GPOINTER_TO_UINT (k->pointer)
586          + (guint)(k->scale_x * 100)
587          + (guint)(k->scale_y * 100)
588          + (guint)k->filter * 2 +
589          + (guint)k->pointer_is_child;
590 }
591 
592 static gboolean
texture_key_equal(gconstpointer v1,gconstpointer v2)593 texture_key_equal (gconstpointer v1, gconstpointer v2)
594 {
595   const GskTextureKey *k1 = (GskTextureKey *)v1;
596   const GskTextureKey *k2 = (GskTextureKey *)v2;
597 
598   return k1->pointer == k2->pointer &&
599          k1->scale_x == k2->scale_x &&
600          k1->scale_y == k2->scale_y &&
601          k1->filter == k2->filter &&
602          k1->pointer_is_child == k2->pointer_is_child &&
603          (!k1->pointer_is_child || graphene_rect_equal (&k1->parent_rect, &k2->parent_rect));
604 }
605 
606 int
gsk_gl_driver_get_texture_for_key(GskGLDriver * self,GskTextureKey * key)607 gsk_gl_driver_get_texture_for_key (GskGLDriver   *self,
608                                    GskTextureKey *key)
609 {
610   int id = 0;
611 
612   if (G_UNLIKELY (self->pointer_textures == NULL))
613     self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
614 
615   id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, key));
616 
617   if (id != 0)
618     {
619       Texture *t;
620 
621       t = g_hash_table_lookup (self->textures, GINT_TO_POINTER (id));
622 
623       if (t != NULL)
624         t->in_use = TRUE;
625     }
626 
627   return id;
628 }
629 
630 void
gsk_gl_driver_set_texture_for_key(GskGLDriver * self,GskTextureKey * key,int texture_id)631 gsk_gl_driver_set_texture_for_key (GskGLDriver   *self,
632                                    GskTextureKey *key,
633                                    int            texture_id)
634 {
635   GskTextureKey *k;
636 
637   if (G_UNLIKELY (self->pointer_textures == NULL))
638     self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
639 
640   k = g_new (GskTextureKey, 1);
641   *k = *key;
642 
643   g_hash_table_insert (self->pointer_textures, k, GINT_TO_POINTER (texture_id));
644 }
645 
646 int
gsk_gl_driver_create_texture(GskGLDriver * self,float width,float height)647 gsk_gl_driver_create_texture (GskGLDriver *self,
648                               float        width,
649                               float        height)
650 {
651   Texture *t;
652 
653   g_return_val_if_fail (GSK_IS_GL_DRIVER (self), -1);
654 
655   t = create_texture (self, width, height);
656 
657   return t->texture_id;
658 }
659 
660 void
gsk_gl_driver_create_render_target(GskGLDriver * self,int width,int height,int min_filter,int mag_filter,int * out_texture_id,int * out_render_target_id)661 gsk_gl_driver_create_render_target (GskGLDriver *self,
662                                     int          width,
663                                     int          height,
664                                     int          min_filter,
665                                     int          mag_filter,
666                                     int         *out_texture_id,
667                                     int         *out_render_target_id)
668 {
669   GLuint fbo_id;
670   Texture *texture;
671 
672   g_return_if_fail (self->in_frame);
673 
674   texture = create_texture (self, width, height);
675   gsk_gl_driver_bind_source_texture (self, texture->texture_id);
676   gsk_gl_driver_init_texture_empty (self, texture->texture_id, min_filter, mag_filter);
677 
678   glGenFramebuffers (1, &fbo_id);
679   glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
680   glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture_id, 0);
681 
682 #if 0
683   if (add_depth_buffer || add_stencil_buffer)
684     {
685       glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
686       gdk_gl_context_label_object_printf (self->gl_context, GL_RENDERBUFFER, depth_stencil_buffer_id,
687                                           "%s buffer for %d", add_depth_buffer ? "Depth" : "Stencil", texture_id);
688     }
689   else
690     depth_stencil_buffer_id = 0;
691 
692   glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
693 
694   if (add_depth_buffer || add_stencil_buffer)
695     {
696       if (add_stencil_buffer)
697         glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
698       else
699         glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
700 
701       if (add_depth_buffer)
702         glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
703                                    GL_RENDERBUFFER, depth_stencil_buffer_id);
704 
705       if (add_stencil_buffer)
706         glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
707                                       GL_RENDERBUFFER, depth_stencil_buffer_id);
708   texture->fbo.depth_stencil_id = depth_stencil_buffer_id;
709     }
710 #endif
711 
712   texture->fbo.fbo_id = fbo_id;
713 
714   g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
715 
716   glBindFramebuffer (GL_FRAMEBUFFER, self->default_fbo.fbo_id);
717 
718   *out_texture_id = texture->texture_id;
719   *out_render_target_id = fbo_id;
720 }
721 
722 /* Mark the texture permanent, meaning it won'e be reused by the GLDriver.
723  * E.g. to store it in some other cache. */
724 void
gsk_gl_driver_mark_texture_permanent(GskGLDriver * self,int texture_id)725 gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
726                                       int          texture_id)
727 {
728   Texture *t = gsk_gl_driver_get_texture (self, texture_id);
729 
730   g_assert (t != NULL);
731 
732   t->permanent = TRUE;
733 }
734 
735 void
gsk_gl_driver_bind_source_texture(GskGLDriver * self,int texture_id)736 gsk_gl_driver_bind_source_texture (GskGLDriver *self,
737                                    int          texture_id)
738 {
739   Texture *t;
740 
741   g_return_if_fail (GSK_IS_GL_DRIVER (self));
742   g_return_if_fail (self->in_frame);
743 
744   t = gsk_gl_driver_get_texture (self, texture_id);
745   if (t == NULL)
746     {
747       g_critical ("No texture %d found.", texture_id);
748       return;
749     }
750 
751   if (self->bound_source_texture != t)
752     {
753       glActiveTexture (GL_TEXTURE0);
754       glBindTexture (GL_TEXTURE_2D, t->texture_id);
755 
756       self->bound_source_texture = t;
757     }
758 }
759 
760 void
gsk_gl_driver_destroy_texture(GskGLDriver * self,int texture_id)761 gsk_gl_driver_destroy_texture (GskGLDriver *self,
762                                int          texture_id)
763 {
764   g_return_if_fail (GSK_IS_GL_DRIVER (self));
765 
766   g_hash_table_remove (self->textures, GINT_TO_POINTER (texture_id));
767 }
768 
769 
770 void
gsk_gl_driver_init_texture_empty(GskGLDriver * self,int texture_id,int min_filter,int mag_filter)771 gsk_gl_driver_init_texture_empty (GskGLDriver *self,
772                                   int          texture_id,
773                                   int          min_filter,
774                                   int          mag_filter)
775 {
776   Texture *t;
777 
778   g_return_if_fail (GSK_IS_GL_DRIVER (self));
779 
780   t = gsk_gl_driver_get_texture (self, texture_id);
781   if (t == NULL)
782     {
783       g_critical ("No texture %d found.", texture_id);
784       return;
785     }
786 
787   if (self->bound_source_texture != t)
788     {
789       g_critical ("You must bind the texture before initializing it.");
790       return;
791     }
792 
793   t->min_filter = min_filter;
794   t->mag_filter = mag_filter;
795 
796   gsk_gl_driver_set_texture_parameters (self, t->min_filter, t->mag_filter);
797 
798   if (gdk_gl_context_get_use_es (self->gl_context))
799     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
800   else
801     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
802 
803   glBindTexture (GL_TEXTURE_2D, 0);
804 }
805 
806 static gboolean
filter_uses_mipmaps(int filter)807 filter_uses_mipmaps (int filter)
808 {
809   return filter != GL_NEAREST && filter != GL_LINEAR;
810 }
811 
812 void
gsk_gl_driver_init_texture(GskGLDriver * self,int texture_id,GdkTexture * texture,int min_filter,int mag_filter)813 gsk_gl_driver_init_texture (GskGLDriver     *self,
814                             int              texture_id,
815                             GdkTexture      *texture,
816                             int              min_filter,
817                             int              mag_filter)
818 {
819   Texture *t;
820 
821   g_return_if_fail (GSK_IS_GL_DRIVER (self));
822 
823   t = gsk_gl_driver_get_texture (self, texture_id);
824   if (t == NULL)
825     {
826       g_critical ("No texture %d found.", texture_id);
827       return;
828     }
829 
830   if (self->bound_source_texture != t)
831     {
832       g_critical ("You must bind the texture before initializing it.");
833       return;
834     }
835 
836   gsk_gl_driver_set_texture_parameters (self, min_filter, mag_filter);
837 
838   upload_gdk_texture (texture, GL_TEXTURE_2D, 0, 0, t->width, t->height);
839 
840 #ifdef G_ENABLE_DEBUG
841   gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
842 #endif
843 
844   t->min_filter = min_filter;
845   t->mag_filter = mag_filter;
846 
847   if (filter_uses_mipmaps (t->min_filter))
848     glGenerateMipmap (GL_TEXTURE_2D);
849 }
850