HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_pipeline_SDF_vulkan_intf.hpp
1// Copyright Take Vos 2020-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "gfx_pipeline_vulkan_intf.hpp"
8#include "../container/container.hpp"
9#include "../geometry/geometry.hpp"
10#include "../image/image.hpp"
11#include "../font/font.hpp"
12#include "../macros.hpp"
13#include <vulkan/vulkan.hpp>
14#include <vma/vk_mem_alloc.h>
15#include <span>
16
17hi_export_module(hikogui.GFX : gfx_pipeline_SDF_intf);
18
19hi_export namespace hi { inline namespace v1 {
20
24class gfx_pipeline_SDF : public gfx_pipeline {
25public:
29 struct vertex {
31 sfloat_rgb32 position;
32
34 sfloat_rgba32 clippingRectangle;
35
38 sfloat_rgb32 textureCoord;
39
41 sfloat_rgba16 color;
42
45 {
46 }
47
48 static vk::VertexInputBindingDescription inputBindingDescription()
49 {
50 return {0, sizeof(vertex), vk::VertexInputRate::eVertex};
51 }
52
53 static std::vector<vk::VertexInputAttributeDescription> inputAttributeDescriptions()
54 {
55 return {
56 {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(vertex, position)},
57 {1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(vertex, clippingRectangle)},
58 {2, 0, vk::Format::eR32G32B32Sfloat, offsetof(vertex, textureCoord)},
59 {3, 0, vk::Format::eR16G16B16A16Sfloat, offsetof(vertex, color)}};
60 }
61 };
62
64 sfloat_rg32 window_extent = extent2{0.0, 0.0};
65 sfloat_rg32 viewport_scale = scale2{0.0, 0.0};
66 sfloat_rg32 red_subpixel_offset = vector2{0.0, 0.0};
67 sfloat_rg32 blue_subpixel_offset = vector2{0.0, 0.0};
68 VkBool32 has_subpixels = false;
69
70 static std::vector<vk::PushConstantRange> pushConstantRanges()
71 {
72 return {{vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, sizeof(push_constants)}};
73 }
74 };
75
77 float sdf_r8maxDistance;
78 float atlasImageWidth;
79
80 [[nodiscard]] vk::SpecializationInfo specializationInfo(std::vector<vk::SpecializationMapEntry>& entries) const noexcept
81 {
82 return {narrow_cast<uint32_t>(ssize(entries)), entries.data(), sizeof(specialization_constants), this};
83 }
84
85 [[nodiscard]] static std::vector<vk::SpecializationMapEntry> specializationConstantMapEntries() noexcept
86 {
87 return {
88 {0, offsetof(specialization_constants, sdf_r8maxDistance), sizeof(sdf_r8maxDistance)},
89 {1, offsetof(specialization_constants, atlasImageWidth), sizeof(atlasImageWidth)},
90 };
91 }
92 };
93
94 struct texture_map {
95 vk::Image image;
96 VmaAllocation allocation = {};
97 vk::ImageView view;
99 vk::ImageLayout layout = vk::ImageLayout::eUndefined;
100
101 void transitionLayout(const gfx_device& device, vk::Format format, vk::ImageLayout nextLayout);
102 };
103
105 // Studies in China have shown that literate individuals know and use between 3,000 and 4,000 characters.
106 // Handle up to 7 * 7 * 128 == 6321 characters with a 16 x 1024 x 1024, 16 x 1 MByte
107 //
108 // For latin characters we can store about 7 * 12 == 84 characters in a single image, which is enough
109 // for the full alpha numeric range that an application will use.
110
111 constexpr static int atlasImageWidth = 256; // 7-12 characters, of 34 pixels wide.
112 constexpr static int atlasImageHeight = 256; // 7 characters, of 34 pixels height.
113 static_assert(atlasImageWidth == atlasImageHeight, "needed for fwidth(textureCoord)");
114
115 constexpr static int atlasMaximumNrImages = 128; // 128 * 49 characters.
116 constexpr static int stagingImageWidth = 64; // One 'em' is 28 pixels, with edges 34 pixels.
117 constexpr static int stagingImageHeight = 64;
118
119 constexpr static float atlasTextureCoordinateMultiplier = 1.0f / atlasImageWidth;
120 constexpr static float drawfontSize = 28.0f;
121 constexpr static float drawBorder = sdf_r8::max_distance;
122 constexpr static float scaledDrawBorder = drawBorder / drawfontSize;
123
124 gfx_device const& device;
125
126 vk::ShaderModule vertexShaderModule;
127 vk::ShaderModule fragmentShaderModule;
128
129 specialization_constants specializationConstants;
130 std::vector<vk::SpecializationMapEntry> fragmentShaderSpecializationMapEntries;
131 vk::SpecializationInfo fragmentShaderSpecializationInfo;
133
134 texture_map stagingTexture;
135 std::vector<texture_map> atlasTextures;
136
138 vk::Sampler atlasSampler;
139 vk::DescriptorImageInfo atlasSamplerDescriptorImageInfo;
140
141 point3 atlas_allocation_position = {};
144
145 device_shared(gfx_device const& device);
147
148 device_shared(device_shared const&) = delete;
149 device_shared& operator=(device_shared const&) = delete;
150 device_shared(device_shared&&) = delete;
151 device_shared& operator=(device_shared&&) = delete;
152
156 void destroy(gfx_device const *vulkanDevice);
157
161 [[nodiscard]] glyph_atlas_info allocate_rect(extent2 draw_extent, scale2 draw_scale) noexcept;
162
163 void drawInCommandBuffer(vk::CommandBuffer const& commandBuffer);
164
168 void uploadStagingPixmapToAtlas(glyph_atlas_info const& location);
169
173
177
188 bool place_vertices(
189 vector_span<vertex>& vertices,
190 aarectangle const& clipping_rectangle,
191 quad const& box,
192 hi::font const& font,
193 glyph_id glyph,
194 quad_color colors) noexcept;
195
196 private:
197 void buildShaders();
198 void teardownShaders(gfx_device const *vulkanDevice);
199 void addAtlasImage();
200 void buildAtlas();
201 void teardownAtlas(gfx_device const *vulkanDevice);
202 void add_glyph_to_atlas(hi::font const& font, glyph_id glyph, glyph_atlas_info& info) noexcept;
203
208 get_glyph_from_atlas(hi::font const& font, glyph_id glyph) noexcept
209 {
210 auto& info = font.atlas_info(glyph);
211
212 if (info) [[likely]] {
213 return {&info, false};
214
215 } else {
216 add_glyph_to_atlas(font, glyph, info);
217 return {&info, true};
218 }
219 }
220 };
221
222 vector_span<vertex> vertexBufferData;
223
224 ~gfx_pipeline_SDF() = default;
225 gfx_pipeline_SDF(const gfx_pipeline_SDF&) = delete;
226 gfx_pipeline_SDF& operator=(const gfx_pipeline_SDF&) = delete;
227 gfx_pipeline_SDF(gfx_pipeline_SDF&&) = delete;
228 gfx_pipeline_SDF& operator=(gfx_pipeline_SDF&&) = delete;
229
230 gfx_pipeline_SDF(gfx_surface *surface) : gfx_pipeline(surface) {}
231
232 void draw_in_command_buffer(vk::CommandBuffer commandBuffer, draw_context const& context) override;
233
234private:
235 push_constants pushConstants;
236 int numberOfAtlasImagesInDescriptor = 0;
237
238 vk::Buffer vertexBuffer;
239 VmaAllocation vertexBufferAllocation;
240
241 [[nodiscard]] std::vector<vk::PipelineShaderStageCreateInfo> createShaderStages() const override;
242 [[nodiscard]] std::vector<vk::DescriptorSetLayoutBinding> createDescriptorSetLayoutBindings() const override;
243 [[nodiscard]] std::vector<vk::WriteDescriptorSet> createWriteDescriptorSet() const override;
244 [[nodiscard]] size_t getDescriptorSetVersion() const override;
245 [[nodiscard]] std::vector<vk::PushConstantRange> createPushConstantRanges() const override;
246 [[nodiscard]] vk::VertexInputBindingDescription createVertexInputBindingDescription() const override;
247 [[nodiscard]] std::vector<vk::VertexInputAttributeDescription> createVertexInputAttributeDescriptions() const override;
248 [[nodiscard]] std::vector<vk::PipelineColorBlendAttachmentState> getPipelineColorBlendAttachmentStates() const override;
249
250private:
251 void build_vertex_buffers() override;
252 void teardown_vertex_buffers() override;
253};
254
255}} // namespace hi
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
This is a RGBA floating point color.
Definition color_intf.hpp:49
A color for each corner of a quad.
Definition quad_color.hpp:22
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:33
A high-level geometric extent.
Definition extent2.hpp:32
Definition scale2.hpp:18
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector2.hpp:27
Definition gfx_pipeline_SDF_vulkan_intf.hpp:24
Definition gfx_pipeline_SDF_vulkan_intf.hpp:29
sfloat_rgb32 position
The pixel-coordinates where the origin is located relative to the bottom-left corner of the window.
Definition gfx_pipeline_SDF_vulkan_intf.hpp:31
sfloat_rgba16 color
The color of the glyph.
Definition gfx_pipeline_SDF_vulkan_intf.hpp:41
sfloat_rgba32 clippingRectangle
Clipping rectangle. (x,y)=bottom-left, (z,w)=top-right.
Definition gfx_pipeline_SDF_vulkan_intf.hpp:34
sfloat_rgb32 textureCoord
The x, y (relative to bottom-left) coordinate inside the texture-atlas, z is used as an index in the ...
Definition gfx_pipeline_SDF_vulkan_intf.hpp:38
Definition gfx_pipeline_SDF_vulkan_intf.hpp:63
Definition gfx_pipeline_SDF_vulkan_intf.hpp:76
Definition gfx_pipeline_SDF_vulkan_intf.hpp:94
Definition gfx_pipeline_SDF_vulkan_intf.hpp:104
void prepareStagingPixmapForDrawing()
This will transition the staging texture to 'general' for writing by the CPU.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:285
int atlasAllocationMaxHeight
During allocation on a row, we keep track of the tallest glyph.
Definition gfx_pipeline_SDF_vulkan_intf.hpp:143
void prepare_atlas_for_rendering()
This will transition the atlas to 'shader-read'.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:290
bool place_vertices(vector_span< vertex > &vertices, aarectangle const &clipping_rectangle, quad const &box, hi::font const &font, glyph_id glyph, quad_color colors) noexcept
Place vertices for a single glyph.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:345
void destroy(gfx_device const *vulkanDevice)
Definition gfx_pipeline_SDF_vulkan_impl.hpp:213
void uploadStagingPixmapToAtlas(glyph_atlas_info const &location)
Once drawing in the staging pixmap is completed, you can upload it to the atlas.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:257
glyph_atlas_info allocate_rect(extent2 draw_extent, scale2 draw_scale) noexcept
Allocate an glyph in the atlas.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:221
A non-owning 2D pixel-based image.
Definition pixmap_span.hpp:34
A 2D pixel-based image.
Definition pixmap.hpp:38
T data(T... args)