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();
21 std::vector<vk::Buffer> tmpvertexBuffers = {vertexBuffer};
22 std::vector<vk::DeviceSize> tmpOffsets = {0};
23 hi_assert(tmpvertexBuffers.
size() == tmpOffsets.
size());
25 device()->image_pipeline->draw_in_command_buffer(commandBuffer);
27 commandBuffer.bindVertexBuffers(0, tmpvertexBuffers, tmpOffsets);
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,
41 hilet numberOfRectangles = vertexBufferData.size() / 4;
42 hilet numberOfTriangles = numberOfRectangles * 2;
43 device()->cmdBeginDebugUtilsLabelEXT(commandBuffer,
"draw images");
45 device()->cmdEndDebugUtilsLabelEXT(commandBuffer);
48inline std::vector<vk::PipelineShaderStageCreateInfo> gfx_pipeline_image::createShaderStages()
const
50 hi_axiom_not_null(device());
51 return device()->image_pipeline->shader_stages;
54inline std::vector<vk::DescriptorSetLayoutBinding> gfx_pipeline_image::createDescriptorSetLayoutBindings()
const
58 vk::DescriptorType::eSampler,
60 vk::ShaderStageFlagBits::eFragment},
62 vk::DescriptorType::eSampledImage,
64 vk::ShaderStageFlagBits::eFragment}};
67inline std::vector<vk::WriteDescriptorSet> gfx_pipeline_image::createWriteDescriptorSet()
const
69 hi_axiom_not_null(device());
70 hilet& sharedImagePipeline = device()->image_pipeline;
78 vk::DescriptorType::eSampler,
79 &sharedImagePipeline->atlas_sampler_descriptor_image_info,
88 vk::DescriptorType::eSampledImage,
89 sharedImagePipeline->atlas_descriptor_image_infos.data(),
95inline size_t gfx_pipeline_image::getDescriptorSetVersion()
const
97 hi_axiom_not_null(device());
98 return device()->image_pipeline->atlas_textures.size();
101inline std::vector<vk::PushConstantRange> gfx_pipeline_image::createPushConstantRanges()
const
103 return push_constants::pushConstantRanges();
106inline vk::VertexInputBindingDescription gfx_pipeline_image::createVertexInputBindingDescription()
const
108 return vertex::inputBindingDescription();
111inline std::vector<vk::VertexInputAttributeDescription> gfx_pipeline_image::createVertexInputAttributeDescriptions()
const
113 return vertex::inputAttributeDescriptions();
116inline void gfx_pipeline_image::build_vertex_buffers()
118 using vertexIndexType = uint16_t;
119 constexpr ssize_t numberOfVertices = 1 << (
sizeof(vertexIndexType) * CHAR_BIT);
121 vk::BufferCreateInfo
const bufferCreateInfo = {
122 vk::BufferCreateFlags(),
123 sizeof(
vertex) * numberOfVertices,
124 vk::BufferUsageFlagBits::eVertexBuffer,
125 vk::SharingMode::eExclusive};
126 VmaAllocationCreateInfo allocationCreateInfo = {};
127 allocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
128 allocationCreateInfo.pUserData =
const_cast<char *
>(
"image-pipeline vertex buffer");
129 allocationCreateInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
131 hi_axiom_not_null(device());
132 std::tie(vertexBuffer, vertexBufferAllocation) = device()->createBuffer(bufferCreateInfo, allocationCreateInfo);
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)
147 if (layout != nextLayout) {
148 device.transition_layout(image, format, layout, nextLayout);
153inline gfx_pipeline_image::paged_image::paged_image(gfx_surface
const *surface, std::size_t width, std::size_t height) noexcept :
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);
172inline gfx_pipeline_image::paged_image::paged_image(gfx_surface
const *surface, pixmap_span<sfloat_rgba16 const> image) noexcept :
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());
233 image.decode_image(staging_image);
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());
250 copy(image, staging_image);
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() {}
267 hi_assert_not_null(old_device);
268 teardown_shaders(old_device);
269 teardown_atlas(old_device);
274 while (num_pages > _atlas_free_pages.size()) {
279 for (
int i = 0; i < num_pages; i++) {
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;
313 narrow_cast<float>((image_page % gfx_pipeline_image::device_shared::atlas_num_pages_per_axis) * page_stride + 1),
314 narrow_cast<float>((image_page / gfx_pipeline_image::device_shared::atlas_num_pages_per_axis) * page_stride + 1),
326 hilet width_in_pages = (image.width + gfx_pipeline_image::paged_image::page_size - 1) / gfx_pipeline_image::paged_image::page_size;
329 narrow_cast<float>((page_index % width_in_pages) * gfx_pipeline_image::paged_image::page_size + 1),
330 narrow_cast<float>((page_index / width_in_pages) * gfx_pipeline_image::paged_image::page_size + 1)};
333inline void gfx_pipeline_image::device_shared::make_staging_border_transparent(aarectangle border_rectangle)
noexcept
335 hilet width = ceil_cast<std::size_t>(border_rectangle.width());
336 hilet height = ceil_cast<std::size_t>(border_rectangle.height());
337 hilet
bottom = floor_cast<std::size_t>(border_rectangle.bottom());
338 hilet
top = ceil_cast<std::size_t>(border_rectangle.top());
339 hilet
left = floor_cast<std::size_t>(border_rectangle.left());
340 hilet
right = ceil_cast<std::size_t>(border_rectangle.right());
343 hi_assert(
left == 0);
345 hi_assert(
right >= 2);
348 auto border_bottom_row = staging_texture.pixmap[
bottom];
349 auto border_top_row = staging_texture.pixmap[
top - 1];
350 auto image_bottom_row = staging_texture.pixmap[
bottom + 1];
351 auto image_top_row = staging_texture.pixmap[
top - 2];
352 for (
auto x = 0_uz; x != width; ++x) {
353 border_bottom_row[x] = make_transparent(image_bottom_row[x]);
354 border_top_row[x] = make_transparent(image_top_row[x]);
358 for (
auto y = 0_uz; y != height; ++y) {
359 auto row = staging_texture.pixmap[y];
360 row[
left] = make_transparent(row[
left + 1]);
361 row[
right - 2] = make_transparent(row[
right - 1]);
365inline void gfx_pipeline_image::device_shared::clear_staging_between_border_and_upload(
366 aarectangle border_rectangle,
367 aarectangle upload_rectangle)
noexcept
369 hi_assert(border_rectangle.left() == 0.0f and border_rectangle.bottom() == 0.0f);
370 hi_assert(upload_rectangle.left() == 0.0f and upload_rectangle.bottom() == 0.0f);
372 hilet border_top = floor_cast<std::size_t>(border_rectangle.top());
373 hilet border_right = floor_cast<std::size_t>(border_rectangle.right());
374 hilet upload_top = floor_cast<std::size_t>(upload_rectangle.top());
375 hilet upload_right = floor_cast<std::size_t>(upload_rectangle.right());
376 hi_assert(border_right <= upload_right);
377 hi_assert(border_top <= upload_top);
380 for (
auto y = 0_uz; y != border_top; ++y) {
381 auto row = staging_texture.pixmap[y];
382 for (
auto x = border_right; x != upload_right; ++x) {
388 for (
auto y = border_top; y != upload_top; ++y) {
389 auto row = staging_texture.pixmap[y];
390 for (
auto x = 0_uz; x != upload_right; ++x) {
396inline void gfx_pipeline_image::device_shared::prepare_staging_for_upload(
paged_image const& image)
noexcept
398 hilet image_rectangle = aarectangle{point2{1.0f, 1.0f}, image.size()};
399 hilet border_rectangle = image_rectangle + 1;
400 hilet upload_width =
ceil(image.width, paged_image::page_size) + 2;
401 hilet upload_height =
ceil(image.height, paged_image::page_size) + 2;
404 make_staging_border_transparent(border_rectangle);
405 clear_staging_between_border_and_upload(border_rectangle, upload_rectangle);
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);
417 std::array<std::vector<vk::ImageCopy>, atlas_maximum_num_images> regions_to_copy_per_atlas_texture;
418 for (std::size_t index = 0; index < size(image.pages); index++) {
419 hilet page = image.pages.at(index);
427 hilet src_x = floor_cast<int32_t>(src_position.x() - 1.0f);
428 hilet src_y = floor_cast<int32_t>(src_position.y() - 1.0f);
429 hilet dst_x = floor_cast<int32_t>(dst_position.x() - 1.0f);
430 hilet dst_y = floor_cast<int32_t>(dst_position.y() - 1.0f);
431 hilet dst_z = floor_cast<std::size_t>(dst_position.z());
433 auto& regionsToCopy = regions_to_copy_per_atlas_texture.
at(dst_z);
434 regionsToCopy.emplace_back(
435 vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
436 vk::Offset3D{src_x, src_y, 0},
437 vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
438 vk::Offset3D{dst_x, dst_y, 0},
439 vk::Extent3D{width, height, 1});
442 for (std::size_t atlas_texture_index = 0; atlas_texture_index < size(atlas_textures); atlas_texture_index++) {
443 hilet& regions_to_copy = regions_to_copy_per_atlas_texture.
at(atlas_texture_index);
444 if (regions_to_copy.empty()) {
448 auto& atlas_texture = atlas_textures.at(atlas_texture_index);
449 atlas_texture.transitionLayout(device, vk::Format::eR16G16B16A16Sfloat, vk::ImageLayout::eTransferDstOptimal);
452 staging_texture.image,
453 vk::ImageLayout::eTransferSrcOptimal,
455 vk::ImageLayout::eTransferDstOptimal,
462 for (
auto& atlas_texture : atlas_textures) {
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)
484 hi_assert_not_null(vulkanDevice);
485 vulkanDevice->destroy(vertex_shader_module);
486 vulkanDevice->destroy(fragment_shader_module);
489inline void gfx_pipeline_image::device_shared::add_atlas_image()
491 hilet current_image_index = size(atlas_textures);
494 vk::ImageCreateInfo
const imageCreateInfo = {
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};
508 VmaAllocationCreateInfo allocationCreateInfo = {};
509 auto allocation_name = std::format(
"image-pipeline atlas image {}", current_image_index);
510 allocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
511 allocationCreateInfo.pUserData =
const_cast<char *
>(allocation_name.c_str());
512 allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
514 hilet[atlasImage, atlasImageAllocation] = device.createImage(imageCreateInfo, allocationCreateInfo);
515 device.setDebugUtilsObjectNameEXT(atlasImage, allocation_name.c_str());
517 hilet atlasImageView = device.createImageView(
518 {vk::ImageViewCreateFlags(),
520 vk::ImageViewType::e2D,
521 imageCreateInfo.format,
522 vk::ComponentMapping(),
524 vk::ImageAspectFlagBits::eColor,
531 atlas_textures.push_back({atlasImage, atlasImageAllocation, atlasImageView});
534 hilet page_offset = current_image_index * atlas_num_pages_per_image;
535 for (
int i = 0; i < atlas_num_pages_per_image; i++) {
536 _atlas_free_pages.push_back({page_offset + 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()
553 vk::ImageCreateInfo
const imageCreateInfo = {
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};
567 VmaAllocationCreateInfo allocationCreateInfo = {};
568 allocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
569 allocationCreateInfo.pUserData =
const_cast<char *
>(
"image-pipeline staging image");
570 allocationCreateInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
571 hilet[image, allocation] = device.createImage(imageCreateInfo, allocationCreateInfo);
572 device.setDebugUtilsObjectNameEXT(image,
"image-pipeline staging image");
573 hilet data = device.mapMemory<sfloat_rgba16>(allocation);
579 hi::pixmap_span<sfloat_rgba16>{data.data(), imageCreateInfo.extent.width, imageCreateInfo.extent.height}};
581 vk::SamplerCreateInfo
const samplerCreateInfo = {
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,
599 atlas_sampler = device.createSampler(samplerCreateInfo);
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)
610 hi_assert_not_null(old_device);
611 old_device->destroy(atlas_sampler);
613 for (
const auto& atlas_texture : atlas_textures) {
614 old_device->destroy(atlas_texture.view);
615 old_device->destroyImage(atlas_texture.image, atlas_texture.allocation);
617 atlas_textures.clear();
619 old_device->unmapMemory(staging_texture.allocation);
620 old_device->destroyImage(staging_texture.image, staging_texture.allocation);
624 vector_span<vertex>& vertices,
627 paged_image
const& image)
noexcept
629 hi_assert(image.state == paged_image::state_type::uploaded);
631 constexpr auto page_size2 =
634 hilet image_size = image.size();
635 hilet size_in_float_pages = f32x4{image.size_in_float_pages()};
636 hilet size_in_int_pages = i32x4{ceil(size_in_float_pages)};
640 hilet page_to_quad_ratio = rcp(size_in_float_pages);
641 hilet page_to_quad_ratio_x =
scale3{page_to_quad_ratio.xxx1()};
642 hilet page_to_quad_ratio_y =
scale3{page_to_quad_ratio.yyy1()};
643 hilet left_increment = page_to_quad_ratio_y * box.left();
644 hilet right_increment = page_to_quad_ratio_y * box.right();
646 auto left_bottom = box.p0;
647 auto right_bottom = box.p1;
648 auto bottom_increment = page_to_quad_ratio_x * (right_bottom - left_bottom);
649 auto it = image.pages.begin();
650 for (
std::size_t page_index = 0, row_nr = 0; row_nr != num_rows; ++row_nr) {
651 hilet left_top = left_bottom + left_increment;
652 hilet right_top = right_bottom + right_increment;
653 hilet top_increment = page_to_quad_ratio_x * (right_top - left_top);
655 auto new_p0 = left_bottom;
656 auto new_p2 = left_top;
657 for (
std::size_t column_nr = 0; column_nr != num_columns; ++column_nr, ++page_index, ++it) {
658 hilet new_p1 = new_p0 + bottom_increment;
659 hilet new_p3 = new_p2 + top_increment;
667 vertices.emplace_back(new_p0, clipping_rectangle, get<0>(uv_rectangle));
668 vertices.emplace_back(new_p1, clipping_rectangle, get<1>(uv_rectangle));
669 vertices.emplace_back(new_p2, clipping_rectangle, get<2>(uv_rectangle));
670 vertices.emplace_back(new_p3, clipping_rectangle, get<3>(uv_rectangle));
676 left_bottom = left_top;
677 right_bottom = right_top;
678 bottom_increment = top_increment;
@ bottom
Align to the bottom.
Definition alignment.hpp:37
@ top
Align to the top.
Definition alignment.hpp:29
@ right
Align the text to the right side.
Definition alignment.hpp:137
@ left
Align the text to the left side.
Definition alignment.hpp:119
@ other
The gui_event does not have associated data.
Definition gui_event_variant.hpp:22
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
The HikoGUI API version 1.
Definition lookahead_iterator.hpp:6
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
Draw context for drawing using the HikoGUI shaders.
Definition draw_context.hpp:208
Definition gfx_pipeline_image_vulkan.hpp:24
Definition gfx_pipeline_image_vulkan.hpp:55
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