1 #include "config.h"
2 
3 #include "gskvulkanrenderpassprivate.h"
4 
5 #include "gskdebugprivate.h"
6 #include "gskprofilerprivate.h"
7 #include "gskrendernodeprivate.h"
8 #include "gskrenderer.h"
9 #include "gskrendererprivate.h"
10 #include "gskroundedrectprivate.h"
11 #include "gsktransform.h"
12 #include "gskvulkanblendmodepipelineprivate.h"
13 #include "gskvulkanblurpipelineprivate.h"
14 #include "gskvulkanborderpipelineprivate.h"
15 #include "gskvulkanboxshadowpipelineprivate.h"
16 #include "gskvulkanclipprivate.h"
17 #include "gskvulkancolorpipelineprivate.h"
18 #include "gskvulkancolortextpipelineprivate.h"
19 #include "gskvulkancrossfadepipelineprivate.h"
20 #include "gskvulkaneffectpipelineprivate.h"
21 #include "gskvulkanlineargradientpipelineprivate.h"
22 #include "gskvulkantextpipelineprivate.h"
23 #include "gskvulkantexturepipelineprivate.h"
24 #include "gskvulkanimageprivate.h"
25 #include "gskvulkanpushconstantsprivate.h"
26 #include "gskvulkanrendererprivate.h"
27 #include "gskprivate.h"
28 
29 #define ORTHO_NEAR_PLANE        -10000
30 #define ORTHO_FAR_PLANE          10000
31 
32 typedef union _GskVulkanOp GskVulkanOp;
33 typedef struct _GskVulkanOpRender GskVulkanOpRender;
34 typedef struct _GskVulkanOpText GskVulkanOpText;
35 typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
36 
37 typedef enum {
38   /* GskVulkanOpRender */
39   GSK_VULKAN_OP_FALLBACK,
40   GSK_VULKAN_OP_FALLBACK_CLIP,
41   GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
42   GSK_VULKAN_OP_TEXTURE,
43   GSK_VULKAN_OP_COLOR,
44   GSK_VULKAN_OP_LINEAR_GRADIENT,
45   GSK_VULKAN_OP_OPACITY,
46   GSK_VULKAN_OP_BLUR,
47   GSK_VULKAN_OP_COLOR_MATRIX,
48   GSK_VULKAN_OP_BORDER,
49   GSK_VULKAN_OP_INSET_SHADOW,
50   GSK_VULKAN_OP_OUTSET_SHADOW,
51   GSK_VULKAN_OP_REPEAT,
52   GSK_VULKAN_OP_CROSS_FADE,
53   GSK_VULKAN_OP_BLEND_MODE,
54   /* GskVulkanOpText */
55   GSK_VULKAN_OP_TEXT,
56   GSK_VULKAN_OP_COLOR_TEXT,
57   /* GskVulkanOpPushConstants */
58   GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
59 } GskVulkanOpType;
60 
61 /* render ops with 0, 1 or 2 sources */
62 struct _GskVulkanOpRender
63 {
64   GskVulkanOpType      type;
65   GskRenderNode       *node; /* node that's the source of this op */
66   GskVulkanPipeline   *pipeline; /* pipeline to use */
67   GskRoundedRect       clip; /* clip rect (or random memory if not relevant) */
68   GskVulkanImage      *source; /* source image to render */
69   GskVulkanImage      *source2; /* second source image to render (if relevant) */
70   gsize                vertex_offset; /* offset into vertex buffer */
71   gsize                vertex_count; /* number of vertices */
72   gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
73   gsize                descriptor_set_index2; /* descriptor index for the second source (if relevant) */
74   graphene_rect_t      source_rect; /* area that source maps to */
75   graphene_rect_t      source2_rect; /* area that source2 maps to */
76 };
77 
78 struct _GskVulkanOpText
79 {
80   GskVulkanOpType      type;
81   GskRenderNode       *node; /* node that's the source of this op */
82   GskVulkanPipeline   *pipeline; /* pipeline to use */
83   GskRoundedRect       clip; /* clip rect (or random memory if not relevant) */
84   GskVulkanImage      *source; /* source image to render */
85   gsize                vertex_offset; /* offset into vertex buffer */
86   gsize                vertex_count; /* number of vertices */
87   gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
88   guint                texture_index; /* index of the texture in the glyph cache */
89   guint                start_glyph; /* the first glyph in nodes glyphstring that we render */
90   guint                num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
91   float                scale;
92 };
93 
94 struct _GskVulkanOpPushConstants
95 {
96   GskVulkanOpType         type;
97   GskRenderNode          *node; /* node that's the source of this op */
98   GskVulkanPushConstants  constants; /* new constants to push */
99 };
100 
101 union _GskVulkanOp
102 {
103   GskVulkanOpType          type;
104   GskVulkanOpRender        render;
105   GskVulkanOpText          text;
106   GskVulkanOpPushConstants constants;
107 };
108 
109 struct _GskVulkanRenderPass
110 {
111   GdkVulkanContext *vulkan;
112 
113   GArray *render_ops;
114 
115   GskVulkanImage *target;
116   int scale_factor;
117   graphene_rect_t viewport;
118   cairo_region_t *clip;
119   graphene_matrix_t mv;
120   graphene_matrix_t p;
121 
122   VkRenderPass render_pass;
123   VkSemaphore signal_semaphore;
124   GArray *wait_semaphores;
125   GskVulkanBuffer *vertex_data;
126 
127   GQuark fallback_pixels;
128   GQuark texture_pixels;
129 };
130 
131 GskVulkanRenderPass *
gsk_vulkan_render_pass_new(GdkVulkanContext * context,GskVulkanImage * target,int scale_factor,graphene_matrix_t * mv,graphene_rect_t * viewport,cairo_region_t * clip,VkSemaphore signal_semaphore)132 gsk_vulkan_render_pass_new (GdkVulkanContext  *context,
133                             GskVulkanImage    *target,
134                             int                scale_factor,
135                             graphene_matrix_t *mv,
136                             graphene_rect_t   *viewport,
137                             cairo_region_t    *clip,
138                             VkSemaphore        signal_semaphore)
139 {
140   GskVulkanRenderPass *self;
141   VkImageLayout final_layout;
142 
143   self = g_slice_new0 (GskVulkanRenderPass);
144   self->vulkan = g_object_ref (context);
145   self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
146 
147   self->target = g_object_ref (target);
148   self->scale_factor = scale_factor;
149   self->clip = cairo_region_copy (clip);
150   self->viewport = *viewport;
151 
152   self->mv = *mv;
153   graphene_matrix_init_ortho (&self->p,
154                               viewport->origin.x, viewport->origin.x + viewport->size.width,
155                               viewport->origin.y, viewport->origin.y + viewport->size.height,
156                               ORTHO_NEAR_PLANE,
157                               ORTHO_FAR_PLANE);
158 
159   if (signal_semaphore != VK_NULL_HANDLE) // this is a dependent pass
160     final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
161   else
162     final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
163   GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
164                                     &(VkRenderPassCreateInfo) {
165                                         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
166                                         .attachmentCount = 1,
167                                         .pAttachments = (VkAttachmentDescription[]) {
168                                            {
169                                               .format = gdk_vulkan_context_get_image_format (self->vulkan),
170                                               .samples = VK_SAMPLE_COUNT_1_BIT,
171                                               .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
172                                               .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
173                                               .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
174                                               .finalLayout = final_layout
175                                            }
176                                         },
177                                         .subpassCount = 1,
178                                         .pSubpasses = (VkSubpassDescription []) {
179                                            {
180                                               .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
181                                               .inputAttachmentCount = 0,
182                                               .colorAttachmentCount = 1,
183                                               .pColorAttachments = (VkAttachmentReference []) {
184                                                  {
185                                                     .attachment = 0,
186                                                      .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
187                                                   }
188                                                },
189                                                .pResolveAttachments = (VkAttachmentReference []) {
190                                                   {
191                                                      .attachment = VK_ATTACHMENT_UNUSED,
192                                                      .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
193                                                   }
194                                                },
195                                                .pDepthStencilAttachment = NULL,
196                                             }
197                                          },
198                                          .dependencyCount = 0
199                                       },
200                                       NULL,
201                                       &self->render_pass);
202 
203   self->signal_semaphore = signal_semaphore;
204   self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
205   self->vertex_data = NULL;
206 
207 #ifdef G_ENABLE_DEBUG
208   self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
209   self->texture_pixels = g_quark_from_static_string ("texture-pixels");
210 #endif
211 
212   return self;
213 }
214 
215 void
gsk_vulkan_render_pass_free(GskVulkanRenderPass * self)216 gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
217 {
218   g_array_unref (self->render_ops);
219   g_object_unref (self->vulkan);
220   g_object_unref (self->target);
221   cairo_region_destroy (self->clip);
222   vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
223                        self->render_pass,
224                        NULL);
225   if (self->vertex_data)
226     gsk_vulkan_buffer_free (self->vertex_data);
227   if (self->signal_semaphore != VK_NULL_HANDLE)
228     vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
229                         self->signal_semaphore,
230                         NULL);
231   g_array_unref (self->wait_semaphores);
232 
233 
234   g_slice_free (GskVulkanRenderPass, self);
235 }
236 
237 #define FALLBACK(...) G_STMT_START { \
238   GSK_RENDERER_NOTE (gsk_vulkan_render_get_renderer (render), FALLBACK, g_message (__VA_ARGS__)); \
239   goto fallback; \
240 }G_STMT_END
241 
242 static void
gsk_vulkan_render_pass_add_node(GskVulkanRenderPass * self,GskVulkanRender * render,const GskVulkanPushConstants * constants,GskRenderNode * node)243 gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
244                                  GskVulkanRender               *render,
245                                  const GskVulkanPushConstants  *constants,
246                                  GskRenderNode                 *node)
247 {
248   GskVulkanOp op = {
249     .render.node = node
250   };
251   GskVulkanPipelineType pipeline_type;
252 
253   switch (gsk_render_node_get_node_type (node))
254     {
255     case GSK_NOT_A_RENDER_NODE:
256       g_assert_not_reached ();
257       return;
258     case GSK_GL_SHADER_NODE:
259     case GSK_SHADOW_NODE:
260     case GSK_RADIAL_GRADIENT_NODE:
261     case GSK_REPEATING_RADIAL_GRADIENT_NODE:
262     case GSK_CONIC_GRADIENT_NODE:
263     default:
264       FALLBACK ("Unsupported node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
265 
266     case GSK_REPEAT_NODE:
267       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
268         pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
269       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
270         pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
271       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
272         pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
273       else
274         FALLBACK ("Repeat nodes can't deal with clip type %u", constants->clip.type);
275       op.type = GSK_VULKAN_OP_REPEAT;
276       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
277       g_array_append_val (self->render_ops, op);
278       return;
279 
280     case GSK_BLEND_NODE:
281       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
282         pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
283       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
284         pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP;
285       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
286         pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
287       else
288         FALLBACK ("Blend nodes can't deal with clip type %u", constants->clip.type);
289       op.type = GSK_VULKAN_OP_BLEND_MODE;
290       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
291       g_array_append_val (self->render_ops, op);
292        return;
293 
294     case GSK_CROSS_FADE_NODE:
295       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
296         pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
297       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
298         pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
299       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
300         pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
301       else
302         FALLBACK ("Cross fade nodes can't deal with clip type %u", constants->clip.type);
303       op.type = GSK_VULKAN_OP_CROSS_FADE;
304       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
305       g_array_append_val (self->render_ops, op);
306       return;
307 
308     case GSK_INSET_SHADOW_NODE:
309       if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
310         FALLBACK ("Blur support not implemented for inset shadows");
311       else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
312         pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW;
313       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
314         pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP;
315       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
316         pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
317       else
318         FALLBACK ("Inset shadow nodes can't deal with clip type %u", constants->clip.type);
319       op.type = GSK_VULKAN_OP_INSET_SHADOW;
320       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
321       g_array_append_val (self->render_ops, op);
322       return;
323 
324     case GSK_OUTSET_SHADOW_NODE:
325       if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
326         FALLBACK ("Blur support not implemented for outset shadows");
327       else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
328         pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW;
329       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
330         pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP;
331       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
332         pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
333       else
334         FALLBACK ("Outset shadow nodes can't deal with clip type %u", constants->clip.type);
335       op.type = GSK_VULKAN_OP_OUTSET_SHADOW;
336       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
337       g_array_append_val (self->render_ops, op);
338       return;
339 
340     case GSK_CAIRO_NODE:
341       if (gsk_cairo_node_get_surface (node) == NULL)
342         return;
343       /* We're using recording surfaces, so drawing them to an image
344        * surface and uploading them is the right thing.
345        * But that's exactly what the fallback code does.
346        */
347       goto fallback;
348 
349     case GSK_TEXT_NODE:
350       {
351         const PangoFont *font = gsk_text_node_get_font (node);
352         const PangoGlyphInfo *glyphs = gsk_text_node_get_glyphs (node, NULL);
353         guint num_glyphs = gsk_text_node_get_num_glyphs (node);
354         gboolean has_color_glyphs = gsk_text_node_has_color_glyphs (node);
355         int i;
356         guint count;
357         guint texture_index;
358         int x_position;
359         GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
360 
361         if (has_color_glyphs)
362           {
363             if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
364               pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
365             else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
366               pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
367             else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
368               pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
369             else
370               FALLBACK ("Text nodes can't deal with clip type %u", constants->clip.type);
371             op.type = GSK_VULKAN_OP_COLOR_TEXT;
372           }
373         else
374           {
375             if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
376               pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
377             else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
378               pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
379             else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
380               pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
381             else
382               FALLBACK ("Text nodes can't deal with clip type %u", constants->clip.type);
383             op.type = GSK_VULKAN_OP_TEXT;
384           }
385         op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
386 
387         op.text.start_glyph = 0;
388         op.text.texture_index = G_MAXUINT;
389         op.text.scale = self->scale_factor;
390 
391         x_position = 0;
392         for (i = 0, count = 0; i < num_glyphs; i++)
393           {
394             const PangoGlyphInfo *gi = &glyphs[i];
395 
396             texture_index = gsk_vulkan_renderer_cache_glyph (renderer,
397                                                              (PangoFont *)font,
398                                                              gi->glyph,
399                                                              x_position + gi->geometry.x_offset,
400                                                              gi->geometry.y_offset,
401                                                              op.text.scale);
402             if (op.text.texture_index == G_MAXUINT)
403               op.text.texture_index = texture_index;
404             if (texture_index != op.text.texture_index)
405               {
406                 op.text.num_glyphs = count;
407 
408                 g_array_append_val (self->render_ops, op);
409 
410                 count = 1;
411                 op.text.start_glyph = i;
412                 op.text.texture_index = texture_index;
413               }
414             else
415               count++;
416 
417             x_position += gi->geometry.width;
418           }
419 
420         if (op.text.texture_index != G_MAXUINT && count != 0)
421           {
422             op.text.num_glyphs = count;
423             g_array_append_val (self->render_ops, op);
424           }
425 
426         return;
427       }
428 
429     case GSK_TEXTURE_NODE:
430       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
431         pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
432       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
433         pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
434       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
435         pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
436       else
437         FALLBACK ("Texture nodes can't deal with clip type %u", constants->clip.type);
438       op.type = GSK_VULKAN_OP_TEXTURE;
439       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
440       g_array_append_val (self->render_ops, op);
441       return;
442 
443     case GSK_COLOR_NODE:
444       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
445         pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
446       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
447         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP;
448       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
449         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
450       else
451         FALLBACK ("Color nodes can't deal with clip type %u", constants->clip.type);
452       op.type = GSK_VULKAN_OP_COLOR;
453       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
454       g_array_append_val (self->render_ops, op);
455       return;
456 
457     case GSK_LINEAR_GRADIENT_NODE:
458     case GSK_REPEATING_LINEAR_GRADIENT_NODE:
459       if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
460         FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u",
461                   gsk_linear_gradient_node_get_n_color_stops (node),
462                   GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
463       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
464         pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT;
465       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
466         pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP;
467       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
468         pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
469       else
470         FALLBACK ("Linear gradient nodes can't deal with clip type %u", constants->clip.type);
471       op.type = GSK_VULKAN_OP_LINEAR_GRADIENT;
472       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
473       g_array_append_val (self->render_ops, op);
474       return;
475 
476     case GSK_OPACITY_NODE:
477       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
478         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
479       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
480         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
481       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
482         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
483       else
484         FALLBACK ("Opacity nodes can't deal with clip type %u", constants->clip.type);
485       op.type = GSK_VULKAN_OP_OPACITY;
486       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
487       g_array_append_val (self->render_ops, op);
488       return;
489 
490     case GSK_BLUR_NODE:
491       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
492         pipeline_type = GSK_VULKAN_PIPELINE_BLUR;
493       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
494         pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP;
495       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
496         pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
497       else
498         FALLBACK ("Blur nodes can't deal with clip type %u", constants->clip.type);
499       op.type = GSK_VULKAN_OP_BLUR;
500       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
501       g_array_append_val (self->render_ops, op);
502       return;
503 
504     case GSK_COLOR_MATRIX_NODE:
505       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
506         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
507       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
508         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
509       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
510         pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
511       else
512         FALLBACK ("Color matrix nodes can't deal with clip type %u", constants->clip.type);
513       op.type = GSK_VULKAN_OP_COLOR_MATRIX;
514       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
515       g_array_append_val (self->render_ops, op);
516       return;
517 
518     case GSK_BORDER_NODE:
519       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
520         pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
521       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
522         pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
523       else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
524         pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
525       else
526         FALLBACK ("Border nodes can't deal with clip type %u", constants->clip.type);
527       op.type = GSK_VULKAN_OP_BORDER;
528       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
529       g_array_append_val (self->render_ops, op);
530       return;
531 
532     case GSK_CONTAINER_NODE:
533       {
534         guint i;
535 
536         for (i = 0; i < gsk_container_node_get_n_children (node); i++)
537           {
538             gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
539           }
540       }
541       return;
542 
543     case GSK_DEBUG_NODE:
544       gsk_vulkan_render_pass_add_node (self, render, constants, gsk_debug_node_get_child (node));
545       return;
546 
547     case GSK_TRANSFORM_NODE:
548       {
549         graphene_matrix_t transform, mv;
550         GskRenderNode *child;
551 
552 #if 0
553        if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
554           FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
555 #endif
556 
557         child = gsk_transform_node_get_child (node);
558         gsk_transform_to_matrix (gsk_transform_node_get_transform (node), &transform);
559         graphene_matrix_init_from_matrix (&mv, &self->mv);
560         graphene_matrix_multiply (&transform, &mv, &self->mv);
561         if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, gsk_transform_node_get_transform (node), &child->bounds))
562           FALLBACK ("Transform nodes can't deal with clip type %u", constants->clip.type);
563         op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
564         g_array_append_val (self->render_ops, op);
565 
566         gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
567         gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
568         graphene_matrix_init_from_matrix (&self->mv, &mv);
569         g_array_append_val (self->render_ops, op);
570       }
571       return;
572 
573     case GSK_CLIP_NODE:
574       {
575         if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_get_clip (node)))
576           FALLBACK ("Failed to find intersection between clip of type %u and rectangle", constants->clip.type);
577         if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
578           return;
579 
580         op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
581         g_array_append_val (self->render_ops, op);
582 
583         gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
584 
585         gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
586         g_array_append_val (self->render_ops, op);
587       }
588       return;
589 
590     case GSK_ROUNDED_CLIP_NODE:
591       {
592         if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
593                                                           constants,
594                                                           gsk_rounded_clip_node_get_clip (node)))
595           FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle", constants->clip.type);
596         if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
597           return;
598 
599         op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
600         g_array_append_val (self->render_ops, op);
601 
602         gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
603 
604         gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
605         g_array_append_val (self->render_ops, op);
606       }
607       return;
608     }
609 
610   g_assert_not_reached ();
611   return;
612 
613 fallback:
614   switch (constants->clip.type)
615     {
616       case GSK_VULKAN_CLIP_NONE:
617         op.type = GSK_VULKAN_OP_FALLBACK;
618         break;
619       case GSK_VULKAN_CLIP_RECT:
620         op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
621         gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
622         break;
623       case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
624       case GSK_VULKAN_CLIP_ROUNDED:
625         op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
626         gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
627         break;
628       case GSK_VULKAN_CLIP_ALL_CLIPPED:
629       default:
630         g_assert_not_reached ();
631         return;
632     }
633   op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
634   g_array_append_val (self->render_ops, op);
635 }
636 #undef FALLBACK
637 
638 void
gsk_vulkan_render_pass_add(GskVulkanRenderPass * self,GskVulkanRender * render,GskRenderNode * node)639 gsk_vulkan_render_pass_add (GskVulkanRenderPass     *self,
640                             GskVulkanRender         *render,
641                             GskRenderNode           *node)
642 {
643   GskVulkanOp op = { 0, };
644   graphene_matrix_t mvp;
645 
646   graphene_matrix_multiply (&self->mv, &self->p, &mvp);
647   op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
648   gsk_vulkan_push_constants_init (&op.constants.constants, &mvp, &self->viewport);
649   g_array_append_val (self->render_ops, op);
650 
651   gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
652 }
653 
654 static GskVulkanImage *
gsk_vulkan_render_pass_get_node_as_texture(GskVulkanRenderPass * self,GskVulkanRender * render,GskVulkanUploader * uploader,GskRenderNode * node,const graphene_rect_t * bounds,GskVulkanClip * current_clip,graphene_rect_t * tex_rect)655 gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass   *self,
656                                             GskVulkanRender       *render,
657                                             GskVulkanUploader     *uploader,
658                                             GskRenderNode         *node,
659                                             const graphene_rect_t *bounds,
660                                             GskVulkanClip         *current_clip,
661                                             graphene_rect_t       *tex_rect)
662 {
663   GskVulkanImage *result;
664   cairo_surface_t *surface;
665   cairo_t *cr;
666 
667   switch ((guint) gsk_render_node_get_node_type (node))
668     {
669     case GSK_TEXTURE_NODE:
670       if (graphene_rect_equal (bounds, &node->bounds))
671         {
672           result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
673                                                           gsk_texture_node_get_texture (node),
674                                                           uploader);
675           gsk_vulkan_render_add_cleanup_image (render, result);
676           *tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
677           return result;
678         }
679       break;
680 
681     case GSK_CAIRO_NODE:
682       /* We're using recording surfaces, so drawing them to an image
683        * surface and uploading them is the right thing.
684        * But that's exactly what the fallback code does.
685        */
686       break;
687 
688     default:
689       {
690         VkSemaphore semaphore;
691         graphene_rect_t view;
692         cairo_region_t *clip;
693         GskVulkanRenderPass *pass;
694         graphene_rect_t clipped;
695 
696         if (current_clip)
697           graphene_rect_intersection (&current_clip->rect.bounds, bounds, &clipped);
698         else
699           clipped = *bounds;
700 
701         if (clipped.size.width == 0 || clipped.size.height == 0)
702           return NULL;
703 
704         graphene_matrix_transform_bounds (&self->mv, &clipped, &view);
705         view.origin.x = floor (view.origin.x);
706         view.origin.y = floor (view.origin.y);
707         view.size.width = ceil (view.size.width);
708         view.size.height = ceil (view.size.height);
709 
710         result = gsk_vulkan_image_new_for_texture (self->vulkan,
711                                                    view.size.width,
712                                                    view.size.height);
713 
714 #ifdef G_ENABLE_DEBUG
715         {
716           GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
717           gsk_profiler_counter_add (profiler,
718                                     self->texture_pixels,
719                                     view.size.width * view.size.height);
720         }
721 #endif
722 
723         vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
724                            &(VkSemaphoreCreateInfo) {
725                              VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
726                              NULL,
727                              0
728                            },
729                            NULL,
730                            &semaphore);
731 
732         g_array_append_val (self->wait_semaphores, semaphore);
733 
734         clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
735                                                 0, 0,
736                                                 gsk_vulkan_image_get_width (result),
737                                                 gsk_vulkan_image_get_height (result)
738                                               });
739 
740         pass = gsk_vulkan_render_pass_new (self->vulkan,
741                                            result,
742                                            self->scale_factor,
743                                            &self->mv,
744                                            &view,
745                                            clip,
746                                            semaphore);
747 
748         cairo_region_destroy (clip);
749 
750         gsk_vulkan_render_add_render_pass (render, pass);
751         gsk_vulkan_render_pass_add (pass, render, node);
752         gsk_vulkan_render_add_cleanup_image (render, result);
753 
754         /* assuming the unclipped bounds should go to texture coordinates 0..1,
755          * calculate the coordinates for the clipped texture size
756          */
757         tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
758         tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
759         tex_rect->size.width = bounds->size.width/clipped.size.width;
760         tex_rect->size.height = bounds->size.height/clipped.size.height;
761 
762         return result;
763       }
764    }
765 
766   GSK_RENDERER_NOTE (gsk_vulkan_render_get_renderer (render), FALLBACK, g_message ("Node as texture not implemented for this case. Using %gx%g fallback surface",
767                                ceil (bounds->size.width),
768                                ceil (bounds->size.height)));
769 #ifdef G_ENABLE_DEBUG
770   {
771     GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
772     gsk_profiler_counter_add (profiler,
773                               self->fallback_pixels,
774                               ceil (bounds->size.width) * ceil (bounds->size.height));
775   }
776 #endif
777 
778   /* XXX: We could intersect bounds with clip bounds here */
779   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
780                                         ceil (bounds->size.width),
781                                         ceil (bounds->size.height));
782   cr = cairo_create (surface);
783   cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
784 
785   gsk_render_node_draw (node, cr);
786 
787   cairo_destroy (cr);
788 
789   result = gsk_vulkan_image_new_from_data (uploader,
790                                            cairo_image_surface_get_data (surface),
791                                            cairo_image_surface_get_width (surface),
792                                            cairo_image_surface_get_height (surface),
793                                            cairo_image_surface_get_stride (surface));
794 
795   cairo_surface_destroy (surface);
796 
797   gsk_vulkan_render_add_cleanup_image (render, result);
798 
799   tex_rect->origin.x = (node->bounds.origin.x - bounds->origin.x)/bounds->size.width;
800   tex_rect->origin.y = (node->bounds.origin.y - bounds->origin.y)/bounds->size.height;
801   tex_rect->size.width = node->bounds.size.width/bounds->size.width;
802   tex_rect->size.height = node->bounds.size.height/bounds->size.height;
803 
804   return result;
805 }
806 
807 static void
gsk_vulkan_render_pass_upload_fallback(GskVulkanRenderPass * self,GskVulkanOpRender * op,GskVulkanRender * render,GskVulkanUploader * uploader)808 gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass  *self,
809                                         GskVulkanOpRender    *op,
810                                         GskVulkanRender      *render,
811                                         GskVulkanUploader    *uploader)
812 {
813   GskRenderNode *node;
814   cairo_surface_t *surface;
815   cairo_t *cr;
816 
817   node = op->node;
818 
819   GSK_RENDERER_NOTE (gsk_vulkan_render_get_renderer (render), FALLBACK,
820             g_message ("Upload op=%s, node %s[%p], bounds %gx%g",
821                      op->type == GSK_VULKAN_OP_FALLBACK_CLIP ? "fallback-clip" :
822                      (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP ? "fallback-rounded-clip" : "fallback"),
823                      g_type_name_from_instance ((GTypeInstance *) node), node,
824                      ceil (node->bounds.size.width),
825                      ceil (node->bounds.size.height)));
826 #ifdef G_ENABLE_DEBUG
827   {
828     GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
829     gsk_profiler_counter_add (profiler,
830                               self->fallback_pixels,
831                               ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
832   }
833 #endif
834 
835   /* XXX: We could intersect bounds with clip bounds here */
836   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
837                                         ceil (node->bounds.size.width * self->scale_factor),
838                                         ceil (node->bounds.size.height * self->scale_factor));
839   cairo_surface_set_device_scale (surface, self->scale_factor, self->scale_factor);
840   cr = cairo_create (surface);
841   cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
842 
843   if (op->type == GSK_VULKAN_OP_FALLBACK_CLIP)
844     {
845       cairo_rectangle (cr,
846                        op->clip.bounds.origin.x, op->clip.bounds.origin.y,
847                        op->clip.bounds.size.width, op->clip.bounds.size.height);
848       cairo_clip (cr);
849     }
850   else if (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP)
851     {
852       gsk_rounded_rect_path (&op->clip, cr);
853       cairo_clip (cr);
854     }
855   else
856     {
857       g_assert (op->type == GSK_VULKAN_OP_FALLBACK);
858     }
859 
860   gsk_render_node_draw (node, cr);
861 
862 #ifdef G_ENABLE_DEBUG
863   if (GSK_RENDERER_DEBUG_CHECK (gsk_vulkan_render_get_renderer (render), FALLBACK))
864     {
865       cairo_rectangle (cr,
866                        op->clip.bounds.origin.x, op->clip.bounds.origin.y,
867                        op->clip.bounds.size.width, op->clip.bounds.size.height);
868       if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
869         cairo_set_source_rgba (cr, 0.3, 0, 1, 0.25);
870       else
871         cairo_set_source_rgba (cr, 1, 0, 0, 0.25);
872       cairo_fill_preserve (cr);
873       if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
874         cairo_set_source_rgba (cr, 0.3, 0, 1, 1);
875       else
876         cairo_set_source_rgba (cr, 1, 0, 0, 1);
877       cairo_stroke (cr);
878     }
879 #endif
880 
881   cairo_destroy (cr);
882 
883   op->source = gsk_vulkan_image_new_from_data (uploader,
884                                                cairo_image_surface_get_data (surface),
885                                                cairo_image_surface_get_width (surface),
886                                                cairo_image_surface_get_height (surface),
887                                                cairo_image_surface_get_stride (surface));
888 
889   op->source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
890 
891   cairo_surface_destroy (surface);
892 
893   gsk_vulkan_render_add_cleanup_image (render, op->source);
894 }
895 
896 void
gsk_vulkan_render_pass_upload(GskVulkanRenderPass * self,GskVulkanRender * render,GskVulkanUploader * uploader)897 gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
898                                GskVulkanRender      *render,
899                                GskVulkanUploader    *uploader)
900 {
901   GskVulkanOp *op;
902   guint i;
903   GskVulkanClip *clip = NULL;
904 
905   for (i = 0; i < self->render_ops->len; i++)
906     {
907       op = &g_array_index (self->render_ops, GskVulkanOp, i);
908 
909       switch (op->type)
910         {
911         case GSK_VULKAN_OP_FALLBACK:
912         case GSK_VULKAN_OP_FALLBACK_CLIP:
913         case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
914           gsk_vulkan_render_pass_upload_fallback (self, &op->render, render, uploader);
915           break;
916 
917         case GSK_VULKAN_OP_TEXT:
918         case GSK_VULKAN_OP_COLOR_TEXT:
919           {
920             op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
921                                                                    uploader,
922                                                                    op->text.texture_index);
923             gsk_vulkan_render_add_cleanup_image (render, op->text.source);
924           }
925           break;
926 
927         case GSK_VULKAN_OP_TEXTURE:
928           {
929             op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
930                                                                        gsk_texture_node_get_texture (op->render.node),
931                                                                        uploader);
932             op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
933             gsk_vulkan_render_add_cleanup_image (render, op->render.source);
934           }
935           break;
936 
937         case GSK_VULKAN_OP_OPACITY:
938           {
939             GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
940 
941             op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
942                                                                             render,
943                                                                             uploader,
944                                                                             child,
945                                                                             &child->bounds,
946                                                                             clip,
947                                                                             &op->render.source_rect);
948           }
949           break;
950 
951         case GSK_VULKAN_OP_REPEAT:
952           {
953             GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
954             const graphene_rect_t *bounds = &op->render.node->bounds;
955             const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (op->render.node);
956 
957             op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
958                                                                             render,
959                                                                             uploader,
960                                                                             child,
961                                                                             child_bounds,
962                                                                             NULL,
963                                                                             &op->render.source_rect);
964 
965             op->render.source_rect.origin.x = (bounds->origin.x - child_bounds->origin.x)/child_bounds->size.width;
966             op->render.source_rect.origin.y = (bounds->origin.y - child_bounds->origin.y)/child_bounds->size.height;
967             op->render.source_rect.size.width = bounds->size.width / child_bounds->size.width;
968             op->render.source_rect.size.height = bounds->size.height / child_bounds->size.height;
969           }
970           break;
971 
972         case GSK_VULKAN_OP_BLUR:
973           {
974             GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
975 
976             op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
977                                                                             render,
978                                                                             uploader,
979                                                                             child,
980                                                                             &child->bounds,
981                                                                             clip,
982                                                                             &op->render.source_rect);
983           }
984           break;
985 
986         case GSK_VULKAN_OP_COLOR_MATRIX:
987           {
988             GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
989 
990             op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
991                                                                             render,
992                                                                             uploader,
993                                                                             child,
994                                                                             &child->bounds,
995                                                                             clip,
996                                                                             &op->render.source_rect);
997           }
998           break;
999 
1000         case GSK_VULKAN_OP_CROSS_FADE:
1001           {
1002             GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
1003             GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
1004             const graphene_rect_t *bounds = &op->render.node->bounds;
1005 
1006             op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
1007                                                                             render,
1008                                                                             uploader,
1009                                                                             start,
1010                                                                             &start->bounds,
1011                                                                             clip,
1012                                                                             &op->render.source_rect);
1013             op->render.source_rect.origin.x = (bounds->origin.x - start->bounds.origin.x)/start->bounds.size.width;
1014             op->render.source_rect.origin.y = (bounds->origin.y - start->bounds.origin.y)/start->bounds.size.height;
1015             op->render.source_rect.size.width = bounds->size.width / start->bounds.size.width;
1016             op->render.source_rect.size.height = bounds->size.height / start->bounds.size.height;
1017 
1018             op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
1019                                                                              render,
1020                                                                              uploader,
1021                                                                              end,
1022                                                                              &end->bounds,
1023                                                                              clip,
1024                                                                              &op->render.source2_rect);
1025             op->render.source2_rect.origin.x = (bounds->origin.x - end->bounds.origin.x)/end->bounds.size.width;
1026             op->render.source2_rect.origin.y = (bounds->origin.y - end->bounds.origin.y)/end->bounds.size.height;
1027             op->render.source2_rect.size.width = bounds->size.width / end->bounds.size.width;
1028             op->render.source2_rect.size.height = bounds->size.height / end->bounds.size.height;
1029           }
1030           break;
1031 
1032         case GSK_VULKAN_OP_BLEND_MODE:
1033           {
1034             GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
1035             GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
1036             const graphene_rect_t *bounds = &op->render.node->bounds;
1037 
1038             op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
1039                                                                             render,
1040                                                                             uploader,
1041                                                                             top,
1042                                                                             &top->bounds,
1043                                                                             clip,
1044                                                                             &op->render.source_rect);
1045             op->render.source_rect.origin.x = (bounds->origin.x - top->bounds.origin.x)/top->bounds.size.width;
1046             op->render.source_rect.origin.y = (bounds->origin.y - top->bounds.origin.y)/top->bounds.size.height;
1047             op->render.source_rect.size.width = bounds->size.width / top->bounds.size.width;
1048             op->render.source_rect.size.height = bounds->size.height / top->bounds.size.height;
1049 
1050             op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
1051                                                                              render,
1052                                                                              uploader,
1053                                                                              bottom,
1054                                                                              &bottom->bounds,
1055                                                                              clip,
1056                                                                              &op->render.source2_rect);
1057             op->render.source2_rect.origin.x = (bounds->origin.x - bottom->bounds.origin.x)/bottom->bounds.size.width;
1058             op->render.source2_rect.origin.y = (bounds->origin.y - bottom->bounds.origin.y)/bottom->bounds.size.height;
1059             op->render.source2_rect.size.width = bounds->size.width / bottom->bounds.size.width;
1060             op->render.source2_rect.size.height = bounds->size.height / bottom->bounds.size.height;
1061           }
1062           break;
1063 
1064         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
1065           clip = &op->constants.constants.clip;
1066           break;
1067 
1068         default:
1069           g_assert_not_reached ();
1070         case GSK_VULKAN_OP_COLOR:
1071         case GSK_VULKAN_OP_LINEAR_GRADIENT:
1072         case GSK_VULKAN_OP_BORDER:
1073         case GSK_VULKAN_OP_INSET_SHADOW:
1074         case GSK_VULKAN_OP_OUTSET_SHADOW:
1075           break;
1076         }
1077     }
1078 }
1079 
1080 static gsize
gsk_vulkan_render_pass_count_vertex_data(GskVulkanRenderPass * self)1081 gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
1082 {
1083   GskVulkanOp *op;
1084   gsize n_bytes;
1085   guint i;
1086 
1087   n_bytes = 0;
1088   for (i = 0; i < self->render_ops->len; i++)
1089     {
1090       op = &g_array_index (self->render_ops, GskVulkanOp, i);
1091 
1092       switch (op->type)
1093         {
1094         case GSK_VULKAN_OP_FALLBACK:
1095         case GSK_VULKAN_OP_FALLBACK_CLIP:
1096         case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
1097         case GSK_VULKAN_OP_TEXTURE:
1098         case GSK_VULKAN_OP_REPEAT:
1099           op->render.vertex_count = gsk_vulkan_texture_pipeline_count_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline));
1100           n_bytes += op->render.vertex_count;
1101           break;
1102 
1103         case GSK_VULKAN_OP_TEXT:
1104           op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
1105                                                                               op->text.num_glyphs);
1106           n_bytes += op->text.vertex_count;
1107           break;
1108 
1109         case GSK_VULKAN_OP_COLOR_TEXT:
1110           op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
1111                                                                                     op->text.num_glyphs);
1112           n_bytes += op->text.vertex_count;
1113           break;
1114 
1115         case GSK_VULKAN_OP_COLOR:
1116           op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
1117           n_bytes += op->render.vertex_count;
1118           break;
1119 
1120         case GSK_VULKAN_OP_LINEAR_GRADIENT:
1121           op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline));
1122           n_bytes += op->render.vertex_count;
1123           break;
1124 
1125         case GSK_VULKAN_OP_OPACITY:
1126         case GSK_VULKAN_OP_COLOR_MATRIX:
1127           op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline));
1128           n_bytes += op->render.vertex_count;
1129           break;
1130 
1131         case GSK_VULKAN_OP_BLUR:
1132           op->render.vertex_count = gsk_vulkan_blur_pipeline_count_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline));
1133           n_bytes += op->render.vertex_count;
1134           break;
1135 
1136         case GSK_VULKAN_OP_BORDER:
1137           op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
1138           n_bytes += op->render.vertex_count;
1139           break;
1140 
1141         case GSK_VULKAN_OP_INSET_SHADOW:
1142         case GSK_VULKAN_OP_OUTSET_SHADOW:
1143           op->render.vertex_count = gsk_vulkan_box_shadow_pipeline_count_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline));
1144           n_bytes += op->render.vertex_count;
1145           break;
1146 
1147         case GSK_VULKAN_OP_CROSS_FADE:
1148           op->render.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline));
1149           n_bytes += op->render.vertex_count;
1150           break;
1151 
1152         case GSK_VULKAN_OP_BLEND_MODE:
1153           op->render.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline));
1154           n_bytes += op->render.vertex_count;
1155           break;
1156 
1157         default:
1158           g_assert_not_reached ();
1159 
1160         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
1161           continue;
1162         }
1163     }
1164 
1165   return n_bytes;
1166 }
1167 
1168 static gsize
gsk_vulkan_render_pass_collect_vertex_data(GskVulkanRenderPass * self,GskVulkanRender * render,guchar * data,gsize offset,gsize total)1169 gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
1170                                             GskVulkanRender     *render,
1171                                             guchar              *data,
1172                                             gsize                offset,
1173                                             gsize                total)
1174 {
1175   GskVulkanOp *op;
1176   gsize n_bytes;
1177   guint i;
1178 
1179   n_bytes = 0;
1180   for (i = 0; i < self->render_ops->len; i++)
1181     {
1182       op = &g_array_index (self->render_ops, GskVulkanOp, i);
1183 
1184       switch (op->type)
1185         {
1186         case GSK_VULKAN_OP_FALLBACK:
1187         case GSK_VULKAN_OP_FALLBACK_CLIP:
1188         case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
1189         case GSK_VULKAN_OP_TEXTURE:
1190           {
1191             op->render.vertex_offset = offset + n_bytes;
1192             gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
1193                                                              data + n_bytes + offset,
1194                                                              &op->render.node->bounds,
1195                                                              &op->render.source_rect);
1196             n_bytes += op->render.vertex_count;
1197           }
1198           break;
1199 
1200         case GSK_VULKAN_OP_REPEAT:
1201           {
1202             op->render.vertex_offset = offset + n_bytes;
1203             gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
1204                                                              data + n_bytes + offset,
1205                                                              &op->render.node->bounds,
1206                                                              &op->render.source_rect);
1207             n_bytes += op->render.vertex_count;
1208           }
1209           break;
1210 
1211         case GSK_VULKAN_OP_TEXT:
1212           {
1213             op->text.vertex_offset = offset + n_bytes;
1214             gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
1215                                                           data + n_bytes + offset,
1216                                                           GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
1217                                                           &op->text.node->bounds,
1218                                                           (PangoFont *)gsk_text_node_get_font (op->text.node),
1219                                                           gsk_text_node_get_num_glyphs (op->text.node),
1220                                                           gsk_text_node_get_glyphs (op->text.node, NULL),
1221                                                           gsk_text_node_get_color (op->text.node),
1222                                                           gsk_text_node_get_offset (op->text.node),
1223                                                           op->text.start_glyph,
1224                                                           op->text.num_glyphs,
1225                                                           op->text.scale);
1226             n_bytes += op->text.vertex_count;
1227           }
1228           break;
1229 
1230         case GSK_VULKAN_OP_COLOR_TEXT:
1231           {
1232             op->text.vertex_offset = offset + n_bytes;
1233             gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
1234                                                                 data + n_bytes + offset,
1235                                                                 GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
1236                                                                 &op->text.node->bounds,
1237                                                                 (PangoFont *)gsk_text_node_get_font (op->text.node),
1238                                                                 gsk_text_node_get_num_glyphs (op->text.node),
1239                                                                 gsk_text_node_get_glyphs (op->text.node, NULL),
1240                                                                 gsk_text_node_get_offset (op->text.node),
1241                                                                 op->text.start_glyph,
1242                                                                 op->text.num_glyphs,
1243                                                                 op->text.scale);
1244             n_bytes += op->text.vertex_count;
1245           }
1246           break;
1247 
1248         case GSK_VULKAN_OP_COLOR:
1249           {
1250             op->render.vertex_offset = offset + n_bytes;
1251             gsk_vulkan_color_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline),
1252                                                            data + n_bytes + offset,
1253                                                            &op->render.node->bounds,
1254                                                            gsk_color_node_get_color (op->render.node));
1255             n_bytes += op->render.vertex_count;
1256           }
1257           break;
1258 
1259         case GSK_VULKAN_OP_LINEAR_GRADIENT:
1260           {
1261             op->render.vertex_offset = offset + n_bytes;
1262             gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline),
1263                                                                      data + n_bytes + offset,
1264                                                                      &op->render.node->bounds,
1265                                                                      gsk_linear_gradient_node_get_start (op->render.node),
1266                                                                      gsk_linear_gradient_node_get_end (op->render.node),
1267                                                                      gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
1268                                                                      gsk_linear_gradient_node_get_n_color_stops (op->render.node),
1269                                                                      gsk_linear_gradient_node_get_color_stops (op->render.node, NULL));
1270             n_bytes += op->render.vertex_count;
1271           }
1272           break;
1273 
1274         case GSK_VULKAN_OP_OPACITY:
1275           {
1276             graphene_matrix_t color_matrix;
1277             graphene_vec4_t color_offset;
1278 
1279             graphene_matrix_init_from_float (&color_matrix,
1280                                              (float[16]) {
1281                                                  1.0, 0.0, 0.0, 0.0,
1282                                                  0.0, 1.0, 0.0, 0.0,
1283                                                  0.0, 0.0, 1.0, 0.0,
1284                                                  0.0, 0.0, 0.0, gsk_opacity_node_get_opacity (op->render.node)
1285                                              });
1286             graphene_vec4_init (&color_offset, 0.0, 0.0, 0.0, 0.0);
1287             op->render.vertex_offset = offset + n_bytes;
1288 
1289             gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
1290                                                             data + n_bytes + offset,
1291                                                             &op->render.node->bounds,
1292                                                             &op->render.source_rect,
1293                                                             &color_matrix,
1294                                                             &color_offset);
1295             n_bytes += op->render.vertex_count;
1296           }
1297           break;
1298 
1299         case GSK_VULKAN_OP_BLUR:
1300           {
1301             op->render.vertex_offset = offset + n_bytes;
1302             gsk_vulkan_blur_pipeline_collect_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline),
1303                                                           data + n_bytes + offset,
1304                                                           &op->render.node->bounds,
1305                                                           &op->render.source_rect,
1306                                                           gsk_blur_node_get_radius (op->render.node));
1307             n_bytes += op->render.vertex_count;
1308           }
1309           break;
1310 
1311         case GSK_VULKAN_OP_COLOR_MATRIX:
1312           {
1313             op->render.vertex_offset = offset + n_bytes;
1314             gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
1315                                                             data + n_bytes + offset,
1316                                                             &op->render.node->bounds,
1317                                                             &op->render.source_rect,
1318                                                             gsk_color_matrix_node_get_color_matrix (op->render.node),
1319                                                             gsk_color_matrix_node_get_color_offset (op->render.node));
1320             n_bytes += op->render.vertex_count;
1321           }
1322           break;
1323 
1324         case GSK_VULKAN_OP_BORDER:
1325           {
1326             op->render.vertex_offset = offset + n_bytes;
1327             gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
1328                                                             data + n_bytes + offset,
1329                                                             gsk_border_node_get_outline (op->render.node),
1330                                                             gsk_border_node_get_widths (op->render.node),
1331                                                             gsk_border_node_get_colors (op->render.node));
1332             n_bytes += op->render.vertex_count;
1333           }
1334           break;
1335 
1336         case GSK_VULKAN_OP_INSET_SHADOW:
1337           {
1338             op->render.vertex_offset = offset + n_bytes;
1339             gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
1340                                                                 data + n_bytes + offset,
1341                                                                 gsk_inset_shadow_node_get_outline (op->render.node),
1342                                                                 gsk_inset_shadow_node_get_color (op->render.node),
1343                                                                 gsk_inset_shadow_node_get_dx (op->render.node),
1344                                                                 gsk_inset_shadow_node_get_dy (op->render.node),
1345                                                                 gsk_inset_shadow_node_get_spread (op->render.node),
1346                                                                 gsk_inset_shadow_node_get_blur_radius (op->render.node));
1347             n_bytes += op->render.vertex_count;
1348           }
1349           break;
1350 
1351         case GSK_VULKAN_OP_OUTSET_SHADOW:
1352           {
1353             op->render.vertex_offset = offset + n_bytes;
1354             gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
1355                                                                 data + n_bytes + offset,
1356                                                                 gsk_outset_shadow_node_get_outline (op->render.node),
1357                                                                 gsk_outset_shadow_node_get_color (op->render.node),
1358                                                                 gsk_outset_shadow_node_get_dx (op->render.node),
1359                                                                 gsk_outset_shadow_node_get_dy (op->render.node),
1360                                                                 gsk_outset_shadow_node_get_spread (op->render.node),
1361                                                                 gsk_outset_shadow_node_get_blur_radius (op->render.node));
1362             n_bytes += op->render.vertex_count;
1363           }
1364           break;
1365 
1366         case GSK_VULKAN_OP_CROSS_FADE:
1367           {
1368             op->render.vertex_offset = offset + n_bytes;
1369             gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline),
1370                                                                 data + n_bytes + offset,
1371                                                                 &op->render.node->bounds,
1372                                                                 &op->render.source_rect,
1373                                                                 &op->render.source2_rect,
1374                                                                 gsk_cross_fade_node_get_progress (op->render.node));
1375             n_bytes += op->render.vertex_count;
1376           }
1377           break;
1378 
1379         case GSK_VULKAN_OP_BLEND_MODE:
1380           {
1381             op->render.vertex_offset = offset + n_bytes;
1382             gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline),
1383                                                                 data + n_bytes + offset,
1384                                                                 &op->render.node->bounds,
1385                                                                 &op->render.source_rect,
1386                                                                 &op->render.source2_rect,
1387                                                                 gsk_blend_node_get_blend_mode (op->render.node));
1388             n_bytes += op->render.vertex_count;
1389           }
1390           break;
1391 
1392         default:
1393           g_assert_not_reached ();
1394         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
1395           continue;
1396         }
1397 
1398       g_assert (n_bytes + offset <= total);
1399     }
1400 
1401   return n_bytes;
1402 }
1403 
1404 static GskVulkanBuffer *
gsk_vulkan_render_pass_get_vertex_data(GskVulkanRenderPass * self,GskVulkanRender * render)1405 gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
1406                                         GskVulkanRender     *render)
1407 {
1408   if (self->vertex_data == NULL)
1409     {
1410       gsize n_bytes;
1411       guchar *data;
1412 
1413       n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
1414       self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
1415       data = gsk_vulkan_buffer_map (self->vertex_data);
1416       gsk_vulkan_render_pass_collect_vertex_data (self, render, data, 0, n_bytes);
1417       gsk_vulkan_buffer_unmap (self->vertex_data);
1418     }
1419 
1420   return self->vertex_data;
1421 }
1422 
1423 gsize
gsk_vulkan_render_pass_get_wait_semaphores(GskVulkanRenderPass * self,VkSemaphore ** semaphores)1424 gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass  *self,
1425                                             VkSemaphore         **semaphores)
1426 {
1427   *semaphores = (VkSemaphore *)self->wait_semaphores->data;
1428   return self->wait_semaphores->len;
1429 }
1430 
1431 gsize
gsk_vulkan_render_pass_get_signal_semaphores(GskVulkanRenderPass * self,VkSemaphore ** semaphores)1432 gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass  *self,
1433                                               VkSemaphore         **semaphores)
1434 {
1435   *semaphores = (VkSemaphore *)&self->signal_semaphore;
1436   return self->signal_semaphore != VK_NULL_HANDLE ? 1 : 0;
1437 }
1438 
1439 void
gsk_vulkan_render_pass_reserve_descriptor_sets(GskVulkanRenderPass * self,GskVulkanRender * render)1440 gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
1441                                                 GskVulkanRender     *render)
1442 {
1443   GskVulkanOp *op;
1444   guint i;
1445 
1446   for (i = 0; i < self->render_ops->len; i++)
1447     {
1448       op = &g_array_index (self->render_ops, GskVulkanOp, i);
1449 
1450       switch (op->type)
1451         {
1452         case GSK_VULKAN_OP_FALLBACK:
1453         case GSK_VULKAN_OP_FALLBACK_CLIP:
1454         case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
1455         case GSK_VULKAN_OP_TEXTURE:
1456         case GSK_VULKAN_OP_OPACITY:
1457         case GSK_VULKAN_OP_BLUR:
1458         case GSK_VULKAN_OP_COLOR_MATRIX:
1459           if (op->render.source)
1460             op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
1461           break;
1462 
1463         case GSK_VULKAN_OP_REPEAT:
1464           if (op->render.source)
1465             op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
1466           break;
1467 
1468         case GSK_VULKAN_OP_TEXT:
1469         case GSK_VULKAN_OP_COLOR_TEXT:
1470           op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
1471           break;
1472 
1473         case GSK_VULKAN_OP_CROSS_FADE:
1474         case GSK_VULKAN_OP_BLEND_MODE:
1475           if (op->render.source && op->render.source2)
1476             {
1477               op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
1478               op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
1479             }
1480           break;
1481 
1482         default:
1483           g_assert_not_reached ();
1484 
1485         case GSK_VULKAN_OP_COLOR:
1486         case GSK_VULKAN_OP_LINEAR_GRADIENT:
1487         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
1488         case GSK_VULKAN_OP_BORDER:
1489         case GSK_VULKAN_OP_INSET_SHADOW:
1490         case GSK_VULKAN_OP_OUTSET_SHADOW:
1491           break;
1492         }
1493     }
1494 }
1495 
1496 static void
gsk_vulkan_render_pass_draw_rect(GskVulkanRenderPass * self,GskVulkanRender * render,guint layout_count,VkPipelineLayout * pipeline_layout,VkCommandBuffer command_buffer)1497 gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass     *self,
1498                                   GskVulkanRender         *render,
1499                                   guint                    layout_count,
1500                                   VkPipelineLayout        *pipeline_layout,
1501                                   VkCommandBuffer          command_buffer)
1502 {
1503   GskVulkanPipeline *current_pipeline = NULL;
1504   gsize current_draw_index = 0;
1505   GskVulkanOp *op;
1506   guint i, step;
1507   GskVulkanBuffer *vertex_buffer;
1508 
1509   vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
1510 
1511   for (i = 0; i < self->render_ops->len; i += step)
1512     {
1513       op = &g_array_index (self->render_ops, GskVulkanOp, i);
1514       step = 1;
1515 
1516       switch (op->type)
1517         {
1518         case GSK_VULKAN_OP_FALLBACK:
1519         case GSK_VULKAN_OP_FALLBACK_CLIP:
1520         case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
1521         case GSK_VULKAN_OP_TEXTURE:
1522         case GSK_VULKAN_OP_REPEAT:
1523           if (!op->render.source)
1524             continue;
1525           if (current_pipeline != op->render.pipeline)
1526             {
1527               current_pipeline = op->render.pipeline;
1528               vkCmdBindPipeline (command_buffer,
1529                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1530                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1531               vkCmdBindVertexBuffers (command_buffer,
1532                                       0,
1533                                       1,
1534                                       (VkBuffer[1]) {
1535                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1536                                       },
1537                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1538               current_draw_index = 0;
1539             }
1540 
1541           vkCmdBindDescriptorSets (command_buffer,
1542                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1543                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1544                                    0,
1545                                    1,
1546                                    (VkDescriptorSet[1]) {
1547                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
1548                                    },
1549                                    0,
1550                                    NULL);
1551 
1552           current_draw_index += gsk_vulkan_texture_pipeline_draw (GSK_VULKAN_TEXTURE_PIPELINE (current_pipeline),
1553                                                                   command_buffer,
1554                                                                   current_draw_index, 1);
1555           break;
1556 
1557         case GSK_VULKAN_OP_TEXT:
1558           if (current_pipeline != op->text.pipeline)
1559             {
1560               current_pipeline = op->text.pipeline;
1561               vkCmdBindPipeline (command_buffer,
1562                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1563                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1564               vkCmdBindVertexBuffers (command_buffer,
1565                                       0,
1566                                       1,
1567                                       (VkBuffer[1]) {
1568                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1569                                       },
1570                                       (VkDeviceSize[1]) { op->text.vertex_offset });
1571               current_draw_index = 0;
1572             }
1573 
1574           vkCmdBindDescriptorSets (command_buffer,
1575                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1576                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1577                                    0,
1578                                    1,
1579                                    (VkDescriptorSet[1]) {
1580                                        gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
1581                                    },
1582                                    0,
1583                                    NULL);
1584 
1585           current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
1586                                                                command_buffer,
1587                                                                current_draw_index, op->text.num_glyphs);
1588           break;
1589 
1590         case GSK_VULKAN_OP_COLOR_TEXT:
1591           if (current_pipeline != op->text.pipeline)
1592             {
1593               current_pipeline = op->text.pipeline;
1594               vkCmdBindPipeline (command_buffer,
1595                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1596                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1597               vkCmdBindVertexBuffers (command_buffer,
1598                                       0,
1599                                       1,
1600                                       (VkBuffer[1]) {
1601                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1602                                       },
1603                                       (VkDeviceSize[1]) { op->text.vertex_offset });
1604               current_draw_index = 0;
1605             }
1606 
1607           vkCmdBindDescriptorSets (command_buffer,
1608                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1609                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1610                                    0,
1611                                    1,
1612                                    (VkDescriptorSet[1]) {
1613                                        gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
1614                                    },
1615                                    0,
1616                                    NULL);
1617 
1618           current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
1619                                                                      command_buffer,
1620                                                                      current_draw_index, op->text.num_glyphs);
1621           break;
1622 
1623         case GSK_VULKAN_OP_OPACITY:
1624         case GSK_VULKAN_OP_COLOR_MATRIX:
1625           if (!op->render.source)
1626             continue;
1627           if (current_pipeline != op->render.pipeline)
1628             {
1629               current_pipeline = op->render.pipeline;
1630               vkCmdBindPipeline (command_buffer,
1631                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1632                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1633               vkCmdBindVertexBuffers (command_buffer,
1634                                       0,
1635                                       1,
1636                                       (VkBuffer[1]) {
1637                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1638                                       },
1639                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1640               current_draw_index = 0;
1641             }
1642 
1643           vkCmdBindDescriptorSets (command_buffer,
1644                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1645                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1646                                    0,
1647                                    1,
1648                                    (VkDescriptorSet[1]) {
1649                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
1650                                    },
1651                                    0,
1652                                    NULL);
1653 
1654           current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline),
1655                                                                  command_buffer,
1656                                                                  current_draw_index, 1);
1657           break;
1658 
1659         case GSK_VULKAN_OP_BLUR:
1660           if (!op->render.source)
1661             continue;
1662           if (current_pipeline != op->render.pipeline)
1663             {
1664               current_pipeline = op->render.pipeline;
1665               vkCmdBindPipeline (command_buffer,
1666                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1667                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1668               vkCmdBindVertexBuffers (command_buffer,
1669                                       0,
1670                                       1,
1671                                       (VkBuffer[1]) {
1672                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1673                                       },
1674                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1675               current_draw_index = 0;
1676             }
1677 
1678           vkCmdBindDescriptorSets (command_buffer,
1679                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1680                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1681                                    0,
1682                                    1,
1683                                    (VkDescriptorSet[1]) {
1684                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
1685                                    },
1686                                    0,
1687                                    NULL);
1688 
1689           current_draw_index += gsk_vulkan_blur_pipeline_draw (GSK_VULKAN_BLUR_PIPELINE (current_pipeline),
1690                                                                command_buffer,
1691                                                                current_draw_index, 1);
1692           break;
1693 
1694         case GSK_VULKAN_OP_COLOR:
1695           if (current_pipeline != op->render.pipeline)
1696             {
1697               current_pipeline = op->render.pipeline;
1698               vkCmdBindPipeline (command_buffer,
1699                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1700                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1701               vkCmdBindVertexBuffers (command_buffer,
1702                                       0,
1703                                       1,
1704                                       (VkBuffer[1]) {
1705                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1706                                       },
1707                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1708               current_draw_index = 0;
1709             }
1710 
1711           for (step = 1; step + i < self->render_ops->len; step++)
1712             {
1713               GskVulkanOp *cmp = &g_array_index (self->render_ops, GskVulkanOp, i + step);
1714               if (cmp->type != GSK_VULKAN_OP_COLOR ||
1715                   cmp->render.pipeline != current_pipeline)
1716                 break;
1717             }
1718           current_draw_index += gsk_vulkan_color_pipeline_draw (GSK_VULKAN_COLOR_PIPELINE (current_pipeline),
1719                                                                 command_buffer,
1720                                                                 current_draw_index, step);
1721           break;
1722 
1723         case GSK_VULKAN_OP_LINEAR_GRADIENT:
1724           if (current_pipeline != op->render.pipeline)
1725             {
1726               current_pipeline = op->render.pipeline;
1727               vkCmdBindPipeline (command_buffer,
1728                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1729                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1730               vkCmdBindVertexBuffers (command_buffer,
1731                                       0,
1732                                       1,
1733                                       (VkBuffer[1]) {
1734                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1735                                       },
1736                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1737               current_draw_index = 0;
1738             }
1739           current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline),
1740                                                                           command_buffer,
1741                                                                           current_draw_index, 1);
1742           break;
1743 
1744         case GSK_VULKAN_OP_BORDER:
1745           if (current_pipeline != op->render.pipeline)
1746             {
1747               current_pipeline = op->render.pipeline;
1748               vkCmdBindPipeline (command_buffer,
1749                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1750                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1751               vkCmdBindVertexBuffers (command_buffer,
1752                                       0,
1753                                       1,
1754                                       (VkBuffer[1]) {
1755                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1756                                       },
1757                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1758               current_draw_index = 0;
1759             }
1760           current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
1761                                                                  command_buffer,
1762                                                                  current_draw_index, 1);
1763           break;
1764 
1765         case GSK_VULKAN_OP_INSET_SHADOW:
1766         case GSK_VULKAN_OP_OUTSET_SHADOW:
1767           if (current_pipeline != op->render.pipeline)
1768             {
1769               current_pipeline = op->render.pipeline;
1770               vkCmdBindPipeline (command_buffer,
1771                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1772                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1773               vkCmdBindVertexBuffers (command_buffer,
1774                                       0,
1775                                       1,
1776                                       (VkBuffer[1]) {
1777                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1778                                       },
1779                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1780               current_draw_index = 0;
1781             }
1782           current_draw_index += gsk_vulkan_box_shadow_pipeline_draw (GSK_VULKAN_BOX_SHADOW_PIPELINE (current_pipeline),
1783                                                                      command_buffer,
1784                                                                      current_draw_index, 1);
1785           break;
1786 
1787         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
1788           for (int j = 0; j < layout_count; j++)
1789             gsk_vulkan_push_constants_push (&op->constants.constants,
1790                                             command_buffer,
1791                                             pipeline_layout[j]);
1792           break;
1793 
1794         case GSK_VULKAN_OP_CROSS_FADE:
1795           if (!op->render.source || !op->render.source2)
1796             continue;
1797           if (current_pipeline != op->render.pipeline)
1798             {
1799               current_pipeline = op->render.pipeline;
1800               vkCmdBindPipeline (command_buffer,
1801                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1802                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1803               vkCmdBindVertexBuffers (command_buffer,
1804                                       0,
1805                                       1,
1806                                       (VkBuffer[1]) {
1807                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1808                                       },
1809                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1810               current_draw_index = 0;
1811             }
1812 
1813           vkCmdBindDescriptorSets (command_buffer,
1814                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1815                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1816                                    0,
1817                                    2,
1818                                    (VkDescriptorSet[2]) {
1819                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
1820                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
1821                                    },
1822                                    0,
1823                                    NULL);
1824 
1825           current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
1826                                                                      command_buffer,
1827                                                                      current_draw_index, 1);
1828           break;
1829 
1830         case GSK_VULKAN_OP_BLEND_MODE:
1831           if (!op->render.source || !op->render.source2)
1832             continue;
1833           if (current_pipeline != op->render.pipeline)
1834             {
1835               current_pipeline = op->render.pipeline;
1836               vkCmdBindPipeline (command_buffer,
1837                                  VK_PIPELINE_BIND_POINT_GRAPHICS,
1838                                  gsk_vulkan_pipeline_get_pipeline (current_pipeline));
1839               vkCmdBindVertexBuffers (command_buffer,
1840                                       0,
1841                                       1,
1842                                       (VkBuffer[1]) {
1843                                           gsk_vulkan_buffer_get_buffer (vertex_buffer)
1844                                       },
1845                                       (VkDeviceSize[1]) { op->render.vertex_offset });
1846               current_draw_index = 0;
1847             }
1848 
1849           vkCmdBindDescriptorSets (command_buffer,
1850                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
1851                                    gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
1852                                    0,
1853                                    2,
1854                                    (VkDescriptorSet[2]) {
1855                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
1856                                        gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
1857                                    },
1858                                    0,
1859                                    NULL);
1860 
1861           current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline),
1862                                                                      command_buffer,
1863                                                                      current_draw_index, 1);
1864           break;
1865 
1866         default:
1867           g_assert_not_reached ();
1868           break;
1869         }
1870     }
1871 }
1872 
1873 void
gsk_vulkan_render_pass_draw(GskVulkanRenderPass * self,GskVulkanRender * render,guint layout_count,VkPipelineLayout * pipeline_layout,VkCommandBuffer command_buffer)1874 gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
1875                              GskVulkanRender         *render,
1876                              guint                    layout_count,
1877                              VkPipelineLayout        *pipeline_layout,
1878                              VkCommandBuffer          command_buffer)
1879 {
1880   guint i;
1881 
1882   vkCmdSetViewport (command_buffer,
1883                     0,
1884                     1,
1885                     &(VkViewport) {
1886                         .x = 0,
1887                         .y = 0,
1888                         .width = self->viewport.size.width,
1889                         .height = self->viewport.size.height,
1890                         .minDepth = 0,
1891                         .maxDepth = 1
1892                     });
1893 
1894   for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
1895     {
1896       cairo_rectangle_int_t rect;
1897 
1898       cairo_region_get_rectangle (self->clip, i, &rect);
1899 
1900       vkCmdSetScissor (command_buffer,
1901                        0,
1902                        1,
1903                        &(VkRect2D) {
1904                           { rect.x * self->scale_factor, rect.y * self->scale_factor },
1905                           { rect.width * self->scale_factor, rect.height * self->scale_factor }
1906                        });
1907 
1908       vkCmdBeginRenderPass (command_buffer,
1909                             &(VkRenderPassBeginInfo) {
1910                                 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1911                                 .renderPass = self->render_pass,
1912                                 .framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
1913                                 .renderArea = {
1914                                     { rect.x * self->scale_factor, rect.y * self->scale_factor },
1915                                     { rect.width * self->scale_factor, rect.height * self->scale_factor }
1916                                 },
1917                                 .clearValueCount = 1,
1918                                 .pClearValues = (VkClearValue [1]) {
1919                                     { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
1920                                 }
1921                             },
1922                             VK_SUBPASS_CONTENTS_INLINE);
1923 
1924       gsk_vulkan_render_pass_draw_rect (self, render, layout_count, pipeline_layout, command_buffer);
1925 
1926       vkCmdEndRenderPass (command_buffer);
1927     }
1928 }
1929