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