HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_pipeline_box_vulkan_impl.hpp
1// Copyright Take Vos 2020-2022.
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_box_vulkan_intf.hpp"
8#include "gfx_device_vulkan_impl.hpp"
9#include "draw_context_intf.hpp"
10#include "../macros.hpp"
11#include <vulkan/vulkan.hpp>
12
13hi_export_module(hikogui.GFX : gfx_pipeline_box_impl);
14
15hi_export namespace hi { inline namespace v1 {
16
17inline void gfx_pipeline_box::draw_in_command_buffer(vk::CommandBuffer commandBuffer, draw_context const& context)
18{
19 gfx_pipeline::draw_in_command_buffer(commandBuffer, context);
20
21 hi_axiom_not_null(device());
22 device()->flushAllocation(vertexBufferAllocation, 0, vertexBufferData.size() * sizeof(vertex));
23
24 std::vector<vk::Buffer> tmpvertexBuffers = {vertexBuffer};
25 std::vector<vk::DeviceSize> tmpOffsets = {0};
26 hi_assert(tmpvertexBuffers.size() == tmpOffsets.size());
27
28 device()->box_pipeline->drawInCommandBuffer(commandBuffer);
29
30 commandBuffer.bindVertexBuffers(0, tmpvertexBuffers, tmpOffsets);
31
32 pushConstants.windowExtent = extent2{narrow_cast<float>(extent.width), narrow_cast<float>(extent.height)};
33 pushConstants.viewportScale = scale2{2.0f / extent.width, 2.0f / extent.height};
34 commandBuffer.pushConstants(
35 pipelineLayout,
36 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
37 0,
38 sizeof(push_constants),
39 &pushConstants);
40
41 auto const numberOfRectangles = vertexBufferData.size() / 4;
42 auto const numberOfTriangles = numberOfRectangles * 2;
43
44 device()->cmdBeginDebugUtilsLabelEXT(commandBuffer, "draw boxes");
45 commandBuffer.drawIndexed(narrow_cast<uint32_t>(numberOfTriangles * 3), 1, 0, 0, 0);
46 device()->cmdEndDebugUtilsLabelEXT(commandBuffer);
47}
48
49inline std::vector<vk::PipelineShaderStageCreateInfo> gfx_pipeline_box::createShaderStages() const
50{
51 hi_axiom_not_null(device());
52 return device()->box_pipeline->shaderStages;
53}
54
55inline std::vector<vk::DescriptorSetLayoutBinding> gfx_pipeline_box::createDescriptorSetLayoutBindings() const
56{
57 return {};
58}
59
60inline std::vector<vk::WriteDescriptorSet> gfx_pipeline_box::createWriteDescriptorSet() const
61{
62 return {};
63}
64
65inline size_t gfx_pipeline_box::getDescriptorSetVersion() const
66{
67 return 0;
68}
69
70inline std::vector<vk::PushConstantRange> gfx_pipeline_box::createPushConstantRanges() const
71{
72 return push_constants::pushConstantRanges();
73}
74
75inline vk::VertexInputBindingDescription gfx_pipeline_box::createVertexInputBindingDescription() const
76{
77 return vertex::inputBindingDescription();
78}
79
80inline std::vector<vk::VertexInputAttributeDescription> gfx_pipeline_box::createVertexInputAttributeDescriptions() const
81{
82 return vertex::inputAttributeDescriptions();
83}
84
85inline void gfx_pipeline_box::build_vertex_buffers()
86{
87 using vertexIndexType = uint16_t;
88 constexpr ssize_t numberOfVertices = 1 << (sizeof(vertexIndexType) * CHAR_BIT);
89
90 vk::BufferCreateInfo const bufferCreateInfo = {
91 vk::BufferCreateFlags(),
92 sizeof(vertex) * numberOfVertices,
93 vk::BufferUsageFlagBits::eVertexBuffer,
94 vk::SharingMode::eExclusive};
95 VmaAllocationCreateInfo allocationCreateInfo = {};
96 allocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
97 allocationCreateInfo.pUserData = const_cast<char *>("box-pipeline vertex buffer");
98 allocationCreateInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
99
100 hi_axiom_not_null(device());
101 std::tie(vertexBuffer, vertexBufferAllocation) = device()->createBuffer(bufferCreateInfo, allocationCreateInfo);
102 device()->setDebugUtilsObjectNameEXT(vertexBuffer, "box-pipeline vertex buffer");
103 vertexBufferData = device()->mapMemory<vertex>(vertexBufferAllocation);
104}
105
106inline void gfx_pipeline_box::teardown_vertex_buffers()
107{
108 hi_axiom_not_null(device());
109 device()->unmapMemory(vertexBufferAllocation);
110 device()->destroyBuffer(vertexBuffer, vertexBufferAllocation);
111}
112
113inline gfx_pipeline_box::device_shared::device_shared(gfx_device const &device) : device(device)
114{
115 buildShaders();
116}
117
118inline gfx_pipeline_box::device_shared::~device_shared() {}
119
120inline void gfx_pipeline_box::device_shared::destroy(gfx_device const *vulkanDevice)
121{
122 hi_assert_not_null(vulkanDevice);
123 teardownShaders(vulkanDevice);
124}
125
126inline void gfx_pipeline_box::device_shared::drawInCommandBuffer(vk::CommandBuffer const &commandBuffer)
127{
128 commandBuffer.bindIndexBuffer(device.quadIndexBuffer, 0, vk::IndexType::eUint16);
129}
130
131inline void gfx_pipeline_box::device_shared::place_vertices(
132 vector_span<vertex> &vertices,
133 aarectangle clipping_rectangle,
134 quad box,
135 quad_color fill_colors,
136 quad_color line_colors,
137 float line_width,
139{
140 // Include the half line_width, so that the border is drawn centered
141 // around the box outline. Then add 1 pixel for anti-aliasing.
142 // The shader will compensate for the pixel and half the border.
143 auto const extra_space = (line_width * 0.5f) + 1.0f;
144 auto const[box_, lengths] = expand_and_edge_hypots(box, extent2{extra_space, extra_space});
145
146 // t0-t3 are used inside the shader to determine how far from the corner
147 // a certain fragment is.
148 //
149 // x = Number of pixels from the right edge.
150 // y = Number of pixels above the bottom edge.
151 // z = Number of pixels from the left edge.
152 // w = Number of pixels below the top edge.
153 auto const t0 = sfloat_rgba32{lengths._00xy()};
154 auto const t1 = sfloat_rgba32{lengths.x00w()};
155 auto const t2 = sfloat_rgba32{lengths._0yz0()};
156 auto const t3 = sfloat_rgba32{lengths.zw00()};
157
158 auto const clipping_rectangle_ = sfloat_rgba32{clipping_rectangle};
159 auto const corner_radii_ = sfloat_rgba32{corner_radii};
160
161 vertices.emplace_back(box_.p0, clipping_rectangle_, t0, corner_radii_, fill_colors.p0, line_colors.p0, line_width);
162 vertices.emplace_back(box_.p1, clipping_rectangle_, t1, corner_radii_, fill_colors.p1, line_colors.p1, line_width);
163 vertices.emplace_back(box_.p2, clipping_rectangle_, t2, corner_radii_, fill_colors.p2, line_colors.p2, line_width);
164 vertices.emplace_back(box_.p3, clipping_rectangle_, t3, corner_radii_, fill_colors.p3, line_colors.p3, line_width);
165}
166
167inline void gfx_pipeline_box::device_shared::buildShaders()
168{
169 vertexShaderModule = device.loadShader(URL("resource:box_vulkan.vert.spv"));
170 device.setDebugUtilsObjectNameEXT(vertexShaderModule, "box-pipeline vertex shader");
171
172 fragmentShaderModule = device.loadShader(URL("resource:box_vulkan.frag.spv"));
173 device.setDebugUtilsObjectNameEXT(vertexShaderModule, "box-pipeline fragment shader");
174
175 shaderStages = {
176 {vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertexShaderModule, "main"},
177 {vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragmentShaderModule, "main"}};
178}
179
180inline void gfx_pipeline_box::device_shared::teardownShaders(gfx_device const*vulkanDevice)
181{
182 hi_assert_not_null(vulkanDevice);
183 vulkanDevice->destroy(vertexShaderModule);
184 vulkanDevice->destroy(fragmentShaderModule);
185}
186
187}} // namespace hi::inline v1::gfx_pipeline_box
The HikoGUI namespace.
Definition array_generic.hpp:20
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition misc.hpp:32
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A color for each corner of a quad.
Definition quad_color.hpp:22
color p0
left-bottom
Definition quad_color.hpp:24
color p2
left-top
Definition quad_color.hpp:26
color p3
right-top
Definition quad_color.hpp:27
color p1
right-bottom
Definition quad_color.hpp:25
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:33
The 4 radii of the corners of a quad or rectangle.
Definition corner_radii.hpp:26
A high-level geometric extent.
Definition extent2.hpp:32
T size(T... args)
T tie(T... args)