UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
vulkan_display::VulkanDisplay Class Reference

#include <vulkan_display.hpp>

Collaboration diagram for vulkan_display::VulkanDisplay:
Collaboration graph

Classes

struct  RenderedImage
 

Public Member Functions

 VulkanDisplay ()=default
 
 VulkanDisplay (const VulkanDisplay &other)=delete
 
 VulkanDisplay (VulkanDisplay &&other)=delete
 
 ~VulkanDisplay () noexcept
 
TransferImage acquire_image (ImageDescription description)
 
void copy_and_queue_image (unsigned char *frame, ImageDescription description)
 
void destroy ()
 
void discard_image (TransferImage image)
 
bool display_queued_image ()
 
uint32_t get_vulkan_version () const
 
void init (VulkanInstance &&instance, vk::SurfaceKHR surface, uint32_t transfer_image_count, WindowChangedCallback &window, uint32_t gpu_index=no_gpu_selected, std::string path_to_shaders="./shaders", bool vsync=true, bool tearing_permitted=false)
 
bool is_image_description_supported (ImageDescription description)
 
bool is_yCbCr_supported () const
 
VulkanDisplay & operator= (const VulkanDisplay &other)=delete
 
VulkanDisplay & operator= (VulkanDisplay &&other)=delete
 
bool queue_image (TransferImage img, bool discardable)
 
void window_parameters_changed ()
 
void window_parameters_changed (WindowParameters new_parameters)
 Hint to vulkan display that some window parameters spicified in struct WindowParameters changed. Thread-safe.
 

Private Types

using TransferImageImpl = detail::TransferImageImpl
 

Private Member Functions

TransferImageImpl & acquire_transfer_image ()
 
void bind_transfer_image (TransferImageImpl &image, detail::PerFrameResources &resources)
 
void destroy_format_dependent_resources ()
 
void reconfigure (const TransferImageImpl &transfer_image)
 
void record_graphics_commands (detail::PerFrameResources &commands, TransferImageImpl &transfer_image, uint32_t swapchain_image_id)
 

Private Attributes

std::vector< TransferImageImpl * > available_images
 local to provider thread
 
detail::ConcurrentQueue< TransferImageImpl * > available_img_queue {}
 available_img_queue - producer is the render thread, consumer is the provided thread
 
vk::CommandPool command_pool
 
detail::VulkanContext context
 
detail::ConversionPipeline conversion_pipeline
 
ImageDescription current_image_description
 
vk::DescriptorPool descriptor_pool
 
bool destroyed = false
 
vk::Device device
 
std::mutex device_mutex {}
 
detail::ConcurrentQueue< TransferImageImpl *, detail::filled_img_max_count > filled_img_queue {}
 filled_img_queue - producer is the provider thread, consumer is the render thread
 
bool format_conversion_enabled = false
 
std::array< detail::PerFrameResources, 3 > frame_resources
 
std::vector< detail::PerFrameResources * > free_frame_resources
 
std::string path_to_shaders
 
detail::RenderPipeline render_pipeline
 
std::queue< RenderedImage > rendered_images
 
std::deque< TransferImageImpl > transfer_images {}
 
WindowChangedCallback * window = nullptr
 

Detailed Description

Definition at line 84 of file vulkan_display.hpp.

Member Typedef Documentation

◆ TransferImageImpl

Constructor & Destructor Documentation

◆ VulkanDisplay() [1/3]

vulkan_display::VulkanDisplay::VulkanDisplay ( )
default

TERMINOLOGY: render thread - thread which renders queued images on the screen provider thread - thread which calls getf and putf and fills image queue with newly filled images

◆ VulkanDisplay() [2/3]

vulkan_display::VulkanDisplay::VulkanDisplay ( const VulkanDisplay & other)
delete

◆ VulkanDisplay() [3/3]

vulkan_display::VulkanDisplay::VulkanDisplay ( VulkanDisplay && other)
delete

◆ ~VulkanDisplay()

vulkan_display::VulkanDisplay::~VulkanDisplay ( )
inlinenoexcept

Definition at line 144 of file vulkan_display.hpp.

144 {
145 if (!destroyed) {
146 try {
147 destroy();
148 } catch (vk::SystemError &e) {
149 std::string err = std::string("~VulkanDisplay vk::SystemError: ") + e.what() + "\n";
151 }
152 }
153 }
std::function< void(vulkan_display::LogLevel, std::string_view)> vulkan_log_msg

References destroy(), destroyed, vulkan_display::error, and vulkan_display_detail::vulkan_log_msg.

Here is the call graph for this function:

Member Function Documentation

◆ acquire_image()

