HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_pipeline_image_vulkan.hpp
1// Copyright Take Vos 2019, 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 "../image/module.hpp"
10#include "../codec/codec.hpp"
11#include "../macros.hpp"
12#include <vma/vk_mem_alloc.h>
13
14namespace hi { inline namespace v1 {
15
19class gfx_pipeline_image : public gfx_pipeline {
20public:
24 struct alignas(16) vertex {
26 sfloat_rgba32 position;
27
30 sfloat_rgba32 clipping_rectangle;
31
33 sfloat_rgba32 atlas_position;
34
35 vertex(sfloat_rgba32 position, sfloat_rgba32 clipping_rectangle, sfloat_rgba32 atlas_position) noexcept :
37 {
38 }
39
40 static vk::VertexInputBindingDescription inputBindingDescription()
41 {
42 return {0, sizeof(vertex), vk::VertexInputRate::eVertex};
43 }
44
45 static std::vector<vk::VertexInputAttributeDescription> inputAttributeDescriptions()
46 {
47 return {
48 {0, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(vertex, position)},
49 {1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(vertex, clipping_rectangle)},
50 {2, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(vertex, atlas_position)},
51 };
52 }
53 };
54
56 sfloat_rg32 windowExtent = extent2{0.0, 0.0};
57 sfloat_rg32 viewportScale = scale2{0.0, 0.0};
58 sfloat_rg32 atlasExtent = extent2{0.0, 0.0};
59 sfloat_rg32 atlasScale = scale2{0.0, 0.0};
60
61 static std::vector<vk::PushConstantRange> pushConstantRanges()
62 {
63 return {{vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, sizeof(push_constants)}};
64 }
65 };
66
67 struct texture_map {
68 vk::Image image;
69 VmaAllocation allocation = {};
70 vk::ImageView view;
72 vk::ImageLayout layout = vk::ImageLayout::eUndefined;
73
74 void transitionLayout(const gfx_device& device, vk::Format format, vk::ImageLayout nextLayout);
75 };
76
79 struct paged_image {
80 enum class state_type { uninitialized, drawing, uploaded };
81
82 constexpr static std::size_t page_size = 62; // 64x64 including a 1 pixel border.
83
84 mutable std::atomic<state_type> state = state_type::uninitialized;
85 gfx_device *device = nullptr;
86 std::size_t width;
87 std::size_t height;
89
91 constexpr paged_image() noexcept = default;
92 paged_image(paged_image&& other) noexcept;
93 paged_image& operator=(paged_image&& other) noexcept;
94 paged_image(paged_image const& other) = delete;
95 paged_image& operator=(paged_image const& other) = delete;
96
97 paged_image(gfx_surface const *surface, std::size_t width, std::size_t height) noexcept;
98 paged_image(gfx_surface const *surface, pixmap_span<sfloat_rgba16 const> image) noexcept;
99 paged_image(gfx_surface const *surface, pixmap<sfloat_rgba16> const& image) noexcept :
101 {
102 }
103
104 paged_image(gfx_surface const *surface, png const& image) noexcept;
105
106 [[nodiscard]] constexpr explicit operator bool() const noexcept
107 {
108 return device != nullptr;
109 }
110
111 [[nodiscard]] constexpr extent2 size() const noexcept
112 {
113 return extent2{narrow_cast<float>(width), narrow_cast<float>(height)};
114 }
115
116 [[nodiscard]] constexpr std::pair<std::size_t, std::size_t> size_in_int_pages() const noexcept
117 {
118 hilet num_columns = (width + page_size - 1) / page_size;
119 hilet num_rows = (height + page_size - 1) / page_size;
120 return {num_columns, num_rows};
121 }
122
123 [[nodiscard]] constexpr extent2 size_in_float_pages() const noexcept
124 {
125 constexpr auto page_size_ = f32x4{narrow_cast<float>(page_size), narrow_cast<float>(page_size), 1.0f, 1.0f};
126 auto size = f32x4{narrow_cast<float>(width), narrow_cast<float>(height)};
127 return extent2{size / page_size_};
128 }
129
132 void upload(pixmap_span<sfloat_rgba16 const> image) noexcept;
133
136 void upload(png const& image) noexcept;
137 };
138
140 constexpr static std::size_t atlas_num_pages_per_axis = 8;
141 constexpr static std::size_t atlas_num_pages_per_image = atlas_num_pages_per_axis * atlas_num_pages_per_axis;
142 constexpr static std::size_t atlas_image_axis_size = atlas_num_pages_per_axis * (paged_image::page_size + 2);
143 constexpr static std::size_t atlas_maximum_num_images = 64;
144 constexpr static std::size_t staging_image_width = 1024;
145 constexpr static std::size_t staging_image_height = 1024;
146
147 gfx_device const& device;
148
149 vk::ShaderModule vertex_shader_module;
150 vk::ShaderModule fragment_shader_module;
152
153 texture_map staging_texture;
154 std::vector<texture_map> atlas_textures;
155
157 vk::Sampler atlas_sampler;
158 vk::DescriptorImageInfo atlas_sampler_descriptor_image_info;
159
160 device_shared(gfx_device const& device);
162
163 device_shared(device_shared const&) = delete;
164 device_shared& operator=(device_shared const&) = delete;
165 device_shared(device_shared&&) = delete;
166 device_shared& operator=(device_shared&&) = delete;
167
171 void destroy(gfx_device const *vulkanDevice);
172
176
179 void free_pages(std::vector<std::size_t> const& pages) noexcept;
180
181 void draw_in_command_buffer(vk::CommandBuffer const& commandBuffer);
182
188
192
201 void place_vertices(
203 aarectangle const& clipping_rectangle,
204 quad const& box,
205 paged_image const& image) noexcept;
206
207 private:
208 std::vector<std::size_t> _atlas_free_pages;
209
213 {
214 return get_staging_pixmap().subimage(0, 0, width, height);
215 }
216
221 void make_staging_border_transparent(aarectangle border_rectangle) noexcept;
222
228 void clear_staging_between_border_and_upload(aarectangle border_rectangle, aarectangle upload_rectangle) noexcept;
229
240 void prepare_staging_for_upload(paged_image const& image) noexcept;
241
244 void update_atlas_with_staging_pixmap(paged_image const& image) noexcept;
245
246 void build_shaders();
247 void teardown_shaders(gfx_device const *device);
248 void add_atlas_image();
249 void build_atlas();
250 void teardown_atlas(gfx_device const *device);
251
252 friend paged_image;
253 };
254
255 vector_span<vertex> vertexBufferData;
256
257 ~gfx_pipeline_image() = default;
258 gfx_pipeline_image(const gfx_pipeline_image&) = delete;
259 gfx_pipeline_image& operator=(const gfx_pipeline_image&) = delete;
261 gfx_pipeline_image& operator=(gfx_pipeline_image&&) = delete;
262
263 gfx_pipeline_image(gfx_surface *surface) : gfx_pipeline(surface) {}
264
265 void draw_in_command_buffer(vk::CommandBuffer commandBuffer, draw_context const& context) override;
266
267private:
268 push_constants pushConstants;
269 int numberOfAtlasImagesInDescriptor = 0;
270
271 vk::Buffer vertexBuffer;
272 VmaAllocation vertexBufferAllocation;
273
274 [[nodiscard]] std::vector<vk::PipelineShaderStageCreateInfo> createShaderStages() const override;
275 [[nodiscard]] std::vector<vk::DescriptorSetLayoutBinding> createDescriptorSetLayoutBindings() const override;
276 [[nodiscard]] std::vector<vk::WriteDescriptorSet> createWriteDescriptorSet() const override;
277 [[nodiscard]] size_t getDescriptorSetVersion() const override;
278 [[nodiscard]] std::vector<vk::PushConstantRange> createPushConstantRanges() const override;
279 [[nodiscard]] vk::VertexInputBindingDescription createVertexInputBindingDescription() const override;
280 [[nodiscard]] std::vector<vk::VertexInputAttributeDescription> createVertexInputAttributeDescriptions() const override;
281
282private:
283 void build_vertex_buffers() override;
284 void teardown_vertex_buffers() override;
285};
286
287}} // namespace hi::v1
@ other
The gui_event does not have associated data.
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
Definition png.hpp:27
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:29
A high-level geometric extent.
Definition extent2.hpp:29
Definition scale2.hpp:13
Draw context for drawing using the HikoGUI shaders.
Definition draw_context.hpp:208
Definition gfx_pipeline_image_vulkan.hpp:19
Definition gfx_pipeline_image_vulkan.hpp:24
sfloat_rgba32 atlas_position
The x, y coordinate inside the texture-atlas, z is used as an index in the texture-atlas array.
Definition gfx_pipeline_image_vulkan.hpp:33
sfloat_rgba32 position
The pixel-coordinates where the origin is located relative to the bottom-left corner of the window.
Definition gfx_pipeline_image_vulkan.hpp:26
sfloat_rgba32 clipping_rectangle
The position in pixels of the clipping rectangle relative to the bottom-left corner of the window,...
Definition gfx_pipeline_image_vulkan.hpp:30
Definition gfx_pipeline_image_vulkan.hpp:55
Definition gfx_pipeline_image_vulkan.hpp:67
This is a image that is uploaded into the texture atlas.
Definition gfx_pipeline_image_vulkan.hpp:79
void upload(pixmap_span< sfloat_rgba16 const > image) noexcept
Upload image to atlas.
Definition gfx_pipeline_image_vulkan_impl.hpp:240
Definition gfx_pipeline_image_vulkan.hpp:139
void destroy(gfx_device const *vulkanDevice)
Definition gfx_pipeline_image_vulkan_impl.hpp:265
void place_vertices(vector_span< vertex > &vertices, aarectangle const &clipping_rectangle, quad const &box, paged_image const &image) noexcept
Place vertices for a single image.
Definition gfx_pipeline_image_vulkan_impl.hpp:623
std::vector< std::size_t > allocate_pages(std::size_t num_pages) noexcept
Allocate pages from the atlas.
Definition gfx_pipeline_image_vulkan_impl.hpp:272
void prepare_atlas_for_rendering()
Prepare the atlas so that it can be used as a texture map by the shaders.
Definition gfx_pipeline_image_vulkan_impl.hpp:460
hi::pixmap_span< sfloat_rgba16 > get_staging_pixmap()
Get the full staging pixel map excluding border.
Definition gfx_pipeline_image_vulkan_impl.hpp:292
void free_pages(std::vector< std::size_t > const &pages) noexcept
Deallocate pages back to the atlas.
Definition gfx_pipeline_image_vulkan_impl.hpp:287
A non-owning 2D pixel-based image.
Definition pixmap_span.hpp:34
A 2D pixel-based image.
Definition pixmap.hpp:38