HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_pipeline_SDF_vulkan.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.hpp"
8#include "../container/module.hpp"
9#include "../font/font.hpp"
10#include "../macros.hpp"
11#include <vma/vk_mem_alloc.h>
12#include <span>
13
14namespace hi { inline namespace v1 {
15
19class gfx_pipeline_SDF : public gfx_pipeline {
20public:
24 struct vertex {
26 sfloat_rgb32 position;
27
29 sfloat_rgba32 clippingRectangle;
30
33 sfloat_rgb32 textureCoord;
34
36 sfloat_rgba16 color;
37
40 {
41 }
42
43 static vk::VertexInputBindingDescription inputBindingDescription()
44 {
45 return {0, sizeof(vertex), vk::VertexInputRate::eVertex};
46 }
47
48 static std::vector<vk::VertexInputAttributeDescription> inputAttributeDescriptions()
49 {
50 return {
51 {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(vertex, position)},
52 {1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(vertex, clippingRectangle)},
53 {2, 0, vk::Format::eR32G32B32Sfloat, offsetof(vertex, textureCoord)},
54 {3, 0, vk::Format::eR16G16B16A16Sfloat, offsetof(vertex, color)}};
55 }
56 };
57
59 sfloat_rg32 window_extent = extent2{0.0, 0.0};
60 sfloat_rg32 viewport_scale = scale2{0.0, 0.0};
61 sfloat_rg32 red_subpixel_offset = vector2{0.0, 0.0};
62 sfloat_rg32 blue_subpixel_offset = vector2{0.0, 0.0};
63 VkBool32 has_subpixels = false;
64
65 static std::vector<vk::PushConstantRange> pushConstantRanges()
66 {
67 return {{vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, sizeof(push_constants)}};
68 }
69 };
70
72 float sdf_r8maxDistance;
73 float atlasImageWidth;
74
75 [[nodiscard]] vk::SpecializationInfo specializationInfo(std::vector<vk::SpecializationMapEntry>& entries) const noexcept
76 {
77 return {narrow_cast<uint32_t>(ssize(entries)), entries.data(), sizeof(specialization_constants), this};
78 }
79
80 [[nodiscard]] static std::vector<vk::SpecializationMapEntry> specializationConstantMapEntries() noexcept
81 {
82 return {
83 {0, offsetof(specialization_constants, sdf_r8maxDistance), sizeof(sdf_r8maxDistance)},
84 {1, offsetof(specialization_constants, atlasImageWidth), sizeof(atlasImageWidth)},
85 };
86 }
87 };
88
89 struct texture_map {
90 vk::Image image;
91 VmaAllocation allocation = {};
92 vk::ImageView view;
94 vk::ImageLayout layout = vk::ImageLayout::eUndefined;
95
96 void transitionLayout(const gfx_device& device, vk::Format format, vk::ImageLayout nextLayout);
97 };
98
100 // Studies in China have shown that literate individuals know and use between 3,000 and 4,000 characters.
101 // Handle up to 7 * 7 * 128 == 6321 characters with a 16 x 1024 x 1024, 16 x 1 MByte
102 //
103 // For latin characters we can store about 7 * 12 == 84 characters in a single image, which is enough
104 // for the full alpha numeric range that an application will use.
105
106 constexpr static int atlasImageWidth = 256; // 7-12 characters, of 34 pixels wide.
107 constexpr static int atlasImageHeight = 256; // 7 characters, of 34 pixels height.
108 static_assert(atlasImageWidth == atlasImageHeight, "needed for fwidth(textureCoord)");
109
110 constexpr static int atlasMaximumNrImages = 128; // 128 * 49 characters.
111 constexpr static int stagingImageWidth = 64; // One 'em' is 28 pixels, with edges 34 pixels.
112 constexpr static int stagingImageHeight = 64;
113
114 constexpr static float atlasTextureCoordinateMultiplier = 1.0f / atlasImageWidth;
115 constexpr static float drawfontSize = 28.0f;
116 constexpr static float drawBorder = sdf_r8::max_distance;
117 constexpr static float scaledDrawBorder = drawBorder / drawfontSize;
118
119 gfx_device const& device;
120
121 vk::ShaderModule vertexShaderModule;
122 vk::ShaderModule fragmentShaderModule;
123
124 specialization_constants specializationConstants;
125 std::vector<vk::SpecializationMapEntry> fragmentShaderSpecializationMapEntries;
126 vk::SpecializationInfo fragmentShaderSpecializationInfo;
128
129 texture_map stagingTexture;
130 std::vector<texture_map> atlasTextures;
131
133 vk::Sampler atlasSampler;
134 vk::DescriptorImageInfo atlasSamplerDescriptorImageInfo;
135
136 point3 atlas_allocation_position = {};
139
140 device_shared(gfx_device const& device);
142
143 device_shared(device_shared const&) = delete;
144 device_shared& operator=(device_shared const&) = delete;
145 device_shared(device_shared&&) = delete;
146 device_shared& operator=(device_shared&&) = delete;
147
151 void destroy(gfx_device const *vulkanDevice);
152
156 [[nodiscard]] glyph_atlas_info allocate_rect(extent2 draw_extent, scale2 draw_scale) noexcept;
157
158 void drawInCommandBuffer(vk::CommandBuffer const& commandBuffer);
159
163 void uploadStagingPixmapToAtlas(glyph_atlas_info const& location);
164
168
172
183 bool place_vertices(
185 aarectangle const& clipping_rectangle,
186 quad const& box,
187 hi::font const& font,
188 glyph_id glyph,
189 quad_color colors) noexcept;
190
191 private:
192 void buildShaders();
193 void teardownShaders(gfx_device const *vulkanDevice);
194 void addAtlasImage();
195 void buildAtlas();
196 void teardownAtlas(gfx_device const *vulkanDevice);
197 void add_glyph_to_atlas(hi::font const& font, glyph_id glyph, glyph_atlas_info& info) noexcept;
198
203 get_glyph_from_atlas(hi::font const& font, glyph_id glyph) noexcept
204 {
205 auto& info = font.atlas_info(glyph);
206
207 if (info) [[likely]] {
208 return {&info, false};
209
210 } else {
211 add_glyph_to_atlas(font, glyph, info);
212 return {&info, true};
213 }
214 }
215 };
216
217 vector_span<vertex> vertexBufferData;
218
219 ~gfx_pipeline_SDF() = default;
220 gfx_pipeline_SDF(const gfx_pipeline_SDF&) = delete;
221 gfx_pipeline_SDF& operator=(const gfx_pipeline_SDF&) = delete;
222 gfx_pipeline_SDF(gfx_pipeline_SDF&&) = delete;
223 gfx_pipeline_SDF& operator=(gfx_pipeline_SDF&&) = delete;
224
225 gfx_pipeline_SDF(gfx_surface *surface) : gfx_pipeline(surface) {}
226
227 void draw_in_command_buffer(vk::CommandBuffer commandBuffer, draw_context const& context) override;
228
229private:
230 push_constants pushConstants;
231 int numberOfAtlasImagesInDescriptor = 0;
232
233 vk::Buffer vertexBuffer;
234 VmaAllocation vertexBufferAllocation;
235
236 [[nodiscard]] std::vector<vk::PipelineShaderStageCreateInfo> createShaderStages() const override;
237 [[nodiscard]] std::vector<vk::DescriptorSetLayoutBinding> createDescriptorSetLayoutBindings() const override;
238 [[nodiscard]] std::vector<vk::WriteDescriptorSet> createWriteDescriptorSet() const override;
239 [[nodiscard]] size_t getDescriptorSetVersion() const override;
240 [[nodiscard]] std::vector<vk::PushConstantRange> createPushConstantRanges() const override;
241 [[nodiscard]] vk::VertexInputBindingDescription createVertexInputBindingDescription() const override;
242 [[nodiscard]] std::vector<vk::VertexInputAttributeDescription> createVertexInputAttributeDescriptions() const override;
243 [[nodiscard]] std::vector<vk::PipelineColorBlendAttachmentState> getPipelineColorBlendAttachmentStates() const override;
244
245private:
246 void build_vertex_buffers() override;
247 void teardown_vertex_buffers() override;
248};
249
250}} // namespace hi
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
This is a RGBA floating point color.
Definition color.hpp:45
A color for each corner of a quad.
Definition quad_color.hpp:20
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:29
A high-level geometric extent.
Definition extent2.hpp:29
Definition scale2.hpp:13
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector2.hpp:19
Definition gfx_pipeline_SDF_vulkan.hpp:19
Definition gfx_pipeline_SDF_vulkan.hpp:24
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.hpp:26
sfloat_rgba16 color
The color of the glyph.
Definition gfx_pipeline_SDF_vulkan.hpp:36
sfloat_rgba32 clippingRectangle
Clipping rectangle. (x,y)=bottom-left, (z,w)=top-right.
Definition gfx_pipeline_SDF_vulkan.hpp:29
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.hpp:33
Definition gfx_pipeline_SDF_vulkan.hpp:58
Definition gfx_pipeline_SDF_vulkan.hpp:71
Definition gfx_pipeline_SDF_vulkan.hpp:89
Definition gfx_pipeline_SDF_vulkan.hpp:99
void prepareStagingPixmapForDrawing()
This will transition the staging texture to 'general' for writing by the CPU.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:282
int atlasAllocationMaxHeight
During allocation on a row, we keep track of the tallest glyph.
Definition gfx_pipeline_SDF_vulkan.hpp:138
void prepare_atlas_for_rendering()
This will transition the atlas to 'shader-read'.
Definition gfx_pipeline_SDF_vulkan_impl.hpp:287
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:342
void destroy(gfx_device const *vulkanDevice)
Definition gfx_pipeline_SDF_vulkan_impl.hpp:210
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:254
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:218
A non-owning 2D pixel-based image.
Definition pixmap_span.hpp:34
A 2D pixel-based image.
Definition pixmap.hpp:38