7#include "gfx_pipeline_image_vulkan.hpp"
8#include "gfx_device_vulkan_impl.hpp"
9#include "../macros.hpp"
11namespace hi {
inline namespace v1 {
13inline void gfx_pipeline_image::draw_in_command_buffer(vk::CommandBuffer commandBuffer, draw_context
const&
context)
15 gfx_pipeline::draw_in_command_buffer(commandBuffer,
context);
17 hi_axiom_not_null(device());
18 device()->flushAllocation(vertexBufferAllocation, 0, vertexBufferData.size() *
sizeof(vertex));
19 device()->image_pipeline->prepare_atlas_for_rendering();
25 device()->image_pipeline->draw_in_command_buffer(commandBuffer);
30 pushConstants.viewportScale = sfloat_rg32{2.0f / extent.width, 2.0f / extent.height};
31 pushConstants.atlasExtent = sfloat_rg32{device_shared::atlas_image_axis_size, device_shared::atlas_image_axis_size};
32 pushConstants.atlasScale =
33 sfloat_rg32{1.0f / device_shared::atlas_image_axis_size, 1.0f / device_shared::atlas_image_axis_size};
34 commandBuffer.pushConstants(
36 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
38 sizeof(push_constants),
43 device()->cmdBeginDebugUtilsLabelEXT(commandBuffer,
"draw images");
45 device()->cmdEndDebugUtilsLabelEXT(commandBuffer);
50 hi_axiom_not_null(device());
51 return device()->image_pipeline->shader_stages;
58 vk::DescriptorType::eSampler,
60 vk::ShaderStageFlagBits::eFragment},
62 vk::DescriptorType::eSampledImage,
64 vk::ShaderStageFlagBits::eFragment}};
69 hi_axiom_not_null(device());
78 vk::DescriptorType::eSampler,
88 vk::DescriptorType::eSampledImage,
95inline size_t gfx_pipeline_image::getDescriptorSetVersion()
const
97 hi_axiom_not_null(device());
98 return device()->image_pipeline->atlas_textures.size();
103 return push_constants::pushConstantRanges();
106inline vk::VertexInputBindingDescription gfx_pipeline_image::createVertexInputBindingDescription()
const
108 return vertex::inputBindingDescription();
113 return vertex::inputAttributeDescriptions();
116inline void gfx_pipeline_image::build_vertex_buffers()
122 vk::BufferCreateFlags(),
124 vk::BufferUsageFlagBits::eVertexBuffer,
125 vk::SharingMode::eExclusive};
131 hi_axiom_not_null(device());
133 device()->setDebugUtilsObjectNameEXT(vertexBuffer,
"image-pipeline vertex buffer");
134 vertexBufferData = device()->mapMemory<vertex>(vertexBufferAllocation);
137inline void gfx_pipeline_image::teardown_vertex_buffers()
139 hi_axiom_not_null(device());
140 device()->unmapMemory(vertexBufferAllocation);
141 device()->destroyBuffer(vertexBuffer, vertexBufferAllocation);
145gfx_pipeline_image::texture_map::transitionLayout(
const gfx_device& device, vk::Format format, vk::ImageLayout
nextLayout)
148 device.transition_layout(image, format, layout,
nextLayout);
154 device(
nullptr), width(width), height(height), pages()
156 if (surface ==
nullptr) {
165 hilet
lock = std::scoped_lock(gfx_system_mutex);
166 if ((this->device = surface->device()) !=
nullptr) {
167 hilet[num_columns, num_rows] = size_in_int_pages();
168 this->pages = device->image_pipeline->allocate_pages(num_columns * num_rows);
176 hilet
lock = std::scoped_lock(gfx_system_mutex);
181inline gfx_pipeline_image::paged_image::paged_image(gfx_surface
const *surface, png
const& image)
noexcept :
185 hilet
lock = std::scoped_lock(gfx_system_mutex);
190inline gfx_pipeline_image::paged_image::paged_image(paged_image&&
other)
noexcept :
191 state(
other.state.exchange(state_type::uninitialized)),
192 device(std::exchange(
other.device,
nullptr)),
194 height(
other.height),
199inline gfx_pipeline_image::paged_image& gfx_pipeline_image::paged_image::operator=(paged_image&&
other)
noexcept
201 hi_return_on_self_assignment(
other);
205 device->image_pipeline->free_pages(pages);
208 state =
other.state.exchange(state_type::uninitialized);
209 device = std::exchange(
other.device,
nullptr);
211 height =
other.height;
216inline gfx_pipeline_image::paged_image::~paged_image()
219 device->image_pipeline->free_pages(pages);
225 hi_assert(image.width() == width
and image.height() == height);
228 hilet lock = std::scoped_lock(gfx_system_mutex);
230 state = state_type::drawing;
232 auto staging_image = device->image_pipeline->get_staging_pixmap(image.width(), image.height());
234 device->image_pipeline->update_atlas_with_staging_pixmap(*
this);
236 state = state_type::uploaded;
242 hi_assert(image.width() == width
and image.height() == height);
245 hilet lock = std::scoped_lock(gfx_system_mutex);
247 state = state_type::drawing;
249 auto staging_image = device->image_pipeline->get_staging_pixmap(image.width(), image.height());
251 device->image_pipeline->update_atlas_with_staging_pixmap(*
this);
253 state = state_type::uploaded;
257inline gfx_pipeline_image::device_shared::device_shared(gfx_device
const& device) : device(device)
263inline gfx_pipeline_image::device_shared::~device_shared() {}
274 while (
num_pages > _atlas_free_pages.size()) {
280 hilet
page = _atlas_free_pages.back();
282 _atlas_free_pages.pop_back();
289 _atlas_free_pages.insert(_atlas_free_pages.end(), pages.begin(), pages.end());
294 staging_texture.transitionLayout(device, vk::Format::eR16G16B16A16Sfloat, vk::ImageLayout::eGeneral);
296 return staging_texture.pixmap.subimage(1, 1, staging_image_width - 2, staging_image_height - 2);
307 constexpr auto page_stride = gfx_pipeline_image::paged_image::page_size + 2;
309 hilet
image_nr =
page / gfx_pipeline_image::device_shared::atlas_num_pages_per_image;
310 hilet
image_page =
page % gfx_pipeline_image::device_shared::atlas_num_pages_per_image;
326 hilet
width_in_pages = (image.width + gfx_pipeline_image::paged_image::page_size - 1) / gfx_pipeline_image::paged_image::page_size;
333inline void gfx_pipeline_image::device_shared::make_staging_border_transparent(aarectangle
border_rectangle)
noexcept
343 hi_assert(
left == 0);
345 hi_assert(
right >= 2);
352 for (
auto x = 0
_uz; x != width; ++x) {
358 for (
auto y = 0
_uz; y != height; ++y) {
359 auto row = staging_texture.pixmap[y];
365inline void gfx_pipeline_image::device_shared::clear_staging_between_border_and_upload(
381 auto row = staging_texture.pixmap[y];
389 auto row = staging_texture.pixmap[y];
396inline void gfx_pipeline_image::device_shared::prepare_staging_for_upload(paged_image
const& image)
noexcept
408 static_assert(std::is_same_v<
decltype(staging_texture.pixmap)::value_type, sfloat_rgba16>);
409 device.flushAllocation(staging_texture.allocation, 0,
upload_height * staging_texture.pixmap.stride() * 8);
410 staging_texture.transitionLayout(device, vk::Format::eR16G16B16A16Sfloat, vk::ImageLayout::eTransferSrcOptimal);
413inline void gfx_pipeline_image::device_shared::update_atlas_with_staging_pixmap(paged_image
const& image)
noexcept
415 prepare_staging_for_upload(image);
418 for (
std::size_t index = 0; index < size(image.pages); index++) {
419 hilet
page = image.pages.at(index);
435 vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
437 vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
439 vk::Extent3D{width, height, 1});
449 atlas_texture.transitionLayout(device, vk::Format::eR16G16B16A16Sfloat, vk::ImageLayout::eTransferDstOptimal);
452 staging_texture.image,
453 vk::ImageLayout::eTransferSrcOptimal,
455 vk::ImageLayout::eTransferDstOptimal,
463 atlas_texture.transitionLayout(device, vk::Format::eR16G16B16A16Sfloat, vk::ImageLayout::eShaderReadOnlyOptimal);
467inline void gfx_pipeline_image::device_shared::draw_in_command_buffer(vk::CommandBuffer
const& commandBuffer)
469 commandBuffer.bindIndexBuffer(device.quadIndexBuffer, 0, vk::IndexType::eUint16);
472inline void gfx_pipeline_image::device_shared::build_shaders()
474 vertex_shader_module = device.loadShader(
URL(
"resource:shaders/image.vert.spv"));
475 fragment_shader_module = device.loadShader(
URL(
"resource:shaders/image.frag.spv"));
478 {vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_shader_module,
"main"},
479 {vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragment_shader_module,
"main"}};
482inline void gfx_pipeline_image::device_shared::teardown_shaders(gfx_device
const *
vulkanDevice)
489inline void gfx_pipeline_image::device_shared::add_atlas_image()
495 vk::ImageCreateFlags(),
497 vk::Format::eR16G16B16A16Sfloat,
498 vk::Extent3D(atlas_image_axis_size, atlas_image_axis_size, 1),
501 vk::SampleCountFlagBits::e1,
502 vk::ImageTiling::eOptimal,
503 vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
504 vk::SharingMode::eExclusive,
507 vk::ImageLayout::eUndefined};
518 {vk::ImageViewCreateFlags(),
520 vk::ImageViewType::e2D,
522 vk::ComponentMapping(),
524 vk::ImageAspectFlagBits::eColor,
535 for (
int i = 0; i < atlas_num_pages_per_image; i++) {
540 for (
std::size_t i = 0; i < size(atlas_descriptor_image_infos); i++) {
543 atlas_descriptor_image_infos.at(i) = {
545 i < atlas_textures.size() ? atlas_textures.at(i).view : atlas_textures.at(0).view,
546 vk::ImageLayout::eShaderReadOnlyOptimal};
550inline void gfx_pipeline_image::device_shared::build_atlas()
554 vk::ImageCreateFlags(),
556 vk::Format::eR16G16B16A16Sfloat,
557 vk::Extent3D(staging_image_width, staging_image_height, 1),
560 vk::SampleCountFlagBits::e1,
561 vk::ImageTiling::eLinear,
562 vk::ImageUsageFlagBits::eTransferSrc,
563 vk::SharingMode::eExclusive,
566 vk::ImageLayout::ePreinitialized};
572 device.setDebugUtilsObjectNameEXT(image,
"image-pipeline staging image");
573 hilet data = device.mapMemory<sfloat_rgba16>(allocation);
582 vk::SamplerCreateFlags(),
585 vk::SamplerMipmapMode::eNearest,
586 vk::SamplerAddressMode::eRepeat,
587 vk::SamplerAddressMode::eRepeat,
588 vk::SamplerAddressMode::eRepeat,
593 vk::CompareOp::eNever,
596 vk::BorderColor::eFloatTransparentBlack,
601 atlas_sampler_descriptor_image_info = {atlas_sampler, vk::ImageView(), vk::ImageLayout::eUndefined};
608inline void gfx_pipeline_image::device_shared::teardown_atlas(gfx_device
const *
old_device)
617 atlas_textures.clear();
619 old_device->unmapMemory(staging_texture.allocation);
620 old_device->destroyImage(staging_texture.image, staging_texture.allocation);
629 hi_assert(image.state == paged_image::state_type::uploaded);
635 hilet size_in_float_pages =
f32x4{image.size_in_float_pages()};
636 hilet size_in_int_pages =
i32x4{ceil(size_in_float_pages)};
646 auto left_bottom =
box.p0;
647 auto right_bottom =
box.p1;
649 auto it = image.pages.begin();
655 auto new_p0 = left_bottom;
676 left_bottom = left_top;
677 right_bottom = right_top;
@ bottom
Align to the bottom.
@ right
Align the text to the right side.
@ left
Align the text to the left side.
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
point2 get_staging_position(const gfx_pipeline_image::paged_image &image, std::size_t page_index)
Get the position in the staging texture map to copy from.
Definition gfx_pipeline_image_vulkan_impl.hpp:324
point3 get_atlas_position(std::size_t page) noexcept
Get the coordinate in the atlas from a page index.
Definition gfx_pipeline_image_vulkan_impl.hpp:304
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition misc.hpp:33
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:29
A high-level geometric extent.
Definition extent2.hpp:29
A rectangle / parallelogram in 3D space.
Definition rectangle.hpp:21
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
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
Universal Resource Locator.
Definition URL.hpp:51