From 91741f6b634cc1317beefa062ab7b5547735fc87 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 30 Dec 2016 06:46:34 +0100 Subject: vulkan: Handle opacity nodes Well, "handle" them actually. We still draw the node's child using Cairo, but we apply the opacity manually now. --- gsk/Makefile.am | 4 +- gsk/gskvulkaneffectpipeline.c | 129 +++++++++++++++++++++ gsk/gskvulkaneffectpipelineprivate.h | 32 +++++ gsk/gskvulkanrender.c | 6 +- gsk/gskvulkanrenderpass.c | 120 +++++++++++++++++++ gsk/gskvulkanrenderprivate.h | 3 + .../vulkan/opacity-clip-rounded.frag.glsl | 64 ++++++++++ gsk/resources/vulkan/opacity-clip-rounded.frag.spv | Bin 0 -> 5584 bytes .../vulkan/opacity-clip-rounded.vert.glsl | 56 +++++++++ gsk/resources/vulkan/opacity-clip-rounded.vert.spv | Bin 0 -> 5124 bytes gsk/resources/vulkan/opacity-clip.frag.glsl | 19 +++ gsk/resources/vulkan/opacity-clip.frag.spv | Bin 0 -> 1068 bytes gsk/resources/vulkan/opacity-clip.vert.glsl | 49 ++++++++ gsk/resources/vulkan/opacity-clip.vert.spv | Bin 0 -> 4788 bytes gsk/resources/vulkan/opacity.frag.glsl | 19 +++ gsk/resources/vulkan/opacity.frag.spv | Bin 0 -> 1068 bytes gsk/resources/vulkan/opacity.vert.glsl | 34 ++++++ gsk/resources/vulkan/opacity.vert.spv | Bin 0 -> 2148 bytes 18 files changed, 533 insertions(+), 2 deletions(-) create mode 100644 gsk/gskvulkaneffectpipeline.c create mode 100644 gsk/gskvulkaneffectpipelineprivate.h create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.frag.glsl create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.frag.spv create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.vert.glsl create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.vert.spv create mode 100644 gsk/resources/vulkan/opacity-clip.frag.glsl create mode 100644 gsk/resources/vulkan/opacity-clip.frag.spv create mode 100644 gsk/resources/vulkan/opacity-clip.vert.glsl create mode 100644 gsk/resources/vulkan/opacity-clip.vert.spv create mode 100644 gsk/resources/vulkan/opacity.frag.glsl create mode 100644 gsk/resources/vulkan/opacity.frag.spv create mode 100644 gsk/resources/vulkan/opacity.vert.glsl create mode 100644 gsk/resources/vulkan/opacity.vert.spv diff --git a/gsk/Makefile.am b/gsk/Makefile.am index 922c727f6d..b92b60bdf9 100644 --- a/gsk/Makefile.am +++ b/gsk/Makefile.am @@ -29,8 +29,9 @@ gsk_private_vulkan_source_h = \ gskvulkanclipprivate.h \ gskvulkancolorpipelineprivate.h \ gskvulkancommandpoolprivate.h \ - gskvulkanlineargradientpipelineprivate.h \ + gskvulkaneffectpipelineprivate.h \ gskvulkanimageprivate.h \ + gskvulkanlineargradientpipelineprivate.h \ gskvulkanmemoryprivate.h \ gskvulkanpipelineprivate.h \ gskvulkanpushconstantsprivate.h \ @@ -44,6 +45,7 @@ gsk_private_vulkan_source_c = \ gskvulkanclip.c \ gskvulkancolorpipeline.c \ gskvulkancommandpool.c \ + gskvulkaneffectpipeline.c \ gskvulkanlineargradientpipeline.c \ gskvulkanimage.c \ gskvulkanmemory.c \ diff --git a/gsk/gskvulkaneffectpipeline.c b/gsk/gskvulkaneffectpipeline.c new file mode 100644 index 0000000000..249185c1cf --- /dev/null +++ b/gsk/gskvulkaneffectpipeline.c @@ -0,0 +1,129 @@ +#include "config.h" + +#include "gskvulkaneffectpipelineprivate.h" + +struct _GskVulkanEffectPipeline +{ + GObject parent_instance; +}; + +typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance; + +struct _GskVulkanEffectInstance +{ + float rect[4]; + float tex_rect[4]; + float value; +}; + +G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE) + +static const VkPipelineVertexInputStateCreateInfo * +gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self) +{ + static const VkVertexInputBindingDescription vertexBindingDescriptions[] = { + { + .binding = 0, + .stride = sizeof (GskVulkanEffectInstance), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, value), + } + }; + static const VkPipelineVertexInputStateCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions), + .pVertexBindingDescriptions = vertexBindingDescriptions, + .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription), + .pVertexAttributeDescriptions = vertexInputAttributeDescription + }; + + return &info; +} + +static void +gsk_vulkan_effect_pipeline_finalize (GObject *gobject) +{ + //GskVulkanEffectPipeline *self = GSK_VULKAN_EFFECT_PIPELINE (gobject); + + G_OBJECT_CLASS (gsk_vulkan_effect_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_effect_pipeline_class_init (GskVulkanEffectPipelineClass *klass) +{ + GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_effect_pipeline_finalize; + + pipeline_class->get_input_state_create_info = gsk_vulkan_effect_pipeline_get_input_state_create_info; +} + +static void +gsk_vulkan_effect_pipeline_init (GskVulkanEffectPipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_effect_pipeline_new (GskVulkanPipelineLayout *layout, + const char *shader_name, + VkRenderPass render_pass) +{ + return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, layout, shader_name, render_pass); +} + +gsize +gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline) +{ + return sizeof (GskVulkanEffectInstance); +} + +void +gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline, + guchar *data, + const graphene_rect_t *rect, + float value) +{ + GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data; + + instance->rect[0] = rect->origin.x; + instance->rect[1] = rect->origin.y; + instance->rect[2] = rect->size.width; + instance->rect[3] = rect->size.height; + instance->tex_rect[0] = 0.0; + instance->tex_rect[1] = 0.0; + instance->tex_rect[2] = 1.0; + instance->tex_rect[3] = 1.0; + instance->value = value; +} + +gsize +gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands) +{ + vkCmdDraw (command_buffer, + 6, n_commands, + 0, offset); + + return n_commands; +} diff --git a/gsk/gskvulkaneffectpipelineprivate.h b/gsk/gskvulkaneffectpipelineprivate.h new file mode 100644 index 0000000000..9a82c0242e --- /dev/null +++ b/gsk/gskvulkaneffectpipelineprivate.h @@ -0,0 +1,32 @@ +#ifndef __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ +#define __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ + +#include + +#include "gskvulkanpipelineprivate.h" + +G_BEGIN_DECLS + +typedef struct _GskVulkanEffectPipelineLayout GskVulkanEffectPipelineLayout; + +#define GSK_TYPE_VULKAN_EFFECT_PIPELINE (gsk_vulkan_effect_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK, VULKAN_EFFECT_PIPELINE, GskVulkanPipeline) + +GskVulkanPipeline * gsk_vulkan_effect_pipeline_new (GskVulkanPipelineLayout *layout, + const char *shader_name, + VkRenderPass render_pass); + +gsize gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline); +void gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline, + guchar *data, + const graphene_rect_t *rect, + float value); +gsize gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands); + +G_END_DECLS + +#endif /* __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ */ diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c index 80b9418373..81bc3193b5 100644 --- a/gsk/gskvulkanrender.c +++ b/gsk/gskvulkanrender.c @@ -10,6 +10,7 @@ #include "gskvulkanblendpipelineprivate.h" #include "gskvulkancolorpipelineprivate.h" +#include "gskvulkaneffectpipelineprivate.h" #include "gskvulkanlineargradientpipelineprivate.h" #define ORTHO_NEAR_PLANE -10000 @@ -319,7 +320,10 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self, { "color-clip-rounded", gsk_vulkan_color_pipeline_new }, { "linear", gsk_vulkan_linear_gradient_pipeline_new }, { "linear-clip", gsk_vulkan_linear_gradient_pipeline_new }, - { "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new } + { "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new }, + { "opacity", gsk_vulkan_effect_pipeline_new }, + { "opacity-clip", gsk_vulkan_effect_pipeline_new }, + { "opacity-clip-rounded", gsk_vulkan_effect_pipeline_new } }; g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index 38947ba6bc..70f1de35c5 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -9,6 +9,7 @@ #include "gskvulkanblendpipelineprivate.h" #include "gskvulkanclipprivate.h" #include "gskvulkancolorpipelineprivate.h" +#include "gskvulkaneffectpipelineprivate.h" #include "gskvulkanlineargradientpipelineprivate.h" #include "gskvulkanimageprivate.h" #include "gskvulkanpushconstantsprivate.h" @@ -27,6 +28,7 @@ typedef enum { GSK_VULKAN_OP_TEXTURE, GSK_VULKAN_OP_COLOR, GSK_VULKAN_OP_LINEAR_GRADIENT, + GSK_VULKAN_OP_OPACITY, /* GskVulkanOpPushConstants */ GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS } GskVulkanOpType; @@ -107,6 +109,12 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, case GSK_NOT_A_RENDER_NODE: g_assert_not_reached (); return; + case GSK_BORDER_NODE: + case GSK_INSET_SHADOW_NODE: + case GSK_OUTSET_SHADOW_NODE: + case GSK_SHADOW_NODE: + case GSK_BLEND_NODE: + case GSK_CROSS_FADE_NODE: default: FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name); @@ -161,6 +169,20 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, 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_OPACITY; + else if (constants->clip.type == GSK_VULKAN_CLIP_RECT) + pipeline_type = GSK_VULKAN_PIPELINE_OPACITY_CLIP; + else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR) + pipeline_type = GSK_VULKAN_PIPELINE_OPACITY_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_CONTAINER_NODE: { guint i; @@ -276,6 +298,41 @@ gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, 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, + const graphene_rect_t *bounds) +{ + GskVulkanImage *result; + cairo_surface_t *surface; + cairo_t *cr; + + /* 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); + + 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); + + return result; +} + static void gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self, GskVulkanOpRender *op, @@ -368,6 +425,18 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, } 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); + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: @@ -411,6 +480,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self) n_bytes += op->render.vertex_count; break; + case GSK_VULKAN_OP_OPACITY: + 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; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -478,6 +552,18 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_OPACITY: + { + 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, + gsk_opacity_node_get_opacity (op->render.node)); + n_bytes += op->render.vertex_count; + } + break; + + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -508,6 +594,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP: case GSK_VULKAN_OP_SURFACE: case GSK_VULKAN_OP_TEXTURE: + case GSK_VULKAN_OP_OPACITY: op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source); break; @@ -577,6 +664,39 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, current_draw_index, 1); break; + case GSK_VULKAN_OP_OPACITY: + 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_layout_get_pipeline_layout (layout), + 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_COLOR: if (current_pipeline != op->render.pipeline) { diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h index 72c4314492..6de38d2747 100644 --- a/gsk/gskvulkanrenderprivate.h +++ b/gsk/gskvulkanrenderprivate.h @@ -17,6 +17,9 @@ typedef enum { GSK_VULKAN_PIPELINE_LINEAR_GRADIENT, GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP, GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED, + GSK_VULKAN_PIPELINE_OPACITY, + GSK_VULKAN_PIPELINE_OPACITY_CLIP, + GSK_VULKAN_PIPELINE_OPACITY_CLIP_ROUNDED, /* add more */ GSK_VULKAN_N_PIPELINES } GskVulkanPipelineType; diff --git a/gsk/resources/vulkan/opacity-clip-rounded.frag.glsl b/gsk/resources/vulkan/opacity-clip-rounded.frag.glsl new file mode 100644 index 0000000000..91c1e54437 --- /dev/null +++ b/gsk/resources/vulkan/opacity-clip-rounded.frag.glsl @@ -0,0 +1,64 @@ +#version 420 core + +struct RoundedRect { + vec4 bounds; + vec4 corners; +}; + +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec2 inTexCoord; +layout(location = 2) in flat float inOpacity; +layout(location = 3) in flat vec4 inClipBounds; +layout(location = 4) in flat vec4 inClipWidths; + +layout(set = 0, binding = 0) uniform sampler2D inTexture; + +layout(location = 0) out vec4 color; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +float clip(vec2 pos, RoundedRect r) { + vec2 ref_tl = r.bounds.xy + vec2( r.corners.x, r.corners.x); + vec2 ref_tr = r.bounds.zy + vec2(-r.corners.y, r.corners.y); + vec2 ref_br = r.bounds.zw + vec2(-r.corners.z, -r.corners.z); + vec2 ref_bl = r.bounds.xw + vec2( r.corners.w, -r.corners.w); + + float d_tl = distance(pos, ref_tl); + float d_tr = distance(pos, ref_tr); + float d_br = distance(pos, ref_br); + float d_bl = distance(pos, ref_bl); + + float pixels_per_fragment = length(fwidth(pos.xy)); + float nudge = 0.5 * pixels_per_fragment; + vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - r.corners + nudge; + + bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y, + pos.x > ref_tr.x && pos.y < ref_tr.y, + pos.x > ref_br.x && pos.y > ref_br.y, + pos.x < ref_bl.x && pos.y > ref_bl.y); + + float distance_from_border = dot(vec4(is_out), + max(vec4(0.0, 0.0, 0.0, 0.0), distances)); + + // Move the distance back into pixels. + distance_from_border /= pixels_per_fragment; + // Apply a more gradual fade out to transparent. + //distance_from_border -= 0.5; + + return 1.0 - smoothstep(0.0, 1.0, distance_from_border); +} + +vec4 +opacity (vec4 color, float value) +{ + return color * value; +} + +void main() +{ + RoundedRect r = RoundedRect(vec4(inClipBounds.xy, inClipBounds.xy + inClipBounds.zw), inClipWidths); + + color = opacity (texture (inTexture, inTexCoord), inOpacity) * clip (inPos, r); +} diff --git a/gsk/resources/vulkan/opacity-clip-rounded.frag.spv b/gsk/resources/vulkan/opacity-clip-rounded.frag.spv new file mode 100644 index 0000000000..42fa156184 Binary files /dev/null and b/gsk/resources/vulkan/opacity-clip-rounded.frag.spv differ diff --git a/gsk/resources/vulkan/opacity-clip-rounded.vert.glsl b/gsk/resources/vulkan/opacity-clip-rounded.vert.glsl new file mode 100644 index 0000000000..5f0b898ef2 --- /dev/null +++ b/gsk/resources/vulkan/opacity-clip-rounded.vert.glsl @@ -0,0 +1,56 @@ +#version 420 core + +layout(location = 0) in vec4 inRect; +layout(location = 1) in vec4 inTexRect; +layout(location = 2) in float inOpacity; + +layout(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out vec2 outPos; +layout(location = 1) out vec2 outTexCoord; +layout(location = 2) out flat float outOpacity; +layout(location = 3) out flat vec4 outClipBounds; +layout(location = 4) out flat vec4 outClipWidths; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 offsets[6] = { vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0) }; + +vec4 intersect(vec4 a, vec4 b) +{ + a = vec4(a.xy, a.xy + a.zw); + b = vec4(b.xy, b.xy + b.zw); + vec4 result = vec4(max(a.xy, b.xy), min(a.zw, b.zw)); + if (any (greaterThanEqual (result.xy, result.zw))) + return vec4(0.0,0.0,0.0,0.0); + return vec4(result.xy, result.zw - result.xy); +} + +void main() { + vec4 rect = intersect(inRect, push.clip_bounds); + vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + + outPos = pos; + outClipBounds = push.clip_bounds; + outClipWidths = push.clip_widths; + + vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw, + rect.zw / inRect.zw); + texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy, + inTexRect.zw * texrect.zw); + outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex]; + outOpacity = inOpacity; +} diff --git a/gsk/resources/vulkan/opacity-clip-rounded.vert.spv b/gsk/resources/vulkan/opacity-clip-rounded.vert.spv new file mode 100644 index 0000000000..1090dabe9e Binary files /dev/null and b/gsk/resources/vulkan/opacity-clip-rounded.vert.spv differ diff --git a/gsk/resources/vulkan/opacity-clip.frag.glsl b/gsk/resources/vulkan/opacity-clip.frag.glsl new file mode 100644 index 0000000000..7ff7d347c7 --- /dev/null +++ b/gsk/resources/vulkan/opacity-clip.frag.glsl @@ -0,0 +1,19 @@ +#version 420 core + +layout(location = 0) in vec2 inTexCoord; +layout(location = 1) in flat float inOpacity; + +layout(set = 0, binding = 0) uniform sampler2D inTexture; + +layout(location = 0) out vec4 color; + +vec4 +opacity (vec4 color, float value) +{ + return color * value; +} + +void main() +{ + color = opacity (texture (inTexture, inTexCoord), inOpacity); +} diff --git a/gsk/resources/vulkan/opacity-clip.frag.spv b/gsk/resources/vulkan/opacity-clip.frag.spv new file mode 100644 index 0000000000..5729abe98c Binary files /dev/null and b/gsk/resources/vulkan/opacity-clip.frag.spv differ diff --git a/gsk/resources/vulkan/opacity-clip.vert.glsl b/gsk/resources/vulkan/opacity-clip.vert.glsl new file mode 100644 index 0000000000..4cf0f13b64 --- /dev/null +++ b/gsk/resources/vulkan/opacity-clip.vert.glsl @@ -0,0 +1,49 @@ +#version 420 core + +layout(location = 0) in vec4 inRect; +layout(location = 1) in vec4 inTexRect; +layout(location = 2) in float inOpacity; + +layout(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out vec2 outTexCoord; +layout(location = 1) out flat float outOpacity; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 offsets[6] = { vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0) }; + +vec4 intersect(vec4 a, vec4 b) +{ + a = vec4(a.xy, a.xy + a.zw); + b = vec4(b.xy, b.xy + b.zw); + vec4 result = vec4(max(a.xy, b.xy), min(a.zw, b.zw)); + if (any (greaterThanEqual (result.xy, result.zw))) + return vec4(0.0,0.0,0.0,0.0); + return vec4(result.xy, result.zw - result.xy); +} + +void main() { + vec4 rect = intersect(inRect, push.clip_bounds); + vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + + vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw, + rect.zw / inRect.zw); + texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy, + inTexRect.zw * texrect.zw); + outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex]; + outOpacity = inOpacity; +} diff --git a/gsk/resources/vulkan/opacity-clip.vert.spv b/gsk/resources/vulkan/opacity-clip.vert.spv new file mode 100644 index 0000000000..81aa4f6f85 Binary files /dev/null and b/gsk/resources/vulkan/opacity-clip.vert.spv differ diff --git a/gsk/resources/vulkan/opacity.frag.glsl b/gsk/resources/vulkan/opacity.frag.glsl new file mode 100644 index 0000000000..7ff7d347c7 --- /dev/null +++ b/gsk/resources/vulkan/opacity.frag.glsl @@ -0,0 +1,19 @@ +#version 420 core + +layout(location = 0) in vec2 inTexCoord; +layout(location = 1) in flat float inOpacity; + +layout(set = 0, binding = 0) uniform sampler2D inTexture; + +layout(location = 0) out vec4 color; + +vec4 +opacity (vec4 color, float value) +{ + return color * value; +} + +void main() +{ + color = opacity (texture (inTexture, inTexCoord), inOpacity); +} diff --git a/gsk/resources/vulkan/opacity.frag.spv b/gsk/resources/vulkan/opacity.frag.spv new file mode 100644 index 0000000000..5729abe98c Binary files /dev/null and b/gsk/resources/vulkan/opacity.frag.spv differ diff --git a/gsk/resources/vulkan/opacity.vert.glsl b/gsk/resources/vulkan/opacity.vert.glsl new file mode 100644 index 0000000000..7e12d41e1a --- /dev/null +++ b/gsk/resources/vulkan/opacity.vert.glsl @@ -0,0 +1,34 @@ +#version 420 core + +layout(location = 0) in vec4 inRect; +layout(location = 1) in vec4 inTexRect; +layout(location = 2) in float inOpacity; + +layout(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out vec2 outTexCoord; +layout(location = 1) out flat float outOpacity; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 offsets[6] = { vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0) }; + +void main() { + vec2 pos = inRect.xy + inRect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + + outTexCoord = inTexRect.xy + inTexRect.zw * offsets[gl_VertexIndex]; + outOpacity = inOpacity; +} diff --git a/gsk/resources/vulkan/opacity.vert.spv b/gsk/resources/vulkan/opacity.vert.spv new file mode 100644 index 0000000000..d0c9b86128 Binary files /dev/null and b/gsk/resources/vulkan/opacity.vert.spv differ -- cgit v1.2.1