TransferImage vulkan_display::VulkanDisplay::acquire_image ( ImageDescription description)

Thread-safe to call from provider thread.

Definition at line 418 of file vulkan_display.cpp.

418 {
419 assert(description.size.width * description.size.height != 0);
420 TransferImageImpl& transfer_image = acquire_transfer_image();
421 assert(transfer_image.get_id() != TransferImageImpl::NO_ID);
422
423 if (transfer_image.get_image_description() != description) {
424 std::scoped_lock device_lock(device_mutex);
425 transfer_image.recreate(context, description);
426 }
427
428 return TransferImage{ transfer_image };
429}
detail::VulkanContext context
TransferImageImpl & acquire_transfer_image()
void recreate(VulkanContext &context, vulkan_display::ImageDescription description)
vulkan_display::ImageDescription get_image_description() const
const char * description
Definition cineform.cpp:126

References acquire_transfer_image(), context, description, device_mutex, vulkan_display_detail::TransferImageImpl::get_id(), vulkan_display_detail::TransferImageImpl::get_image_description(), vulkan_display_detail::TransferImageImpl::NO_ID, and vulkan_display_detail::TransferImageImpl::recreate().

Referenced by copy_and_queue_image().

Here is the call graph for this function:

◆ acquire_transfer_image()

TransferImageImpl & vulkan_display::VulkanDisplay::acquire_transfer_image ( )
nodiscardprivate

Definition at line 400 of file vulkan_display.cpp.

400 {
401 TransferImageImpl* result = nullptr;
402 if (!available_images.empty()){
403 result = available_images.back();
404 available_images.pop_back();
405 assert(result != nullptr);
406 return *result;
407 }
408
409 result = available_img_queue.try_pop();
410 if (result != nullptr){
411 return *result;
412 }
413 uint32_t id = transfer_images.size();
414 transfer_images.emplace_back(device, id);
415 return transfer_images.back();
416}
detail::ConcurrentQueue< TransferImageImpl * > available_img_queue
available_img_queue - producer is the render thread, consumer is the provided thread
std::vector< TransferImageImpl * > available_images
local to provider thread
std::deque< TransferImageImpl > transfer_images

References available_images, available_img_queue, device, and transfer_images.

Referenced by acquire_image().

◆ bind_transfer_image()

void vulkan_display::VulkanDisplay::bind_transfer_image ( TransferImageImpl & image,
detail::PerFrameResources & resources )
private

Definition at line 320 of file vulkan_display.cpp.

320 {
321 auto image_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
322 auto descriptor_type = vk::DescriptorType::eCombinedImageSampler;
323
324 auto yCbCr_conversion = format_conversion_enabled ?
326 auto sampler = format_conversion_enabled ?
328 auto descriptor_set = format_conversion_enabled ?
330
331
332 auto view = transfer_image.get_image_view(device, yCbCr_conversion);
333
334 vk::DescriptorImageInfo description_image_info;
335 description_image_info
336 .setImageLayout(image_layout)
337 .setSampler(sampler)
338 .setImageView(view);
339
340 vk::WriteDescriptorSet descriptor_writes{};
341 descriptor_writes
342 .setDstBinding(0)
343 .setDescriptorType(descriptor_type)
344 .setPImageInfo(&description_image_info)
345 .setDescriptorCount(1)
346 .setDstSet(descriptor_set);
347
348 device.updateDescriptorSets(descriptor_writes, nullptr);
349}
detail::ConversionPipeline conversion_pipeline
detail::RenderPipeline render_pipeline
vk::SamplerYcbcrConversion get_yCbCr_conversion()
vk::SamplerYcbcrConversion get_yCbCr_conversion()

References conversion_pipeline, vulkan_display_detail::PerFrameResources::conversion_source_descriptor_set, device, format_conversion_enabled, vulkan_display_detail::TransferImageImpl::get_image_view(), vulkan_display_detail::ConversionPipeline::get_sampler(), vulkan_display_detail::RenderPipeline::get_sampler(), vulkan_display_detail::ConversionPipeline::get_yCbCr_conversion(), vulkan_display_detail::RenderPipeline::get_yCbCr_conversion(), vulkan_display_detail::PerFrameResources::render_descriptor_set, and render_pipeline.

Referenced by display_queued_image().

Here is the call graph for this function:

◆ copy_and_queue_image()

void vulkan_display::VulkanDisplay::copy_and_queue_image ( unsigned char * frame,
ImageDescription description )

Thread-safe to call from provider thread.

Definition at line 431 of file vulkan_display.cpp.

