mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 22:41:43 +00:00
3aaea0ef40
In some cases, we were creating gigantic intermediate textures only to clip out a small section afterwards (e.g. in the listbox example in gtk4-demo). This is wasteful if we apply effects on the texture, such as blur or color-matrix. So, clip the dimensions of the intermediate texture with the current clip. To make this feasible, we move the texture coordinate computation out of the pipeline setup functions into the node_as_texture function where this clipping happens. One extra complication we encounter is that the node might get clipped away completely. Since Vulkan does not allow to create empty images, we bail out in this case and not draw anything. With these changes, the listbox example in gtk4-demo goes from 32M pixels of intermediate texture to 320000.
1910 lines
85 KiB
C
1910 lines
85 KiB
C
#include "config.h"
|
|
|
|
#include "gskvulkanrenderpassprivate.h"
|
|
|
|
#include "gskdebugprivate.h"
|
|
#include "gskprofilerprivate.h"
|
|
#include "gskrendernodeprivate.h"
|
|
#include "gskrenderer.h"
|
|
#include "gskrendererprivate.h"
|
|
#include "gskroundedrectprivate.h"
|
|
#include "gskvulkanblendmodepipelineprivate.h"
|
|
#include "gskvulkanblurpipelineprivate.h"
|
|
#include "gskvulkanborderpipelineprivate.h"
|
|
#include "gskvulkanboxshadowpipelineprivate.h"
|
|
#include "gskvulkanclipprivate.h"
|
|
#include "gskvulkancolorpipelineprivate.h"
|
|
#include "gskvulkancolortextpipelineprivate.h"
|
|
#include "gskvulkancrossfadepipelineprivate.h"
|
|
#include "gskvulkaneffectpipelineprivate.h"
|
|
#include "gskvulkanlineargradientpipelineprivate.h"
|
|
#include "gskvulkantextpipelineprivate.h"
|
|
#include "gskvulkantexturepipelineprivate.h"
|
|
#include "gskvulkanimageprivate.h"
|
|
#include "gskvulkanpushconstantsprivate.h"
|
|
#include "gskvulkanrendererprivate.h"
|
|
#include "gskprivate.h"
|
|
|
|
#include <cairo-ft.h>
|
|
|
|
#define ORTHO_NEAR_PLANE -10000
|
|
#define ORTHO_FAR_PLANE 10000
|
|
|
|
typedef union _GskVulkanOp GskVulkanOp;
|
|
typedef struct _GskVulkanOpRender GskVulkanOpRender;
|
|
typedef struct _GskVulkanOpText GskVulkanOpText;
|
|
typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
|
|
|
|
typedef enum {
|
|
/* GskVulkanOpRender */
|
|
GSK_VULKAN_OP_FALLBACK,
|
|
GSK_VULKAN_OP_FALLBACK_CLIP,
|
|
GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
|
|
GSK_VULKAN_OP_SURFACE,
|
|
GSK_VULKAN_OP_TEXTURE,
|
|
GSK_VULKAN_OP_COLOR,
|
|
GSK_VULKAN_OP_LINEAR_GRADIENT,
|
|
GSK_VULKAN_OP_OPACITY,
|
|
GSK_VULKAN_OP_BLUR,
|
|
GSK_VULKAN_OP_COLOR_MATRIX,
|
|
GSK_VULKAN_OP_BORDER,
|
|
GSK_VULKAN_OP_INSET_SHADOW,
|
|
GSK_VULKAN_OP_OUTSET_SHADOW,
|
|
GSK_VULKAN_OP_REPEAT,
|
|
GSK_VULKAN_OP_CROSS_FADE,
|
|
GSK_VULKAN_OP_BLEND_MODE,
|
|
/* GskVulkanOpText */
|
|
GSK_VULKAN_OP_TEXT,
|
|
GSK_VULKAN_OP_COLOR_TEXT,
|
|
/* GskVulkanOpPushConstants */
|
|
GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
|
|
} GskVulkanOpType;
|
|
|
|
/* render ops with 0, 1 or 2 sources */
|
|
struct _GskVulkanOpRender
|
|
{
|
|
GskVulkanOpType type;
|
|
GskRenderNode *node; /* node that's the source of this op */
|
|
GskVulkanPipeline *pipeline; /* pipeline to use */
|
|
GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
|
|
GskVulkanImage *source; /* source image to render */
|
|
GskVulkanImage *source2; /* second source image to render (if relevant) */
|
|
gsize vertex_offset; /* offset into vertex buffer */
|
|
gsize vertex_count; /* number of vertices */
|
|
gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
|
|
gsize descriptor_set_index2; /* descriptor index for the second source (if relevant) */
|
|
graphene_rect_t source_rect; /* area that source maps to */
|
|
graphene_rect_t source2_rect; /* area that source2 maps to */
|
|
};
|
|
|
|
struct _GskVulkanOpText
|
|
{
|
|
GskVulkanOpType type;
|
|
GskRenderNode *node; /* node that's the source of this op */
|
|
GskVulkanPipeline *pipeline; /* pipeline to use */
|
|
GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
|
|
GskVulkanImage *source; /* source image to render */
|
|
gsize vertex_offset; /* offset into vertex buffer */
|
|
gsize vertex_count; /* number of vertices */
|
|
gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
|
|
guint texture_index; /* index of the texture in the glyph cache */
|
|
guint start_glyph; /* the first glyph in nodes glyphstring that we render */
|
|
guint num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
|
|
};
|
|
|
|
struct _GskVulkanOpPushConstants
|
|
{
|
|
GskVulkanOpType type;
|
|
GskRenderNode *node; /* node that's the source of this op */
|
|
GskVulkanPushConstants constants; /* new constants to push */
|
|
};
|
|
|
|
union _GskVulkanOp
|
|
{
|
|
GskVulkanOpType type;
|
|
GskVulkanOpRender render;
|
|
GskVulkanOpText text;
|
|
GskVulkanOpPushConstants constants;
|
|
};
|
|
|
|
struct _GskVulkanRenderPass
|
|
{
|
|
GdkVulkanContext *vulkan;
|
|
|
|
GArray *render_ops;
|
|
|
|
GskVulkanImage *target;
|
|
int scale_factor;
|
|
graphene_rect_t viewport;
|
|
cairo_region_t *clip;
|
|
graphene_matrix_t mv;
|
|
graphene_matrix_t p;
|
|
|
|
VkRenderPass render_pass;
|
|
VkSemaphore signal_semaphore;
|
|
GArray *wait_semaphores;
|
|
GskVulkanBuffer *vertex_data;
|
|
|
|
GQuark fallback_pixels;
|
|
GQuark texture_pixels;
|
|
};
|
|
|
|
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)
|
|
{
|
|
GskVulkanRenderPass *self;
|
|
VkImageLayout final_layout;
|
|
|
|
self = g_slice_new0 (GskVulkanRenderPass);
|
|
self->vulkan = g_object_ref (context);
|
|
self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
|
|
|
|
self->target = g_object_ref (target);
|
|
self->scale_factor = scale_factor;
|
|
self->clip = cairo_region_copy (clip);
|
|
self->viewport = *viewport;
|
|
|
|
self->mv = *mv;
|
|
graphene_matrix_init_ortho (&self->p,
|
|
viewport->origin.x, viewport->origin.x + viewport->size.width,
|
|
viewport->origin.y, viewport->origin.y + viewport->size.height,
|
|
ORTHO_NEAR_PLANE,
|
|
ORTHO_FAR_PLANE);
|
|
|
|
if (signal_semaphore != VK_NULL_HANDLE) // this is a dependent pass
|
|
final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
else
|
|
final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
|
|
&(VkRenderPassCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.attachmentCount = 1,
|
|
.pAttachments = (VkAttachmentDescription[]) {
|
|
{
|
|
.format = gdk_vulkan_context_get_image_format (self->vulkan),
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.finalLayout = final_layout
|
|
}
|
|
},
|
|
.subpassCount = 1,
|
|
.pSubpasses = (VkSubpassDescription []) {
|
|
{
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.inputAttachmentCount = 0,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachments = (VkAttachmentReference []) {
|
|
{
|
|
.attachment = 0,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
}
|
|
},
|
|
.pResolveAttachments = (VkAttachmentReference []) {
|
|
{
|
|
.attachment = VK_ATTACHMENT_UNUSED,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
}
|
|
},
|
|
.pDepthStencilAttachment = NULL,
|
|
}
|
|
},
|
|
.dependencyCount = 0
|
|
},
|
|
NULL,
|
|
&self->render_pass);
|
|
|
|
self->signal_semaphore = signal_semaphore;
|
|
self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
|
|
self->vertex_data = NULL;
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
|
|
self->texture_pixels = g_quark_from_static_string ("texture-pixels");
|
|
#endif
|
|
|
|
return self;
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
|
|
{
|
|
g_array_unref (self->render_ops);
|
|
g_object_unref (self->vulkan);
|
|
g_object_unref (self->target);
|
|
cairo_region_destroy (self->clip);
|
|
vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
|
|
self->render_pass,
|
|
NULL);
|
|
if (self->vertex_data)
|
|
gsk_vulkan_buffer_free (self->vertex_data);
|
|
if (self->signal_semaphore != VK_NULL_HANDLE)
|
|
vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
|
|
self->signal_semaphore,
|
|
NULL);
|
|
g_array_unref (self->wait_semaphores);
|
|
|
|
|
|
g_slice_free (GskVulkanRenderPass, self);
|
|
}
|
|
|
|
static gboolean
|
|
font_has_color_glyphs (PangoFont *font)
|
|
{
|
|
cairo_scaled_font_t *scaled_font;
|
|
gboolean has_color = FALSE;
|
|
|
|
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
|
|
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
|
|
{
|
|
FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
|
|
has_color = (FT_HAS_COLOR (ft_face) != 0);
|
|
cairo_ft_scaled_font_unlock_face (scaled_font);
|
|
}
|
|
|
|
return has_color;
|
|
}
|
|
|
|
#define FALLBACK(...) G_STMT_START { \
|
|
GSK_NOTE (FALLBACK, g_print (__VA_ARGS__)); \
|
|
goto fallback; \
|
|
}G_STMT_END
|
|
|
|
static void
|
|
gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
const GskVulkanPushConstants *constants,
|
|
GskRenderNode *node)
|
|
{
|
|
GskVulkanOp op = {
|
|
.type = GSK_VULKAN_OP_FALLBACK,
|
|
.render.node = node
|
|
};
|
|
GskVulkanPipelineType pipeline_type;
|
|
|
|
switch (gsk_render_node_get_node_type (node))
|
|
{
|
|
case GSK_NOT_A_RENDER_NODE:
|
|
g_assert_not_reached ();
|
|
return;
|
|
case GSK_SHADOW_NODE:
|
|
default:
|
|
FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
|
|
|
|
case GSK_REPEAT_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Repeat nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_REPEAT;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_BLEND_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Blend nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_BLEND_MODE;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_CROSS_FADE_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_CROSS_FADE;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_INSET_SHADOW_NODE:
|
|
if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
|
|
FALLBACK ("Blur support not implemented for inset shadows\n");
|
|
else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Inset shadow nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_INSET_SHADOW;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_OUTSET_SHADOW_NODE:
|
|
if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
|
|
FALLBACK ("Blur support not implemented for outset shadows\n");
|
|
else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Outset shadow nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_OUTSET_SHADOW;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_CAIRO_NODE:
|
|
if (gsk_cairo_node_get_surface (node) == NULL)
|
|
return;
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_SURFACE;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_TEXT_NODE:
|
|
{
|
|
PangoFont *font = gsk_text_node_get_font (node);
|
|
PangoGlyphString *glyphs = gsk_text_node_get_glyphs (node);
|
|
int i;
|
|
guint count;
|
|
guint texture_index;
|
|
GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
|
|
|
|
if (font_has_color_glyphs (font))
|
|
{
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_COLOR_TEXT;
|
|
}
|
|
else
|
|
{
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_TEXT;
|
|
}
|
|
op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
|
|
op.text.start_glyph = 0;
|
|
op.text.texture_index = G_MAXUINT;
|
|
|
|
for (i = 0, count = 0; i < glyphs->num_glyphs; i++)
|
|
{
|
|
PangoGlyphInfo *gi = &glyphs->glyphs[i];
|
|
|
|
if (gi->glyph != PANGO_GLYPH_EMPTY && !(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
|
|
{
|
|
texture_index = gsk_vulkan_renderer_cache_glyph (renderer, font, gi->glyph);
|
|
if (op.text.texture_index == G_MAXUINT)
|
|
op.text.texture_index = texture_index;
|
|
if (texture_index != op.text.texture_index)
|
|
{
|
|
op.text.num_glyphs = count;
|
|
|
|
g_array_append_val (self->render_ops, op);
|
|
|
|
count = 1;
|
|
op.text.start_glyph = i;
|
|
op.text.texture_index = texture_index;
|
|
}
|
|
else
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (op.text.texture_index != G_MAXUINT && count != 0)
|
|
{
|
|
op.text.num_glyphs = count;
|
|
g_array_append_val (self->render_ops, op);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
case GSK_TEXTURE_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Texture nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_TEXTURE;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_COLOR_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_COLOR;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_LINEAR_GRADIENT_NODE:
|
|
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
|
if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
|
|
FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u\n",
|
|
gsk_linear_gradient_node_get_n_color_stops (node),
|
|
GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Linear gradient nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_LINEAR_GRADIENT;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_OPACITY_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Opacity nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_OPACITY;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_BLUR_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BLUR;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Blur nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_BLUR;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_COLOR_MATRIX_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Color matrix nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_COLOR_MATRIX;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_BORDER_NODE:
|
|
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
|
|
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
|
|
pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
|
|
else
|
|
FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_BORDER;
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
|
g_array_append_val (self->render_ops, op);
|
|
return;
|
|
|
|
case GSK_CONTAINER_NODE:
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
|
|
{
|
|
gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
|
|
}
|
|
}
|
|
return;
|
|
|
|
case GSK_TRANSFORM_NODE:
|
|
{
|
|
graphene_matrix_t transform;
|
|
graphene_matrix_t mv;
|
|
GskRenderNode *child;
|
|
|
|
#if 0
|
|
if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
|
|
FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
|
|
#endif
|
|
|
|
gsk_transform_node_get_transform (node, &transform);
|
|
mv = self->mv;
|
|
graphene_matrix_multiply (&transform, &mv, &self->mv);
|
|
child = gsk_transform_node_get_child (node);
|
|
if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, &transform, &child->bounds))
|
|
FALLBACK ("Transform nodes can't deal with clip type %u\n", constants->clip.type);
|
|
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
|
|
g_array_append_val (self->render_ops, op);
|
|
|
|
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
|
|
gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
|
|
self->mv = mv;
|
|
g_array_append_val (self->render_ops, op);
|
|
}
|
|
return;
|
|
|
|
case GSK_CLIP_NODE:
|
|
{
|
|
if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_peek_clip (node)))
|
|
FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", constants->clip.type);
|
|
if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
|
|
return;
|
|
|
|
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
|
|
g_array_append_val (self->render_ops, op);
|
|
|
|
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
|
|
|
|
gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
|
|
g_array_append_val (self->render_ops, op);
|
|
}
|
|
return;
|
|
|
|
case GSK_ROUNDED_CLIP_NODE:
|
|
{
|
|
if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
|
|
constants,
|
|
gsk_rounded_clip_node_peek_clip (node)))
|
|
FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", constants->clip.type);
|
|
if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
|
|
return;
|
|
|
|
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
|
|
g_array_append_val (self->render_ops, op);
|
|
|
|
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
|
|
|
|
gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
|
|
g_array_append_val (self->render_ops, op);
|
|
}
|
|
return;
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
return;
|
|
|
|
fallback:
|
|
switch (constants->clip.type)
|
|
{
|
|
case GSK_VULKAN_CLIP_NONE:
|
|
op.type = GSK_VULKAN_OP_FALLBACK;
|
|
break;
|
|
case GSK_VULKAN_CLIP_RECT:
|
|
op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
|
|
gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
|
|
break;
|
|
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
|
|
case GSK_VULKAN_CLIP_ROUNDED:
|
|
op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
|
|
gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
|
|
break;
|
|
case GSK_VULKAN_CLIP_ALL_CLIPPED:
|
|
default:
|
|
g_assert_not_reached ();
|
|
return;
|
|
}
|
|
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
|
|
g_array_append_val (self->render_ops, op);
|
|
}
|
|
#undef FALLBACK
|
|
|
|
void
|
|
gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
GskRenderNode *node)
|
|
{
|
|
GskVulkanOp op = { 0, };
|
|
graphene_matrix_t mvp;
|
|
|
|
graphene_matrix_multiply (&self->mv, &self->p, &mvp);
|
|
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
|
|
gsk_vulkan_push_constants_init (&op.constants.constants, &mvp, &self->viewport);
|
|
g_array_append_val (self->render_ops, op);
|
|
|
|
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
|
|
}
|
|
|
|
static GskVulkanImage *
|
|
gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
GskVulkanUploader *uploader,
|
|
GskRenderNode *node,
|
|
graphene_rect_t *bounds,
|
|
GskVulkanClip *current_clip,
|
|
graphene_rect_t *tex_rect)
|
|
{
|
|
GskVulkanImage *result;
|
|
cairo_surface_t *surface;
|
|
cairo_t *cr;
|
|
|
|
switch (gsk_render_node_get_node_type (node))
|
|
{
|
|
case GSK_TEXTURE_NODE:
|
|
if (graphene_rect_equal (bounds, &node->bounds))
|
|
{
|
|
result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
|
gsk_texture_node_get_texture (node),
|
|
uploader);
|
|
gsk_vulkan_render_add_cleanup_image (render, result);
|
|
*tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
|
|
return result;
|
|
}
|
|
break;
|
|
|
|
case GSK_CAIRO_NODE:
|
|
if (graphene_rect_equal (bounds, &node->bounds))
|
|
{
|
|
surface = cairo_surface_reference (gsk_cairo_node_get_surface (node));
|
|
goto got_surface;
|
|
}
|
|
break;
|
|
|
|
default: ;
|
|
{
|
|
VkSemaphore semaphore;
|
|
graphene_rect_t view;
|
|
cairo_region_t *clip;
|
|
GskVulkanRenderPass *pass;
|
|
graphene_rect_t clipped;
|
|
|
|
if (current_clip)
|
|
graphene_rect_intersection (¤t_clip->rect.bounds, bounds, &clipped);
|
|
else
|
|
clipped = *bounds;
|
|
|
|
if (clipped.size.width == 0 || clipped.size.height == 0)
|
|
return NULL;
|
|
|
|
graphene_matrix_transform_bounds (&self->mv, &clipped, &view);
|
|
view.origin.x = floor (view.origin.x);
|
|
view.origin.y = floor (view.origin.y);
|
|
view.size.width = ceil (view.size.width);
|
|
view.size.height = ceil (view.size.height);
|
|
|
|
result = gsk_vulkan_image_new_for_texture (self->vulkan,
|
|
view.size.width,
|
|
view.size.height);
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
{
|
|
GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
|
|
gsk_profiler_counter_add (profiler,
|
|
self->texture_pixels,
|
|
view.size.width * view.size.height);
|
|
}
|
|
#endif
|
|
|
|
vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
|
|
&(VkSemaphoreCreateInfo) {
|
|
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
NULL,
|
|
0
|
|
},
|
|
NULL,
|
|
&semaphore);
|
|
|
|
g_array_append_val (self->wait_semaphores, semaphore);
|
|
|
|
clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
|
|
0, 0,
|
|
gsk_vulkan_image_get_width (result),
|
|
gsk_vulkan_image_get_height (result)
|
|
});
|
|
|
|
pass = gsk_vulkan_render_pass_new (self->vulkan,
|
|
result,
|
|
self->scale_factor,
|
|
&self->mv,
|
|
&view,
|
|
clip,
|
|
semaphore);
|
|
|
|
cairo_region_destroy (clip);
|
|
|
|
gsk_vulkan_render_add_render_pass (render, pass);
|
|
gsk_vulkan_render_pass_add (pass, render, node);
|
|
gsk_vulkan_render_add_cleanup_image (render, result);
|
|
|
|
/* assuming the unclipped bounds should go to texture coordinates 0..1,
|
|
* calculate the coordinates for the clipped texture size
|
|
*/
|
|
tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
|
|
tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
|
|
tex_rect->size.width = bounds->size.width/clipped.size.width;
|
|
tex_rect->size.height = bounds->size.height/clipped.size.height;
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
GSK_NOTE (FALLBACK, g_print ("Node as texture not implemented for this case. Using %gx%g fallback surface\n",
|
|
ceil (bounds->size.width),
|
|
ceil (bounds->size.height)));
|
|
#ifdef G_ENABLE_DEBUG
|
|
{
|
|
GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
|
|
gsk_profiler_counter_add (profiler,
|
|
self->fallback_pixels,
|
|
ceil (bounds->size.width) * ceil (bounds->size.height));
|
|
}
|
|
#endif
|
|
|
|
/* XXX: We could intersect bounds with clip bounds here */
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
ceil (bounds->size.width),
|
|
ceil (bounds->size.height));
|
|
cr = cairo_create (surface);
|
|
cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
|
|
|
|
gsk_render_node_draw (node, cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
got_surface:
|
|
result = gsk_vulkan_image_new_from_data (uploader,
|
|
cairo_image_surface_get_data (surface),
|
|
cairo_image_surface_get_width (surface),
|
|
cairo_image_surface_get_height (surface),
|
|
cairo_image_surface_get_stride (surface));
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
gsk_vulkan_render_add_cleanup_image (render, result);
|
|
|
|
*tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
|
|
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
|
|
GskVulkanOpRender *op,
|
|
GskVulkanRender *render,
|
|
GskVulkanUploader *uploader)
|
|
{
|
|
GskRenderNode *node;
|
|
cairo_surface_t *surface;
|
|
cairo_t *cr;
|
|
|
|
node = op->node;
|
|
|
|
GSK_NOTE (FALLBACK,
|
|
g_print ("Upload op=%s, node %s[%p], bounds %gx%g\n",
|
|
op->type == GSK_VULKAN_OP_FALLBACK_CLIP ? "fallback-clip" :
|
|
(op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP ? "fallback-rounded-clip" : "fallback"),
|
|
node->name ? node->name : node->node_class->type_name, node,
|
|
ceil (node->bounds.size.width),
|
|
ceil (node->bounds.size.height)));
|
|
#ifdef G_ENABLE_DEBUG
|
|
{
|
|
GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
|
|
gsk_profiler_counter_add (profiler,
|
|
self->fallback_pixels,
|
|
ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
|
|
}
|
|
#endif
|
|
|
|
/* XXX: We could intersect bounds with clip bounds here */
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
ceil (node->bounds.size.width),
|
|
ceil (node->bounds.size.height));
|
|
cr = cairo_create (surface);
|
|
cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
|
|
|
|
if (op->type == GSK_VULKAN_OP_FALLBACK_CLIP)
|
|
{
|
|
cairo_rectangle (cr,
|
|
op->clip.bounds.origin.x, op->clip.bounds.origin.y,
|
|
op->clip.bounds.size.width, op->clip.bounds.size.height);
|
|
cairo_clip (cr);
|
|
}
|
|
else if (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP)
|
|
{
|
|
gsk_rounded_rect_path (&op->clip, cr);
|
|
cairo_clip (cr);
|
|
}
|
|
else
|
|
{
|
|
g_assert (op->type == GSK_VULKAN_OP_FALLBACK);
|
|
}
|
|
|
|
gsk_render_node_draw (node, cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
op->source = gsk_vulkan_image_new_from_data (uploader,
|
|
cairo_image_surface_get_data (surface),
|
|
cairo_image_surface_get_width (surface),
|
|
cairo_image_surface_get_height (surface),
|
|
cairo_image_surface_get_stride (surface));
|
|
|
|
op->source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
gsk_vulkan_render_add_cleanup_image (render, op->source);
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
GskVulkanUploader *uploader)
|
|
{
|
|
GskVulkanOp *op;
|
|
guint i;
|
|
const GskVulkanClip *clip = NULL;
|
|
|
|
for (i = 0; i < self->render_ops->len; i++)
|
|
{
|
|
op = &g_array_index (self->render_ops, GskVulkanOp, i);
|
|
|
|
switch (op->type)
|
|
{
|
|
case GSK_VULKAN_OP_FALLBACK:
|
|
case GSK_VULKAN_OP_FALLBACK_CLIP:
|
|
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
|
|
gsk_vulkan_render_pass_upload_fallback (self, &op->render, render, uploader);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_SURFACE:
|
|
{
|
|
cairo_surface_t *surface;
|
|
|
|
surface = gsk_cairo_node_get_surface (op->render.node);
|
|
op->render.source = gsk_vulkan_image_new_from_data (uploader,
|
|
cairo_image_surface_get_data (surface),
|
|
cairo_image_surface_get_width (surface),
|
|
cairo_image_surface_get_height (surface),
|
|
cairo_image_surface_get_stride (surface));
|
|
op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
|
|
|
|
gsk_vulkan_render_add_cleanup_image (render, op->render.source);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_TEXT:
|
|
case GSK_VULKAN_OP_COLOR_TEXT:
|
|
{
|
|
op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
|
uploader,
|
|
op->text.texture_index);
|
|
gsk_vulkan_render_add_cleanup_image (render, op->text.source);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_TEXTURE:
|
|
{
|
|
op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
|
gsk_texture_node_get_texture (op->render.node),
|
|
uploader);
|
|
op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
|
|
gsk_vulkan_render_add_cleanup_image (render, op->render.source);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_OPACITY:
|
|
{
|
|
GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
|
|
|
|
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
child,
|
|
&child->bounds,
|
|
clip,
|
|
&op->render.source_rect);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_REPEAT:
|
|
{
|
|
GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
|
|
const graphene_rect_t *bounds = gsk_repeat_node_peek_child_bounds (op->render.node);
|
|
|
|
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
child,
|
|
bounds,
|
|
NULL,
|
|
&op->render.source_rect);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLUR:
|
|
{
|
|
GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
|
|
|
|
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
child,
|
|
&child->bounds,
|
|
clip,
|
|
&op->render.source_rect);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR_MATRIX:
|
|
{
|
|
GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
|
|
|
|
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
child,
|
|
&child->bounds,
|
|
clip,
|
|
&op->render.source_rect);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_CROSS_FADE:
|
|
{
|
|
GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
|
|
GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
|
|
|
|
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
start,
|
|
&start->bounds,
|
|
clip,
|
|
&op->render.source_rect);
|
|
op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
end,
|
|
&end->bounds,
|
|
clip,
|
|
&op->render.source2_rect);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLEND_MODE:
|
|
{
|
|
GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
|
|
GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
|
|
|
|
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
top,
|
|
&top->bounds,
|
|
clip,
|
|
&op->render.source_rect);
|
|
op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
|
|
render,
|
|
uploader,
|
|
bottom,
|
|
&bottom->bounds,
|
|
clip,
|
|
&op->render.source2_rect);
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
|
clip = &op->constants.constants.clip;
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
case GSK_VULKAN_OP_COLOR:
|
|
case GSK_VULKAN_OP_LINEAR_GRADIENT:
|
|
case GSK_VULKAN_OP_BORDER:
|
|
case GSK_VULKAN_OP_INSET_SHADOW:
|
|
case GSK_VULKAN_OP_OUTSET_SHADOW:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static gsize
|
|
gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
|
|
{
|
|
GskVulkanOp *op;
|
|
gsize n_bytes;
|
|
guint i;
|
|
|
|
n_bytes = 0;
|
|
for (i = 0; i < self->render_ops->len; i++)
|
|
{
|
|
op = &g_array_index (self->render_ops, GskVulkanOp, i);
|
|
|
|
switch (op->type)
|
|
{
|
|
case GSK_VULKAN_OP_FALLBACK:
|
|
case GSK_VULKAN_OP_FALLBACK_CLIP:
|
|
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
|
|
case GSK_VULKAN_OP_SURFACE:
|
|
case GSK_VULKAN_OP_TEXTURE:
|
|
case GSK_VULKAN_OP_REPEAT:
|
|
op->render.vertex_count = gsk_vulkan_texture_pipeline_count_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_TEXT:
|
|
op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
|
|
op->text.num_glyphs);
|
|
n_bytes += op->text.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR_TEXT:
|
|
op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
|
|
op->text.num_glyphs);
|
|
n_bytes += op->text.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR:
|
|
op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_LINEAR_GRADIENT:
|
|
op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_OPACITY:
|
|
case GSK_VULKAN_OP_COLOR_MATRIX:
|
|
op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLUR:
|
|
op->render.vertex_count = gsk_vulkan_blur_pipeline_count_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BORDER:
|
|
op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_INSET_SHADOW:
|
|
case GSK_VULKAN_OP_OUTSET_SHADOW:
|
|
op->render.vertex_count = gsk_vulkan_box_shadow_pipeline_count_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_CROSS_FADE:
|
|
op->render.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLEND_MODE:
|
|
op->render.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline));
|
|
n_bytes += op->render.vertex_count;
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
|
|
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return n_bytes;
|
|
}
|
|
|
|
static gsize
|
|
gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
guchar *data,
|
|
gsize offset,
|
|
gsize total)
|
|
{
|
|
GskVulkanOp *op;
|
|
gsize n_bytes;
|
|
guint i;
|
|
|
|
n_bytes = 0;
|
|
for (i = 0; i < self->render_ops->len; i++)
|
|
{
|
|
op = &g_array_index (self->render_ops, GskVulkanOp, i);
|
|
|
|
switch (op->type)
|
|
{
|
|
case GSK_VULKAN_OP_FALLBACK:
|
|
case GSK_VULKAN_OP_FALLBACK_CLIP:
|
|
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
|
|
case GSK_VULKAN_OP_SURFACE:
|
|
case GSK_VULKAN_OP_TEXTURE:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect);
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_REPEAT:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect);
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_TEXT:
|
|
{
|
|
op->text.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
|
|
data + n_bytes + offset,
|
|
GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
|
&op->text.node->bounds,
|
|
gsk_text_node_get_font (op->text.node),
|
|
gsk_text_node_get_glyphs (op->text.node),
|
|
gsk_text_node_get_color (op->text.node),
|
|
gsk_text_node_get_x (op->text.node),
|
|
gsk_text_node_get_y (op->text.node),
|
|
op->text.start_glyph,
|
|
op->text.num_glyphs);
|
|
n_bytes += op->text.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR_TEXT:
|
|
{
|
|
op->text.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
|
|
data + n_bytes + offset,
|
|
GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
|
&op->text.node->bounds,
|
|
gsk_text_node_get_font (op->text.node),
|
|
gsk_text_node_get_glyphs (op->text.node),
|
|
gsk_text_node_get_x (op->text.node),
|
|
gsk_text_node_get_y (op->text.node),
|
|
op->text.start_glyph,
|
|
op->text.num_glyphs);
|
|
n_bytes += op->text.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_color_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
gsk_color_node_peek_color (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_LINEAR_GRADIENT:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
gsk_linear_gradient_node_peek_start (op->render.node),
|
|
gsk_linear_gradient_node_peek_end (op->render.node),
|
|
gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
|
|
gsk_linear_gradient_node_get_n_color_stops (op->render.node),
|
|
gsk_linear_gradient_node_peek_color_stops (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_OPACITY:
|
|
{
|
|
graphene_matrix_t color_matrix;
|
|
graphene_vec4_t color_offset;
|
|
|
|
graphene_matrix_init_from_float (&color_matrix,
|
|
(float[16]) {
|
|
1.0, 0.0, 0.0, 0.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
0.0, 0.0, 0.0, gsk_opacity_node_get_opacity (op->render.node)
|
|
});
|
|
graphene_vec4_init (&color_offset, 0.0, 0.0, 0.0, 0.0);
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
|
|
gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect,
|
|
&color_matrix,
|
|
&color_offset);
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLUR:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_blur_pipeline_collect_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect,
|
|
gsk_blur_node_get_radius (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR_MATRIX:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect,
|
|
gsk_color_matrix_node_peek_color_matrix (op->render.node),
|
|
gsk_color_matrix_node_peek_color_offset (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BORDER:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
gsk_border_node_peek_outline (op->render.node),
|
|
gsk_border_node_peek_widths (op->render.node),
|
|
gsk_border_node_peek_colors (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_INSET_SHADOW:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
gsk_inset_shadow_node_peek_outline (op->render.node),
|
|
gsk_inset_shadow_node_peek_color (op->render.node),
|
|
gsk_inset_shadow_node_get_dx (op->render.node),
|
|
gsk_inset_shadow_node_get_dy (op->render.node),
|
|
gsk_inset_shadow_node_get_spread (op->render.node),
|
|
gsk_inset_shadow_node_get_blur_radius (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_OUTSET_SHADOW:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
gsk_outset_shadow_node_peek_outline (op->render.node),
|
|
gsk_outset_shadow_node_peek_color (op->render.node),
|
|
gsk_outset_shadow_node_get_dx (op->render.node),
|
|
gsk_outset_shadow_node_get_dy (op->render.node),
|
|
gsk_outset_shadow_node_get_spread (op->render.node),
|
|
gsk_outset_shadow_node_get_blur_radius (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_CROSS_FADE:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect,
|
|
&op->render.source2_rect,
|
|
gsk_cross_fade_node_get_progress (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLEND_MODE:
|
|
{
|
|
op->render.vertex_offset = offset + n_bytes;
|
|
gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline),
|
|
data + n_bytes + offset,
|
|
&op->render.node->bounds,
|
|
&op->render.source_rect,
|
|
&op->render.source2_rect,
|
|
gsk_blend_node_get_blend_mode (op->render.node));
|
|
n_bytes += op->render.vertex_count;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
|
continue;
|
|
}
|
|
|
|
g_assert (n_bytes + offset <= total);
|
|
}
|
|
|
|
return n_bytes;
|
|
}
|
|
|
|
static GskVulkanBuffer *
|
|
gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render)
|
|
{
|
|
if (self->vertex_data == NULL)
|
|
{
|
|
gsize n_bytes;
|
|
guchar *data;
|
|
|
|
n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
|
|
self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
|
|
data = gsk_vulkan_buffer_map (self->vertex_data);
|
|
gsk_vulkan_render_pass_collect_vertex_data (self, render, data, 0, n_bytes);
|
|
gsk_vulkan_buffer_unmap (self->vertex_data);
|
|
}
|
|
|
|
return self->vertex_data;
|
|
}
|
|
|
|
gsize
|
|
gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass *self,
|
|
VkSemaphore **semaphores)
|
|
{
|
|
*semaphores = (VkSemaphore *)self->wait_semaphores->data;
|
|
return self->wait_semaphores->len;
|
|
}
|
|
|
|
gsize
|
|
gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass *self,
|
|
VkSemaphore **semaphores)
|
|
{
|
|
*semaphores = (VkSemaphore *)&self->signal_semaphore;
|
|
return self->signal_semaphore != VK_NULL_HANDLE ? 1 : 0;
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render)
|
|
{
|
|
GskVulkanOp *op;
|
|
guint i;
|
|
|
|
for (i = 0; i < self->render_ops->len; i++)
|
|
{
|
|
op = &g_array_index (self->render_ops, GskVulkanOp, i);
|
|
|
|
switch (op->type)
|
|
{
|
|
case GSK_VULKAN_OP_FALLBACK:
|
|
case GSK_VULKAN_OP_FALLBACK_CLIP:
|
|
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
|
|
case GSK_VULKAN_OP_SURFACE:
|
|
case GSK_VULKAN_OP_TEXTURE:
|
|
case GSK_VULKAN_OP_OPACITY:
|
|
case GSK_VULKAN_OP_BLUR:
|
|
case GSK_VULKAN_OP_COLOR_MATRIX:
|
|
if (op->render.source)
|
|
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_REPEAT:
|
|
if (op->render.source)
|
|
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_TEXT:
|
|
case GSK_VULKAN_OP_COLOR_TEXT:
|
|
op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_CROSS_FADE:
|
|
case GSK_VULKAN_OP_BLEND_MODE:
|
|
if (op->render.source && op->render.source2)
|
|
{
|
|
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
|
|
op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
|
|
case GSK_VULKAN_OP_COLOR:
|
|
case GSK_VULKAN_OP_LINEAR_GRADIENT:
|
|
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
|
case GSK_VULKAN_OP_BORDER:
|
|
case GSK_VULKAN_OP_INSET_SHADOW:
|
|
case GSK_VULKAN_OP_OUTSET_SHADOW:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
guint layout_count,
|
|
VkPipelineLayout *pipeline_layout,
|
|
VkCommandBuffer command_buffer)
|
|
{
|
|
GskVulkanPipeline *current_pipeline = NULL;
|
|
gsize current_draw_index = 0;
|
|
GskVulkanOp *op;
|
|
guint i, step;
|
|
GskVulkanBuffer *vertex_buffer;
|
|
|
|
vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
|
|
|
|
for (i = 0; i < self->render_ops->len; i += step)
|
|
{
|
|
op = &g_array_index (self->render_ops, GskVulkanOp, i);
|
|
step = 1;
|
|
|
|
switch (op->type)
|
|
{
|
|
case GSK_VULKAN_OP_FALLBACK:
|
|
case GSK_VULKAN_OP_FALLBACK_CLIP:
|
|
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
|
|
case GSK_VULKAN_OP_SURFACE:
|
|
case GSK_VULKAN_OP_TEXTURE:
|
|
case GSK_VULKAN_OP_REPEAT:
|
|
if (!op->render.source)
|
|
continue;
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
1,
|
|
(VkDescriptorSet[1]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_texture_pipeline_draw (GSK_VULKAN_TEXTURE_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_TEXT:
|
|
if (current_pipeline != op->text.pipeline)
|
|
{
|
|
current_pipeline = op->text.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->text.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
1,
|
|
(VkDescriptorSet[1]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, op->text.num_glyphs);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR_TEXT:
|
|
if (current_pipeline != op->text.pipeline)
|
|
{
|
|
current_pipeline = op->text.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->text.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
1,
|
|
(VkDescriptorSet[1]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, op->text.num_glyphs);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_OPACITY:
|
|
case GSK_VULKAN_OP_COLOR_MATRIX:
|
|
if (!op->render.source)
|
|
continue;
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
1,
|
|
(VkDescriptorSet[1]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLUR:
|
|
if (!op->render.source)
|
|
continue;
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
1,
|
|
(VkDescriptorSet[1]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_blur_pipeline_draw (GSK_VULKAN_BLUR_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_COLOR:
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
for (step = 1; step + i < self->render_ops->len; step++)
|
|
{
|
|
GskVulkanOp *cmp = &g_array_index (self->render_ops, GskVulkanOp, i + step);
|
|
if (cmp->type != GSK_VULKAN_OP_COLOR ||
|
|
cmp->render.pipeline != current_pipeline)
|
|
break;
|
|
}
|
|
current_draw_index += gsk_vulkan_color_pipeline_draw (GSK_VULKAN_COLOR_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, step);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_LINEAR_GRADIENT:
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BORDER:
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_INSET_SHADOW:
|
|
case GSK_VULKAN_OP_OUTSET_SHADOW:
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
current_draw_index += gsk_vulkan_box_shadow_pipeline_draw (GSK_VULKAN_BOX_SHADOW_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
|
for (int i = 0; i < layout_count; i++)
|
|
gsk_vulkan_push_constants_push (&op->constants.constants,
|
|
command_buffer,
|
|
pipeline_layout[i]);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_CROSS_FADE:
|
|
if (!op->render.source || !op->render.source2)
|
|
continue;
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
2,
|
|
(VkDescriptorSet[2]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
case GSK_VULKAN_OP_BLEND_MODE:
|
|
if (!op->render.source || !op->render.source2)
|
|
continue;
|
|
if (current_pipeline != op->render.pipeline)
|
|
{
|
|
current_pipeline = op->render.pipeline;
|
|
vkCmdBindPipeline (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
|
vkCmdBindVertexBuffers (command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
|
},
|
|
(VkDeviceSize[1]) { op->render.vertex_offset });
|
|
current_draw_index = 0;
|
|
}
|
|
|
|
vkCmdBindDescriptorSets (command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
|
0,
|
|
2,
|
|
(VkDescriptorSet[2]) {
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
|
|
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
|
|
},
|
|
0,
|
|
NULL);
|
|
|
|
current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline),
|
|
command_buffer,
|
|
current_draw_index, 1);
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
|
|
GskVulkanRender *render,
|
|
guint layout_count,
|
|
VkPipelineLayout *pipeline_layout,
|
|
VkCommandBuffer command_buffer)
|
|
{
|
|
guint i;
|
|
|
|
vkCmdSetViewport (command_buffer,
|
|
0,
|
|
1,
|
|
&(VkViewport) {
|
|
.x = 0,
|
|
.y = 0,
|
|
.width = self->viewport.size.width,
|
|
.height = self->viewport.size.height,
|
|
.minDepth = 0,
|
|
.maxDepth = 1
|
|
});
|
|
|
|
for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
|
|
{
|
|
cairo_rectangle_int_t rect;
|
|
|
|
cairo_region_get_rectangle (self->clip, i, &rect);
|
|
|
|
vkCmdSetScissor (command_buffer,
|
|
0,
|
|
1,
|
|
&(VkRect2D) {
|
|
{ rect.x * self->scale_factor, rect.y * self->scale_factor },
|
|
{ rect.width * self->scale_factor, rect.height * self->scale_factor }
|
|
});
|
|
|
|
vkCmdBeginRenderPass (command_buffer,
|
|
&(VkRenderPassBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
.renderPass = self->render_pass,
|
|
.framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
|
|
.renderArea = {
|
|
{ rect.x * self->scale_factor, rect.y * self->scale_factor },
|
|
{ rect.width * self->scale_factor, rect.height * self->scale_factor }
|
|
},
|
|
.clearValueCount = 1,
|
|
.pClearValues = (VkClearValue [1]) {
|
|
{ .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
|
|
}
|
|
},
|
|
VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
gsk_vulkan_render_pass_draw_rect (self, render, layout_count, pipeline_layout, command_buffer);
|
|
|
|
vkCmdEndRenderPass (command_buffer);
|
|
}
|
|
}
|