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 (¤t_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