431 {
433 memcpy(image.get_memory_ptr(), frame, image.get_size().height * image.get_row_pitch());
434 queue_image(image, false);
435}
struct video_frame * frame
bool queue_image(TransferImage img, bool discardable)
TransferImage acquire_image(ImageDescription description)

References acquire_image(), description, frame, vulkan_display::TransferImage::get_memory_ptr(), vulkan_display::TransferImage::get_row_pitch(), vulkan_display::TransferImage::get_size(), and queue_image().

Here is the call graph for this function:

◆ destroy()

void vulkan_display::VulkanDisplay::destroy ( )

Definition at line 278 of file vulkan_display.cpp.

278 {
279 if (!destroyed) {
280 destroyed = true;
281 if (device) {
282 device.waitIdle();
283 device.destroy(descriptor_pool);
284
285 for (auto& image : transfer_images) {
286 image.destroy(device);
287 }
288 device.destroy(command_pool);
289 for (auto& resources : frame_resources) {
290 device.destroy(resources.image_acquired_semaphore);
291 device.destroy(resources.image_rendered_semaphore);
292 }
296 }
298 }
299}
std::array< detail::PerFrameResources, 3 > frame_resources
vk::DescriptorPool descriptor_pool

References command_pool, context, conversion_pipeline, descriptor_pool, vulkan_display_detail::ConversionPipeline::destroy(), vulkan_display_detail::RenderPipeline::destroy(), vulkan_display_detail::VulkanContext::destroy(), destroy_format_dependent_resources(), destroyed, device, frame_resources, render_pipeline, and transfer_images.

Referenced by ~VulkanDisplay().

Here is the call graph for this function:

◆ destroy_format_dependent_resources()

void vulkan_display::VulkanDisplay::destroy_format_dependent_resources ( )
private

Definition at line 270 of file vulkan_display.cpp.

270 {
272
273 for(auto& resorces: frame_resources){
274 resorces.converted_image.destroy(device);
275 }
276}

References conversion_pipeline, vulkan_display_detail::ConversionPipeline::destroy(), device, and frame_resources.

Referenced by destroy(), and reconfigure().

Here is the call graph for this function:

◆ discard_image()

void vulkan_display::VulkanDisplay::discard_image ( TransferImage image)
inline

Thread-safe to call from provider thread.

Definition at line 177 of file vulkan_display.hpp.

177 {
178 auto* ptr = image.get_transfer_image();
179 assert(ptr);
180 available_images.push_back(ptr);
181 }

References available_images, and vulkan_display::TransferImage::get_transfer_image().

Here is the call graph for this function:

◆ display_queued_image()

bool vulkan_display::VulkanDisplay::display_queued_image ( )

Thread-safe to call from render thread.

Returns
true if image was displayed

Definition at line 508 of file vulkan_display.cpp.

