1 #include "config.h"
2 
3 #include "gskglrendererprivate.h"
4 
5 #include "gskdebugprivate.h"
6 #include "gskenums.h"
7 #include "gskgldriverprivate.h"
8 #include "gskglprofilerprivate.h"
9 #include "gskprofilerprivate.h"
10 #include "gskrendererprivate.h"
11 #include "gskrendernodeprivate.h"
12 #include "gsktransformprivate.h"
13 #include "gskglshaderbuilderprivate.h"
14 #include "gskglglyphcacheprivate.h"
15 #include "gskgliconcacheprivate.h"
16 #include "gskglrenderopsprivate.h"
17 #include "gskcairoblurprivate.h"
18 #include "gskglshadowcacheprivate.h"
19 #include "gskglnodesampleprivate.h"
20 #include "gsktransform.h"
21 #include "glutilsprivate.h"
22 #include "gskglshaderprivate.h"
23 
24 #include "gskprivate.h"
25 
26 #include "gdk/gdkgltextureprivate.h"
27 #include "gdk/gdkglcontextprivate.h"
28 #include "gdk/gdkprofilerprivate.h"
29 #include "gdk/gdkrgbaprivate.h"
30 
31 #include <epoxy/gl.h>
32 
33 #define SHADER_VERSION_GLES             100
34 #define SHADER_VERSION_GL2_LEGACY       110
35 #define SHADER_VERSION_GL3_LEGACY       130
36 #define SHADER_VERSION_GL3              150
37 
38 #define ORTHO_NEAR_PLANE        -10000
39 #define ORTHO_FAR_PLANE          10000
40 
41 #define DEBUG_OPS          0
42 
43 #define SHADOW_EXTRA_SIZE  4
44 
45 #if DEBUG_OPS
46 #define OP_PRINT(format, ...) g_print(format, ## __VA_ARGS__)
47 #else
48 #define OP_PRINT(format, ...)
49 #endif
50 
51 #define INIT_PROGRAM_UNIFORM_LOCATION(program_name, uniform_basename) \
52               G_STMT_START{\
53                 programs->program_name ## _program.program_name.uniform_basename ## _location = \
54                               glGetUniformLocation(programs->program_name ## _program.id, "u_" #uniform_basename);\
55                 if (programs->program_name ## _program.program_name.uniform_basename ## _location == -1) \
56                   { \
57                     g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED, \
58                                  "Failed to find variable \"u_%s\" in shader program \"%s\"", #uniform_basename, #program_name); \
59                     g_clear_pointer (&programs, gsk_gl_renderer_programs_unref); \
60                     goto out; \
61                   } \
62               }G_STMT_END
63 
64 #define INIT_COMMON_UNIFORM_LOCATION(program_ptr, uniform_basename) \
65               G_STMT_START{\
66                 program_ptr->uniform_basename ## _location =  \
67                               glGetUniformLocation(program_ptr->id, "u_" #uniform_basename);\
68               }G_STMT_END
69 
70 static Program *gsk_gl_renderer_lookup_custom_program (GskGLRenderer  *self,
71                                                        GskGLShader *shader);
72 static Program *gsk_gl_renderer_create_custom_program (GskGLRenderer  *self,
73                                                        GskGLShader *shader);
74 
75 typedef enum
76 {
77   FORCE_OFFSCREEN  = 1 << 0,
78   RESET_CLIP       = 1 << 1,
79   DUMP_FRAMEBUFFER = 1 << 3,
80   NO_CACHE_PLZ     = 1 << 5,
81   LINEAR_FILTER    = 1 << 6,
82 } OffscreenFlags;
83 
84 static inline void
init_full_texture_region(TextureRegion * r,int texture_id)85 init_full_texture_region (TextureRegion *r,
86                           int            texture_id)
87 {
88   r->texture_id = texture_id;
89   r->x = 0;
90   r->y = 0;
91   r->x2 = 1;
92   r->y2 = 1;
93 }
94 
95 static void G_GNUC_UNUSED
print_render_node_tree(GskRenderNode * root,int level)96 print_render_node_tree (GskRenderNode *root, int level)
97 {
98 #define INDENT 4
99   const guint type = gsk_render_node_get_node_type (root);
100   guint i;
101 
102   switch (type)
103     {
104       case GSK_CONTAINER_NODE:
105         g_print ("%*s Container\n", level * INDENT, " ");
106         for (i = 0; i < gsk_container_node_get_n_children (root); i++)
107           print_render_node_tree (gsk_container_node_get_child (root, i), level + 1);
108         break;
109 
110       case GSK_TRANSFORM_NODE:
111         g_print ("%*s Transform\n", level * INDENT, " ");
112         print_render_node_tree (gsk_transform_node_get_child (root), level + 1);
113         break;
114 
115       case GSK_COLOR_MATRIX_NODE:
116         g_print ("%*s Color Matrix\n", level * INDENT, " ");
117         print_render_node_tree (gsk_color_matrix_node_get_child (root), level + 1);
118         break;
119 
120       case GSK_CROSS_FADE_NODE:
121         g_print ("%*s Crossfade(%.2f)\n", level * INDENT, " ",
122                  gsk_cross_fade_node_get_progress (root));
123         print_render_node_tree (gsk_cross_fade_node_get_start_child (root), level + 1);
124         print_render_node_tree (gsk_cross_fade_node_get_end_child (root), level + 1);
125         break;
126 
127       case GSK_TEXT_NODE:
128         g_print ("%*s Text\n", level * INDENT, " ");
129         break;
130 
131       case GSK_COLOR_NODE:
132         g_print ("%*s Color %s\n", level * INDENT, " ", gdk_rgba_to_string (gsk_color_node_get_color (root)));
133         break;
134 
135       case GSK_SHADOW_NODE:
136         g_print ("%*s Shadow\n", level * INDENT, " ");
137         print_render_node_tree (gsk_shadow_node_get_child (root), level + 1);
138         break;
139 
140       case GSK_GL_SHADER_NODE:
141         g_print ("%*s GL Shader\n", level * INDENT, " ");
142         for (i = 0; i < gsk_gl_shader_node_get_n_children (root); i++)
143           print_render_node_tree (gsk_gl_shader_node_get_child (root, i), level + 1);
144         break;
145 
146       case GSK_TEXTURE_NODE:
147         g_print ("%*s Texture %p\n", level * INDENT, " ", gsk_texture_node_get_texture (root));
148         break;
149 
150       case GSK_DEBUG_NODE:
151         g_print ("%*s Debug: %s\n", level * INDENT, " ", gsk_debug_node_get_message (root));
152         print_render_node_tree (gsk_debug_node_get_child (root), level + 1);
153         break;
154 
155       case GSK_CLIP_NODE:
156         g_print ("%*s Clip (%f, %f, %f, %f):\n", level * INDENT, " ",
157                  root->bounds.origin.x, root->bounds.origin.y, root->bounds.size.width, root->bounds.size.height);
158         print_render_node_tree (gsk_clip_node_get_child (root), level + 1);
159         break;
160 
161       default:
162         g_print ("%*s %s\n", level * INDENT, " ", g_type_name_from_instance ((GTypeInstance *) root));
163     }
164 
165 #undef INDENT
166 }
167 
168 
169 static void G_GNUC_UNUSED
dump_framebuffer(const char * filename,int w,int h)170 dump_framebuffer (const char *filename, int w, int h)
171 {
172   int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
173   guchar *data = g_malloc (h * stride);
174   cairo_surface_t *s;
175 
176   glReadPixels (0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, data);
177   s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, w, h, stride);
178   cairo_surface_write_to_png (s, filename);
179 
180   cairo_surface_destroy (s);
181   g_free (data);
182 }
183 
184 static void G_GNUC_UNUSED
dump_node(GskRenderNode * node,const char * filename)185 dump_node (GskRenderNode *node,
186            const char    *filename)
187 {
188   const int surface_width = ceilf (node->bounds.size.width);
189   const int surface_height = ceilf (node->bounds.size.height);
190   cairo_surface_t *surface;
191   cairo_t *cr;
192 
193   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
194                                         surface_width,
195                                         surface_height);
196 
197   cr = cairo_create (surface);
198   cairo_save (cr);
199   cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
200   gsk_render_node_draw (node, cr);
201   cairo_restore (cr);
202   cairo_destroy (cr);
203 
204   cairo_surface_write_to_png (surface, filename);
205   cairo_surface_destroy (surface);
206 }
207 
208 static inline bool G_GNUC_PURE
node_is_invisible(const GskRenderNode * node)209 node_is_invisible (const GskRenderNode *node)
210 {
211   return node->bounds.size.width == 0.0f ||
212          node->bounds.size.height == 0.0f ||
213          isnan (node->bounds.size.width) ||
214          isnan (node->bounds.size.height);
215 }
216 
217 static inline bool G_GNUC_PURE
graphene_rect_intersects(const graphene_rect_t * r1,const graphene_rect_t * r2)218 graphene_rect_intersects (const graphene_rect_t *r1,
219                           const graphene_rect_t *r2)
220 {
221   /* Assume both rects are already normalized, as they usually are */
222   if (r1->origin.x > (r2->origin.x + r2->size.width) ||
223       (r1->origin.x + r1->size.width) < r2->origin.x)
224     return false;
225 
226   if (r1->origin.y > (r2->origin.y + r2->size.height) ||
227       (r1->origin.y + r1->size.height) < r2->origin.y)
228     return false;
229 
230   return true;
231 }
232 
233 static inline bool G_GNUC_PURE
_graphene_rect_contains_rect(const graphene_rect_t * r1,const graphene_rect_t * r2)234 _graphene_rect_contains_rect (const graphene_rect_t *r1,
235                               const graphene_rect_t *r2)
236 {
237   if (r2->origin.x >= r1->origin.x &&
238       (r2->origin.x + r2->size.width) <= (r1->origin.x + r1->size.width) &&
239       r2->origin.y >= r1->origin.y &&
240       (r2->origin.y + r2->size.height) <= (r1->origin.y + r1->size.height))
241     return true;
242 
243   return false;
244 }
245 
246 static inline bool G_GNUC_PURE
equal_texture_nodes(GskRenderNode * node1,GskRenderNode * node2)247 equal_texture_nodes (GskRenderNode *node1,
248                      GskRenderNode *node2)
249 {
250   if (gsk_render_node_get_node_type (node1) != GSK_TEXTURE_NODE ||
251       gsk_render_node_get_node_type (node2) != GSK_TEXTURE_NODE)
252     return false;
253 
254   if (gsk_texture_node_get_texture (node1) !=
255       gsk_texture_node_get_texture (node2))
256     return false;
257 
258   return graphene_rect_equal (&node1->bounds, &node2->bounds);
259 }
260 
261 static inline void
sort_border_sides(const GdkRGBA * colors,int * indices)262 sort_border_sides (const GdkRGBA *colors,
263                    int           *indices)
264 {
265   gboolean done[4] = {0, 0, 0, 0};
266   int i, k;
267   int cur = 0;
268 
269   for (i = 0; i < 3; i ++)
270     {
271       if (done[i])
272         continue;
273 
274       indices[cur] = i;
275       done[i] = TRUE;
276       cur ++;
277 
278       for (k = i + 1; k < 4; k ++)
279         {
280           if (gdk_rgba_equal (&colors[k], &colors[i]))
281             {
282               indices[cur] = k;
283               done[k] = TRUE;
284               cur ++;
285             }
286         }
287 
288       if (cur >= 4)
289         break;
290     }
291 }
292 
293 static inline void
init_projection_matrix(graphene_matrix_t * out_proj,const graphene_rect_t * viewport)294 init_projection_matrix (graphene_matrix_t     *out_proj,
295                         const graphene_rect_t *viewport)
296 {
297   graphene_matrix_init_ortho (out_proj,
298                               viewport->origin.x,
299                               viewport->origin.x + viewport->size.width,
300                               viewport->origin.y,
301                               viewport->origin.y + viewport->size.height,
302                               ORTHO_NEAR_PLANE,
303                               ORTHO_FAR_PLANE);
304   graphene_matrix_scale (out_proj, 1, -1, 1);
305 }
306 
307 static inline gboolean G_GNUC_PURE
color_matrix_modifies_alpha(GskRenderNode * node)308 color_matrix_modifies_alpha (GskRenderNode *node)
309 {
310   const graphene_matrix_t *matrix = gsk_color_matrix_node_get_color_matrix (node);
311   const graphene_vec4_t *offset = gsk_color_matrix_node_get_color_offset (node);
312   graphene_vec4_t row3;
313 
314   if (graphene_vec4_get_w (offset) != 0.0f)
315     return TRUE;
316 
317   graphene_matrix_get_row (matrix, 3, &row3);
318 
319   return !graphene_vec4_equal (graphene_vec4_w_axis (), &row3);
320 }
321 
322 static inline void
gsk_rounded_rect_shrink_to_minimum(GskRoundedRect * self)323 gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
324 {
325   self->bounds.size.width  = MAX (self->corner[0].width + self->corner[1].width,
326                                   self->corner[3].width + self->corner[2].width);
327   self->bounds.size.height = MAX (self->corner[0].height + self->corner[3].height,
328                                   self->corner[1].height + self->corner[2].height);
329 }
330 
331 static inline gboolean G_GNUC_PURE
node_supports_transform(GskRenderNode * node)332 node_supports_transform (GskRenderNode *node)
333 {
334   /* Some nodes can't handle non-trivial transforms without being
335    * rendered to a texture (e.g. rotated clips, etc.). Some however
336    * work just fine, mostly because they already draw their child
337    * to a texture and just render the texture manipulated in some
338    * way, think opacity or color matrix. */
339   const guint node_type = gsk_render_node_get_node_type (node);
340 
341   switch (node_type)
342     {
343       case GSK_COLOR_NODE:
344       case GSK_OPACITY_NODE:
345       case GSK_COLOR_MATRIX_NODE:
346       case GSK_TEXTURE_NODE:
347       case GSK_CROSS_FADE_NODE:
348       case GSK_LINEAR_GRADIENT_NODE:
349       case GSK_DEBUG_NODE:
350       case GSK_TEXT_NODE:
351         return TRUE;
352 
353       case GSK_TRANSFORM_NODE:
354         return node_supports_transform (gsk_transform_node_get_child (node));
355 
356       default:
357         return FALSE;
358     }
359   return FALSE;
360 }
361 
362 static inline void
load_vertex_data_with_region(GskQuadVertex vertex_data[GL_N_VERTICES],const graphene_rect_t * bounds,RenderOpBuilder * builder,const TextureRegion * r,gboolean flip_y)363 load_vertex_data_with_region (GskQuadVertex          vertex_data[GL_N_VERTICES],
364                               const graphene_rect_t *bounds,
365                               RenderOpBuilder       *builder,
366                               const TextureRegion   *r,
367                               gboolean               flip_y)
368 {
369   const float min_x = builder->dx + bounds->origin.x;
370   const float min_y = builder->dy + bounds->origin.y;
371   const float max_x = min_x + bounds->size.width;
372   const float max_y = min_y + bounds->size.height;
373   const float y1 = flip_y ? r->y2 : r->y;
374   const float y2 = flip_y ? r->y  : r->y2;
375 
376   vertex_data[0].position[0] = min_x;
377   vertex_data[0].position[1] = min_y;
378   vertex_data[0].uv[0] = r->x;
379   vertex_data[0].uv[1] = y1;
380 
381   vertex_data[1].position[0] = min_x;
382   vertex_data[1].position[1] = max_y;
383   vertex_data[1].uv[0] = r->x;
384   vertex_data[1].uv[1] = y2;
385 
386   vertex_data[2].position[0] = max_x;
387   vertex_data[2].position[1] = min_y;
388   vertex_data[2].uv[0] = r->x2;
389   vertex_data[2].uv[1] = y1;
390 
391   vertex_data[3].position[0] = max_x;
392   vertex_data[3].position[1] = max_y;
393   vertex_data[3].uv[0] = r->x2;
394   vertex_data[3].uv[1] = y2;
395 
396   vertex_data[4].position[0] = min_x;
397   vertex_data[4].position[1] = max_y;
398   vertex_data[4].uv[0] = r->x;
399   vertex_data[4].uv[1] = y2;
400 
401   vertex_data[5].position[0] = max_x;
402   vertex_data[5].position[1] = min_y;
403   vertex_data[5].uv[0] = r->x2;
404   vertex_data[5].uv[1] = y1;
405 }
406 
407 static inline void
load_float_vertex_data(GskQuadVertex vertex_data[GL_N_VERTICES],RenderOpBuilder * builder,float x,float y,float width,float height)408 load_float_vertex_data (GskQuadVertex    vertex_data[GL_N_VERTICES],
409                         RenderOpBuilder *builder,
410                         float            x,
411                         float            y,
412                         float            width,
413                         float            height)
414 {
415   const float min_x = builder->dx + x;
416   const float min_y = builder->dy + y;
417   const float max_x = min_x + width;
418   const float max_y = min_y + height;
419 
420   vertex_data[0].position[0] = min_x;
421   vertex_data[0].position[1] = min_y;
422   vertex_data[0].uv[0] = 0;
423   vertex_data[0].uv[1] = 0;
424 
425   vertex_data[1].position[0] = min_x;
426   vertex_data[1].position[1] = max_y;
427   vertex_data[1].uv[0] = 0;
428   vertex_data[1].uv[1] = 1;
429 
430   vertex_data[2].position[0] = max_x;
431   vertex_data[2].position[1] = min_y;
432   vertex_data[2].uv[0] = 1;
433   vertex_data[2].uv[1] = 0;
434 
435   vertex_data[3].position[0] = max_x;
436   vertex_data[3].position[1] = max_y;
437   vertex_data[3].uv[0] = 1;
438   vertex_data[3].uv[1] = 1;
439 
440   vertex_data[4].position[0] = min_x;
441   vertex_data[4].position[1] = max_y;
442   vertex_data[4].uv[0] = 0;
443   vertex_data[4].uv[1] = 1;
444 
445   vertex_data[5].position[0] = max_x;
446   vertex_data[5].position[1] = min_y;
447   vertex_data[5].uv[0] = 1;
448   vertex_data[5].uv[1] = 0;
449 }
450 
451 static void
load_vertex_data(GskQuadVertex vertex_data[GL_N_VERTICES],const graphene_rect_t * bounds,RenderOpBuilder * builder)452 load_vertex_data (GskQuadVertex          vertex_data[GL_N_VERTICES],
453                   const graphene_rect_t *bounds,
454                   RenderOpBuilder       *builder)
455 {
456   load_float_vertex_data (vertex_data, builder,
457                           bounds->origin.x, bounds->origin.y,
458                           bounds->size.width, bounds->size.height);
459 }
460 
461 static void
fill_vertex_data(GskQuadVertex vertex_data[GL_N_VERTICES],const float min_x,const float min_y,const float max_x,const float max_y)462 fill_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
463                   const float   min_x,
464                   const float   min_y,
465                   const float   max_x,
466                   const float   max_y)
467 {
468   vertex_data[0].position[0] = min_x;
469   vertex_data[0].position[1] = min_y;
470   vertex_data[0].uv[0] = 0;
471   vertex_data[0].uv[1] = 1;
472 
473   vertex_data[1].position[0] = min_x;
474   vertex_data[1].position[1] = max_y;
475   vertex_data[1].uv[0] = 0;
476   vertex_data[1].uv[1] = 0;
477 
478   vertex_data[2].position[0] = max_x;
479   vertex_data[2].position[1] = min_y;
480   vertex_data[2].uv[0] = 1;
481   vertex_data[2].uv[1] = 1;
482 
483   vertex_data[3].position[0] = max_x;
484   vertex_data[3].position[1] = max_y;
485   vertex_data[3].uv[0] = 1;
486   vertex_data[3].uv[1] = 0;
487 
488   vertex_data[4].position[0] = min_x;
489   vertex_data[4].position[1] = max_y;
490   vertex_data[4].uv[0] = 0;
491   vertex_data[4].uv[1] = 0;
492 
493   vertex_data[5].position[0] = max_x;
494   vertex_data[5].position[1] = min_y;
495   vertex_data[5].uv[0] = 1;
496   vertex_data[5].uv[1] = 1;
497 }
498 
499 static void
load_offscreen_vertex_data(GskQuadVertex vertex_data[GL_N_VERTICES],GskRenderNode * node,RenderOpBuilder * builder)500 load_offscreen_vertex_data (GskQuadVertex    vertex_data[GL_N_VERTICES],
501                             GskRenderNode   *node,
502                             RenderOpBuilder *builder)
503 {
504   const float min_x = builder->dx + node->bounds.origin.x;
505   const float min_y = builder->dy + node->bounds.origin.y;
506   const float max_x = min_x + node->bounds.size.width;
507   const float max_y = min_y + node->bounds.size.height;
508 
509   fill_vertex_data (vertex_data,
510                     min_x, min_y,
511                     max_x, max_y);
512 }
513 
514 
515 static void gsk_gl_renderer_setup_render_mode (GskGLRenderer   *self);
516 static gboolean add_offscreen_ops             (GskGLRenderer   *self,
517                                                RenderOpBuilder       *builder,
518                                                const graphene_rect_t *bounds,
519                                                GskRenderNode         *child_node,
520                                                TextureRegion         *region_out,
521                                                gboolean              *is_offscreen,
522                                                guint                  flags) G_GNUC_WARN_UNUSED_RESULT;
523 static void gsk_gl_renderer_add_render_ops     (GskGLRenderer   *self,
524                                                 GskRenderNode   *node,
525                                                 RenderOpBuilder *builder);
526 
527 struct _GskGLRenderer
528 {
529   GskRenderer parent_instance;
530 
531   int scale_factor;
532 
533   GdkGLContext *gl_context;
534   GskGLDriver *gl_driver;
535   GskGLProfiler *gl_profiler;
536 
537   GskGLRendererPrograms *programs;
538 
539   RenderOpBuilder op_builder;
540 
541   GskGLTextureAtlases *atlases;
542   GskGLGlyphCache *glyph_cache;
543   GskGLIconCache *icon_cache;
544   GskGLShadowCache shadow_cache;
545 
546 #ifdef G_ENABLE_DEBUG
547   struct {
548     GQuark frames;
549   } profile_counters;
550   struct {
551     GQuark cpu_time;
552     GQuark gpu_time;
553   } profile_timers;
554 #endif
555 
556   cairo_region_t *render_region;
557 };
558 
559 struct _GskGLRendererClass
560 {
561   GskRendererClass parent_class;
562 };
563 
G_DEFINE_TYPE(GskGLRenderer,gsk_gl_renderer,GSK_TYPE_RENDERER)564 G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
565 
566 static void
567 init_shader_builder (GskGLRenderer       *self,
568                      GskGLShaderBuilder  *shader_builder)
569 {
570 #ifdef G_ENABLE_DEBUG
571   if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS))
572     shader_builder->debugging = TRUE;
573 #endif
574 
575   if (gdk_gl_context_get_use_es (self->gl_context))
576     {
577       gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GLES);
578       shader_builder->gles = TRUE;
579     }
580   else if (gdk_gl_context_is_legacy (self->gl_context))
581     {
582       int maj, min;
583 
584       gdk_gl_context_get_version (self->gl_context, &maj, &min);
585 
586       if (maj == 3)
587         gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3_LEGACY);
588       else
589         gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL2_LEGACY);
590 
591       shader_builder->legacy = TRUE;
592         }
593   else
594     {
595       gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3);
596       shader_builder->gl3 = TRUE;
597     }
598 }
599 
600 static GdkRGBA BLACK = {0, 0, 0, 1};
601 static void G_GNUC_UNUSED
add_rect_outline_ops(GskGLRenderer * self,RenderOpBuilder * builder,const graphene_rect_t * rect)602 add_rect_outline_ops (GskGLRenderer         *self,
603                       RenderOpBuilder       *builder,
604                       const graphene_rect_t *rect)
605 {
606   ops_set_program (builder, &self->programs->color_program);
607   ops_set_color (builder, &BLACK);
608 
609   load_vertex_data (ops_draw (builder, NULL),
610                     &GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y, 1, rect->size.height),
611                     builder);
612   load_vertex_data (ops_draw (builder, NULL),
613                     &GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y, rect->size.width, 1),
614                     builder);
615   load_vertex_data (ops_draw (builder, NULL),
616                     &GRAPHENE_RECT_INIT (rect->origin.x + rect->size.width - 1,rect->origin.y,
617                                          1, rect->size.height),
618                     builder);
619   load_vertex_data (ops_draw (builder, NULL),
620                     &GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y + rect->size.height - 1,
621                                          rect->size.width, 1),
622                     builder);
623 }
624 
625 static inline GskRoundedRect
transform_rect(GskGLRenderer * self,RenderOpBuilder * builder,const GskRoundedRect * rect)626 transform_rect (GskGLRenderer        *self,
627                 RenderOpBuilder      *builder,
628                 const GskRoundedRect *rect)
629 {
630   GskRoundedRect r;
631 
632   r.bounds.origin.x = builder->dx + rect->bounds.origin.x;
633   r.bounds.origin.y = builder->dy + rect->bounds.origin.y;
634   r.bounds.size = rect->bounds.size;
635 
636   r.corner[0] = rect->corner[0];
637   r.corner[1] = rect->corner[1];
638   r.corner[2] = rect->corner[2];
639   r.corner[3] = rect->corner[3];
640 
641   return r;
642 }
643 
644 static inline void
render_fallback_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)645 render_fallback_node (GskGLRenderer   *self,
646                       GskRenderNode   *node,
647                       RenderOpBuilder *builder)
648 {
649   const float scale_x = builder->scale_x;
650   const float scale_y = builder->scale_y;
651   const int surface_width = ceilf (node->bounds.size.width * scale_x);
652   const int surface_height = ceilf (node->bounds.size.height * scale_y);
653   GdkTexture *texture;
654   cairo_surface_t *surface;
655   cairo_surface_t *rendered_surface;
656   cairo_t *cr;
657   int cached_id;
658   int texture_id;
659   GskTextureKey key;
660 
661   if (surface_width <= 0 ||
662       surface_height <= 0)
663     return;
664 
665   key.pointer = node;
666   key.pointer_is_child = FALSE;
667   key.scale_x = scale_x;
668   key.scale_y = scale_y;
669   key.filter = GL_NEAREST;
670 
671   cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
672 
673   if (cached_id != 0)
674     {
675       ops_set_program (builder, &self->programs->blit_program);
676       ops_set_texture (builder, cached_id);
677       load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
678       return;
679     }
680 
681 
682   /* We first draw the recording surface on an image surface,
683    * just because the scaleY(-1) later otherwise screws up the
684    * rendering... */
685   {
686     rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
687                                                    surface_width,
688                                                    surface_height);
689 
690     cairo_surface_set_device_scale (rendered_surface, scale_x, scale_y);
691     cr = cairo_create (rendered_surface);
692 
693     cairo_save (cr);
694     cairo_translate (cr, - floorf (node->bounds.origin.x), - floorf (node->bounds.origin.y));
695     gsk_render_node_draw (node, cr);
696     cairo_restore (cr);
697     cairo_destroy (cr);
698   }
699 
700   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
701                                         surface_width,
702                                         surface_height);
703   cairo_surface_set_device_scale (surface, scale_x, scale_y);
704   cr = cairo_create (surface);
705 
706   /* We draw upside down here, so it matches what GL does. */
707   cairo_save (cr);
708   cairo_scale (cr, 1, -1);
709   cairo_translate (cr, 0, - surface_height / scale_y);
710   cairo_set_source_surface (cr, rendered_surface, 0, 0);
711   cairo_rectangle (cr, 0, 0, surface_width / scale_x, surface_height / scale_y);
712   cairo_fill (cr);
713   cairo_restore (cr);
714 
715 #ifdef G_ENABLE_DEBUG
716   if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
717     {
718       cairo_move_to (cr, 0, 0);
719       cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height);
720       if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
721         cairo_set_source_rgba (cr, 0.3, 0, 1, 0.25);
722       else
723         cairo_set_source_rgba (cr, 1, 0, 0, 0.25);
724       cairo_fill_preserve (cr);
725       if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
726         cairo_set_source_rgba (cr, 0.3, 0, 1, 1);
727       else
728         cairo_set_source_rgba (cr, 1, 0, 0, 1);
729       cairo_stroke (cr);
730     }
731 #endif
732   cairo_destroy (cr);
733 
734 
735   /* Upload the Cairo surface to a GL texture */
736   texture_id = gsk_gl_driver_create_texture (self->gl_driver,
737                                              surface_width,
738                                              surface_height);
739   gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
740 
741   texture = gdk_texture_new_for_surface (surface);
742   gsk_gl_driver_init_texture (self->gl_driver,
743                               texture_id,
744                               texture,
745                               GL_NEAREST, GL_NEAREST);
746 
747   if (gdk_gl_context_has_debug (self->gl_context))
748     gdk_gl_context_label_object_printf  (self->gl_context, GL_TEXTURE, texture_id,
749                                          "Fallback %s %d",
750                                          g_type_name_from_instance ((GTypeInstance *) node),
751                                          texture_id);
752 
753   g_object_unref (texture);
754   cairo_surface_destroy (surface);
755   cairo_surface_destroy (rendered_surface);
756 
757   gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
758 
759   ops_set_program (builder, &self->programs->blit_program);
760   ops_set_texture (builder, texture_id);
761   load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
762 }
763 
764 static inline void
render_text_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder,const GdkRGBA * color,gboolean force_color)765 render_text_node (GskGLRenderer   *self,
766                   GskRenderNode   *node,
767                   RenderOpBuilder *builder,
768                   const GdkRGBA   *color,
769                   gboolean         force_color)
770 {
771   const PangoFont *font = gsk_text_node_get_font (node);
772   const PangoGlyphInfo *glyphs = gsk_text_node_get_glyphs (node, NULL);
773   const float text_scale = MAX (builder->scale_x, builder->scale_y); /* TODO: Fix for uneven scales? */
774   const graphene_point_t *offset = gsk_text_node_get_offset (node);
775   const guint num_glyphs = gsk_text_node_get_num_glyphs (node);
776   const float x = offset->x + builder->dx;
777   const float y = offset->y + builder->dy;
778   int i;
779   int x_position = 0;
780   GlyphCacheKey lookup;
781 
782   /* If the font has color glyphs, we don't need to recolor anything */
783   if (!force_color && gsk_text_node_has_color_glyphs (node))
784     {
785       ops_set_program (builder, &self->programs->blit_program);
786     }
787   else
788     {
789       ops_set_program (builder, &self->programs->coloring_program);
790       ops_set_color (builder, color);
791     }
792 
793   memset (&lookup, 0, sizeof (CacheKeyData));
794   lookup.data.font = (PangoFont *)font;
795   lookup.data.scale = (guint) (text_scale * 1024);
796 
797   /* We use one quad per character */
798   for (i = 0; i < num_glyphs; i++)
799     {
800       const PangoGlyphInfo *gi = &glyphs[i];
801       const GskGLCachedGlyph *glyph;
802       float glyph_x, glyph_y, glyph_x2, glyph_y2;
803       float tx, ty, tx2, ty2;
804       float cx;
805       float cy;
806 
807       if (gi->glyph == PANGO_GLYPH_EMPTY)
808         continue;
809 
810       cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
811       cy = (float)(gi->geometry.y_offset) / PANGO_SCALE;
812 
813       glyph_cache_key_set_glyph_and_shift (&lookup, gi->glyph, x + cx, y + cy);
814 
815       gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache,
816                                         &lookup,
817                                         self->gl_driver,
818                                         &glyph);
819 
820       if (glyph->texture_id == 0)
821         goto next;
822 
823       ops_set_texture (builder, glyph->texture_id);
824 
825       tx  = glyph->tx;
826       ty  = glyph->ty;
827       tx2 = tx + glyph->tw;
828       ty2 = ty + glyph->th;
829 
830       glyph_x = floor (x + cx + 0.125) + glyph->draw_x;
831       glyph_y = floor (y + cy + 0.125) + glyph->draw_y;
832       glyph_x2 = glyph_x + glyph->draw_width;
833       glyph_y2 = glyph_y + glyph->draw_height;
834 
835       ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
836         { { glyph_x,  glyph_y  }, { tx,  ty  }, },
837         { { glyph_x,  glyph_y2 }, { tx,  ty2 }, },
838         { { glyph_x2, glyph_y  }, { tx2, ty  }, },
839 
840         { { glyph_x2, glyph_y2 }, { tx2, ty2 }, },
841         { { glyph_x,  glyph_y2 }, { tx,  ty2 }, },
842         { { glyph_x2, glyph_y  }, { tx2, ty  }, },
843       });
844 
845 next:
846       x_position += gi->geometry.width;
847     }
848 }
849 
850 static inline void
render_border_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)851 render_border_node (GskGLRenderer   *self,
852                     GskRenderNode   *node,
853                     RenderOpBuilder *builder)
854 {
855   const GdkRGBA *colors = gsk_border_node_get_colors (node);
856   const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node);
857   const float *widths = gsk_border_node_get_widths (node);
858   int i;
859   struct {
860     float w;
861     float h;
862   } sizes[4];
863 
864   if (gsk_border_node_get_uniform (node))
865     {
866       ops_set_program (builder, &self->programs->inset_shadow_program);
867       ops_set_inset_shadow (builder, transform_rect (self, builder, rounded_outline),
868                             widths[0], &colors[0], 0, 0);
869 
870       load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
871       return;
872     }
873 
874   /* Top left */
875   if (widths[3] > 0)
876     sizes[0].w = MAX (widths[3], rounded_outline->corner[0].width);
877   else
878     sizes[0].w = 0;
879 
880   if (widths[0] > 0)
881     sizes[0].h = MAX (widths[0], rounded_outline->corner[0].height);
882   else
883     sizes[0].h = 0;
884 
885   /* Top right */
886   if (widths[1] > 0)
887     sizes[1].w = MAX (widths[1], rounded_outline->corner[1].width);
888   else
889     sizes[1].w = 0;
890 
891   if (widths[0] > 0)
892     sizes[1].h = MAX (widths[0], rounded_outline->corner[1].height);
893   else
894     sizes[1].h = 0;
895 
896   /* Bottom right */
897   if (widths[1] > 0)
898     sizes[2].w = MAX (widths[1], rounded_outline->corner[2].width);
899   else
900     sizes[2].w = 0;
901 
902   if (widths[2] > 0)
903     sizes[2].h = MAX (widths[2], rounded_outline->corner[2].height);
904   else
905     sizes[2].h = 0;
906 
907 
908   /* Bottom left */
909   if (widths[3] > 0)
910     sizes[3].w = MAX (widths[3], rounded_outline->corner[3].width);
911   else
912     sizes[3].w = 0;
913 
914   if (widths[2] > 0)
915     sizes[3].h = MAX (widths[2], rounded_outline->corner[3].height);
916   else
917     sizes[3].h = 0;
918 
919   {
920     const float min_x = builder->dx + node->bounds.origin.x;
921     const float min_y = builder->dy + node->bounds.origin.y;
922     const float max_x = min_x + node->bounds.size.width;
923     const float max_y = min_y + node->bounds.size.height;
924     const GskQuadVertex side_data[4][6] = {
925       /* Top */
926       {
927         { { min_x,              min_y              }, { 0, 1 }, }, /* Upper left */
928         { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
929         { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
930 
931         { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, }, /* Lower right */
932         { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
933         { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
934       },
935       /* Right */
936       {
937         { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, }, /* Upper left */
938         { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
939         { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
940 
941         { { max_x,              max_y              }, { 1, 0 }, }, /* Lower right */
942         { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
943         { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
944       },
945       /* Bottom */
946       {
947         { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, }, /* Upper left */
948         { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
949         { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
950 
951         { { max_x,              max_y              }, { 1, 0 }, }, /* Lower right */
952         { { min_x            ,  max_y              }, { 0, 0 }, }, /* Lower left */
953         { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
954       },
955       /* Left */
956       {
957         { { min_x,              min_y              }, { 0, 1 }, }, /* Upper left */
958         { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
959         { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
960 
961         { { min_x + sizes[3].w, max_y - sizes[3].h }, { 1, 0 }, }, /* Lower right */
962         { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
963         { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
964       }
965     };
966     int indices[4] = { 0, 1, 2, 3 };
967     GskRoundedRect outline;
968 
969     /* We sort them by color */
970     sort_border_sides (colors, indices);
971 
972     /* Prepare outline */
973     outline = transform_rect (self, builder, rounded_outline);
974 
975     ops_set_program (builder, &self->programs->border_program);
976     ops_set_border_width (builder, widths);
977     ops_set_border (builder, &outline);
978 
979     for (i = 0; i < 4; i ++)
980       {
981         if (widths[indices[i]] > 0)
982           {
983             ops_set_border_color (builder, &colors[indices[i]]);
984             ops_draw (builder, side_data[indices[i]]);
985           }
986       }
987   }
988 }
989 
990 static inline void
render_color_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)991 render_color_node (GskGLRenderer   *self,
992                    GskRenderNode   *node,
993                    RenderOpBuilder *builder)
994 {
995   ops_set_program (builder, &self->programs->color_program);
996   ops_set_color (builder, gsk_color_node_get_color (node));
997   load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
998 }
999 
1000 static inline void
upload_texture(GskGLRenderer * self,GdkTexture * texture,TextureRegion * out_region)1001 upload_texture (GskGLRenderer *self,
1002                 GdkTexture    *texture,
1003                 TextureRegion *out_region)
1004 {
1005   if (texture->width <= 128 &&
1006       texture->height <= 128 &&
1007       !GDK_IS_GL_TEXTURE (texture))
1008     {
1009       const IconData *icon_data;
1010 
1011       gsk_gl_icon_cache_lookup_or_add (self->icon_cache,
1012                                        texture,
1013                                        &icon_data);
1014 
1015       out_region->texture_id = icon_data->texture_id;
1016       out_region->x = icon_data->x;
1017       out_region->y = icon_data->y;
1018       out_region->x2 = icon_data->x2;
1019       out_region->y2 = icon_data->y2;
1020     }
1021   else
1022     {
1023 
1024       out_region->texture_id =
1025           gsk_gl_driver_get_texture_for_texture (self->gl_driver,
1026                                                  texture,
1027                                                  GL_LINEAR,
1028                                                  GL_LINEAR);
1029 
1030       out_region->x  = 0;
1031       out_region->y  = 0;
1032       out_region->x2 = 1;
1033       out_region->y2 = 1;
1034     }
1035 }
1036 
1037 static inline void
render_texture_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1038 render_texture_node (GskGLRenderer       *self,
1039                      GskRenderNode       *node,
1040                      RenderOpBuilder     *builder)
1041 {
1042   GdkTexture *texture = gsk_texture_node_get_texture (node);
1043   const int max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver);
1044 
1045   if (texture->width > max_texture_size || texture->height > max_texture_size)
1046     {
1047       const float min_x = builder->dx + node->bounds.origin.x;
1048       const float min_y = builder->dy + node->bounds.origin.y;
1049       const float max_x = min_x + node->bounds.size.width;
1050       const float max_y = min_y + node->bounds.size.height;
1051       const float scale_x = (max_x - min_x) / texture->width;
1052       const float scale_y = (max_y - min_y) / texture->height;
1053       TextureSlice *slices;
1054       guint n_slices;
1055       guint i;
1056 
1057       gsk_gl_driver_slice_texture (self->gl_driver, texture, &slices, &n_slices);
1058 
1059       ops_set_program (builder, &self->programs->blit_program);
1060       for (i = 0; i < n_slices; i ++)
1061         {
1062           const TextureSlice *slice = &slices[i];
1063           float x1, x2, y1, y2;
1064 
1065           x1 = min_x + (scale_x * slice->rect.x);
1066           x2 = x1 + (slice->rect.width * scale_x);
1067           y1 = min_y + (scale_y * slice->rect.y);
1068           y2 = y1 + (slice->rect.height * scale_y);
1069 
1070           ops_set_texture (builder, slice->texture_id);
1071           ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
1072             { { x1, y1 }, { 0, 0 }, },
1073             { { x1, y2 }, { 0, 1 }, },
1074             { { x2, y1 }, { 1, 0 }, },
1075 
1076             { { x2, y2 }, { 1, 1 }, },
1077             { { x1, y2 }, { 0, 1 }, },
1078             { { x2, y1 }, { 1, 0 }, },
1079           });
1080         }
1081     }
1082   else
1083     {
1084       TextureRegion r;
1085 
1086       upload_texture (self, texture, &r);
1087 
1088       ops_set_program (builder, &self->programs->blit_program);
1089       ops_set_texture (builder, r.texture_id);
1090 
1091       load_vertex_data_with_region (ops_draw (builder, NULL),
1092                                     &node->bounds, builder,
1093                                     &r,
1094                                     FALSE);
1095     }
1096 }
1097 
1098 static Program *
compile_glshader(GskGLRenderer * self,GskGLShader * shader,GError ** error)1099 compile_glshader (GskGLRenderer  *self,
1100                   GskGLShader    *shader,
1101                   GError        **error)
1102 {
1103   GskGLShaderBuilder shader_builder;
1104   const char *shader_source;
1105   gsize shader_source_len;
1106   int n_uniforms;
1107   const GskGLUniform *uniforms;
1108   GBytes *bytes;
1109   int n_required_textures = gsk_gl_shader_get_n_textures (shader);
1110   int program_id;
1111   Program *program;
1112 
1113   bytes = gsk_gl_shader_get_source (shader);
1114   shader_source = g_bytes_get_data (bytes, &shader_source_len);
1115   uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms);
1116 
1117   if (n_uniforms > G_N_ELEMENTS (program->glshader.args_locations))
1118     {
1119       g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
1120                    "GLShaderNode supports max %d custom uniforms", (int)G_N_ELEMENTS (program->glshader.args_locations));
1121       return NULL;
1122     }
1123 
1124   if (n_required_textures > G_N_ELEMENTS (program->glshader.texture_locations))
1125     {
1126       g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
1127                    "GLShaderNode supports max %d texture sources", (int)(G_N_ELEMENTS (program->glshader.texture_locations)));
1128       return NULL;
1129     }
1130 
1131   gsk_gl_shader_builder_init (&shader_builder,
1132                               "/org/gtk/libgsk/gl/preamble.glsl",
1133                               "/org/gtk/libgsk/gl/preamble.vs.glsl",
1134                               "/org/gtk/libgsk/gl/preamble.fs.glsl");
1135 
1136   init_shader_builder (self, &shader_builder);
1137   program_id = gsk_gl_shader_builder_create_program (&shader_builder,
1138                                                      "/org/gtk/libgsk/gl/custom.glsl",
1139                                                      shader_source, shader_source_len,
1140                                                      error);
1141   gsk_gl_shader_builder_finish (&shader_builder);
1142 
1143   if (program_id  < 0)
1144     return NULL;
1145 
1146   program = gsk_gl_renderer_create_custom_program (self, shader);
1147 
1148   program->id = program_id;
1149   INIT_COMMON_UNIFORM_LOCATION (program, alpha);
1150   INIT_COMMON_UNIFORM_LOCATION (program, clip_rect);
1151   INIT_COMMON_UNIFORM_LOCATION (program, viewport);
1152   INIT_COMMON_UNIFORM_LOCATION (program, projection);
1153   INIT_COMMON_UNIFORM_LOCATION (program, modelview);
1154   program->glshader.size_location = glGetUniformLocation(program->id, "u_size");
1155   program->glshader.texture_locations[0] = glGetUniformLocation(program->id, "u_texture1");
1156   program->glshader.texture_locations[1] = glGetUniformLocation(program->id, "u_texture2");
1157   program->glshader.texture_locations[2] = glGetUniformLocation(program->id, "u_texture3");
1158   program->glshader.texture_locations[3] = glGetUniformLocation(program->id, "u_texture4");
1159 
1160   /* We use u_texture1 for the texture 0 in the glshaders, so alias it here so we can use the regular setters */
1161   program->source_location = program->glshader.texture_locations[0];
1162 
1163   for (int i = 0; i < G_N_ELEMENTS (program->glshader.args_locations); i++)
1164     {
1165       if (i < n_uniforms)
1166         {
1167           program->glshader.args_locations[i] = glGetUniformLocation(program->id, uniforms[i].name);
1168           /* This isn't necessary a hard error, you might declare uniforms that are not actually
1169              always used, for instance if you have an "API" in uniforms for multiple shaders. */
1170           if (program->glshader.args_locations[i] == -1)
1171             g_debug ("Declared uniform `%s` not found in GskGLShader", uniforms[i].name);
1172         }
1173       else
1174         program->glshader.args_locations[i] = -1;
1175     }
1176 
1177   return program;
1178 }
1179 
1180 gboolean
gsk_gl_renderer_try_compile_gl_shader(GskGLRenderer * self,GskGLShader * shader,GError ** error)1181 gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer  *self,
1182                                        GskGLShader    *shader,
1183                                        GError        **error)
1184 {
1185   Program *program;
1186 
1187   gdk_gl_context_make_current (self->gl_context);
1188 
1189   /* Maybe we tried to compile it already? */
1190   program = gsk_gl_renderer_lookup_custom_program (self, shader);
1191   if (program != NULL)
1192     {
1193       if (program->id > 0)
1194         return TRUE;
1195       else
1196         {
1197           g_propagate_error (error, g_error_copy (program->glshader.compile_error));
1198           return FALSE;
1199         }
1200     }
1201 
1202   program = compile_glshader (self, shader, error);
1203   return program != NULL;
1204 }
1205 
1206 static inline void
render_gl_shader_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1207 render_gl_shader_node (GskGLRenderer       *self,
1208                        GskRenderNode       *node,
1209                        RenderOpBuilder     *builder)
1210 {
1211   GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
1212   Program *program = gsk_gl_renderer_lookup_custom_program (self, shader);
1213   int n_children = gsk_gl_shader_node_get_n_children (node);
1214 
1215   if (program == NULL)
1216     {
1217       GError *error = NULL;
1218 
1219       program = compile_glshader (self, shader, &error);
1220       if (program == NULL)
1221         {
1222           /* We create the program anyway (in a failed state), so that any compiler warnings or other are only reported once */
1223           program = gsk_gl_renderer_create_custom_program (self, shader);
1224           program->id = -1;
1225           program->glshader.compile_error = error;
1226 
1227           g_warning ("Failed to compile gl shader: %s", error->message);
1228         }
1229     }
1230 
1231   if (program->id >= 0 && n_children <= G_N_ELEMENTS (program->glshader.texture_locations))
1232     {
1233       GBytes *args;
1234       TextureRegion regions[4];
1235       gboolean is_offscreen[4];
1236       for (guint i = 0; i < n_children; i++)
1237         {
1238           GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
1239           if (!add_offscreen_ops (self, builder,
1240                                   &node->bounds,
1241                                   child,
1242                                   &regions[i], &is_offscreen[i],
1243                                   FORCE_OFFSCREEN | RESET_CLIP))
1244             return;
1245         }
1246 
1247       args = gsk_gl_shader_node_get_args (node);
1248       ops_set_program (builder, program);
1249 
1250       ops_set_gl_shader_args (builder, shader, node->bounds.size.width, node->bounds.size.height, g_bytes_get_data (args, NULL));
1251       for (guint i = 0; i < n_children; i++)
1252         {
1253           if (i == 0)
1254             ops_set_texture (builder, regions[i].texture_id);
1255           else
1256             ops_set_extra_texture (builder, regions[i].texture_id, i);
1257         }
1258 
1259       load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
1260     }
1261   else
1262     {
1263       static GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
1264       ops_set_program (builder, &self->programs->color_program);
1265       ops_set_color (builder, &pink);
1266       load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
1267     }
1268 }
1269 
1270 /* Returns TRUE if applying @transform to @bounds
1271  * yields an axis-aligned rectangle
1272  */
1273 static gboolean
result_is_axis_aligned(GskTransform * transform,const graphene_rect_t * bounds)1274 result_is_axis_aligned (GskTransform          *transform,
1275                         const graphene_rect_t *bounds)
1276 {
1277   graphene_matrix_t m;
1278   graphene_quad_t q;
1279   graphene_rect_t b;
1280   graphene_point_t b1, b2;
1281   const graphene_point_t *p;
1282   int i;
1283 
1284   gsk_transform_to_matrix (transform, &m);
1285   gsk_matrix_transform_rect (&m, bounds, &q);
1286   graphene_quad_bounds (&q, &b);
1287   graphene_rect_get_top_left (&b, &b1);
1288   graphene_rect_get_bottom_right (&b, &b2);
1289 
1290   for (i = 0; i < 4; i++)
1291     {
1292       p = graphene_quad_get_point (&q, i);
1293       if (fabs (p->x - b1.x) > FLT_EPSILON && fabs (p->x - b2.x) > FLT_EPSILON)
1294         return FALSE;
1295       if (fabs (p->y - b1.y) > FLT_EPSILON && fabs (p->y - b2.y) > FLT_EPSILON)
1296         return FALSE;
1297     }
1298 
1299   return TRUE;
1300 }
1301 
1302 static inline void
render_transform_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1303 render_transform_node (GskGLRenderer   *self,
1304                        GskRenderNode   *node,
1305                        RenderOpBuilder *builder)
1306 {
1307   GskTransform *node_transform = gsk_transform_node_get_transform (node);
1308   const GskTransformCategory category = gsk_transform_get_category (node_transform);
1309   GskRenderNode *child = gsk_transform_node_get_child (node);
1310 
1311   switch (category)
1312     {
1313     case GSK_TRANSFORM_CATEGORY_IDENTITY:
1314       gsk_gl_renderer_add_render_ops (self, child, builder);
1315     break;
1316 
1317     case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
1318       {
1319         float dx, dy;
1320 
1321         gsk_transform_to_translate (node_transform, &dx, &dy);
1322 
1323         ops_offset (builder, dx, dy);
1324         gsk_gl_renderer_add_render_ops (self, child, builder);
1325         ops_offset (builder, -dx, -dy);
1326       }
1327     break;
1328 
1329     case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
1330       {
1331         ops_push_modelview (builder, node_transform);
1332         gsk_gl_renderer_add_render_ops (self, child, builder);
1333         ops_pop_modelview (builder);
1334       }
1335     break;
1336 
1337     case GSK_TRANSFORM_CATEGORY_2D:
1338     case GSK_TRANSFORM_CATEGORY_3D:
1339     case GSK_TRANSFORM_CATEGORY_ANY:
1340     case GSK_TRANSFORM_CATEGORY_UNKNOWN:
1341       {
1342         TextureRegion region;
1343         gboolean is_offscreen;
1344 
1345         if (node_supports_transform (child))
1346           {
1347             ops_push_modelview (builder, node_transform);
1348             gsk_gl_renderer_add_render_ops (self, child, builder);
1349             ops_pop_modelview (builder);
1350           }
1351         else
1352           {
1353             int filter_flag = 0;
1354 
1355             if (!result_is_axis_aligned (node_transform, &child->bounds))
1356               filter_flag = LINEAR_FILTER;
1357 
1358             if (add_offscreen_ops (self, builder,
1359                                    &child->bounds,
1360                                    child,
1361                                    &region, &is_offscreen,
1362                                    RESET_CLIP | filter_flag))
1363               {
1364                 /* For non-trivial transforms, we draw everything on a texture and then
1365                  * draw the texture transformed. */
1366                 /* TODO: We should compute a modelview containing only the "non-trivial"
1367                  *       part (e.g. the rotation) and use that. We want to keep the scale
1368                  *       for the texture.
1369                  */
1370                 ops_push_modelview (builder, node_transform);
1371                 ops_set_texture (builder, region.texture_id);
1372                 ops_set_program (builder, &self->programs->blit_program);
1373 
1374                 load_vertex_data_with_region (ops_draw (builder, NULL),
1375                                               &child->bounds, builder,
1376                                               &region,
1377                                               is_offscreen);
1378                 ops_pop_modelview (builder);
1379               }
1380           }
1381       }
1382       break;
1383 
1384     default:
1385       g_assert_not_reached ();
1386       break;
1387     }
1388 }
1389 
1390 static inline void
render_opacity_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1391 render_opacity_node (GskGLRenderer   *self,
1392                      GskRenderNode   *node,
1393                      RenderOpBuilder *builder)
1394 {
1395   GskRenderNode *child = gsk_opacity_node_get_child (node);
1396   const float opacity = gsk_opacity_node_get_opacity (node);
1397   float prev_opacity;
1398 
1399   if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
1400     {
1401       gboolean is_offscreen;
1402       TextureRegion region;
1403 
1404       /* The semantics of an opacity node mandate that when, e.g., two color nodes overlap,
1405        * there may not be any blending between them */
1406       if (!add_offscreen_ops (self, builder, &child->bounds,
1407                               child,
1408                               &region, &is_offscreen,
1409                               FORCE_OFFSCREEN | RESET_CLIP))
1410         return;
1411 
1412       prev_opacity = ops_set_opacity (builder,
1413                                       builder->current_opacity * opacity);
1414 
1415       if (builder->current_opacity >= ((float) 0x00ff / (float) 0xffff))
1416         {
1417           ops_set_program (builder, &self->programs->blit_program);
1418           ops_set_texture (builder, region.texture_id);
1419 
1420           load_vertex_data_with_region (ops_draw (builder, NULL),
1421                                         &node->bounds, builder,
1422                                         &region,
1423                                         is_offscreen);
1424         }
1425     }
1426   else
1427     {
1428       prev_opacity = ops_set_opacity (builder,
1429                                       builder->current_opacity * opacity);
1430 
1431       if (builder->current_opacity >= ((float) 0x00ff / (float) 0xffff))
1432         gsk_gl_renderer_add_render_ops (self, child, builder);
1433     }
1434 
1435   ops_set_opacity (builder, prev_opacity);
1436 }
1437 
1438 static inline void
render_linear_gradient_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1439 render_linear_gradient_node (GskGLRenderer   *self,
1440                              GskRenderNode   *node,
1441                              RenderOpBuilder *builder)
1442 {
1443   const int n_color_stops = gsk_linear_gradient_node_get_n_color_stops (node);
1444 
1445   if (n_color_stops < GL_MAX_GRADIENT_STOPS)
1446     {
1447       const GskColorStop *stops = gsk_linear_gradient_node_get_color_stops (node, NULL);
1448       const graphene_point_t *start = gsk_linear_gradient_node_get_start (node);
1449       const graphene_point_t *end = gsk_linear_gradient_node_get_end (node);
1450 
1451       ops_set_program (builder, &self->programs->linear_gradient_program);
1452       ops_set_linear_gradient (builder,
1453                                n_color_stops,
1454                                stops,
1455                                gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
1456                                builder->dx + start->x,
1457                                builder->dy + start->y,
1458                                builder->dx + end->x,
1459                                builder->dy + end->y);
1460 
1461       load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
1462     }
1463   else
1464     {
1465       render_fallback_node (self, node, builder);
1466     }
1467 }
1468 
1469 static inline void
render_radial_gradient_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1470 render_radial_gradient_node (GskGLRenderer   *self,
1471                              GskRenderNode   *node,
1472                              RenderOpBuilder *builder)
1473 {
1474   const int n_color_stops = gsk_radial_gradient_node_get_n_color_stops (node);
1475 
1476   if (n_color_stops < GL_MAX_GRADIENT_STOPS)
1477     {
1478       const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node, NULL);
1479       const graphene_point_t *center = gsk_radial_gradient_node_get_center (node);
1480       const float start = gsk_radial_gradient_node_get_start (node);
1481       const float end = gsk_radial_gradient_node_get_end (node);
1482       const float hradius = gsk_radial_gradient_node_get_hradius (node);
1483       const float vradius = gsk_radial_gradient_node_get_vradius (node);
1484 
1485       ops_set_program (builder, &self->programs->radial_gradient_program);
1486       ops_set_radial_gradient (builder,
1487                                n_color_stops,
1488                                stops,
1489                                gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE,
1490                                builder->dx + center->x,
1491                                builder->dy + center->y,
1492                                start, end,
1493                                hradius * builder->scale_x,
1494                                vradius * builder->scale_y);
1495 
1496       load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
1497     }
1498   else
1499     {
1500       render_fallback_node (self, node, builder);
1501     }
1502 }
1503 
1504 static inline void
render_conic_gradient_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1505 render_conic_gradient_node (GskGLRenderer   *self,
1506                              GskRenderNode   *node,
1507                              RenderOpBuilder *builder)
1508 {
1509   const int n_color_stops = gsk_conic_gradient_node_get_n_color_stops (node);
1510 
1511   if (n_color_stops < GL_MAX_GRADIENT_STOPS)
1512     {
1513       const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, NULL);
1514       const graphene_point_t *center = gsk_conic_gradient_node_get_center (node);
1515       const float angle = gsk_conic_gradient_node_get_angle (node);
1516 
1517       ops_set_program (builder, &self->programs->conic_gradient_program);
1518       ops_set_conic_gradient (builder,
1519                               n_color_stops,
1520                               stops,
1521                               builder->dx + center->x,
1522                               builder->dy + center->y,
1523                               angle);
1524 
1525       load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
1526     }
1527   else
1528     {
1529       render_fallback_node (self, node, builder);
1530     }
1531 }
1532 
1533 static inline gboolean
rounded_inner_rect_contains_rect(const GskRoundedRect * rounded,const graphene_rect_t * rect)1534 rounded_inner_rect_contains_rect (const GskRoundedRect  *rounded,
1535                                   const graphene_rect_t *rect)
1536 {
1537   const graphene_rect_t *rounded_bounds = &rounded->bounds;
1538   graphene_rect_t inner;
1539   float offset_x, offset_y;
1540 
1541   /* TODO: This is pretty conservative and we could to further, more
1542    *       fine-grained checks to avoid offscreen drawing. */
1543 
1544   offset_x = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].width,
1545                   rounded->corner[GSK_CORNER_BOTTOM_LEFT].width);
1546   offset_y = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].height,
1547                   rounded->corner[GSK_CORNER_TOP_RIGHT].height);
1548 
1549 
1550   inner.origin.x = rounded_bounds->origin.x + offset_x;
1551   inner.origin.y = rounded_bounds->origin.y + offset_y;
1552   inner.size.width = rounded_bounds->size.width - offset_x -
1553                      MAX (rounded->corner[GSK_CORNER_TOP_RIGHT].width,
1554                           rounded->corner[GSK_CORNER_BOTTOM_RIGHT].width);
1555   inner.size.height = rounded_bounds->size.height - offset_y -
1556                       MAX (rounded->corner[GSK_CORNER_BOTTOM_LEFT].height,
1557                            rounded->corner[GSK_CORNER_BOTTOM_RIGHT].height);
1558 
1559   return _graphene_rect_contains_rect (&inner, rect);
1560 }
1561 
1562 /* Current clip is NOT rounded but new one is definitely! */
1563 static inline bool
intersect_rounded_rectilinear(const graphene_rect_t * non_rounded,const GskRoundedRect * rounded,GskRoundedRect * result)1564 intersect_rounded_rectilinear (const graphene_rect_t *non_rounded,
1565                                const GskRoundedRect  *rounded,
1566                                GskRoundedRect        *result)
1567 {
1568   bool corners[4];
1569 
1570   /* Intersects with top left corner? */
1571   corners[0] = rounded_rect_has_corner (rounded, 0) &&
1572                graphene_rect_intersects (non_rounded,
1573                                          &rounded_rect_corner (rounded, 0));
1574   /* top right? */
1575   corners[1] = rounded_rect_has_corner (rounded, 1) &&
1576                graphene_rect_intersects (non_rounded,
1577                                          &rounded_rect_corner (rounded, 1));
1578   /* bottom right? */
1579   corners[2] = rounded_rect_has_corner (rounded, 2) &&
1580                graphene_rect_intersects (non_rounded,
1581                                          &rounded_rect_corner (rounded, 2));
1582   /* bottom left */
1583   corners[3] = rounded_rect_has_corner (rounded, 3) &&
1584                graphene_rect_intersects (non_rounded,
1585                                          &rounded_rect_corner (rounded, 3));
1586 
1587   if (corners[0] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 0)))
1588     return false;
1589   if (corners[1] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 1)))
1590     return false;
1591   if (corners[2] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 2)))
1592     return false;
1593   if (corners[3] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 3)))
1594     return false;
1595 
1596   /* We do intersect with at least one of the corners, but in such a way that the
1597    * intersection between the two clips can still be represented by a single rounded
1598    * rect in a trivial way. do that. */
1599   graphene_rect_intersection (non_rounded, &rounded->bounds, &result->bounds);
1600 
1601   for (int i = 0; i < 4; i++)
1602     {
1603       if (corners[i])
1604         result->corner[i] = rounded->corner[i];
1605       else
1606         result->corner[i].width = result->corner[i].height = 0;
1607     }
1608 
1609   return true;
1610 }
1611 
1612 /* This code intersects the current (maybe rounded) clip with the new
1613  * non-rounded clip */
1614 static inline void
render_clipped_child(GskGLRenderer * self,RenderOpBuilder * builder,const graphene_rect_t * clip,GskRenderNode * child)1615 render_clipped_child (GskGLRenderer         *self,
1616                       RenderOpBuilder       *builder,
1617                       const graphene_rect_t *clip,
1618                       GskRenderNode         *child)
1619 {
1620   graphene_rect_t transformed_clip;
1621   GskRoundedRect intersection;
1622 
1623   ops_transform_bounds_modelview (builder, clip, &transformed_clip);
1624 
1625   if (builder->clip_is_rectilinear)
1626     {
1627       memset (&intersection, 0, sizeof (GskRoundedRect));
1628       graphene_rect_intersection (&transformed_clip,
1629                                   &builder->current_clip->bounds,
1630                                   &intersection.bounds);
1631 
1632       ops_push_clip (builder, &intersection);
1633       gsk_gl_renderer_add_render_ops (self, child, builder);
1634       ops_pop_clip (builder);
1635     }
1636   else if (intersect_rounded_rectilinear (&transformed_clip,
1637                                           builder->current_clip,
1638                                           &intersection))
1639     {
1640       ops_push_clip (builder, &intersection);
1641       gsk_gl_renderer_add_render_ops (self, child, builder);
1642       ops_pop_clip (builder);
1643     }
1644   else
1645     {
1646       /* well fuck */
1647       const float scale_x = builder->scale_x;
1648       const float scale_y = builder->scale_y;
1649       const GskRoundedRect scaled_clip = GSK_ROUNDED_RECT_INIT ((builder->dx + clip->origin.x) * scale_x,
1650                                                                 (builder->dy + clip->origin.y) * scale_y,
1651                                                                 clip->size.width * scale_x,
1652                                                                 clip->size.height * scale_y);
1653       gboolean is_offscreen;
1654       TextureRegion region;
1655 
1656       ops_push_clip (builder, &scaled_clip);
1657       if (!add_offscreen_ops (self, builder, &child->bounds,
1658                               child,
1659                               &region, &is_offscreen,
1660                               FORCE_OFFSCREEN))
1661         g_assert_not_reached ();
1662       ops_pop_clip (builder);
1663 
1664       ops_set_program (builder, &self->programs->blit_program);
1665       ops_set_texture (builder, region.texture_id);
1666 
1667       load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
1668     }
1669 }
1670 
1671 static inline void
render_clip_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1672 render_clip_node (GskGLRenderer   *self,
1673                   GskRenderNode   *node,
1674                   RenderOpBuilder *builder)
1675 {
1676   const graphene_rect_t *clip = gsk_clip_node_get_clip (node);
1677   GskRenderNode *child = gsk_clip_node_get_child (node);
1678 
1679   render_clipped_child (self, builder, clip, child);
1680 }
1681 
1682 static inline void
render_rounded_clip_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1683 render_rounded_clip_node (GskGLRenderer       *self,
1684                           GskRenderNode       *node,
1685                           RenderOpBuilder     *builder)
1686 {
1687   const float scale_x = builder->scale_x;
1688   const float scale_y = builder->scale_y;
1689   const GskRoundedRect *clip = gsk_rounded_clip_node_get_clip (node);
1690   GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
1691   GskRoundedRect transformed_clip;
1692   gboolean need_offscreen;
1693   int i;
1694 
1695   if (node_is_invisible (child))
1696     return;
1697 
1698   ops_transform_bounds_modelview (builder, &clip->bounds, &transformed_clip.bounds);
1699   for (i = 0; i < 4; i ++)
1700     {
1701       transformed_clip.corner[i].width = clip->corner[i].width * scale_x;
1702       transformed_clip.corner[i].height = clip->corner[i].height * scale_y;
1703     }
1704 
1705   if (builder->clip_is_rectilinear)
1706     {
1707       GskRoundedRect intersected_clip;
1708 
1709       if (intersect_rounded_rectilinear (&builder->current_clip->bounds,
1710                                          &transformed_clip,
1711                                          &intersected_clip))
1712         {
1713           ops_push_clip (builder, &intersected_clip);
1714           gsk_gl_renderer_add_render_ops (self, child, builder);
1715           ops_pop_clip (builder);
1716           return;
1717         }
1718     }
1719 
1720   /* After this point we are really working with a new and a current clip
1721    * which both have rounded corners. */
1722 
1723   if (!ops_has_clip (builder))
1724     need_offscreen = FALSE;
1725   else if (rounded_inner_rect_contains_rect (builder->current_clip,
1726                                              &transformed_clip.bounds))
1727     need_offscreen = FALSE;
1728   else
1729     need_offscreen = TRUE;
1730 
1731   if (!need_offscreen)
1732     {
1733       /* If they don't intersect at all, we can simply set
1734        * the new clip and add the render ops */
1735 
1736       /* If the new clip entirely contains the current clip, the intersection is simply
1737        * the current clip, so we can ignore the new one */
1738       if (rounded_inner_rect_contains_rect (&transformed_clip, &builder->current_clip->bounds))
1739         {
1740           gsk_gl_renderer_add_render_ops (self, child, builder);
1741           return;
1742         }
1743 
1744       ops_push_clip (builder, &transformed_clip);
1745       gsk_gl_renderer_add_render_ops (self, child, builder);
1746       ops_pop_clip (builder);
1747     }
1748   else
1749     {
1750       gboolean is_offscreen;
1751       TextureRegion region;
1752 
1753       ops_push_clip (builder, &transformed_clip);
1754       if (!add_offscreen_ops (self, builder, &node->bounds,
1755                               child,
1756                               &region, &is_offscreen,
1757                               FORCE_OFFSCREEN))
1758         g_assert_not_reached ();
1759       ops_pop_clip (builder);
1760 
1761       ops_set_program (builder, &self->programs->blit_program);
1762       ops_set_texture (builder, region.texture_id);
1763 
1764       load_vertex_data_with_region (ops_draw (builder, NULL), &node->bounds, builder,
1765                                     &region, is_offscreen);
1766     }
1767 }
1768 
1769 static inline void
render_color_matrix_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1770 render_color_matrix_node (GskGLRenderer       *self,
1771                           GskRenderNode       *node,
1772                           RenderOpBuilder     *builder)
1773 {
1774   GskRenderNode *child = gsk_color_matrix_node_get_child (node);
1775   TextureRegion region;
1776   gboolean is_offscreen;
1777 
1778   if (node_is_invisible (child))
1779     return;
1780 
1781   if (!add_offscreen_ops (self, builder,
1782                           &node->bounds,
1783                           child,
1784                           &region, &is_offscreen,
1785                           RESET_CLIP))
1786     g_assert_not_reached ();
1787 
1788   ops_set_program (builder, &self->programs->color_matrix_program);
1789   ops_set_color_matrix (builder,
1790                         gsk_color_matrix_node_get_color_matrix (node),
1791                         gsk_color_matrix_node_get_color_offset (node));
1792 
1793   ops_set_texture (builder, region.texture_id);
1794 
1795   load_vertex_data_with_region (ops_draw (builder, NULL),
1796                                 &node->bounds, builder,
1797                                 &region,
1798                                 is_offscreen);
1799 }
1800 
1801 static inline int
blur_texture(GskGLRenderer * self,RenderOpBuilder * builder,const TextureRegion * region,const int texture_to_blur_width,const int texture_to_blur_height,float blur_radius_x,float blur_radius_y)1802 blur_texture (GskGLRenderer       *self,
1803               RenderOpBuilder     *builder,
1804               const TextureRegion *region,
1805               const int            texture_to_blur_width,
1806               const int            texture_to_blur_height,
1807               float                blur_radius_x,
1808               float                blur_radius_y)
1809 {
1810   const GskRoundedRect new_clip = GSK_ROUNDED_RECT_INIT (0, 0, texture_to_blur_width, texture_to_blur_height);
1811   int pass1_texture_id, pass1_render_target;
1812   int pass2_texture_id, pass2_render_target;
1813   int prev_render_target;
1814   graphene_matrix_t prev_projection;
1815   graphene_rect_t prev_viewport;
1816   graphene_matrix_t item_proj;
1817   OpBlur *op;
1818 
1819   g_assert (blur_radius_x > 0);
1820   g_assert (blur_radius_y > 0);
1821 
1822   gsk_gl_driver_create_render_target (self->gl_driver,
1823                                       MAX (texture_to_blur_width, 1), MAX (texture_to_blur_height, 1),
1824                                       GL_NEAREST, GL_NEAREST,
1825                                       &pass1_texture_id, &pass1_render_target);
1826 
1827   if (texture_to_blur_width <= 0 || texture_to_blur_height <= 0)
1828     {
1829       return pass1_texture_id;
1830     }
1831 
1832   gsk_gl_driver_create_render_target (self->gl_driver,
1833                                       texture_to_blur_width, texture_to_blur_height,
1834                                       GL_NEAREST, GL_NEAREST,
1835                                       &pass2_texture_id, &pass2_render_target);
1836 
1837   init_projection_matrix (&item_proj, &new_clip.bounds);
1838 
1839   ops_set_program (builder, &self->programs->blur_program);
1840   prev_projection = ops_set_projection (builder, &item_proj);
1841   ops_set_modelview (builder, NULL);
1842   prev_viewport = ops_set_viewport (builder, &new_clip.bounds);
1843   ops_push_clip (builder, &new_clip);
1844 
1845   prev_render_target = ops_set_render_target (builder, pass1_render_target);
1846   ops_begin (builder, OP_CLEAR);
1847 
1848   op = ops_begin (builder, OP_CHANGE_BLUR);
1849   op->size.width = texture_to_blur_width;
1850   op->size.height = texture_to_blur_height;
1851   op->radius = blur_radius_x;
1852   op->dir[0] = 1;
1853   op->dir[1] = 0;
1854   ops_set_texture (builder, region->texture_id);
1855 
1856   load_vertex_data_with_region (ops_draw (builder, NULL),
1857                                 &new_clip.bounds,
1858                                 builder, region,
1859                                 FALSE);
1860 #if 0
1861   {
1862     static int k;
1863     ops_dump_framebuffer (builder,
1864                           g_strdup_printf ("pass1_%d.png", k++),
1865                           texture_to_blur_width,
1866                           texture_to_blur_height);
1867   }
1868 #endif
1869   op = ops_begin (builder, OP_CHANGE_BLUR);
1870   op->size.width = texture_to_blur_width;
1871   op->size.height = texture_to_blur_height;
1872   op->radius = blur_radius_y;
1873   op->dir[0] = 0;
1874   op->dir[1] = 1;
1875   ops_set_texture (builder, pass1_texture_id);
1876   ops_set_render_target (builder, pass2_render_target);
1877   ops_begin (builder, OP_CLEAR);
1878   load_vertex_data_with_region (ops_draw (builder, NULL), /* render pass 2 */
1879                                 &new_clip.bounds,
1880                                 builder, region,
1881                                 FALSE);
1882 
1883 #if 0
1884   {
1885     static int k;
1886     ops_dump_framebuffer (builder,
1887                           g_strdup_printf ("blurred%d.png", k++),
1888                           texture_to_blur_width,
1889                           texture_to_blur_height);
1890   }
1891 #endif
1892 
1893   ops_set_render_target (builder, prev_render_target);
1894   ops_set_viewport (builder, &prev_viewport);
1895   ops_set_projection (builder, &prev_projection);
1896   ops_pop_modelview (builder);
1897   ops_pop_clip (builder);
1898 
1899   return pass2_texture_id;
1900 }
1901 
1902 static inline void
blur_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder,float blur_radius,guint extra_flags,TextureRegion * out_region,float * out_vertex_data[4])1903 blur_node (GskGLRenderer   *self,
1904            GskRenderNode   *node,
1905            RenderOpBuilder *builder,
1906            float            blur_radius,
1907            guint            extra_flags,
1908            TextureRegion   *out_region,
1909            float           *out_vertex_data[4]) /* min, max, min, max */
1910 {
1911   const float scale_x = builder->scale_x;
1912   const float scale_y = builder->scale_y;
1913   const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */
1914   float texture_width, texture_height;
1915   gboolean is_offscreen;
1916   TextureRegion region;
1917   int blurred_texture_id;
1918 
1919   g_assert (blur_radius > 0);
1920 
1921   /* Increase texture size for the given blur radius and scale it */
1922   texture_width  = ceilf ((node->bounds.size.width  + blur_extra));
1923   texture_height = ceilf ((node->bounds.size.height + blur_extra));
1924 
1925   /* Only blur this if the out region has no texture id yet */
1926   if (out_region->texture_id == 0)
1927     {
1928       if (!add_offscreen_ops (self, builder,
1929                               &GRAPHENE_RECT_INIT (node->bounds.origin.x - (blur_extra / 2.0),
1930                                                    node->bounds.origin.y - (blur_extra / 2.0),
1931                                                    texture_width, texture_height),
1932                               node,
1933                               &region, &is_offscreen,
1934                               RESET_CLIP | FORCE_OFFSCREEN | extra_flags))
1935         g_assert_not_reached ();
1936 
1937       blurred_texture_id = blur_texture (self, builder,
1938                                          &region,
1939                                          texture_width * scale_x, texture_height * scale_y,
1940                                          blur_radius * scale_x,
1941                                          blur_radius * scale_y);
1942       init_full_texture_region (out_region, blurred_texture_id);
1943     }
1944 
1945   if (out_vertex_data)
1946     {
1947       *out_vertex_data[0] = builder->dx + node->bounds.origin.x - (blur_extra / 2.0);
1948       *out_vertex_data[1] = builder->dx + node->bounds.origin.x + node->bounds.size.width + (blur_extra / 2.0);
1949       *out_vertex_data[2] = builder->dy + node->bounds.origin.y - (blur_extra / 2.0);
1950       *out_vertex_data[3] = builder->dy + node->bounds.origin.y + node->bounds.size.height + (blur_extra / 2.0);
1951     }
1952 }
1953 
1954 static inline void
render_blur_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1955 render_blur_node (GskGLRenderer   *self,
1956                   GskRenderNode   *node,
1957                   RenderOpBuilder *builder)
1958 {
1959   const float blur_radius = gsk_blur_node_get_radius (node);
1960   GskRenderNode *child = gsk_blur_node_get_child (node);
1961   TextureRegion blurred_region;
1962   GskTextureKey key;
1963   float min_x, max_x, min_y, max_y;
1964 
1965   if (node_is_invisible (child))
1966     return;
1967 
1968   if (blur_radius <= 0)
1969     {
1970       gsk_gl_renderer_add_render_ops (self, child, builder);
1971       return;
1972     }
1973 
1974   key.pointer = node;
1975   key.pointer_is_child = FALSE;
1976   key.scale_x = builder->scale_x;
1977   key.scale_y = builder->scale_y;
1978   key.filter = GL_NEAREST;
1979   blurred_region.texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
1980   blur_node (self, child, builder, blur_radius, 0, &blurred_region,
1981              (float*[4]){&min_x, &max_x, &min_y, &max_y});
1982 
1983   g_assert (blurred_region.texture_id != 0);
1984 
1985   /* Draw the result */
1986   ops_set_program (builder, &self->programs->blit_program);
1987   ops_set_texture (builder, blurred_region.texture_id);
1988   fill_vertex_data (ops_draw (builder, NULL), min_x, min_y, max_x, max_y);
1989 
1990 
1991   /* Add to cache for the blur node */
1992   gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_region.texture_id);
1993 }
1994 
1995 static inline void
render_unblurred_inset_shadow_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)1996 render_unblurred_inset_shadow_node (GskGLRenderer   *self,
1997                                     GskRenderNode   *node,
1998                                     RenderOpBuilder *builder)
1999 {
2000   const float dx = gsk_inset_shadow_node_get_dx (node);
2001   const float dy = gsk_inset_shadow_node_get_dy (node);
2002   const float spread = gsk_inset_shadow_node_get_spread (node);
2003 
2004   g_assert (gsk_inset_shadow_node_get_blur_radius (node) == 0);
2005 
2006   ops_set_program (builder, &self->programs->inset_shadow_program);
2007   ops_set_inset_shadow (builder, transform_rect (self, builder, gsk_inset_shadow_node_get_outline (node)),
2008                         spread,
2009                         gsk_inset_shadow_node_get_color (node),
2010                         dx, dy);
2011 
2012   load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
2013 }
2014 
2015 static inline void
render_inset_shadow_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2016 render_inset_shadow_node (GskGLRenderer   *self,
2017                           GskRenderNode   *node,
2018                           RenderOpBuilder *builder)
2019 {
2020   const float scale_x = builder->scale_x;
2021   const float scale_y = builder->scale_y;
2022   const float blur_radius = gsk_inset_shadow_node_get_blur_radius (node);
2023   const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */
2024   const float dx = gsk_inset_shadow_node_get_dx (node);
2025   const float dy = gsk_inset_shadow_node_get_dy (node);
2026   const GskRoundedRect *node_outline = gsk_inset_shadow_node_get_outline (node);
2027   float texture_width;
2028   float texture_height;
2029   int blurred_texture_id;
2030   GskTextureKey key;
2031 
2032   g_assert (blur_radius > 0);
2033 
2034   texture_width = ceilf ((node_outline->bounds.size.width + blur_extra) * scale_x);
2035   texture_height = ceilf ((node_outline->bounds.size.height + blur_extra) * scale_y);
2036 
2037   key.pointer = node;
2038   key.pointer_is_child = FALSE;
2039   key.scale_x = scale_x;
2040   key.scale_y = scale_y;
2041   key.filter = GL_NEAREST;
2042   blurred_texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
2043   if (blurred_texture_id == 0)
2044     {
2045       const float spread = gsk_inset_shadow_node_get_spread (node) + (blur_extra / 2.0);
2046       GskRoundedRect outline_to_blur;
2047       int render_target, texture_id;
2048       int prev_render_target;
2049       graphene_matrix_t prev_projection;
2050       graphene_rect_t prev_viewport;
2051       graphene_matrix_t item_proj;
2052       int i;
2053 
2054       /* TODO: In the following code, we have to be careful about where we apply the scale.
2055        * We're manually scaling stuff (e.g. the outline) so we can later use texture_width
2056        * and texture_height (which are already scaled) as the geometry and keep the modelview
2057        * at a scale of 1. That's kinda complicated though... */
2058 
2059       /* Outline of what we actually want to blur later.
2060        * Spread grows inside, so we don't need to account for that. But the blur will need
2061        * to read outside of the inset shadow, so we need to draw some color in there. */
2062       outline_to_blur = *node_outline;
2063       gsk_rounded_rect_shrink (&outline_to_blur,
2064                                - blur_extra / 2.0, - blur_extra / 2.0,
2065                                - blur_extra / 2.0, - blur_extra / 2.0);
2066 
2067       /* Fit to our texture */
2068       outline_to_blur.bounds.origin.x = 0;
2069       outline_to_blur.bounds.origin.y = 0;
2070       outline_to_blur.bounds.size.width *= scale_x;
2071       outline_to_blur.bounds.size.height *= scale_y;
2072 
2073       for (i = 0; i < 4; i ++)
2074         {
2075           outline_to_blur.corner[i].width *= scale_x;
2076           outline_to_blur.corner[i].height *= scale_y;
2077         }
2078 
2079       gsk_gl_driver_create_render_target (self->gl_driver,
2080                                           texture_width, texture_height,
2081                                           GL_NEAREST, GL_NEAREST,
2082                                           &texture_id, &render_target);
2083 
2084       init_projection_matrix (&item_proj,
2085                               &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
2086 
2087       prev_projection = ops_set_projection (builder, &item_proj);
2088       ops_set_modelview (builder, NULL);
2089       prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
2090       ops_push_clip (builder, &GSK_ROUNDED_RECT_INIT (0, 0, texture_width, texture_height));
2091 
2092       prev_render_target = ops_set_render_target (builder, render_target);
2093       ops_begin (builder, OP_CLEAR);
2094 
2095       /* Actual inset shadow outline drawing */
2096       ops_set_program (builder, &self->programs->inset_shadow_program);
2097       ops_set_inset_shadow (builder, transform_rect (self, builder, &outline_to_blur),
2098                             spread * MAX (scale_x, scale_y),
2099                             gsk_inset_shadow_node_get_color (node),
2100                             dx * scale_x, dy * scale_y);
2101 
2102       load_float_vertex_data (ops_draw (builder, NULL), builder,
2103                               0, 0, texture_width, texture_height);
2104 
2105       ops_set_render_target (builder, prev_render_target);
2106       ops_set_viewport (builder, &prev_viewport);
2107       ops_set_projection (builder, &prev_projection);
2108       ops_pop_modelview (builder);
2109       ops_pop_clip (builder);
2110 
2111       blurred_texture_id = blur_texture (self, builder,
2112                                          &(TextureRegion) { texture_id, 0, 0, 1, 1 },
2113                                          texture_width,
2114                                          texture_height,
2115                                          blur_radius * scale_x,
2116                                          blur_radius * scale_y);
2117     }
2118 
2119   g_assert (blurred_texture_id != 0);
2120 
2121   /* Blur the rendered unblurred inset shadow */
2122   /* Use a clip to cut away the unwanted parts outside of the original outline */
2123   {
2124     const gboolean needs_clip = !gsk_rounded_rect_is_rectilinear (node_outline);
2125     const float tx1 = blur_extra / 2.0 * scale_x / texture_width;
2126     const float tx2 = 1.0 - tx1;
2127     const float ty1 = blur_extra / 2.0 * scale_y / texture_height;
2128     const float ty2 = 1.0 - ty1;
2129 
2130     gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_texture_id);
2131 
2132     if (needs_clip)
2133       {
2134         GskRoundedRect node_clip;
2135 
2136         ops_transform_bounds_modelview (builder, &node_outline->bounds, &node_clip.bounds);
2137         for (int i = 0; i < 4; i ++)
2138           {
2139             node_clip.corner[i].width = node_outline->corner[i].width * scale_x;
2140             node_clip.corner[i].height = node_outline->corner[i].height * scale_y;
2141           }
2142 
2143         ops_push_clip (builder, &node_clip);
2144       }
2145 
2146     ops_set_program (builder, &self->programs->blit_program);
2147     ops_set_texture (builder, blurred_texture_id);
2148 
2149     load_vertex_data_with_region (ops_draw (builder, NULL),
2150                                   &node->bounds, builder,
2151                                   &(TextureRegion) { 0, tx1, ty1, tx2, ty2 },
2152                                   TRUE);
2153 
2154     if (needs_clip)
2155       ops_pop_clip (builder);
2156   }
2157 
2158 }
2159 
2160 /* Spread *grows* the outline. The offset moves the shadow and leaves the
2161  * inner rect where it was */
2162 static inline void
render_unblurred_outset_shadow_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2163 render_unblurred_outset_shadow_node (GskGLRenderer   *self,
2164                                      GskRenderNode   *node,
2165                                      RenderOpBuilder *builder)
2166 {
2167   const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node);
2168   const float x = node->bounds.origin.x;
2169   const float y = node->bounds.origin.y;
2170   const float w = node->bounds.size.width;
2171   const float h = node->bounds.size.height;
2172   const float spread = gsk_outset_shadow_node_get_spread (node);
2173   const float dx = gsk_outset_shadow_node_get_dx (node);
2174   const float dy = gsk_outset_shadow_node_get_dy (node);
2175   const float edge_sizes[] = { // Top, right, bottom, left
2176     spread - dy, spread + dx, spread + dy, spread - dx
2177   };
2178   const float corner_sizes[][2] = { // top left, top right, bottom right, bottom left
2179     { outline->corner[0].width + spread - dx, outline->corner[0].height + spread - dy },
2180     { outline->corner[1].width + spread + dx, outline->corner[1].height + spread - dy },
2181     { outline->corner[2].width + spread + dx, outline->corner[2].height + spread + dy },
2182     { outline->corner[3].width + spread - dx, outline->corner[3].height + spread + dy },
2183   };
2184 
2185   ops_set_program (builder, &self->programs->unblurred_outset_shadow_program);
2186   ops_set_unblurred_outset_shadow (builder, transform_rect (self, builder, outline),
2187                                    spread,
2188                                    gsk_outset_shadow_node_get_color (node),
2189                                    dx, dy);
2190 
2191   /* Corners... */
2192   if (corner_sizes[0][0] > 0 && corner_sizes[0][1] > 0) /* Top left */
2193       load_float_vertex_data (ops_draw (builder, NULL), builder,
2194                               x, y,
2195                               corner_sizes[0][0], corner_sizes[0][1]);
2196   if (corner_sizes[1][0] > 0 && corner_sizes[1][1] > 0) /* Top right */
2197       load_float_vertex_data (ops_draw (builder, NULL), builder,
2198                               x + w - corner_sizes[1][0], y,
2199                               corner_sizes[1][0], corner_sizes[1][1]);
2200   if (corner_sizes[2][0] > 0 && corner_sizes[2][1] > 0) /* Bottom right */
2201       load_float_vertex_data (ops_draw (builder, NULL), builder,
2202                               x + w - corner_sizes[2][0], y + h - corner_sizes[2][1],
2203                               corner_sizes[2][0], corner_sizes[2][1]);
2204   if (corner_sizes[3][0] > 0 && corner_sizes[3][1] > 0) /* Bottom left */
2205       load_float_vertex_data (ops_draw (builder, NULL), builder,
2206                               x, y + h - corner_sizes[3][1],
2207                               corner_sizes[3][0], corner_sizes[3][1]);
2208   /* Edges... */;
2209   if (edge_sizes[0] > 0) /* Top */
2210     load_float_vertex_data (ops_draw (builder, NULL), builder,
2211                             x + corner_sizes[0][0], y,
2212                             w - corner_sizes[0][0] - corner_sizes[1][0], edge_sizes[0]);
2213   if (edge_sizes[1] > 0) /* Right */
2214     load_float_vertex_data (ops_draw (builder, NULL), builder,
2215                             x + w - edge_sizes[1], y + corner_sizes[1][1],
2216                             edge_sizes[1], h - corner_sizes[1][1] - corner_sizes[2][1]);
2217   if (edge_sizes[2] > 0) /* Bottom */
2218     load_float_vertex_data (ops_draw (builder, NULL), builder,
2219                             x + corner_sizes[3][0], y + h - edge_sizes[2],
2220                             w - corner_sizes[3][0] - corner_sizes[2][0], edge_sizes[2]);
2221   if (edge_sizes[3] > 0) /* Left */
2222     load_float_vertex_data (ops_draw (builder, NULL), builder,
2223                             x, y + corner_sizes[0][1],
2224                             edge_sizes[3], h - corner_sizes[0][1] - corner_sizes[3][1]);
2225 }
2226 
2227 
2228 static GdkRGBA COLOR_WHITE = { 1, 1, 1, 1 };
2229 static inline void
render_outset_shadow_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2230 render_outset_shadow_node (GskGLRenderer   *self,
2231                            GskRenderNode   *node,
2232                            RenderOpBuilder *builder)
2233 {
2234   const float scale_x = builder->scale_x;
2235   const float scale_y = builder->scale_y;
2236   const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node);
2237   const GdkRGBA *color = gsk_outset_shadow_node_get_color (node);
2238   const float blur_radius = gsk_outset_shadow_node_get_blur_radius (node);
2239   const float blur_extra = blur_radius * 2.0f; /* 2.0 = shader radius_multiplier */
2240   const int extra_blur_pixels = (int) ceilf(blur_extra / 2.0 * MAX (scale_x, scale_y)); /* TODO: No need to MAX() her actually */
2241   const float spread = gsk_outset_shadow_node_get_spread (node);
2242   const float dx = gsk_outset_shadow_node_get_dx (node);
2243   const float dy = gsk_outset_shadow_node_get_dy (node);
2244   GskRoundedRect scaled_outline;
2245   int texture_width, texture_height;
2246   OpOutsetShadow *shadow;
2247   int blurred_texture_id;
2248   int cached_tid;
2249   bool do_slicing;
2250 
2251   /* scaled_outline is the minimal outline we need to draw the given drop shadow,
2252    * enlarged by the spread and offset by the blur radius. */
2253   scaled_outline = *outline;
2254 
2255   if (outline->bounds.size.width < blur_extra ||
2256       outline->bounds.size.height < blur_extra)
2257     {
2258       do_slicing = false;
2259       gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
2260     }
2261   else
2262     {
2263       /* Shrink our outline to the minimum size that can still hold all the border radii */
2264       gsk_rounded_rect_shrink_to_minimum (&scaled_outline);
2265       /* Increase by the spread */
2266       gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
2267       /* Grow bounds but don't grow corners */
2268       graphene_rect_inset (&scaled_outline.bounds, - blur_extra / 2.0, - blur_extra / 2.0);
2269       /* For the center part, we add a few pixels */
2270       scaled_outline.bounds.size.width += SHADOW_EXTRA_SIZE;
2271       scaled_outline.bounds.size.height += SHADOW_EXTRA_SIZE;
2272 
2273       do_slicing = true;
2274     }
2275 
2276   texture_width  = (int)ceil ((scaled_outline.bounds.size.width  + blur_extra) * scale_x);
2277   texture_height = (int)ceil ((scaled_outline.bounds.size.height + blur_extra) * scale_y);
2278 
2279   scaled_outline.bounds.origin.x = extra_blur_pixels;
2280   scaled_outline.bounds.origin.y = extra_blur_pixels;
2281   scaled_outline.bounds.size.width = texture_width - (extra_blur_pixels * 2);
2282   scaled_outline.bounds.size.height = texture_height - (extra_blur_pixels * 2);
2283 
2284   for (int i = 0; i < 4; i ++)
2285     {
2286       scaled_outline.corner[i].width *= scale_x;
2287       scaled_outline.corner[i].height *= scale_y;
2288     }
2289 
2290   cached_tid = gsk_gl_shadow_cache_get_texture_id (&self->shadow_cache,
2291                                                    self->gl_driver,
2292                                                    &scaled_outline,
2293                                                    blur_radius);
2294 
2295   if (cached_tid == 0)
2296     {
2297       int texture_id, render_target;
2298       int prev_render_target;
2299       graphene_matrix_t prev_projection;
2300       graphene_rect_t prev_viewport;
2301       graphene_matrix_t item_proj;
2302 
2303       gsk_gl_driver_create_render_target (self->gl_driver,
2304                                           texture_width, texture_height,
2305                                           GL_NEAREST, GL_NEAREST,
2306                                           &texture_id, &render_target);
2307       if (gdk_gl_context_has_debug (self->gl_context))
2308         {
2309           gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
2310                                               "Outset Shadow Temp %d", texture_id);
2311           gdk_gl_context_label_object_printf  (self->gl_context, GL_FRAMEBUFFER, render_target,
2312                                                "Outset Shadow FB Temp %d", render_target);
2313         }
2314 
2315       ops_set_program (builder, &self->programs->color_program);
2316       init_projection_matrix (&item_proj,
2317                               &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
2318 
2319       prev_render_target = ops_set_render_target (builder, render_target);
2320       ops_begin (builder, OP_CLEAR);
2321       prev_projection = ops_set_projection (builder, &item_proj);
2322       ops_set_modelview (builder, NULL);
2323       prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
2324 
2325       /* Draw outline */
2326       ops_push_clip (builder, &scaled_outline);
2327       ops_set_color (builder, &COLOR_WHITE);
2328       load_float_vertex_data (ops_draw (builder, NULL), builder,
2329                               0, 0, texture_width, texture_height);
2330 
2331       ops_pop_clip (builder);
2332       ops_set_viewport (builder, &prev_viewport);
2333       ops_pop_modelview (builder);
2334       ops_set_projection (builder, &prev_projection);
2335       ops_set_render_target (builder, prev_render_target);
2336 
2337       /* Now blur the outline */
2338       blurred_texture_id = blur_texture (self, builder,
2339                                          &(TextureRegion) { texture_id, 0, 0, 1, 1 },
2340                                          texture_width,
2341                                          texture_height,
2342                                          blur_radius * scale_x,
2343                                          blur_radius * scale_y);
2344 
2345       gsk_gl_driver_mark_texture_permanent (self->gl_driver, blurred_texture_id);
2346       gsk_gl_shadow_cache_commit (&self->shadow_cache,
2347                                   &scaled_outline,
2348                                   blur_radius,
2349                                   blurred_texture_id);
2350     }
2351   else
2352     {
2353       blurred_texture_id = cached_tid;
2354     }
2355 
2356 
2357   if (!do_slicing)
2358     {
2359       const float min_x = floorf (outline->bounds.origin.x - spread - (blur_extra / 2.0) + dx);
2360       const float min_y = floorf (outline->bounds.origin.y - spread - (blur_extra / 2.0) + dy);
2361 
2362       ops_set_program (builder, &self->programs->outset_shadow_program);
2363       ops_set_color (builder, color);
2364       ops_set_texture (builder, blurred_texture_id);
2365 
2366       shadow = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW);
2367       shadow->outline.value = transform_rect (self, builder, outline);
2368       shadow->outline.send = TRUE;
2369 
2370       load_vertex_data_with_region (ops_draw (builder, NULL),
2371                                     &GRAPHENE_RECT_INIT (
2372                                       min_x, min_y,
2373                                       texture_width / scale_x, texture_height / scale_y
2374                                     ), builder,
2375                                     &(TextureRegion) { 0, 0, 0, 1, 1 },
2376                                     FALSE);
2377       return;
2378     }
2379 
2380 
2381   ops_set_program (builder, &self->programs->outset_shadow_program);
2382   ops_set_color (builder, color);
2383   ops_set_texture (builder, blurred_texture_id);
2384 
2385   shadow = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW);
2386   shadow->outline.value = transform_rect (self, builder, outline);
2387   shadow->outline.send = TRUE;
2388 
2389   {
2390     const float min_x = floorf (outline->bounds.origin.x - spread - (blur_extra / 2.0) + dx);
2391     const float min_y = floorf (outline->bounds.origin.y - spread - (blur_extra / 2.0) + dy);
2392     const float max_x = ceilf (outline->bounds.origin.x + outline->bounds.size.width +
2393                                (blur_extra / 2.0) + dx + spread);
2394     const float max_y = ceilf (outline->bounds.origin.y + outline->bounds.size.height +
2395                                (blur_extra / 2.0) + dy + spread);
2396     cairo_rectangle_int_t slices[9];
2397     TextureRegion tregs[9];
2398 
2399     /* TODO: The slicing never changes and could just go into the cache */
2400     nine_slice_rounded_rect (&scaled_outline, slices);
2401     nine_slice_grow (slices, extra_blur_pixels);
2402     nine_slice_to_texture_coords (slices, texture_width, texture_height, tregs);
2403 
2404     /* Our texture coordinates MUST be scaled, while the actual vertex coords
2405      * MUST NOT be scaled. */
2406 
2407     /* Top left */
2408     if (slice_is_visible (&slices[NINE_SLICE_TOP_LEFT]))
2409       {
2410         load_vertex_data_with_region (ops_draw (builder, NULL),
2411                                       &GRAPHENE_RECT_INIT (
2412                                         min_x, min_y,
2413                                         slices[NINE_SLICE_TOP_LEFT].width / scale_x,
2414                                         slices[NINE_SLICE_TOP_LEFT].height / scale_y
2415                                       ),
2416                                       builder,
2417                                       &tregs[NINE_SLICE_TOP_LEFT], TRUE);
2418       }
2419 
2420     /* Top center */
2421     if (slice_is_visible (&slices[NINE_SLICE_TOP_CENTER]))
2422       {
2423         const float width = (max_x - min_x) - (slices[NINE_SLICE_TOP_LEFT].width / scale_x +
2424                                                slices[NINE_SLICE_TOP_RIGHT].width / scale_x);
2425         load_vertex_data_with_region (ops_draw (builder, NULL),
2426                                       &GRAPHENE_RECT_INIT (
2427                                         min_x + (slices[NINE_SLICE_TOP_LEFT].width / scale_x),
2428                                         min_y,
2429                                         width,
2430                                         slices[NINE_SLICE_TOP_CENTER].height / scale_y
2431                                       ),
2432                                       builder,
2433                                       &tregs[NINE_SLICE_TOP_CENTER], TRUE);
2434       }
2435     /* Top right */
2436     if (slice_is_visible (&slices[NINE_SLICE_TOP_RIGHT]))
2437       {
2438         load_vertex_data_with_region (ops_draw (builder, NULL),
2439                                       &GRAPHENE_RECT_INIT (
2440                                         max_x - (slices[NINE_SLICE_TOP_RIGHT].width / scale_x),
2441                                         min_y,
2442                                         slices[NINE_SLICE_TOP_RIGHT].width / scale_x,
2443                                         slices[NINE_SLICE_TOP_RIGHT].height / scale_y
2444                                       ),
2445                                       builder,
2446                                       &tregs[NINE_SLICE_TOP_RIGHT], TRUE);
2447       }
2448 
2449     /* Bottom right */
2450     if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_RIGHT]))
2451       {
2452         load_vertex_data_with_region (ops_draw (builder, NULL),
2453                                       &GRAPHENE_RECT_INIT (
2454                                         max_x - (slices[NINE_SLICE_BOTTOM_RIGHT].width / scale_x),
2455                                         max_y - (slices[NINE_SLICE_BOTTOM_RIGHT].height / scale_y),
2456                                         slices[NINE_SLICE_BOTTOM_RIGHT].width / scale_x,
2457                                         slices[NINE_SLICE_BOTTOM_RIGHT].height / scale_y
2458                                       ),
2459                                       builder,
2460                                       &tregs[NINE_SLICE_BOTTOM_RIGHT], TRUE);
2461       }
2462 
2463     /* Bottom left */
2464     if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_LEFT]))
2465       {
2466         load_vertex_data_with_region (ops_draw (builder, NULL),
2467                                       &GRAPHENE_RECT_INIT (
2468                                         min_x,
2469                                         max_y - (slices[NINE_SLICE_BOTTOM_LEFT].height / scale_y),
2470                                         slices[NINE_SLICE_BOTTOM_LEFT].width / scale_x,
2471                                         slices[NINE_SLICE_BOTTOM_LEFT].height / scale_y
2472                                       ),
2473                                       builder,
2474                                       &tregs[NINE_SLICE_BOTTOM_LEFT], TRUE);
2475       }
2476 
2477     /* Left side */
2478     if (slice_is_visible (&slices[NINE_SLICE_LEFT_CENTER]))
2479       {
2480         const float height = (max_y - min_y) - (slices[NINE_SLICE_TOP_LEFT].height / scale_y +
2481                                                 slices[NINE_SLICE_BOTTOM_LEFT].height / scale_y);
2482         load_vertex_data_with_region (ops_draw (builder, NULL),
2483                                       &GRAPHENE_RECT_INIT (
2484                                         min_x,
2485                                         min_y + (slices[NINE_SLICE_TOP_LEFT].height / scale_y),
2486                                         slices[NINE_SLICE_LEFT_CENTER].width / scale_x,
2487                                         height
2488                                       ),
2489                                       builder,
2490                                       &tregs[NINE_SLICE_LEFT_CENTER], TRUE);
2491       }
2492 
2493     /* Right side */
2494     if (slice_is_visible (&slices[NINE_SLICE_RIGHT_CENTER]))
2495       {
2496         const float height = (max_y - min_y) - (slices[NINE_SLICE_TOP_RIGHT].height / scale_y +
2497                                                 slices[NINE_SLICE_BOTTOM_RIGHT].height / scale_y);
2498         load_vertex_data_with_region (ops_draw (builder, NULL),
2499                                       &GRAPHENE_RECT_INIT (
2500                                         max_x - (slices[NINE_SLICE_RIGHT_CENTER].width / scale_x),
2501                                         min_y + (slices[NINE_SLICE_TOP_LEFT].height / scale_y),
2502                                         slices[NINE_SLICE_RIGHT_CENTER].width / scale_x,
2503                                         height
2504                                       ),
2505                                       builder,
2506                                       &tregs[NINE_SLICE_RIGHT_CENTER], TRUE);
2507       }
2508 
2509     /* Bottom side */
2510     if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_CENTER]))
2511       {
2512         const float width = (max_x - min_x) - (slices[NINE_SLICE_BOTTOM_LEFT].width / scale_x +
2513                                                slices[NINE_SLICE_BOTTOM_RIGHT].width / scale_x);
2514         load_vertex_data_with_region (ops_draw (builder, NULL),
2515                                       &GRAPHENE_RECT_INIT (
2516                                         min_x + (slices[NINE_SLICE_BOTTOM_LEFT].width / scale_x),
2517                                         max_y - (slices[NINE_SLICE_BOTTOM_CENTER].height / scale_y),
2518                                         width,
2519                                         slices[NINE_SLICE_BOTTOM_CENTER].height / scale_y
2520                                       ),
2521                                       builder,
2522                                       &tregs[NINE_SLICE_BOTTOM_CENTER], TRUE);
2523       }
2524 
2525     /* Middle */
2526     if (slice_is_visible (&slices[NINE_SLICE_CENTER]))
2527       {
2528         const float width = (max_x - min_x) - (slices[NINE_SLICE_LEFT_CENTER].width / scale_x +
2529                                                slices[NINE_SLICE_RIGHT_CENTER].width / scale_x);
2530         const float height = (max_y - min_y) - (slices[NINE_SLICE_TOP_CENTER].height / scale_y +
2531                                                 slices[NINE_SLICE_BOTTOM_CENTER].height / scale_y);
2532 
2533         load_vertex_data_with_region (ops_draw (builder, NULL),
2534                                       &GRAPHENE_RECT_INIT (
2535                                         min_x + (slices[NINE_SLICE_LEFT_CENTER].width / scale_x),
2536                                         min_y + (slices[NINE_SLICE_TOP_CENTER].height / scale_y),
2537                                         width, height
2538                                       ),
2539                                       builder,
2540                                       &tregs[NINE_SLICE_CENTER], TRUE);
2541       }
2542   }
2543 }
2544 
2545 static inline void
render_shadow_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2546 render_shadow_node (GskGLRenderer   *self,
2547                     GskRenderNode   *node,
2548                     RenderOpBuilder *builder)
2549 {
2550   const gsize n_shadows = gsk_shadow_node_get_n_shadows (node);
2551   GskRenderNode *original_child = gsk_shadow_node_get_child (node);
2552   GskRenderNode *shadow_child = original_child;
2553   guint i;
2554 
2555   /* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact.
2556    * If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */
2557   if (gsk_render_node_get_node_type (shadow_child) == GSK_COLOR_MATRIX_NODE &&
2558       !color_matrix_modifies_alpha (shadow_child))
2559     {
2560       shadow_child = gsk_color_matrix_node_get_child (shadow_child);
2561     }
2562 
2563   for (i = 0; i < n_shadows; i ++)
2564     {
2565       const GskShadow *shadow = gsk_shadow_node_get_shadow (node, i);
2566       const float dx = shadow->dx;
2567       const float dy = shadow->dy;
2568       TextureRegion region;
2569       gboolean is_offscreen;
2570       graphene_rect_t bounds;
2571 
2572       if (shadow->radius == 0 &&
2573           gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
2574         {
2575           ops_offset (builder, dx, dy);
2576           render_text_node (self, shadow_child, builder, &shadow->color, TRUE);
2577           ops_offset (builder, - dx, - dy);
2578           continue;
2579         }
2580 
2581       if (gdk_rgba_is_clear (&shadow->color))
2582         continue;
2583 
2584       if (node_is_invisible (shadow_child))
2585         continue;
2586 
2587       if (shadow->radius > 0)
2588         {
2589           float min_x;
2590           float min_y;
2591           float max_x;
2592           float max_y;
2593 
2594           region.texture_id = 0;
2595           blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, &region,
2596                      (float*[4]){&min_x, &max_x, &min_y, &max_y});
2597           bounds.origin.x = min_x - builder->dx;
2598           bounds.origin.y = min_y - builder->dy;
2599           bounds.size.width = max_x - min_x;
2600           bounds.size.height = max_y - min_y;
2601           is_offscreen = TRUE;
2602         }
2603       else if (dx == 0 && dy == 0)
2604         {
2605           continue; /* Invisible anyway */
2606         }
2607       else
2608         {
2609           if (!add_offscreen_ops (self, builder,
2610                                   &shadow_child->bounds,
2611                                   shadow_child, &region, &is_offscreen,
2612                                   RESET_CLIP | NO_CACHE_PLZ))
2613             g_assert_not_reached ();
2614 
2615           bounds = shadow_child->bounds;
2616         }
2617 
2618       ops_set_program (builder, &self->programs->coloring_program);
2619       ops_set_color (builder, &shadow->color);
2620       ops_set_texture (builder, region.texture_id);
2621 
2622       ops_offset (builder, dx, dy);
2623       load_vertex_data_with_region (ops_draw (builder, NULL),
2624                                     &bounds, builder,
2625                                     &region,
2626                                     is_offscreen);
2627       ops_offset (builder, -dx, -dy);
2628     }
2629 
2630   /* Now draw the child normally */
2631   gsk_gl_renderer_add_render_ops (self, original_child, builder);
2632 }
2633 
2634 static inline void
render_cross_fade_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2635 render_cross_fade_node (GskGLRenderer   *self,
2636                         GskRenderNode   *node,
2637                         RenderOpBuilder *builder)
2638 {
2639   GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
2640   GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node);
2641   const float progress = gsk_cross_fade_node_get_progress (node);
2642   TextureRegion start_region;
2643   TextureRegion end_region;
2644   gboolean is_offscreen1, is_offscreen2;
2645   OpCrossFade *op;
2646 
2647   if (progress <= 0)
2648     {
2649       gsk_gl_renderer_add_render_ops (self, start_node, builder);
2650       return;
2651     }
2652   else if (progress >= 1)
2653     {
2654       gsk_gl_renderer_add_render_ops (self, end_node, builder);
2655       return;
2656     }
2657 
2658   if (equal_texture_nodes (start_node, end_node))
2659     {
2660       gsk_gl_renderer_add_render_ops (self, end_node, builder);
2661       return;
2662     }
2663 
2664   /* TODO: We create 2 textures here as big as the cross-fade node, but both the
2665    * start and the end node might be a lot smaller than that. */
2666 
2667   if (!add_offscreen_ops (self, builder,
2668                           &node->bounds,
2669                           start_node,
2670                           &start_region, &is_offscreen1,
2671                           FORCE_OFFSCREEN | RESET_CLIP))
2672     {
2673       gsk_gl_renderer_add_render_ops (self, end_node, builder);
2674       return;
2675     }
2676 
2677   if (!add_offscreen_ops (self, builder,
2678                           &node->bounds,
2679                           end_node,
2680                           &end_region, &is_offscreen2,
2681                           FORCE_OFFSCREEN | RESET_CLIP))
2682     {
2683       const float prev_opacity = ops_set_opacity (builder, builder->current_opacity * progress);
2684       gsk_gl_renderer_add_render_ops (self, start_node, builder);
2685       ops_set_opacity (builder, prev_opacity);
2686 
2687       return;
2688     }
2689 
2690   ops_set_program (builder, &self->programs->cross_fade_program);
2691 
2692   op = ops_begin (builder, OP_CHANGE_CROSS_FADE);
2693   op->progress = progress;
2694   op->source2 = end_region.texture_id;
2695 
2696   ops_set_texture (builder, start_region.texture_id);
2697 
2698   load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
2699 }
2700 
2701 static inline void
render_blend_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2702 render_blend_node (GskGLRenderer   *self,
2703                    GskRenderNode   *node,
2704                    RenderOpBuilder *builder)
2705 {
2706   GskRenderNode *top_child = gsk_blend_node_get_top_child (node);
2707   GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node);
2708   TextureRegion top_region;
2709   TextureRegion bottom_region;
2710   gboolean is_offscreen1, is_offscreen2;
2711   OpBlend *op;
2712 
2713   /* TODO: We create 2 textures here as big as the blend node, but both the
2714    * start and the end node might be a lot smaller than that. */
2715   if (!add_offscreen_ops (self, builder,
2716                           &node->bounds,
2717                           bottom_child,
2718                           &bottom_region, &is_offscreen1,
2719                           FORCE_OFFSCREEN | RESET_CLIP))
2720     {
2721       gsk_gl_renderer_add_render_ops (self, top_child, builder);
2722       return;
2723     }
2724 
2725   if (!add_offscreen_ops (self, builder,
2726                           &node->bounds,
2727                           top_child,
2728                           &top_region, &is_offscreen2,
2729                           FORCE_OFFSCREEN | RESET_CLIP))
2730     {
2731       load_vertex_data_with_region (ops_draw (builder, NULL),
2732                                     &node->bounds,
2733                                     builder,
2734                                     &bottom_region,
2735                                     TRUE);
2736       return;
2737     }
2738 
2739   ops_set_program (builder, &self->programs->blend_program);
2740   ops_set_texture (builder, bottom_region.texture_id);
2741 
2742   op = ops_begin (builder, OP_CHANGE_BLEND);
2743   op->source2 = top_region.texture_id;
2744   op->mode = gsk_blend_node_get_blend_mode (node);
2745 
2746   load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
2747 }
2748 
2749 static inline void
render_repeat_node(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)2750 render_repeat_node (GskGLRenderer   *self,
2751                     GskRenderNode   *node,
2752                     RenderOpBuilder *builder)
2753 {
2754   GskRenderNode *child = gsk_repeat_node_get_child (node);
2755   const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node);
2756   TextureRegion region;
2757   gboolean is_offscreen;
2758   OpRepeat *op;
2759 
2760   if (node_is_invisible (child))
2761     return;
2762 
2763   if (!graphene_rect_equal (child_bounds, &child->bounds))
2764     {
2765       /* TODO: Implement these repeat nodes. */
2766       render_fallback_node (self, node, builder);
2767       return;
2768     }
2769 
2770   /* If the size of the repeat node is smaller than the size of the
2771    * child node, we don't repeat at all and can just draw that part
2772    * of the child texture... */
2773   if (graphene_rect_contains_rect (child_bounds, &node->bounds))
2774     {
2775       render_clipped_child (self, builder, &node->bounds, child);
2776       return;
2777     }
2778 
2779   /* Draw the entire child on a texture */
2780   if (!add_offscreen_ops (self, builder,
2781                           &child->bounds,
2782                           child,
2783                           &region, &is_offscreen,
2784                           RESET_CLIP))
2785     g_assert_not_reached ();
2786 
2787   ops_set_program (builder, &self->programs->repeat_program);
2788   ops_set_texture (builder, region.texture_id);
2789 
2790   op = ops_begin (builder, OP_CHANGE_REPEAT);
2791   op->child_bounds[0] = (node->bounds.origin.x - child_bounds->origin.x) / child_bounds->size.width;
2792   op->child_bounds[1] = (node->bounds.origin.y - child_bounds->origin.y) / child_bounds->size.height;
2793   op->child_bounds[2] = node->bounds.size.width / child_bounds->size.width;
2794   op->child_bounds[3] = node->bounds.size.height / child_bounds->size.height;
2795 
2796   op->texture_rect[0] = region.x;
2797   op->texture_rect[2] = region.x2;
2798 
2799   if (is_offscreen)
2800     {
2801       op->texture_rect[1] = region.y2;
2802       op->texture_rect[3] = region.y;
2803     }
2804   else
2805     {
2806       op->texture_rect[1] = region.y;
2807       op->texture_rect[3] = region.y2;
2808     }
2809 
2810   load_vertex_data_with_region (ops_draw (builder, NULL),
2811                                 &node->bounds, builder,
2812                                 &region,
2813                                 is_offscreen);
2814 }
2815 
2816 static inline void
apply_viewport_op(const Program * program,const OpViewport * op)2817 apply_viewport_op (const Program    *program,
2818                    const OpViewport *op)
2819 {
2820   OP_PRINT (" -> New Viewport: %f, %f, %f, %f",
2821             op->viewport.origin.x, op->viewport.origin.y,
2822             op->viewport.size.width, op->viewport.size.height);
2823   glUniform4f (program->viewport_location,
2824                op->viewport.origin.x, op->viewport.origin.y,
2825                op->viewport.size.width, op->viewport.size.height);
2826   glViewport (0, 0, op->viewport.size.width, op->viewport.size.height);
2827 }
2828 
2829 static inline void
apply_modelview_op(const Program * program,const OpMatrix * op)2830 apply_modelview_op (const Program  *program,
2831                     const OpMatrix *op)
2832 {
2833   float mat[16];
2834 
2835   graphene_matrix_to_float (&op->matrix, mat);
2836   OP_PRINT (" -> Modelview { { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }",
2837             mat[0], mat[1], mat[2], mat[3],
2838             mat[4], mat[5], mat[6], mat[7],
2839             mat[8], mat[9], mat[10], mat[11],
2840             mat[12], mat[13], mat[14], mat[15]);
2841   glUniformMatrix4fv (program->modelview_location, 1, GL_FALSE, mat);
2842 }
2843 
2844 static inline void
apply_projection_op(const Program * program,const OpMatrix * op)2845 apply_projection_op (const Program  *program,
2846                      const OpMatrix *op)
2847 {
2848   float mat[16];
2849 
2850   graphene_matrix_to_float (&op->matrix, mat);
2851   OP_PRINT (" -> Projection { { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }",
2852             mat[0], mat[1], mat[2], mat[3],
2853             mat[4], mat[5], mat[6], mat[7],
2854             mat[8], mat[9], mat[10], mat[11],
2855             mat[12], mat[13], mat[14], mat[15]);
2856   glUniformMatrix4fv (program->projection_location, 1, GL_FALSE, mat);
2857 }
2858 
2859 static inline void
apply_program_op(const Program * program,const OpProgram * op)2860 apply_program_op (const Program  *program,
2861                   const OpProgram *op)
2862 {
2863   OP_PRINT (" -> Program: %d", op->program->index);
2864   glUseProgram (op->program->id);
2865 }
2866 
2867 static inline void
apply_render_target_op(GskGLRenderer * self,const OpRenderTarget * op)2868 apply_render_target_op (GskGLRenderer        *self,
2869                         const OpRenderTarget *op)
2870 {
2871   OP_PRINT (" -> Render Target: %d", op->render_target_id);
2872 
2873   glBindFramebuffer (GL_FRAMEBUFFER, op->render_target_id);
2874 
2875   if (op->render_target_id != 0)
2876     glDisable (GL_SCISSOR_TEST);
2877   else
2878     gsk_gl_renderer_setup_render_mode (self); /* Reset glScissor etc. */
2879 }
2880 
2881 static inline void
apply_color_op(const Program * program,const OpColor * op)2882 apply_color_op (const Program *program,
2883                 const OpColor *op)
2884 {
2885   OP_PRINT (" -> Color: (%f, %f, %f, %f)",
2886             op->rgba->red, op->rgba->green, op->rgba->blue, op->rgba->alpha);
2887   glUniform4fv (program->color.color_location, 1, (float *)op->rgba);
2888 }
2889 
2890 static inline void
apply_opacity_op(const Program * program,const OpOpacity * op)2891 apply_opacity_op (const Program   *program,
2892                   const OpOpacity *op)
2893 {
2894   OP_PRINT (" -> Opacity %f", op->opacity);
2895   glUniform1f (program->alpha_location, op->opacity);
2896 }
2897 
2898 static inline void
apply_source_texture_op(const Program * program,const OpTexture * op)2899 apply_source_texture_op (const Program   *program,
2900                          const OpTexture *op)
2901 {
2902   g_assert(op->texture_id != 0);
2903   OP_PRINT (" -> New texture: %d", op->texture_id);
2904   /* Use texture unit 0 for the source */
2905   glUniform1i (program->source_location, 0);
2906   glActiveTexture (GL_TEXTURE0);
2907   glBindTexture (GL_TEXTURE_2D, op->texture_id);
2908 }
2909 
2910 static inline void
apply_source_extra_texture_op(const Program * program,const OpExtraTexture * op)2911 apply_source_extra_texture_op (const Program        *program,
2912                                const OpExtraTexture *op)
2913 {
2914   g_assert(op->texture_id != 0);
2915   OP_PRINT (" -> New extra texture %d: %d", op->idx, op->texture_id);
2916   glUniform1i (program->glshader.texture_locations[op->idx], op->idx);
2917   glActiveTexture (GL_TEXTURE0 + op->idx);
2918   glBindTexture (GL_TEXTURE_2D, op->texture_id);
2919 }
2920 
2921 static inline void
apply_color_matrix_op(const Program * program,const OpColorMatrix * op)2922 apply_color_matrix_op (const Program       *program,
2923                        const OpColorMatrix *op)
2924 {
2925   OP_PRINT (" -> Color matrix. Send matrix: %d. Send offset: %d.",
2926             op->matrix.send, op->offset.send);
2927 
2928   if (op->matrix.send)
2929     {
2930       float mat[16];
2931       graphene_matrix_to_float (op->matrix.value, mat);
2932       glUniformMatrix4fv (program->color_matrix.color_matrix_location, 1, GL_FALSE, mat);
2933     }
2934 
2935   if (op->offset.send)
2936     {
2937       float vec[4];
2938       graphene_vec4_to_float (op->offset.value, vec);
2939       glUniform4fv (program->color_matrix.color_offset_location, 1, vec);
2940     }
2941 }
2942 
2943 static inline void
apply_clip_op(const Program * program,const OpClip * op)2944 apply_clip_op (const Program *program,
2945                const OpClip  *op)
2946 {
2947   int count;
2948 
2949   if (op->send_corners)
2950     {
2951       OP_PRINT (" -> Clip: %s", gsk_rounded_rect_to_string (&op->clip));
2952       count = 3;
2953     }
2954   else
2955     {
2956       OP_PRINT (" -> clip: %f, %f, %f, %f",
2957                 op->clip.bounds.origin.x, op->clip.bounds.origin.y,
2958                 op->clip.bounds.size.width, op->clip.bounds.size.height);
2959       count = 1;
2960     }
2961 
2962   glUniform4fv (program->clip_rect_location, count, (float *)&op->clip.bounds);
2963 }
2964 
2965 static inline void
apply_inset_shadow_op(const Program * program,const OpShadow * op)2966 apply_inset_shadow_op (const Program  *program,
2967                        const OpShadow *op)
2968 {
2969   OP_PRINT (" -> inset shadow. Color: %s, Offset: (%f, %f), Spread: %f, Outline: %s",
2970             op->color.send ? gdk_rgba_to_string (op->color.value) : "don't send",
2971             op->offset.send ? op->offset.value[0] : -1337.0,
2972             op->offset.send ? op->offset.value[1] : -1337.0,
2973             op->spread.send ? op->spread.value : -1337.0,
2974             op->outline.send ? gsk_rounded_rect_to_string (&op->outline.value) : "don't send");
2975   if (op->outline.send)
2976     {
2977       if (op->outline.send_corners)
2978         glUniform4fv (program->inset_shadow.outline_rect_location, 3, (float *)&op->outline.value);
2979       else
2980         glUniform4fv (program->inset_shadow.outline_rect_location, 1, (float *)&op->outline.value);
2981     }
2982 
2983   if (op->color.send)
2984     glUniform4fv (program->inset_shadow.color_location, 1, (float *)op->color.value);
2985 
2986   if (op->spread.send)
2987     glUniform1f (program->inset_shadow.spread_location, op->spread.value);
2988 
2989   if (op->offset.send)
2990     glUniform2fv (program->inset_shadow.offset_location, 1, op->offset.value);
2991 }
2992 
2993 static inline void
apply_unblurred_outset_shadow_op(const Program * program,const OpShadow * op)2994 apply_unblurred_outset_shadow_op (const Program  *program,
2995                                   const OpShadow *op)
2996 {
2997   OP_PRINT (" -> unblurred outset shadow");
2998 
2999   if (op->outline.send)
3000     {
3001       if (op->outline.send_corners)
3002         glUniform4fv (program->unblurred_outset_shadow.outline_rect_location, 3, (float *)&op->outline.value);
3003       else
3004         glUniform4fv (program->unblurred_outset_shadow.outline_rect_location, 1, (float *)&op->outline.value);
3005     }
3006 
3007   if (op->color.send)
3008     glUniform4fv (program->unblurred_outset_shadow.color_location, 1, (float *)op->color.value);
3009 
3010   if (op->spread.send)
3011     glUniform1f (program->unblurred_outset_shadow.spread_location, op->spread.value);
3012 
3013   if (op->offset.send)
3014     glUniform2fv (program->unblurred_outset_shadow.offset_location, 1, op->offset.value);
3015 }
3016 
3017 static inline void
apply_outset_shadow_op(const Program * program,const OpOutsetShadow * op)3018 apply_outset_shadow_op (const Program        *program,
3019                         const OpOutsetShadow *op)
3020 {
3021   OP_PRINT (" -> outset shadow");
3022   glUniform4fv (program->outset_shadow.outline_rect_location, 3, (float *)&op->outline.value.bounds);
3023 }
3024 
3025 static inline void
apply_linear_gradient_op(const Program * program,const OpLinearGradient * op)3026 apply_linear_gradient_op (const Program          *program,
3027                           const OpLinearGradient *op)
3028 {
3029   OP_PRINT (" -> Linear gradient");
3030   if (op->n_color_stops.send)
3031     glUniform1i (program->linear_gradient.num_color_stops_location, op->n_color_stops.value);
3032 
3033   if (op->color_stops.send)
3034     glUniform1fv (program->linear_gradient.color_stops_location,
3035                   op->n_color_stops.value * 5,
3036                   (float *)op->color_stops.value);
3037 
3038   glUniform4f (program->linear_gradient.points_location,
3039                op->start_point[0], op->start_point[1],
3040                op->end_point[0] - op->start_point[0], op->end_point[1] - op->start_point[1]);
3041   glUniform1i (program->linear_gradient.repeat_location, op->repeat);
3042 }
3043 
3044 static inline void
apply_radial_gradient_op(const Program * program,const OpRadialGradient * op)3045 apply_radial_gradient_op (const Program          *program,
3046                           const OpRadialGradient *op)
3047 {
3048   float scale;
3049   float bias;
3050 
3051   OP_PRINT (" -> Radial gradient");
3052   if (op->n_color_stops.send)
3053     glUniform1i (program->radial_gradient.num_color_stops_location, op->n_color_stops.value);
3054 
3055   if (op->color_stops.send)
3056     glUniform1fv (program->radial_gradient.color_stops_location,
3057                   op->n_color_stops.value * 5,
3058                   (float *)op->color_stops.value);
3059 
3060   scale = 1.0f / (op->end - op->start);
3061   bias = -op->start * scale;
3062 
3063   glUniform1i (program->radial_gradient.repeat_location, op->repeat);
3064   glUniform2f (program->radial_gradient.range_location, scale, bias);
3065   glUniform4f (program->radial_gradient.geometry_location,
3066                op->center[0], op->center[1],
3067                1.0f / op->radius[0], 1.0f / op->radius[1]);
3068 }
3069 
3070 static inline void
apply_conic_gradient_op(const Program * program,const OpConicGradient * op)3071 apply_conic_gradient_op (const Program         *program,
3072                          const OpConicGradient *op)
3073 {
3074   float bias;
3075   float scale;
3076 
3077   OP_PRINT (" -> Conic gradient");
3078   if (op->n_color_stops.send)
3079     glUniform1i (program->conic_gradient.num_color_stops_location, op->n_color_stops.value);
3080 
3081   if (op->color_stops.send)
3082     glUniform1fv (program->conic_gradient.color_stops_location,
3083                   op->n_color_stops.value * 5,
3084                   (float *)op->color_stops.value);
3085 
3086   scale = 0.5f * M_1_PI;
3087   bias = op->angle * scale + 2.0f;
3088   glUniform4f (program->conic_gradient.geometry_location, op->center[0], op->center[1], scale, bias);
3089 }
3090 
3091 static inline void
apply_border_op(const Program * program,const OpBorder * op)3092 apply_border_op (const Program  *program,
3093                  const OpBorder *op)
3094 {
3095   OP_PRINT (" -> Border Outline");
3096 
3097   glUniform4fv (program->border.outline_rect_location, 3, (float *)&op->outline.bounds);
3098 }
3099 
3100 static inline void
apply_gl_shader_args_op(const Program * program,const OpGLShader * op)3101 apply_gl_shader_args_op (const Program  *program,
3102                          const OpGLShader *op)
3103 {
3104   int n_uniforms, i;
3105   const GskGLUniform *uniforms;
3106 
3107   OP_PRINT (" -> GL Shader Args");
3108 
3109   glUniform2fv (program->glshader.size_location, 1, op->size);
3110 
3111   uniforms = gsk_gl_shader_get_uniforms (op->shader, &n_uniforms);
3112   for (i = 0; i < n_uniforms; i++)
3113     {
3114       const GskGLUniform *u = &uniforms[i];
3115       const guchar *data = op->uniform_data + u->offset;
3116 
3117       switch (u->type)
3118         {
3119         default:
3120         case GSK_GL_UNIFORM_TYPE_NONE:
3121           break;
3122         case GSK_GL_UNIFORM_TYPE_FLOAT:
3123           glUniform1fv (program->glshader.args_locations[i], 1, (const float *)data);
3124           break;
3125         case GSK_GL_UNIFORM_TYPE_INT:
3126           glUniform1iv (program->glshader.args_locations[i], 1, (const gint32 *)data);
3127           break;
3128         case GSK_GL_UNIFORM_TYPE_UINT:
3129         case GSK_GL_UNIFORM_TYPE_BOOL:
3130           glUniform1uiv (program->glshader.args_locations[i], 1, (const guint32 *) data);
3131           break;
3132         case GSK_GL_UNIFORM_TYPE_VEC2:
3133           glUniform2fv (program->glshader.args_locations[i], 1, (const float *)data);
3134           break;
3135         case GSK_GL_UNIFORM_TYPE_VEC3:
3136           glUniform3fv (program->glshader.args_locations[i], 1, (const float *)data);
3137           break;
3138         case GSK_GL_UNIFORM_TYPE_VEC4:
3139           glUniform4fv (program->glshader.args_locations[i], 1, (const float *)data);
3140           break;
3141         }
3142     }
3143 }
3144 
3145 static inline void
apply_border_width_op(const Program * program,const OpBorder * op)3146 apply_border_width_op (const Program  *program,
3147                        const OpBorder *op)
3148 {
3149   OP_PRINT (" -> Border width (%f, %f, %f, %f)",
3150             op->widths[0], op->widths[1], op->widths[2], op->widths[3]);
3151 
3152   glUniform4fv (program->border.widths_location, 1, op->widths);
3153 }
3154 
3155 static inline void
apply_border_color_op(const Program * program,const OpBorder * op)3156 apply_border_color_op (const Program  *program,
3157                        const OpBorder *op)
3158 {
3159   OP_PRINT (" -> Border color: %s", gdk_rgba_to_string (op->color));
3160   glUniform4fv (program->border.color_location, 1, (float *)op->color);
3161 }
3162 
3163 static inline void
apply_blur_op(const Program * program,const OpBlur * op)3164 apply_blur_op (const Program *program,
3165                const OpBlur  *op)
3166 {
3167   OP_PRINT (" -> Blur");
3168   glUniform1f (program->blur.blur_radius_location, op->radius);
3169   glUniform2f (program->blur.blur_size_location, op->size.width, op->size.height);
3170   glUniform2f (program->blur.blur_dir_location, op->dir[0], op->dir[1]);
3171 }
3172 
3173 static inline void
apply_cross_fade_op(const Program * program,const OpCrossFade * op)3174 apply_cross_fade_op (const Program     *program,
3175                      const OpCrossFade *op)
3176 {
3177   OP_PRINT (" -> Cross fade");
3178   /* End texture id */
3179   glUniform1i (program->cross_fade.source2_location, 1);
3180   glActiveTexture (GL_TEXTURE0 + 1);
3181   glBindTexture (GL_TEXTURE_2D, op->source2);
3182   /* progress */
3183   glUniform1f (program->cross_fade.progress_location, op->progress);
3184 }
3185 
3186 static inline void
apply_blend_op(const Program * program,const OpBlend * op)3187 apply_blend_op (const Program *program,
3188                 const OpBlend *op)
3189 {
3190   /* End texture id */
3191   glUniform1i (program->blend.source2_location, 1);
3192   glActiveTexture (GL_TEXTURE0 + 1);
3193   glBindTexture (GL_TEXTURE_2D, op->source2);
3194   /* progress */
3195   glUniform1i (program->blend.mode_location, op->mode);
3196 }
3197 
3198 static inline void
apply_repeat_op(const Program * program,const OpRepeat * op)3199 apply_repeat_op (const Program  *program,
3200                  const OpRepeat *op)
3201 {
3202   OP_PRINT (" -> Repeat");
3203   glUniform4fv (program->repeat.child_bounds_location, 1, op->child_bounds);
3204   glUniform4fv (program->repeat.texture_rect_location, 1, op->texture_rect);
3205 }
3206 
3207 static void
gsk_gl_renderer_dispose(GObject * gobject)3208 gsk_gl_renderer_dispose (GObject *gobject)
3209 {
3210   GskGLRenderer *self = GSK_GL_RENDERER (gobject);
3211 
3212   ops_free (&self->op_builder);
3213 
3214   G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
3215 }
3216 
3217 static void
program_init(Program * program)3218 program_init (Program *program)
3219 {
3220   program->index = -1;
3221   program->state.opacity = 1.0f;
3222 }
3223 
3224 static void
program_finalize(Program * program)3225 program_finalize (Program *program)
3226 {
3227   if (program->id > 0)
3228     glDeleteProgram (program->id);
3229   if (program->index == -1 &&
3230       program->glshader.compile_error != NULL)
3231     g_error_free (program->glshader.compile_error);
3232 
3233   gsk_transform_unref (program->state.modelview);
3234 }
3235 
3236 static void
program_free(Program * program)3237 program_free (Program *program)
3238 {
3239   program_finalize (program);
3240   g_free (program);
3241 }
3242 
3243 static GskGLRendererPrograms *
gsk_gl_renderer_programs_new(void)3244 gsk_gl_renderer_programs_new (void)
3245 {
3246   GskGLRendererPrograms *programs;
3247   int i;
3248 
3249   programs = g_new0 (GskGLRendererPrograms, 1);
3250   programs->ref_count = 1;
3251   for (i = 0; i < GL_N_PROGRAMS; i ++)
3252     program_init (&programs->programs[i]);
3253 
3254   /* We use direct hash for performance, not string hash on the source, because we assume each caller
3255    * reuses a single GskGLShader for all uses and different callers will use different source content. */
3256   programs->custom_programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify)g_object_unref, (GDestroyNotify)program_free);
3257 
3258   return programs;
3259 }
3260 
3261 static GskGLRendererPrograms *
gsk_gl_renderer_programs_ref(GskGLRendererPrograms * programs)3262 gsk_gl_renderer_programs_ref (GskGLRendererPrograms *programs)
3263 {
3264   programs->ref_count++;
3265   return programs;
3266 }
3267 
3268 /* Must be called with the context current */
3269 static void
gsk_gl_renderer_programs_unref(GskGLRendererPrograms * programs)3270 gsk_gl_renderer_programs_unref (GskGLRendererPrograms *programs)
3271 {
3272   int i;
3273   programs->ref_count--;
3274   if (programs->ref_count == 0)
3275     {
3276       for (i = 0; i < GL_N_PROGRAMS; i ++)
3277         program_finalize (&programs->programs[i]);
3278 
3279       g_hash_table_destroy (programs->custom_programs);
3280       g_free (programs);
3281     }
3282 }
3283 
3284 static Program *
gsk_gl_renderer_lookup_custom_program(GskGLRenderer * self,GskGLShader * shader)3285 gsk_gl_renderer_lookup_custom_program (GskGLRenderer  *self,
3286                                        GskGLShader *shader)
3287 {
3288   return g_hash_table_lookup (self->programs->custom_programs, shader);
3289 }
3290 
3291 static Program *
gsk_gl_renderer_create_custom_program(GskGLRenderer * self,GskGLShader * shader)3292 gsk_gl_renderer_create_custom_program (GskGLRenderer  *self,
3293                                        GskGLShader *shader)
3294 {
3295   Program *program = g_new0 (Program, 1);
3296 
3297   program_init (program);
3298 
3299   g_hash_table_insert (self->programs->custom_programs, g_object_ref (shader), program);
3300 
3301   return program;
3302 }
3303 
3304 static GskGLRendererPrograms *
gsk_gl_renderer_create_programs(GskGLRenderer * self,GError ** error)3305 gsk_gl_renderer_create_programs (GskGLRenderer  *self,
3306                                  GError        **error)
3307 {
3308   GskGLShaderBuilder shader_builder;
3309   GskGLRendererPrograms *programs = NULL;
3310   int i;
3311   static const struct {
3312     const char *resource_path;
3313     const char *name;
3314   } program_definitions[] = {
3315     { "/org/gtk/libgsk/gl/blend.glsl",                     "blend" },
3316     { "/org/gtk/libgsk/gl/blit.glsl",                      "blit" },
3317     { "/org/gtk/libgsk/gl/blur.glsl",                      "blur" },
3318     { "/org/gtk/libgsk/gl/border.glsl",                    "border" },
3319     { "/org/gtk/libgsk/gl/color_matrix.glsl",              "color matrix" },
3320     { "/org/gtk/libgsk/gl/color.glsl",                     "color" },
3321     { "/org/gtk/libgsk/gl/coloring.glsl",                  "coloring" },
3322     { "/org/gtk/libgsk/gl/cross_fade.glsl",                "cross fade" },
3323     { "/org/gtk/libgsk/gl/inset_shadow.glsl",              "inset shadow" },
3324     { "/org/gtk/libgsk/gl/linear_gradient.glsl",           "linear gradient" },
3325     { "/org/gtk/libgsk/gl/radial_gradient.glsl",           "radial gradient" },
3326     { "/org/gtk/libgsk/gl/conic_gradient.glsl",            "conic gradient" },
3327     { "/org/gtk/libgsk/gl/outset_shadow.glsl",             "outset shadow" },
3328     { "/org/gtk/libgsk/gl/repeat.glsl",                    "repeat" },
3329     { "/org/gtk/libgsk/gl/unblurred_outset_shadow.glsl",   "unblurred_outset shadow" },
3330   };
3331 
3332   gsk_gl_shader_builder_init (&shader_builder,
3333                               "/org/gtk/libgsk/gl/preamble.glsl",
3334                               "/org/gtk/libgsk/gl/preamble.vs.glsl",
3335                               "/org/gtk/libgsk/gl/preamble.fs.glsl");
3336 
3337   g_assert (G_N_ELEMENTS (program_definitions) == GL_N_PROGRAMS);
3338 
3339   init_shader_builder (self, &shader_builder);
3340 
3341   programs = gsk_gl_renderer_programs_new ();
3342 
3343   for (i = 0; i < GL_N_PROGRAMS; i ++)
3344     {
3345       Program *prog = &programs->programs[i];
3346 
3347       prog->name = program_definitions[i].name;
3348       prog->index = i;
3349       prog->id = gsk_gl_shader_builder_create_program (&shader_builder,
3350                                                        program_definitions[i].resource_path,
3351                                                        NULL, 0, error);
3352       if (prog->id < 0)
3353         {
3354           g_clear_pointer (&programs, gsk_gl_renderer_programs_unref);
3355           goto out;
3356         }
3357 
3358       INIT_COMMON_UNIFORM_LOCATION (prog, alpha);
3359       INIT_COMMON_UNIFORM_LOCATION (prog, source);
3360       INIT_COMMON_UNIFORM_LOCATION (prog, clip_rect);
3361       INIT_COMMON_UNIFORM_LOCATION (prog, viewport);
3362       INIT_COMMON_UNIFORM_LOCATION (prog, projection);
3363       INIT_COMMON_UNIFORM_LOCATION (prog, modelview);
3364     }
3365   /* color */
3366   INIT_PROGRAM_UNIFORM_LOCATION (color, color);
3367 
3368   /* coloring */
3369   INIT_PROGRAM_UNIFORM_LOCATION (coloring, color);
3370 
3371   /* color matrix */
3372   INIT_PROGRAM_UNIFORM_LOCATION (color_matrix, color_matrix);
3373   INIT_PROGRAM_UNIFORM_LOCATION (color_matrix, color_offset);
3374 
3375   /* linear gradient */
3376   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, color_stops);
3377   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, num_color_stops);
3378   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, repeat);
3379   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, points);
3380 
3381   /* radial gradient */
3382   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops);
3383   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, num_color_stops);
3384   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, repeat);
3385   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, geometry);
3386   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, range);
3387 
3388   /* conic gradient */
3389   INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, color_stops);
3390   INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, num_color_stops);
3391   INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, geometry);
3392 
3393   /* blur */
3394   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius);
3395   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_size);
3396   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_dir);
3397 
3398   /* inset shadow */
3399   INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, color);
3400   INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, spread);
3401   INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, offset);
3402   INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, outline_rect);
3403 
3404   /* outset shadow */
3405   INIT_PROGRAM_UNIFORM_LOCATION (outset_shadow, color);
3406   INIT_PROGRAM_UNIFORM_LOCATION (outset_shadow, outline_rect);
3407 
3408   /* unblurred outset shadow */
3409   INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, color);
3410   INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, spread);
3411   INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, offset);
3412   INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, outline_rect);
3413 
3414   /* border */
3415   INIT_PROGRAM_UNIFORM_LOCATION (border, color);
3416   INIT_PROGRAM_UNIFORM_LOCATION (border, widths);
3417   INIT_PROGRAM_UNIFORM_LOCATION (border, outline_rect);
3418 
3419   /* cross fade */
3420   INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, progress);
3421   INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
3422 
3423   /* blend */
3424   INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
3425   INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
3426 
3427   /* repeat */
3428   INIT_PROGRAM_UNIFORM_LOCATION (repeat, child_bounds);
3429   INIT_PROGRAM_UNIFORM_LOCATION (repeat, texture_rect);
3430 
3431 
3432   /* We initialize the alpha uniform here, since the default value is important.
3433    * We can't do it in the shader like a reasonable person would because that doesn't
3434    * work in gles. */
3435   for (i = 0; i < GL_N_PROGRAMS; i++)
3436     {
3437       glUseProgram(programs->programs[i].id);
3438       glUniform1f (programs->programs[i].alpha_location, 1.0);
3439     }
3440 
3441 out:
3442   gsk_gl_shader_builder_finish (&shader_builder);
3443 
3444   /* Check we indeed emitted an error if there was one */
3445   g_assert (programs || !error || *error);
3446 
3447   return programs;
3448 }
3449 
3450 static GskGLRendererPrograms *
get_programs_for_display(GskGLRenderer * self,GdkDisplay * display,GError ** error)3451 get_programs_for_display (GskGLRenderer  *self,
3452                           GdkDisplay     *display,
3453                           GError        **error)
3454 {
3455   GskGLRendererPrograms *programs;
3456 
3457   if (g_getenv ("GSK_NO_SHARED_PROGRAMS"))
3458     return gsk_gl_renderer_create_programs (self, error);
3459 
3460   programs = (GskGLRendererPrograms *)g_object_get_data (G_OBJECT (display), "gsk-gl-programs");
3461   if (programs == NULL)
3462     {
3463       programs = gsk_gl_renderer_create_programs (self, error);
3464       if (programs)
3465         g_object_set_data_full (G_OBJECT (display), "gsk-gl-programs",
3466                                 programs,
3467                                 (GDestroyNotify) gsk_gl_renderer_programs_unref);
3468     }
3469 
3470   if (programs)
3471     return gsk_gl_renderer_programs_ref (programs);
3472   return NULL;
3473 }
3474 
3475 
3476 static GskGLTextureAtlases *
get_texture_atlases_for_display(GdkDisplay * display)3477 get_texture_atlases_for_display (GdkDisplay *display)
3478 {
3479   GskGLTextureAtlases *atlases;
3480 
3481   if (g_getenv ("GSK_NO_SHARED_CACHES"))
3482     return gsk_gl_texture_atlases_new ();
3483 
3484   atlases = (GskGLTextureAtlases*)g_object_get_data (G_OBJECT (display), "gsk-gl-texture-atlases");
3485   if (atlases == NULL)
3486     {
3487       atlases = gsk_gl_texture_atlases_new ();
3488       g_object_set_data_full (G_OBJECT (display), "gsk-gl-texture-atlases",
3489                               atlases,
3490                               (GDestroyNotify) gsk_gl_texture_atlases_unref);
3491     }
3492 
3493   return gsk_gl_texture_atlases_ref (atlases);
3494 }
3495 
3496 static GskGLGlyphCache *
get_glyph_cache_for_display(GdkDisplay * display,GskGLTextureAtlases * atlases)3497 get_glyph_cache_for_display (GdkDisplay *display,
3498                              GskGLTextureAtlases *atlases)
3499 {
3500   GskGLGlyphCache *glyph_cache;
3501 
3502   if (g_getenv ("GSK_NO_SHARED_CACHES"))
3503     return gsk_gl_glyph_cache_new (display, atlases);
3504 
3505   glyph_cache = (GskGLGlyphCache*)g_object_get_data (G_OBJECT (display), "gsk-gl-glyph-cache");
3506   if (glyph_cache == NULL)
3507     {
3508       glyph_cache = gsk_gl_glyph_cache_new (display, atlases);
3509       g_object_set_data_full (G_OBJECT (display), "gsk-gl-glyph-cache",
3510                               glyph_cache,
3511                               (GDestroyNotify) gsk_gl_glyph_cache_unref);
3512     }
3513 
3514   return gsk_gl_glyph_cache_ref (glyph_cache);
3515 }
3516 
3517 static GskGLIconCache *
get_icon_cache_for_display(GdkDisplay * display,GskGLTextureAtlases * atlases)3518 get_icon_cache_for_display (GdkDisplay *display,
3519                             GskGLTextureAtlases *atlases)
3520 {
3521   GskGLIconCache *icon_cache;
3522 
3523   if (g_getenv ("GSK_NO_SHARED_CACHES"))
3524     return gsk_gl_icon_cache_new (display, atlases);
3525 
3526   icon_cache = (GskGLIconCache*)g_object_get_data (G_OBJECT (display), "gsk-gl-icon-cache");
3527   if (icon_cache == NULL)
3528     {
3529       icon_cache = gsk_gl_icon_cache_new (display, atlases);
3530       g_object_set_data_full (G_OBJECT (display), "gsk-gl-icon-cache",
3531                               icon_cache,
3532                               (GDestroyNotify) gsk_gl_icon_cache_unref);
3533     }
3534 
3535   return gsk_gl_icon_cache_ref (icon_cache);
3536 }
3537 
3538 static gboolean
gsk_gl_renderer_realize(GskRenderer * renderer,GdkSurface * surface,GError ** error)3539 gsk_gl_renderer_realize (GskRenderer  *renderer,
3540                          GdkSurface    *surface,
3541                          GError      **error)
3542 {
3543   GskGLRenderer *self = GSK_GL_RENDERER (renderer);
3544   gint64 before G_GNUC_UNUSED;
3545 
3546   before = GDK_PROFILER_CURRENT_TIME;
3547   /* If we didn't get a GdkGLContext before realization, try creating
3548    * one now, for our exclusive use.
3549    */
3550   if (self->gl_context == NULL)
3551     {
3552       self->gl_context = gdk_surface_create_gl_context (surface, error);
3553       if (self->gl_context == NULL)
3554         return FALSE;
3555     }
3556 
3557   if (!gdk_gl_context_realize (self->gl_context, error))
3558     return FALSE;
3559 
3560   gdk_gl_context_make_current (self->gl_context);
3561 
3562   g_assert (self->gl_driver == NULL);
3563   self->gl_profiler = gsk_gl_profiler_new (self->gl_context);
3564   self->gl_driver = gsk_gl_driver_new (self->gl_context);
3565 
3566   GSK_RENDERER_NOTE (renderer, OPENGL, g_message ("Creating buffers and programs"));
3567   self->programs = get_programs_for_display (self, gdk_surface_get_display (surface), error);
3568   if (self->programs == NULL)
3569     return FALSE;
3570   self->op_builder.programs = self->programs;
3571 
3572   self->atlases = get_texture_atlases_for_display (gdk_surface_get_display (surface));
3573   self->glyph_cache = get_glyph_cache_for_display (gdk_surface_get_display (surface), self->atlases);
3574   self->icon_cache = get_icon_cache_for_display (gdk_surface_get_display (surface), self->atlases);
3575   gsk_gl_shadow_cache_init (&self->shadow_cache);
3576 
3577   gdk_profiler_end_mark (before, "gl renderer realize", NULL);
3578 
3579   return TRUE;
3580 }
3581 
3582 static void
gsk_gl_renderer_unrealize(GskRenderer * renderer)3583 gsk_gl_renderer_unrealize (GskRenderer *renderer)
3584 {
3585   GskGLRenderer *self = GSK_GL_RENDERER (renderer);
3586 
3587   if (self->gl_context == NULL)
3588     return;
3589 
3590   gdk_gl_context_make_current (self->gl_context);
3591 
3592   /* We don't need to iterate to destroy the associated GL resources,
3593    * as they will be dropped when we finalize the GskGLDriver
3594    */
3595   ops_reset (&self->op_builder);
3596   self->op_builder.programs = NULL;
3597 
3598   g_clear_pointer (&self->programs, gsk_gl_renderer_programs_unref);
3599   g_clear_pointer (&self->glyph_cache, gsk_gl_glyph_cache_unref);
3600   g_clear_pointer (&self->icon_cache, gsk_gl_icon_cache_unref);
3601   g_clear_pointer (&self->atlases, gsk_gl_texture_atlases_unref);
3602   gsk_gl_shadow_cache_free (&self->shadow_cache, self->gl_driver);
3603 
3604   g_clear_object (&self->gl_profiler);
3605   g_clear_object (&self->gl_driver);
3606 
3607   if (self->gl_context == gdk_gl_context_get_current ())
3608     gdk_gl_context_clear_current ();
3609 
3610   g_clear_object (&self->gl_context);
3611 }
3612 
3613 static void
gsk_gl_renderer_clear_tree(GskGLRenderer * self)3614 gsk_gl_renderer_clear_tree (GskGLRenderer *self)
3615 {
3616   if (self->gl_context == NULL)
3617     return;
3618 
3619   gdk_gl_context_make_current (self->gl_context);
3620 
3621   ops_reset (&self->op_builder);
3622 
3623 #ifdef G_ENABLE_DEBUG
3624   int removed_textures = gsk_gl_driver_collect_textures (self->gl_driver);
3625   GSK_RENDERER_NOTE (GSK_RENDERER (self), OPENGL, g_message ("Collected: %d textures", removed_textures));
3626 #else
3627   gsk_gl_driver_collect_textures (self->gl_driver);
3628 #endif
3629 }
3630 
3631 static void
gsk_gl_renderer_clear(GskGLRenderer * self)3632 gsk_gl_renderer_clear (GskGLRenderer *self)
3633 {
3634   GSK_RENDERER_NOTE (GSK_RENDERER (self), OPENGL, g_message ("Clearing viewport"));
3635   glClearColor (0, 0, 0, 0);
3636   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3637 }
3638 
3639 static void
gsk_gl_renderer_setup_render_mode(GskGLRenderer * self)3640 gsk_gl_renderer_setup_render_mode (GskGLRenderer *self)
3641 {
3642   if (self->render_region == NULL)
3643     {
3644       glDisable (GL_SCISSOR_TEST);
3645     }
3646   else
3647     {
3648       GdkSurface *surface = gsk_renderer_get_surface (GSK_RENDERER (self));
3649       cairo_rectangle_int_t extents;
3650       int surface_height;
3651 
3652       g_assert (cairo_region_num_rectangles (self->render_region) == 1);
3653 
3654       surface_height = gdk_surface_get_height (surface) * self->scale_factor;
3655       cairo_region_get_rectangle (self->render_region, 0, &extents);
3656 
3657       glEnable (GL_SCISSOR_TEST);
3658       glScissor (extents.x * self->scale_factor,
3659                  surface_height - (extents.height * self->scale_factor) - (extents.y * self->scale_factor),
3660                  extents.width * self->scale_factor,
3661                  extents.height * self->scale_factor);
3662     }
3663 }
3664 
3665 static void
gsk_gl_renderer_add_render_ops(GskGLRenderer * self,GskRenderNode * node,RenderOpBuilder * builder)3666 gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
3667                                 GskRenderNode   *node,
3668                                 RenderOpBuilder *builder)
3669 {
3670   /* This can still happen, even if the render nodes are created using
3671    * GtkSnapshot, so let's just be safe. */
3672   if (node_is_invisible (node))
3673     return;
3674 
3675   /* Check whether the render node is entirely out of the current
3676    * already transformed clip region */
3677   {
3678     graphene_rect_t transformed_node_bounds;
3679 
3680     ops_transform_bounds_modelview (builder,
3681                                     &node->bounds,
3682                                     &transformed_node_bounds);
3683 
3684     if (!graphene_rect_intersects (&builder->current_clip->bounds,
3685                                    &transformed_node_bounds))
3686       return;
3687   }
3688 
3689   switch (gsk_render_node_get_node_type (node))
3690     {
3691     case GSK_NOT_A_RENDER_NODE:
3692       g_assert_not_reached ();
3693 
3694     case GSK_CONTAINER_NODE:
3695       {
3696         guint i, p;
3697 
3698         for (i = 0, p = gsk_container_node_get_n_children (node); i < p; i ++)
3699           {
3700             GskRenderNode *child = gsk_container_node_get_child (node, i);
3701 
3702             gsk_gl_renderer_add_render_ops (self, child, builder);
3703           }
3704       }
3705     break;
3706 
3707     case GSK_DEBUG_NODE:
3708       {
3709         const char *message = gsk_debug_node_get_message (node);
3710         if (message)
3711           ops_push_debug_group (builder, message);
3712         gsk_gl_renderer_add_render_ops (self,
3713                                         gsk_debug_node_get_child (node),
3714                                         builder);
3715         if (message)
3716           ops_pop_debug_group (builder);
3717       }
3718     break;
3719 
3720     case GSK_COLOR_NODE:
3721       render_color_node (self, node, builder);
3722     break;
3723 
3724     case GSK_TEXTURE_NODE:
3725       render_texture_node (self, node, builder);
3726     break;
3727 
3728     case GSK_TRANSFORM_NODE:
3729       render_transform_node (self, node, builder);
3730     break;
3731 
3732     case GSK_OPACITY_NODE:
3733       render_opacity_node (self, node, builder);
3734     break;
3735 
3736     case GSK_LINEAR_GRADIENT_NODE:
3737     case GSK_REPEATING_LINEAR_GRADIENT_NODE:
3738       render_linear_gradient_node (self, node, builder);
3739     break;
3740 
3741     case GSK_RADIAL_GRADIENT_NODE:
3742     case GSK_REPEATING_RADIAL_GRADIENT_NODE:
3743       render_radial_gradient_node (self, node, builder);
3744     break;
3745 
3746     case GSK_CONIC_GRADIENT_NODE:
3747       render_conic_gradient_node (self, node, builder);
3748     break;
3749 
3750     case GSK_CLIP_NODE:
3751       render_clip_node (self, node, builder);
3752     break;
3753 
3754     case GSK_ROUNDED_CLIP_NODE:
3755       render_rounded_clip_node (self, node, builder);
3756     break;
3757 
3758     case GSK_TEXT_NODE:
3759       render_text_node (self, node, builder,
3760                         gsk_text_node_get_color (node), FALSE);
3761     break;
3762 
3763     case GSK_COLOR_MATRIX_NODE:
3764       render_color_matrix_node (self, node, builder);
3765     break;
3766 
3767     case GSK_BLUR_NODE:
3768       render_blur_node (self, node, builder);
3769     break;
3770 
3771     case GSK_INSET_SHADOW_NODE:
3772       if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
3773         render_inset_shadow_node (self, node, builder);
3774       else
3775         render_unblurred_inset_shadow_node (self, node, builder);
3776     break;
3777 
3778     case GSK_OUTSET_SHADOW_NODE:
3779       if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
3780         render_outset_shadow_node (self, node, builder);
3781       else
3782         render_unblurred_outset_shadow_node (self, node, builder);
3783     break;
3784 
3785     case GSK_SHADOW_NODE:
3786       render_shadow_node (self, node, builder);
3787     break;
3788 
3789     case GSK_BORDER_NODE:
3790       render_border_node (self, node, builder);
3791     break;
3792 
3793     case GSK_CROSS_FADE_NODE:
3794       render_cross_fade_node (self, node, builder);
3795     break;
3796 
3797     case GSK_BLEND_NODE:
3798       render_blend_node (self, node, builder);
3799     break;
3800 
3801     case GSK_REPEAT_NODE:
3802       render_repeat_node (self, node, builder);
3803     break;
3804 
3805     case GSK_GL_SHADER_NODE:
3806       render_gl_shader_node (self, node, builder);
3807     break;
3808 
3809     case GSK_CAIRO_NODE:
3810     default:
3811       {
3812         render_fallback_node (self, node, builder);
3813       }
3814     }
3815 }
3816 
3817 static gboolean
add_offscreen_ops(GskGLRenderer * self,RenderOpBuilder * builder,const graphene_rect_t * bounds,GskRenderNode * child_node,TextureRegion * texture_region_out,gboolean * is_offscreen,guint flags)3818 add_offscreen_ops (GskGLRenderer         *self,
3819                    RenderOpBuilder       *builder,
3820                    const graphene_rect_t *bounds,
3821                    GskRenderNode         *child_node,
3822                    TextureRegion         *texture_region_out,
3823                    gboolean              *is_offscreen,
3824                    guint                  flags)
3825 {
3826   const float dx = builder->dx;
3827   const float dy = builder->dy;
3828   float scaled_width, scaled_height;
3829   float scale_x;
3830   float scale_y;
3831   int render_target;
3832   int prev_render_target;
3833   graphene_matrix_t prev_projection;
3834   graphene_rect_t prev_viewport;
3835   graphene_matrix_t item_proj;
3836   float prev_opacity = 1.0;
3837   int texture_id = 0;
3838   int filter;
3839   GskTextureKey key;
3840   int cached_id;
3841   graphene_rect_t viewport;
3842 
3843   if (node_is_invisible (child_node))
3844     {
3845       /* Just to be safe */
3846       *is_offscreen = FALSE;
3847       init_full_texture_region (texture_region_out, 0);
3848       return FALSE;
3849     }
3850 
3851   /* We need the child node as a texture. If it already is one, we don't need to draw
3852    * it on a framebuffer of course. */
3853   if (gsk_render_node_get_node_type (child_node) == GSK_TEXTURE_NODE &&
3854       (flags & FORCE_OFFSCREEN) == 0)
3855     {
3856       GdkTexture *texture = gsk_texture_node_get_texture (child_node);
3857       upload_texture (self, texture, texture_region_out);
3858       *is_offscreen = FALSE;
3859       return TRUE;
3860     }
3861 
3862   if (flags & LINEAR_FILTER)
3863     filter = GL_LINEAR;
3864   else
3865     filter = GL_NEAREST;
3866 
3867   /* Check if we've already cached the drawn texture. */
3868   key.pointer = child_node;
3869   key.pointer_is_child = TRUE; /* Don't conflict with the child using the cache too */
3870   key.parent_rect = *bounds;
3871   key.scale_x = builder->scale_x;
3872   key.scale_y = builder->scale_y;
3873   key.filter = filter;
3874   cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
3875 
3876   if (cached_id != 0)
3877     {
3878       init_full_texture_region (texture_region_out, cached_id);
3879       /* We didn't render it offscreen, but hand out an offscreen texture id */
3880       *is_offscreen = TRUE;
3881       return TRUE;
3882     }
3883 
3884   scale_x = builder->scale_x;
3885   scale_y = builder->scale_y;
3886 
3887   /* Tweak the scale factor so that the required texture doesn't
3888    * exceed the max texture limit. This will render with a lower
3889    * resolution, but this is better than clipping.
3890    */
3891   {
3892     const int max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver);
3893 
3894     scaled_width = ceilf (bounds->size.width * scale_x);
3895     if (scaled_width > max_texture_size)
3896       {
3897         scale_x *= (float)max_texture_size / scaled_width;
3898         scaled_width = max_texture_size;
3899       }
3900 
3901     scaled_height = ceilf (bounds->size.height * scale_y);
3902     if (scaled_height > max_texture_size)
3903       {
3904         scale_y *= (float)max_texture_size / scaled_height;
3905         scaled_height = max_texture_size;
3906       }
3907   }
3908 
3909   gsk_gl_driver_create_render_target (self->gl_driver,
3910                                       scaled_width, scaled_height,
3911                                       filter, filter,
3912                                       &texture_id, &render_target);
3913   if (gdk_gl_context_has_debug (self->gl_context))
3914     {
3915       gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
3916                                           "Offscreen<%s> %d",
3917                                           g_type_name_from_instance ((GTypeInstance *) child_node),
3918                                           texture_id);
3919       gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
3920                                           "Offscreen<%s> FB %d",
3921                                           g_type_name_from_instance ((GTypeInstance *) child_node),
3922                                           render_target);
3923     }
3924 
3925   ops_transform_bounds_modelview (builder, bounds, &viewport);
3926   /* Code above will scale the size with the scale we use in the render ops,
3927    * but for the viewport size, we need our own size limited by the texture size */
3928   viewport.size.width = scaled_width;
3929   viewport.size.height = scaled_height;
3930 
3931   init_projection_matrix (&item_proj, &viewport);
3932   prev_render_target = ops_set_render_target (builder, render_target);
3933   /* Clear since we use this rendertarget for the first time */
3934   ops_begin (builder, OP_CLEAR);
3935   prev_projection = ops_set_projection (builder, &item_proj);
3936   ops_set_modelview (builder, gsk_transform_scale (NULL, scale_x, scale_y));
3937   prev_viewport = ops_set_viewport (builder, &viewport);
3938   if (flags & RESET_CLIP)
3939     ops_push_clip (builder, &GSK_ROUNDED_RECT_INIT_FROM_RECT (viewport));
3940 
3941   builder->dx = dx;
3942   builder->dy = dy;
3943 
3944   prev_opacity = ops_set_opacity (builder, 1.0);
3945 
3946   gsk_gl_renderer_add_render_ops (self, child_node, builder);
3947 
3948 #ifdef G_ENABLE_DEBUG
3949   if (G_UNLIKELY (flags & DUMP_FRAMEBUFFER))
3950     {
3951       static int k;
3952       ops_dump_framebuffer (builder,
3953                             g_strdup_printf ("%s_%p_%d.png",
3954                                              g_type_name_from_instance ((GTypeInstance *) child_node),
3955                                              child_node,
3956                                              k ++),
3957                             scaled_width, scaled_height);
3958     }
3959 #endif
3960 
3961   ops_set_opacity (builder, prev_opacity);
3962 
3963   builder->dx = dx;
3964   builder->dy = dy;
3965 
3966   if (flags & RESET_CLIP)
3967     ops_pop_clip (builder);
3968 
3969   ops_set_viewport (builder, &prev_viewport);
3970   ops_pop_modelview (builder);
3971   ops_set_projection (builder, &prev_projection);
3972   ops_set_render_target (builder, prev_render_target);
3973 
3974   *is_offscreen = TRUE;
3975   init_full_texture_region (texture_region_out, texture_id);
3976 
3977   if ((flags & NO_CACHE_PLZ) == 0)
3978     gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
3979 
3980   return TRUE;
3981 }
3982 
3983 static void
gsk_gl_renderer_render_ops(GskGLRenderer * self)3984 gsk_gl_renderer_render_ops (GskGLRenderer *self)
3985 {
3986   const Program *program = NULL;
3987   const gsize vertex_data_size = self->op_builder.vertices->len * sizeof (GskQuadVertex);
3988   const float *vertex_data = (float *)self->op_builder.vertices->data;
3989   OpBufferIter iter;
3990   OpKind kind;
3991   gpointer ptr;
3992   GLuint buffer_id, vao_id;
3993 
3994 #if DEBUG_OPS
3995   g_print ("============================================\n");
3996 #endif
3997 
3998   glGenVertexArrays (1, &vao_id);
3999   glBindVertexArray (vao_id);
4000 
4001   glGenBuffers (1, &buffer_id);
4002   glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
4003 
4004   glBufferData (GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_STATIC_DRAW);
4005 
4006   /* 0 = position location */
4007   glEnableVertexAttribArray (0);
4008   glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE,
4009                          sizeof (GskQuadVertex),
4010                          (void *) G_STRUCT_OFFSET (GskQuadVertex, position));
4011   /* 1 = texture coord location */
4012   glEnableVertexAttribArray (1);
4013   glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE,
4014                          sizeof (GskQuadVertex),
4015                          (void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
4016 
4017   op_buffer_iter_init (&iter, ops_get_buffer (&self->op_builder));
4018   while ((ptr = op_buffer_iter_next (&iter, &kind)))
4019     {
4020       if (kind == OP_NONE)
4021         continue;
4022 
4023       if (program == NULL &&
4024           kind != OP_PUSH_DEBUG_GROUP &&
4025           kind != OP_POP_DEBUG_GROUP &&
4026           kind != OP_CHANGE_PROGRAM &&
4027           kind != OP_CHANGE_RENDER_TARGET &&
4028           kind != OP_CLEAR)
4029         continue;
4030 
4031       OP_PRINT ("Op %u: %u", iter.pos - 2, kind);
4032 
4033       switch (kind)
4034         {
4035         case OP_CHANGE_PROJECTION:
4036           apply_projection_op (program, ptr);
4037           break;
4038 
4039         case OP_CHANGE_MODELVIEW:
4040           apply_modelview_op (program, ptr);
4041           break;
4042 
4043         case OP_CHANGE_PROGRAM:
4044           {
4045             const OpProgram *op = ptr;
4046             apply_program_op (program, op);
4047             program = op->program;
4048             break;
4049           }
4050 
4051         case OP_CHANGE_RENDER_TARGET:
4052           apply_render_target_op (self, ptr);
4053           break;
4054 
4055         case OP_CLEAR:
4056           OP_PRINT ("-> CLEAR");
4057           glClearColor (0, 0, 0, 0);
4058           glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4059           break;
4060 
4061         case OP_CHANGE_VIEWPORT:
4062           apply_viewport_op (program, ptr);
4063           break;
4064 
4065         case OP_CHANGE_OPACITY:
4066           apply_opacity_op (program, ptr);
4067           break;
4068 
4069         case OP_CHANGE_COLOR_MATRIX:
4070           apply_color_matrix_op (program, ptr);
4071           break;
4072 
4073         case OP_CHANGE_COLOR:
4074           /*g_assert (program == &self->color_program || program == &self->coloring_program ||*/
4075                     /*program == &self->shadow_program);*/
4076           apply_color_op (program, ptr);
4077           break;
4078 
4079         case OP_CHANGE_BORDER_COLOR:
4080           apply_border_color_op (program, ptr);
4081           break;
4082 
4083         case OP_CHANGE_CLIP:
4084           apply_clip_op (program, ptr);
4085           break;
4086 
4087         case OP_CHANGE_SOURCE_TEXTURE:
4088           apply_source_texture_op (program, ptr);
4089           break;
4090 
4091         case OP_CHANGE_EXTRA_SOURCE_TEXTURE:
4092           apply_source_extra_texture_op (program, ptr);
4093           break;
4094 
4095         case OP_CHANGE_CROSS_FADE:
4096           g_assert (program == &self->programs->cross_fade_program);
4097           apply_cross_fade_op (program, ptr);
4098           break;
4099 
4100         case OP_CHANGE_BLEND:
4101           g_assert (program == &self->programs->blend_program);
4102           apply_blend_op (program, ptr);
4103           break;
4104 
4105         case OP_CHANGE_LINEAR_GRADIENT:
4106           apply_linear_gradient_op (program, ptr);
4107           break;
4108 
4109         case OP_CHANGE_RADIAL_GRADIENT:
4110           apply_radial_gradient_op (program, ptr);
4111           break;
4112 
4113         case OP_CHANGE_CONIC_GRADIENT:
4114           apply_conic_gradient_op (program, ptr);
4115           break;
4116 
4117         case OP_CHANGE_BLUR:
4118           apply_blur_op (program, ptr);
4119           break;
4120 
4121         case OP_CHANGE_INSET_SHADOW:
4122           apply_inset_shadow_op (program, ptr);
4123           break;
4124 
4125         case OP_CHANGE_OUTSET_SHADOW:
4126           apply_outset_shadow_op (program, ptr);
4127           break;
4128 
4129         case OP_CHANGE_BORDER:
4130           apply_border_op (program, ptr);
4131           break;
4132 
4133         case OP_CHANGE_BORDER_WIDTH:
4134           apply_border_width_op (program, ptr);
4135           break;
4136 
4137         case OP_CHANGE_UNBLURRED_OUTSET_SHADOW:
4138           apply_unblurred_outset_shadow_op (program, ptr);
4139           break;
4140 
4141         case OP_CHANGE_REPEAT:
4142           apply_repeat_op (program, ptr);
4143           break;
4144 
4145         case OP_CHANGE_GL_SHADER_ARGS:
4146           apply_gl_shader_args_op (program, ptr);
4147           break;
4148 
4149         case OP_DRAW:
4150           {
4151             const OpDraw *op = ptr;
4152 
4153             OP_PRINT (" -> draw %ld, size %ld and program %d: %s",
4154                       op->vao_offset, op->vao_size, program->index,
4155                       program->name ?: "");
4156             glDrawArrays (GL_TRIANGLES, op->vao_offset, op->vao_size);
4157             break;
4158           }
4159 
4160         case OP_DUMP_FRAMEBUFFER:
4161           {
4162             const OpDumpFrameBuffer *op = ptr;
4163 
4164             dump_framebuffer (op->filename, op->width, op->height);
4165             break;
4166           }
4167 
4168         case OP_PUSH_DEBUG_GROUP:
4169           {
4170             const OpDebugGroup *op = ptr;
4171             gdk_gl_context_push_debug_group (self->gl_context, op->text);
4172             OP_PRINT (" Debug: %s", op->text);
4173             break;
4174           }
4175 
4176         case OP_POP_DEBUG_GROUP:
4177           gdk_gl_context_pop_debug_group (self->gl_context);
4178           break;
4179 
4180         case OP_NONE:
4181         case OP_LAST:
4182         default:
4183           g_warn_if_reached ();
4184         }
4185 
4186       OP_PRINT ("\n");
4187     }
4188 
4189   glDeleteVertexArrays (1, &vao_id);
4190   glDeleteBuffers (1, &buffer_id);
4191 }
4192 
4193 static void
gsk_gl_renderer_do_render(GskRenderer * renderer,GskRenderNode * root,const graphene_rect_t * viewport,int fbo_id,int scale_factor)4194 gsk_gl_renderer_do_render (GskRenderer           *renderer,
4195                            GskRenderNode         *root,
4196                            const graphene_rect_t *viewport,
4197                            int                    fbo_id,
4198                            int                    scale_factor)
4199 {
4200   GskGLRenderer *self = GSK_GL_RENDERER (renderer);
4201   graphene_matrix_t projection;
4202 #ifdef G_ENABLE_DEBUG
4203   GskProfiler *profiler;
4204   gint64 gpu_time, cpu_time;
4205   gint64 start_time G_GNUC_UNUSED;
4206 #endif
4207   GPtrArray *removed;
4208 
4209 #ifdef G_ENABLE_DEBUG
4210   profiler = gsk_renderer_get_profiler (renderer);
4211 #endif
4212 
4213   if (self->gl_context == NULL)
4214     {
4215       GSK_RENDERER_NOTE (renderer, OPENGL, g_message ("No valid GL context associated to the renderer"));
4216       return;
4217     }
4218 
4219   g_assert (gsk_gl_driver_in_frame (self->gl_driver));
4220 
4221   removed = g_ptr_array_new ();
4222   gsk_gl_texture_atlases_begin_frame (self->atlases, removed);
4223   gsk_gl_glyph_cache_begin_frame (self->glyph_cache, self->gl_driver, removed);
4224   gsk_gl_icon_cache_begin_frame (self->icon_cache, removed);
4225   gsk_gl_shadow_cache_begin_frame (&self->shadow_cache, self->gl_driver);
4226   g_ptr_array_unref (removed);
4227 
4228   /* Set up the modelview and projection matrices to fit our viewport */
4229   init_projection_matrix (&projection, viewport);
4230   ops_set_projection (&self->op_builder, &projection);
4231   ops_set_viewport (&self->op_builder, viewport);
4232   ops_set_modelview (&self->op_builder, gsk_transform_scale (NULL, scale_factor, scale_factor));
4233 
4234   /* Initial clip is self->render_region! */
4235   if (self->render_region != NULL)
4236     {
4237       graphene_rect_t transformed_render_region;
4238       cairo_rectangle_int_t render_extents;
4239 
4240       cairo_region_get_extents (self->render_region, &render_extents);
4241 
4242       ops_transform_bounds_modelview (&self->op_builder,
4243                                       &GRAPHENE_RECT_INIT (render_extents.x,
4244                                                            render_extents.y,
4245                                                            render_extents.width,
4246                                                            render_extents.height),
4247                                       &transformed_render_region);
4248       ops_push_clip (&self->op_builder,
4249                      &GSK_ROUNDED_RECT_INIT (transformed_render_region.origin.x,
4250                                              transformed_render_region.origin.y,
4251                                              transformed_render_region.size.width,
4252                                              transformed_render_region.size.height));
4253     }
4254   else
4255     {
4256       ops_push_clip (&self->op_builder,
4257                      &GSK_ROUNDED_RECT_INIT (viewport->origin.x,
4258                                              viewport->origin.y,
4259                                              viewport->size.width,
4260                                              viewport->size.height));
4261     }
4262 
4263   if (fbo_id != 0)
4264     ops_set_render_target (&self->op_builder, fbo_id);
4265 
4266   gdk_gl_context_push_debug_group (self->gl_context, "Adding render ops");
4267   gsk_gl_renderer_add_render_ops (self, root, &self->op_builder);
4268   gdk_gl_context_pop_debug_group (self->gl_context);
4269 
4270   /* We correctly reset the state everywhere */
4271   g_assert_cmpint (self->op_builder.current_render_target, ==, fbo_id);
4272   ops_pop_modelview (&self->op_builder);
4273   ops_pop_clip (&self->op_builder);
4274   ops_finish (&self->op_builder);
4275 
4276   /*g_message ("Ops: %u", self->render_ops->len);*/
4277 
4278   /* Now actually draw things... */
4279 #ifdef G_ENABLE_DEBUG
4280   gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
4281   gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
4282 #endif
4283 
4284   /* Actually do the rendering */
4285   if (fbo_id != 0)
4286     glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
4287 
4288   glViewport (0, 0, ceilf (viewport->size.width), ceilf (viewport->size.height));
4289   gsk_gl_renderer_setup_render_mode (self);
4290   gsk_gl_renderer_clear (self);
4291 
4292   glEnable (GL_DEPTH_TEST);
4293   glDepthFunc (GL_LEQUAL);
4294 
4295   /* Pre-multiplied alpha! */
4296   glEnable (GL_BLEND);
4297   glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
4298   glBlendEquation (GL_FUNC_ADD);
4299 
4300   gdk_gl_context_push_debug_group (self->gl_context, "Rendering ops");
4301   gsk_gl_renderer_render_ops (self);
4302   gdk_gl_context_pop_debug_group (self->gl_context);
4303 
4304 #ifdef G_ENABLE_DEBUG
4305   gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
4306 
4307   start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
4308   cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
4309   gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
4310 
4311   gpu_time = gsk_gl_profiler_end_gpu_region (self->gl_profiler);
4312   gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
4313 
4314   gsk_profiler_push_samples (profiler);
4315 
4316   gdk_profiler_add_mark (start_time * 1000, cpu_time * 1000, "GL render", "");
4317 #endif
4318 }
4319 
4320 static GdkTexture *
gsk_gl_renderer_render_texture(GskRenderer * renderer,GskRenderNode * root,const graphene_rect_t * viewport)4321 gsk_gl_renderer_render_texture (GskRenderer           *renderer,
4322                                 GskRenderNode         *root,
4323                                 const graphene_rect_t *viewport)
4324 {
4325   GskGLRenderer *self = GSK_GL_RENDERER (renderer);
4326   GdkTexture *texture;
4327   int width, height;
4328   guint texture_id;
4329   guint fbo_id;
4330 
4331   g_return_val_if_fail (self->gl_context != NULL, NULL);
4332 
4333   gdk_gl_context_make_current (self->gl_context);
4334   gdk_gl_context_push_debug_group_printf (self->gl_context,
4335                                           "Render %s<%p> to texture",
4336                                           g_type_name_from_instance ((GTypeInstance *) root),
4337                                           root);
4338 
4339   width = ceilf (viewport->size.width);
4340   height = ceilf (viewport->size.height);
4341 
4342   self->scale_factor = gdk_surface_get_scale_factor (gsk_renderer_get_surface (renderer));
4343 
4344   /* Prepare our framebuffer */
4345   gsk_gl_driver_begin_frame (self->gl_driver);
4346   glGenTextures (1, &texture_id);
4347   glBindTexture (GL_TEXTURE_2D, texture_id);
4348 
4349   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4350   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4351   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
4352   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
4353 
4354   if (gdk_gl_context_has_debug (self->gl_context))
4355     gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
4356                                         "Texture %s<%p> %d",
4357                                         g_type_name_from_instance ((GTypeInstance *) root),
4358                                         root,
4359                                         texture_id);
4360 
4361   if (gdk_gl_context_get_use_es (self->gl_context))
4362     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
4363   else
4364     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
4365 
4366   glGenFramebuffers (1, &fbo_id);
4367   glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
4368 
4369   if (gdk_gl_context_has_debug (self->gl_context))
4370     gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, fbo_id,
4371                                         "FB %s<%p> %d",
4372                                         g_type_name_from_instance ((GTypeInstance *) root),
4373                                         root,
4374                                         fbo_id);
4375   glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
4376 
4377   /* Render the actual scene */
4378   gsk_gl_renderer_do_render (renderer, root, viewport, fbo_id, 1);
4379 
4380   glDeleteFramebuffers (1, &fbo_id);
4381 
4382 
4383   /* Render the now drawn framebuffer y-flipped so it's as GdkGLTexture expects it to be */
4384   {
4385     guint final_texture_id, final_fbo_id;
4386     graphene_matrix_t m;
4387 
4388     ops_reset (&self->op_builder);
4389 
4390     glGenFramebuffers (1, &final_fbo_id);
4391     glBindFramebuffer (GL_FRAMEBUFFER, final_fbo_id);
4392     glGenTextures (1, &final_texture_id);
4393     glBindTexture (GL_TEXTURE_2D, final_texture_id);
4394 
4395     if (gdk_gl_context_get_use_es (self->gl_context))
4396       glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
4397     else
4398       glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
4399 
4400     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4401     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4402     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
4403     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
4404 
4405     glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, final_texture_id, 0);
4406     g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
4407 
4408     ops_set_render_target (&self->op_builder, final_fbo_id);
4409     ops_push_clip (&self->op_builder, &GSK_ROUNDED_RECT_INIT (0, 0, width, height));
4410     ops_set_program (&self->op_builder, &self->programs->blit_program);
4411 
4412     ops_begin (&self->op_builder, OP_CLEAR);
4413     ops_set_texture (&self->op_builder, texture_id);
4414     ops_set_modelview (&self->op_builder, NULL);
4415     ops_set_viewport (&self->op_builder, &GRAPHENE_RECT_INIT (0, 0, width, height));
4416     init_projection_matrix (&m, &GRAPHENE_RECT_INIT (0, 0, width, height));
4417     graphene_matrix_scale (&m, 1, -1, 1); /* Undo the scale init_projection_matrix() does again */
4418     ops_set_projection (&self->op_builder, &m);
4419 
4420     fill_vertex_data (ops_draw (&self->op_builder, NULL),
4421                       0, 0, width, height);
4422     ops_pop_clip (&self->op_builder);
4423     gsk_gl_renderer_render_ops (self);
4424 
4425     ops_finish (&self->op_builder);
4426 
4427     glDeleteTextures (1, &texture_id);
4428 
4429     texture_id = final_texture_id;
4430   }
4431 
4432   texture = gdk_gl_texture_new (self->gl_context,
4433                                 texture_id,
4434                                 width, height,
4435                                 NULL, NULL);
4436 
4437   gsk_gl_driver_end_frame (self->gl_driver);
4438 
4439   gdk_gl_context_pop_debug_group (self->gl_context);
4440 
4441   gsk_gl_renderer_clear_tree (self);
4442   return texture;
4443 }
4444 
4445 static void
gsk_gl_renderer_render(GskRenderer * renderer,GskRenderNode * root,const cairo_region_t * update_area)4446 gsk_gl_renderer_render (GskRenderer          *renderer,
4447                         GskRenderNode        *root,
4448                         const cairo_region_t *update_area)
4449 {
4450   GskGLRenderer *self = GSK_GL_RENDERER (renderer);
4451   graphene_rect_t viewport;
4452   const cairo_region_t *damage;
4453   GdkRectangle whole_surface;
4454   GdkSurface *surface;
4455 
4456   if (self->gl_context == NULL)
4457     return;
4458 
4459   surface = gsk_renderer_get_surface (renderer);
4460   self->scale_factor = gdk_surface_get_scale_factor (surface);
4461 
4462   gdk_gl_context_make_current (self->gl_context);
4463   gdk_gl_context_push_debug_group_printf (self->gl_context,
4464                                           "Render root node %p", root);
4465 
4466   whole_surface = (GdkRectangle) {
4467                       0, 0,
4468                       gdk_surface_get_width (surface) * self->scale_factor,
4469                       gdk_surface_get_height (surface) * self->scale_factor
4470                   };
4471 
4472   gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->gl_context),
4473                                 update_area);
4474 
4475   damage = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->gl_context));
4476 
4477   if (cairo_region_contains_rectangle (damage, &whole_surface) == CAIRO_REGION_OVERLAP_IN)
4478     {
4479       self->render_region = NULL;
4480     }
4481   else
4482     {
4483       GdkRectangle extents;
4484 
4485       cairo_region_get_extents (damage, &extents);
4486 
4487       if (gdk_rectangle_equal (&extents, &whole_surface))
4488         self->render_region = NULL;
4489       else
4490         self->render_region = cairo_region_create_rectangle (&extents);
4491     }
4492 
4493   gdk_gl_context_make_current (self->gl_context);
4494 
4495   viewport.origin.x = 0;
4496   viewport.origin.y = 0;
4497   viewport.size.width = whole_surface.width;
4498   viewport.size.height = whole_surface.height;
4499 
4500   gsk_gl_driver_begin_frame (self->gl_driver);
4501   gsk_gl_renderer_do_render (renderer, root, &viewport, 0, self->scale_factor);
4502   gsk_gl_driver_end_frame (self->gl_driver);
4503 
4504   gsk_gl_renderer_clear_tree (self);
4505 
4506   gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->gl_context));
4507   gdk_gl_context_make_current (self->gl_context);
4508 
4509   gdk_gl_context_pop_debug_group (self->gl_context);
4510 
4511   g_clear_pointer (&self->render_region, cairo_region_destroy);
4512 }
4513 
4514 static void
gsk_gl_renderer_class_init(GskGLRendererClass * klass)4515 gsk_gl_renderer_class_init (GskGLRendererClass *klass)
4516 {
4517   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
4518   GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
4519 
4520   gobject_class->dispose = gsk_gl_renderer_dispose;
4521 
4522   renderer_class->realize = gsk_gl_renderer_realize;
4523   renderer_class->unrealize = gsk_gl_renderer_unrealize;
4524   renderer_class->render = gsk_gl_renderer_render;
4525   renderer_class->render_texture = gsk_gl_renderer_render_texture;
4526 }
4527 
4528 static void
gsk_gl_renderer_init(GskGLRenderer * self)4529 gsk_gl_renderer_init (GskGLRenderer *self)
4530 {
4531   gsk_ensure_resources ();
4532 
4533   ops_init (&self->op_builder);
4534   self->op_builder.renderer = self;
4535 
4536 #ifdef G_ENABLE_DEBUG
4537   {
4538     GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
4539 
4540     self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
4541 
4542     self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
4543     self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
4544   }
4545 #endif
4546 }
4547 
4548 /**
4549  * gsk_gl_renderer_new:
4550  *
4551  * Creates a new `GskRenderer` using OpenGL.
4552  *
4553  * Returns: a new GL renderer
4554  */
4555 GskRenderer *
gsk_gl_renderer_new(void)4556 gsk_gl_renderer_new (void)
4557 {
4558   return g_object_new (GSK_TYPE_GL_RENDERER, NULL);
4559 }
4560