508 {
509 auto window_parameters = window->get_window_parameters();
510 if (window_parameters.is_minimized()) {
511 discard_filled_image(filled_img_queue, available_img_queue);
512 return false;
513 }
514
515 {
516 std::scoped_lock lock{device_mutex};
517 while (!rendered_images.empty()){
518 auto* first_image = rendered_images.front().image;
519 auto result = device.waitForFences(first_image->is_available_fence, VK_TRUE, 0);
520 if (result == vk::Result::eSuccess){
521 device.resetFences(first_image->is_available_fence);
522 free_frame_resources.push_back(rendered_images.front().gpu_commands);
523 rendered_images.pop();
524 assert(first_image != nullptr);
525 available_img_queue.wait_push(first_image);
526 }
527 else if (result == vk::Result::eTimeout){
528 break;
529 }
530 else {
531 throw VulkanError{"Waiting for fence failed."};
532 }
533 }
534 }
535
536 if(free_frame_resources.empty()){
537 return false;
538 }
539 auto& resources = *free_frame_resources.back();
540 free_frame_resources.pop_back();
541
542 bool frame_resources_used_by_gpu = false;
543 AtScopeExit frame_resources_cleaner{[&](){
544 if(!frame_resources_used_by_gpu){
545 free_frame_resources.push_back(&resources);
546 }
547 }};
548
549 // 24FPS (lowest expected framerate) has a period of approximately 42ms
550 TransferImageImpl* transfer_image_ptr = filled_img_queue.timed_pop(84ms);
551 if (transfer_image_ptr == nullptr) {
552 return false;
553 }
554
555 TransferImageImpl& transfer_image = *transfer_image_ptr;
556 transfer_image.preprocess();
557
558 std::unique_lock lock(device_mutex);
559 if (transfer_image.get_image_description() != current_image_description) {
560 reconfigure(transfer_image);
561 }
562
563 uint32_t swapchain_image_id = context.acquire_next_swapchain_image(resources.image_acquired_semaphore);
564 int swapchain_recreation_attempt = 0;
565 while (swapchain_image_id == swapchain_image_out_of_date || swapchain_image_id == swapchain_image_timeout)
566 {
567 swapchain_recreation_attempt++;
568 if (swapchain_recreation_attempt > 3) {
569 throw VulkanError{"Cannot acquire swapchain image"};
570 }
571
572 auto window_parameters = window->get_window_parameters();
573 if (window_parameters.is_minimized()) {
574 discard_filled_image(filled_img_queue, available_img_queue);
575 return false;
576 }
578 auto render_area_size = context.get_render_area_size();
580
581 swapchain_image_id = context.acquire_next_swapchain_image(resources.image_acquired_semaphore);
582 }
583
584 bind_transfer_image(transfer_image, resources);
585 lock.unlock();
586
587 record_graphics_commands(resources, transfer_image, swapchain_image_id);
588 std::vector<vk::PipelineStageFlags> wait_masks{ vk::PipelineStageFlagBits::eColorAttachmentOutput };
589 vk::SubmitInfo submit_info{};
590 submit_info
591 .setCommandBufferCount(1)
592 .setPCommandBuffers(&resources.command_buffer)
593 .setPWaitDstStageMask(wait_masks.data())
594 .setWaitSemaphoreCount(1)
595 .setPWaitSemaphores(&resources.image_acquired_semaphore)
596 .setSignalSemaphoreCount(1)
597 .setPSignalSemaphores(&resources.image_rendered_semaphore);
598
599 context.get_queue().submit(submit_info, transfer_image.is_available_fence);
600
601 frame_resources_used_by_gpu = true;
602 rendered_images.emplace(RenderedImage{&transfer_image, &resources});
603
604 auto swapchain = context.get_swapchain();
605 vk::PresentInfoKHR present_info{};
606 present_info
607 .setPImageIndices(&swapchain_image_id)
608 .setSwapchainCount(1)
609 .setPSwapchains(&swapchain)
610 .setWaitSemaphoreCount(1)
611 .setPWaitSemaphores(&resources.image_rendered_semaphore);
612
613 auto present_result = context.get_queue().presentKHR(&present_info);
614
615 switch (present_result) {
616 case vk::Result::eSuccess:
617 break;
618 // skip recoverable errors, othervise return/throw error
619 case vk::Result::eErrorOutOfDateKHR:
620 case vk::Result::eSuboptimalKHR:
621 break;
622 default:
623 throw VulkanError{"Error presenting image:"s + vk::to_string(present_result)};
624 }
625
626 return true;
627}
std::queue< RenderedImage > rendered_images
ImageDescription current_image_description
void reconfigure(const TransferImageImpl &transfer_image)
std::vector< detail::PerFrameResources * > free_frame_resources
void bind_transfer_image(TransferImageImpl &image, detail::PerFrameResources &resources)
detail::ConcurrentQueue< TransferImageImpl *, detail::filled_img_max_count > filled_img_queue
filled_img_queue - producer is the provider thread, consumer is the render thread
void record_graphics_commands(detail::PerFrameResources &commands, TransferImageImpl &transfer_image, uint32_t swapchain_image_id)
WindowChangedCallback * window
virtual WindowParameters get_window_parameters()=0
void update_render_area(vk::Extent2D render_area_siza, vk::Extent2D image_size)
void recreate_swapchain(vulkan_display::WindowParameters parameters, vk::RenderPass render_pass)
uint32_t acquire_next_swapchain_image(vk::Semaphore acquire_semaphore) const
constexpr uint32_t swapchain_image_out_of_date
constexpr uint32_t swapchain_image_timeout

References vulkan_display_detail::VulkanContext::acquire_next_swapchain_image(), available_img_queue, bind_transfer_image(), context, current_image_description, device, device_mutex, filled_img_queue, free_frame_resources, vulkan_display_detail::TransferImageImpl::get_image_description(), vulkan_display_detail::VulkanContext::get_queue(), vulkan_display_detail::VulkanContext::get_render_area_size(), vulkan_display_detail::RenderPipeline::get_render_pass(), vulkan_display_detail::VulkanContext::get_swapchain(), vulkan_display::WindowChangedCallback::get_window_parameters(), vulkan_display_detail::TransferImageImpl::is_available_fence, vulkan_display_detail::TransferImageImpl::preprocess(), reconfigure(), record_graphics_commands(), vulkan_display_detail::VulkanContext::recreate_swapchain(), render_pipeline, rendered_images, vulkan_display::ImageDescription::size, vulkan_display_detail::swapchain_image_out_of_date, vulkan_display_detail::swapchain_image_timeout, vulkan_display_detail::RenderPipeline::update_render_area(), and window.

Here is the call graph for this function:

◆ get_vulkan_version()

uint32_t vulkan_display::VulkanDisplay::get_vulkan_version ( ) const
inline

Thread-safe

Definition at line 192 of file vulkan_display.hpp.

References context, and vulkan_display_detail::VulkanContext::get_vulkan_version().

Here is the call graph for this function:

◆ init()

void vulkan_display::VulkanDisplay::init ( VulkanInstance && instance,
vk::SurfaceKHR surface,
uint32_t transfer_image_count,
WindowChangedCallback & window,
uint32_t gpu_index = no_gpu_selected,
std::string path_to_shaders = "./shaders",
bool vsync = true,
bool tearing_permitted = false )

Definition at line 232 of file vulkan_display.cpp.

233 {
234 assert(surface);
235 this->window = &window;
236 this->path_to_shaders = std::move(shaders_path);
237
238 auto window_parameters = window.get_window_parameters();
239
240 context.init(std::move(instance), surface, window_parameters, gpu_index, get_present_mode(vsync, tearing_permitted));
242
243 command_pool = create_command_pool(device, context.get_queue_family_index());
244 descriptor_pool = create_descriptor_pool(device, frame_resources.size());
245
247
249
250 available_images.reserve(initial_image_count);
251 for (uint32_t i = 0; i < initial_image_count; i++) {
252 transfer_images.emplace_back(device, i);
253 available_images.push_back(&transfer_images.back());
254 }
255
256 auto command_buffers = create_command_buffers(device, command_pool, frame_resources.size());
257 for (size_t i = 0; i < frame_resources.size(); i++){
258 auto& resources = frame_resources[i];
259 resources.image_acquired_semaphore = create_semaphore(device);
260 resources.image_rendered_semaphore = create_semaphore(device);
261 resources.command_buffer = command_buffers[i];
262 }
263
265 for(auto& resources: frame_resources){
266 free_frame_resources.emplace_back(&resources);
267 }
268}
void create(VulkanContext &context, const std::string &path_to_shaders)
void create_framebuffers(vk::RenderPass render_pass)
void init(vulkan_display::VulkanInstance &&instance, vk::SurfaceKHR surface, vulkan_display::WindowParameters window_parameters, uint32_t gpu_index, vk::PresentModeKHR preferred_mode)
static class worker_pool instance
Definition worker.cpp:250

References available_images, command_pool, context, vulkan_display_detail::RenderPipeline::create(), vulkan_display_detail::VulkanContext::create_framebuffers(), descriptor_pool, device, frame_resources, free_frame_resources, vulkan_display_detail::VulkanContext::get_device(), vulkan_display_detail::VulkanContext::get_queue_family_index(), vulkan_display_detail::RenderPipeline::get_render_pass(), vulkan_display::WindowChangedCallback::get_window_parameters(), vulkan_display_detail::VulkanContext::init(), instance, path_to_shaders, render_pipeline, transfer_images, and window.

Here is the call graph for this function:

◆ is_image_description_supported()

bool vulkan_display::VulkanDisplay::is_image_description_supported ( ImageDescription description)

Thread-safe

Definition at line 301 of file vulkan_display.cpp.

301 {
302 std::scoped_lock lock(device_mutex);
303
304 auto& format_info = description.format_info();
306 format_info.buffer_format, vk::ImageTiling::eLinear, vk::ImageUsageFlagBits::eSampled))
307 {
308 return false;;
309 }
310
311 if (format_info.conversion_image_format == vk::Format::eUndefined){
312 return true;
313 }
314
316 format_info.conversion_image_format, vk::ImageTiling::eOptimal,
317 vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eStorage);
318}
static bool is_format_supported(void *data, size_t *len)
Definition pipewire.cpp:163
vk::Extent2D get_buffer_size(const vulkan_display::ImageDescription &description)
const FormatInfo & format_info(vulkan_display::Format format)

References vulkan_display_detail::FormatInfo::buffer_format, context, vulkan_display_detail::FormatInfo::conversion_image_format, description, device_mutex, vulkan_display_detail::format_info(), vulkan_display_detail::get_buffer_size(), vulkan_display_detail::VulkanContext::get_gpu(), is_format_supported(), and vulkan_display_detail::VulkanContext::is_yCbCr_supported().

Here is the call graph for this function:

◆ is_yCbCr_supported()

bool vulkan_display::VulkanDisplay::is_yCbCr_supported ( ) const
inline

Thread-safe

Definition at line 195 of file vulkan_display.hpp.

195{ return context.is_yCbCr_supported(); }

References context, and vulkan_display_detail::VulkanContext::is_yCbCr_supported().

Here is the call graph for this function:

◆ operator=() [1/2]

VulkanDisplay & vulkan_display::VulkanDisplay::operator= ( const VulkanDisplay & other)
delete

◆ operator=() [2/2]

VulkanDisplay & vulkan_display::VulkanDisplay::operator= ( VulkanDisplay && other)
delete

◆ queue_image()

bool vulkan_display::VulkanDisplay::queue_image ( TransferImage img,
bool discardable )

Thread-safe to call from provider thread.

Returns
true if image was discarded

Definition at line 437 of file vulkan_display.cpp.

437 {
438 assert(image.get_transfer_image() != nullptr);
439 if(!discardable){
440 filled_img_queue.wait_push(image.get_transfer_image());
441 return false;
442 }
443
444 auto removed = filled_img_queue.force_push(image.get_transfer_image());
445 if (removed != nullptr){
446 available_images.push_back(removed);
447 return true;
448 }
449 return false;
450}

References available_images, filled_img_queue, and vulkan_display::TransferImage::get_transfer_image().

Referenced by copy_and_queue_image().

Here is the call graph for this function:

◆ reconfigure()

void vulkan_display::VulkanDisplay::reconfigure ( const TransferImageImpl & transfer_image)
private

Definition at line 452 of file vulkan_display.cpp.

452 {
453 auto image_description = transfer_image.get_image_description();
454 auto& image_format_info = image_description.format_info();
455
456 if (image_description != current_image_description) {
457 vulkan_log_msg(LogLevel::info, "Recreating render_pipeline");
458 context.get_queue().waitIdle();
459 device.resetDescriptorPool(descriptor_pool);
460
462
463 format_conversion_enabled = !image_format_info.conversion_shader.empty();
464
466 image_format_info.conversion_image_format : image_format_info.buffer_format);
467
468 auto descriptor_sets = allocate_description_sets(device, descriptor_pool,
470 for(size_t i = 0; i < frame_resources.size(); i++){
471 frame_resources[i].render_descriptor_set = descriptor_sets[i];
472 }
473
475 auto shader_path = path_to_shaders + "/" + image_format_info.conversion_shader + ".comp.spv";
476 conversion_pipeline.create(device, shader_path, image_format_info.buffer_format);
477 vk::Extent2D image_size = transfer_image.get_image_description().size;
478 for(size_t i = 0; i < frame_resources.size(); i++){
479 frame_resources[i].converted_image.init(
480 context,
481 image_size,
482 image_format_info.conversion_image_format,
483 vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eSampled,
484 vk::AccessFlagBits::eShaderWrite,
485 InitialImageData::undefined, MemoryLocation::device_local);
486 }
487 auto conversion_source_descriptor_sets = allocate_description_sets(device, descriptor_pool,
489 auto conversion_destination_descriptor_sets = allocate_description_sets(device, descriptor_pool,
491 for(size_t i = 0; i < frame_resources.size(); i++){
492 assert(conversion_source_descriptor_sets.size() == frame_resources.size());
493 assert(conversion_destination_descriptor_sets.size() == frame_resources.size());
494 auto& resources = frame_resources[i];
495 resources.conversion_source_descriptor_set = conversion_source_descriptor_sets[i];
496 resources.conversion_destination_descriptor_set = conversion_destination_descriptor_sets[i];
497 }
498
499 bind_conversion_images(device, conversion_pipeline.get_sampler(), frame_resources);
500 }
501 }
502
504 auto render_area_size = context.get_render_area_size();
506}
vk::DescriptorSetLayout get_destination_image_desc_set_layout()
void create(vk::Device device, const std::string &shader_path, vk::Format format)
vk::DescriptorSetLayout get_source_image_desc_set_layout()
vk::DescriptorSetLayout get_image_desc_set_layout()
void reconfigure(vk::Device device, vk::Format sampler)
const detail::FormatInfo & format_info() const

References context, conversion_pipeline, vulkan_display_detail::ConversionPipeline::create(), current_image_description, descriptor_pool, destroy_format_dependent_resources(), device, format_conversion_enabled, vulkan_display::ImageDescription::format_info(), frame_resources, vulkan_display_detail::ConversionPipeline::get_destination_image_desc_set_layout(), vulkan_display_detail::RenderPipeline::get_image_desc_set_layout(), vulkan_display_detail::TransferImageImpl::get_image_description(), vulkan_display_detail::VulkanContext::get_queue(), vulkan_display_detail::VulkanContext::get_render_area_size(), vulkan_display_detail::ConversionPipeline::get_sampler(), vulkan_display_detail::ConversionPipeline::get_source_image_desc_set_layout(), vulkan_display::info, path_to_shaders, vulkan_display_detail::RenderPipeline::reconfigure(), render_pipeline, vulkan_display::ImageDescription::size, vulkan_display_detail::RenderPipeline::update_render_area(), and vulkan_display_detail::vulkan_log_msg.

Referenced by display_queued_image().

Here is the call graph for this function:

◆ record_graphics_commands()

void vulkan_display::VulkanDisplay::record_graphics_commands ( detail::PerFrameResources & commands,
TransferImageImpl & transfer_image,
uint32_t swapchain_image_id )
private

Definition at line 351 of file vulkan_display.cpp.

353{
354 vk::CommandBuffer cmd_buffer = frame_resources.command_buffer;
355 cmd_buffer.reset(vk::CommandBufferResetFlags{});
356
357 vk::CommandBufferBeginInfo begin_info{};
358 begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
359 cmd_buffer.begin(begin_info);
360
363 auto conversion_image_memory_barrier = frame_resources.converted_image.create_memory_barrier(
364 vk::ImageLayout::eGeneral, vk::AccessFlagBits::eShaderWrite);
365 cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader, vk::PipelineStageFlagBits::eComputeShader,
366 vk::DependencyFlagBits::eByRegion, nullptr, nullptr, conversion_image_memory_barrier);
367 }
368
369 auto transfer_image_memory_barrier = transfer_image.get_buffer().create_memory_barrier(
370 vk::ImageLayout::eShaderReadOnlyOptimal, vk::AccessFlagBits::eShaderRead);
371 cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eComputeShader,
372 vk::DependencyFlagBits::eByRegion, nullptr, nullptr, transfer_image_memory_barrier);
373
374 auto image_size = ImageSize::fromExtent2D(frame_resources.converted_image.size);
375 conversion_pipeline.record_commands(cmd_buffer, image_size,
376 {frame_resources.conversion_source_descriptor_set,
377 frame_resources.conversion_destination_descriptor_set});
378 }
379
380 Image2D& rendered_image = format_conversion_enabled ? frame_resources.converted_image : transfer_image.get_buffer();
381 auto render_begin_memory_barrier = rendered_image.create_memory_barrier(
382 vk::ImageLayout::eShaderReadOnlyOptimal, vk::AccessFlagBits::eShaderRead);
383 auto previous_stage = format_conversion_enabled ?
384 vk::PipelineStageFlagBits::eComputeShader : vk::PipelineStageFlagBits::eHost;
385 cmd_buffer.pipelineBarrier(previous_stage, vk::PipelineStageFlagBits::eFragmentShader,
386 vk::DependencyFlagBits::eByRegion, nullptr, nullptr, render_begin_memory_barrier);
387
388 render_pipeline.record_commands(cmd_buffer, frame_resources.render_descriptor_set,
389 context.get_framebuffer(swapchain_image_id));
390
391 auto transfer_image_memory_barrier = transfer_image.get_buffer().create_memory_barrier(
392 vk::ImageLayout::eGeneral, vk::AccessFlagBits::eHostWrite | vk::AccessFlagBits::eHostRead);
393 auto transfer_image_last_stage = format_conversion_enabled ?
394 vk::PipelineStageFlagBits::eComputeShader : vk::PipelineStageFlagBits::eFragmentShader;
395 cmd_buffer.pipelineBarrier(transfer_image_last_stage, vk::PipelineStageFlagBits::eHost,
396 vk::DependencyFlagBits::eByRegion, nullptr, nullptr, transfer_image_memory_barrier);
397 cmd_buffer.end();
398}
void record_commands(vk::CommandBuffer cmd_buffer, ImageSize image_size, std::array< vk::DescriptorSet, 2 > descriptor_set)
vk::ImageMemoryBarrier create_memory_barrier(vk::ImageLayout new_layout, vk::AccessFlags new_access_mask, uint32_t src_queue_family_index=VK_QUEUE_FAMILY_IGNORED, uint32_t dst_queue_family_index=VK_QUEUE_FAMILY_IGNORED)
void record_commands(vk::CommandBuffer cmd_buffer, vk::DescriptorSet image, vk::Framebuffer framebuffer)
vk::Framebuffer get_framebuffer(uint32_t framebuffer_id)
static ImageSize fromExtent2D(vk::Extent2D extent)

References context, conversion_pipeline, vulkan_display_detail::Image2D::create_memory_barrier(), format_conversion_enabled, frame_resources, vulkan_display_detail::ImageSize::fromExtent2D(), vulkan_display_detail::TransferImageImpl::get_buffer(), vulkan_display_detail::VulkanContext::get_framebuffer(), vulkan_display_detail::ConversionPipeline::record_commands(), vulkan_display_detail::RenderPipeline::record_commands(), and render_pipeline.

Referenced by display_queued_image().

Here is the call graph for this function:

◆ window_parameters_changed() [1/2]

void vulkan_display::VulkanDisplay::window_parameters_changed ( )
inline

Thread-safe

Definition at line 205 of file vulkan_display.hpp.

References vulkan_display::WindowChangedCallback::get_window_parameters(), window, and window_parameters_changed().

Referenced by window_parameters_changed().

Here is the call graph for this function:

◆ window_parameters_changed() [2/2]

void vulkan_display::VulkanDisplay::window_parameters_changed ( WindowParameters new_parameters)

Member Data Documentation

◆ available_images

std::vector<TransferImageImpl*> vulkan_display::VulkanDisplay::available_images
private

local to provider thread

Definition at line 113 of file vulkan_display.hpp.

Referenced by acquire_transfer_image(), discard_image(), init(), and queue_image().

◆ available_img_queue

detail::ConcurrentQueue<TransferImageImpl*> vulkan_display::VulkanDisplay::available_img_queue {}
private

available_img_queue - producer is the render thread, consumer is the provided thread

Definition at line 109 of file vulkan_display.hpp.

109{};

Referenced by acquire_transfer_image(), and display_queued_image().

◆ command_pool

vk::CommandPool vulkan_display::VulkanDisplay::command_pool
private

Definition at line 98 of file vulkan_display.hpp.

Referenced by destroy(), and init().

◆ context

◆ conversion_pipeline

detail::ConversionPipeline vulkan_display::VulkanDisplay::conversion_pipeline
private

◆ current_image_description

ImageDescription vulkan_display::VulkanDisplay::current_image_description
private

◆ descriptor_pool

vk::DescriptorPool vulkan_display::VulkanDisplay::descriptor_pool
private

Definition at line 97 of file vulkan_display.hpp.

Referenced by destroy(), init(), and reconfigure().

◆ destroyed

bool vulkan_display::VulkanDisplay::destroyed = false
private

Definition at line 121 of file vulkan_display.hpp.

Referenced by ~VulkanDisplay(), and destroy().

◆ device

vk::Device vulkan_display::VulkanDisplay::device
private

◆ device_mutex

std::mutex vulkan_display::VulkanDisplay::device_mutex {}
private

◆ filled_img_queue

detail::ConcurrentQueue<TransferImageImpl*, detail::filled_img_max_count> vulkan_display::VulkanDisplay::filled_img_queue {}
private

filled_img_queue - producer is the provider thread, consumer is the render thread

Definition at line 111 of file vulkan_display.hpp.

111{};

Referenced by display_queued_image(), and queue_image().

◆ format_conversion_enabled

bool vulkan_display::VulkanDisplay::format_conversion_enabled = false
private

Definition at line 92 of file vulkan_display.hpp.

Referenced by bind_transfer_image(), reconfigure(), and record_graphics_commands().

◆ frame_resources

std::array<detail::PerFrameResources, 3> vulkan_display::VulkanDisplay::frame_resources
private

◆ free_frame_resources

std::vector<detail::PerFrameResources*> vulkan_display::VulkanDisplay::free_frame_resources
private

Definition at line 101 of file vulkan_display.hpp.

Referenced by display_queued_image(), and init().

◆ path_to_shaders

std::string vulkan_display::VulkanDisplay::path_to_shaders
private

Definition at line 85 of file vulkan_display.hpp.

Referenced by init(), and reconfigure().

◆ render_pipeline

detail::RenderPipeline vulkan_display::VulkanDisplay::render_pipeline
private

◆ rendered_images

std::queue<RenderedImage> vulkan_display::VulkanDisplay::rendered_images
private

Definition at line 119 of file vulkan_display.hpp.

Referenced by display_queued_image().

◆ transfer_images

std::deque<TransferImageImpl> vulkan_display::VulkanDisplay::transfer_images {}
private

Definition at line 106 of file vulkan_display.hpp.

106{};

Referenced by acquire_transfer_image(), destroy(), and init().

◆ window

WindowChangedCallback* vulkan_display::VulkanDisplay::window = nullptr
private

Definition at line 86 of file vulkan_display.hpp.

Referenced by display_queued_image(), init(), and window_parameters_changed().


The documentation for this class was generated from the following files: