UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
vulkan_display.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2021-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include "vulkan_display.hpp"
39
40#include <algorithm>
41#include <cmath>
42#include <cstdint>
43#include <cstring>
44#include <fstream>
45#include <iostream>
46#include <memory>
47#include <tuple>
48#include <utility>
49#include <vector>
50
51using namespace vulkan_display_detail;
52using namespace vulkan_display;
53
54namespace {
55constexpr bool is_yCbCr_format(vk::Format format) {
56 auto f = static_cast<VkFormat>(format);
57 return VK_FORMAT_G8B8G8R8_422_UNORM <= f && f <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
58}
59
60vk::PresentModeKHR get_present_mode(bool vsync_enabled, bool tearing_permitted){
61 using Mode = vk::PresentModeKHR;
62 if (vsync_enabled){
63 return tearing_permitted ? Mode::eFifoRelaxed : Mode::eFifo;
64 }
65 return tearing_permitted ? Mode::eImmediate : Mode::eMailbox;
66}
67
68void discard_filled_image(ConcurrentQueue<TransferImageImpl*, filled_img_max_count>& filled_img_queue,
69 ConcurrentQueue<TransferImageImpl*>& available_img_queue)
70{
71 TransferImageImpl* transfer_image = filled_img_queue.try_pop();
72 if (transfer_image != nullptr) {
73 available_img_queue.wait_push(transfer_image);
74 }
75}
76
77vk::CommandPool create_command_pool(vk::Device device, uint32_t queue_family_index) {
78 vk::CommandPoolCreateInfo pool_info{};
79 using Bits = vk::CommandPoolCreateFlagBits;
80 pool_info
81 .setQueueFamilyIndex(queue_family_index)
82 .setFlags(Bits::eTransient | Bits::eResetCommandBuffer);
83 return device.createCommandPool(pool_info);
84}
85
86std::vector<vk::CommandBuffer> create_command_buffers(vk::Device device, vk::CommandPool command_pool, uint32_t count) {
87 vk::CommandBufferAllocateInfo allocate_info{};
88 allocate_info
89 .setCommandPool(command_pool)
90 .setLevel(vk::CommandBufferLevel::ePrimary)
91 .setCommandBufferCount(count);
92 return device.allocateCommandBuffers(allocate_info);
93}
94
95vk::Semaphore create_semaphore(vk::Device device) {
96 vk::SemaphoreCreateInfo semaphore_info{};
97 return device.createSemaphore(semaphore_info);
98}
99
100vk::DescriptorPool create_descriptor_pool(vk::Device device, size_t descriptor_count){
101 std::array<vk::DescriptorPoolSize,2> descriptor_sizes{};
102 descriptor_sizes[0]
103 .setType(vk::DescriptorType::eCombinedImageSampler)
104 .setDescriptorCount(descriptor_count * 2);
105
106 descriptor_sizes[1]
107 .setType(vk::DescriptorType::eStorageImage)
108 .setDescriptorCount(descriptor_count);
109
110 vk::DescriptorPoolCreateInfo pool_info{};
111 pool_info
112 .setPoolSizeCount(descriptor_sizes.size())
113 .setPPoolSizes(descriptor_sizes.data())
114 .setMaxSets(descriptor_count * 3);
115 return device.createDescriptorPool(pool_info);
116}
117
118std::vector<vk::DescriptorSet> allocate_description_sets(vk::Device device, vk::DescriptorPool pool, vk::DescriptorSetLayout layout, size_t descriptor_count) {
119 std::vector<vk::DescriptorSetLayout> layouts(descriptor_count, layout);
120
121 vk::DescriptorSetAllocateInfo allocate_info;
122 allocate_info
123 .setDescriptorPool(pool)
124 .setDescriptorSetCount(static_cast<uint32_t>(layouts.size()))
125 .setPSetLayouts(layouts.data());
126
127 return device.allocateDescriptorSets(allocate_info);
128}
129
130template<size_t frame_count>
131void bind_conversion_images(vk::Device device, vk::Sampler sampler,
132 std::array<PerFrameResources, frame_count>& frame_resources)
133{
134 std::vector<vk::DescriptorImageInfo> descriptor_image_infos;
135 descriptor_image_infos.reserve(frame_resources.size() * 2);
136
137 std::vector<vk::WriteDescriptorSet> descriptor_writes;
138 descriptor_writes.reserve(frame_resources.size() * 2);
139
140
141 vk::DescriptorImageInfo store_image_info;
142 store_image_info
143 .setImageLayout(vk::ImageLayout::eGeneral);
144
145 vk::WriteDescriptorSet store_write{};
146 store_write
147 .setDstBinding(1)
148 .setDescriptorType(vk::DescriptorType::eStorageImage)
149 .setDescriptorCount(1);
150
151 vk::DescriptorImageInfo sample_image_info;
152 sample_image_info
153 .setSampler(sampler)
154 .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
155
156 vk::WriteDescriptorSet sample_write{};
157 sample_write
158 .setDstBinding(0)
159 .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
160 .setDescriptorCount(1);
161
162
163 for(size_t i = 0; i < frame_resources.size(); i++){
164 auto view = frame_resources[i].converted_image.get_image_view(device, nullptr);
165 store_image_info.imageView = view;
166 sample_image_info.imageView = view;
167
168 store_write.setDstSet(frame_resources[i].conversion_destination_descriptor_set);
169 sample_write.setDstSet(frame_resources[i].render_descriptor_set);
170
171 descriptor_image_infos.push_back(store_image_info);
172 store_write.setPImageInfo(&descriptor_image_infos.back());
173 descriptor_writes.push_back(store_write);
174
175 descriptor_image_infos.push_back(sample_image_info);
176 sample_write.setPImageInfo(&descriptor_image_infos.back());
177 descriptor_writes.push_back(sample_write);
178 }
179 device.updateDescriptorSets(descriptor_writes, nullptr);
180}
181
182template<typename Fun>
183class AtScopeExit {
184private:
185 Fun function;
186public:
187 AtScopeExit(Fun function) :
188 function{std::move(function)} { }
189
190 ~AtScopeExit(){ function(); };
191
192 AtScopeExit(const AtScopeExit& other) = delete;
193 AtScopeExit& operator=(const AtScopeExit& other) = delete;
194 AtScopeExit(AtScopeExit&& other) = delete;
195 AtScopeExit& operator=(AtScopeExit&& other) = delete;
196};
197
199bool is_format_supported(vk::PhysicalDevice gpu, bool is_yCbCr_supported, vk::Extent2D size, vk::Format format,
200 vk::ImageTiling tiling, vk::ImageUsageFlags usage_flags)
201{
202 if (!is_yCbCr_supported && is_yCbCr_format(format)){
203 return false;
204 }
205 vk::ImageFormatProperties properties;
206 auto result = gpu.getImageFormatProperties(
207 format,
208 vk::ImageType::e2D,
209 tiling,
210 usage_flags,
211 {},
212 &properties);
213 switch (result){
214 case vk::Result::eSuccess:
215 break;
216 case vk::Result::eErrorFormatNotSupported:
217 return false;
218 default:
219 throw VulkanError{"Error queriing image properties."};
220 }
221
222 return size.height <= properties.maxExtent.height
223 && size.width <= properties.maxExtent.width;
224}
225
226
227} //namespace -------------------------------------------------------------
228
229
230namespace vulkan_display {
231
232void VulkanDisplay::init(VulkanInstance&& instance, vk::SurfaceKHR surface, uint32_t initial_image_count,
233 WindowChangedCallback& window, uint32_t gpu_index, std::string shaders_path, bool vsync, bool tearing_permitted) {
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}
269
272
273 for(auto& resorces: frame_resources){
274 resorces.converted_image.destroy(device);
275 }
276}
277
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}
300
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}
319
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}
350
352 TransferImageImpl& transfer_image, uint32_t swapchain_image_id)
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}
399
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}
417
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}
430
433 memcpy(image.get_memory_ptr(), frame, image.get_size().height * image.get_row_pitch());
434 queue_image(image, false);
435}
436
437bool VulkanDisplay::queue_image(TransferImage image, bool discardable) {
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}
451
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}
507
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}
628
630 if (new_parameters != context.get_window_parameters() && !new_parameters.is_minimized()) {
631 std::scoped_lock lock{device_mutex};
633 auto render_area_size = context.get_render_area_size();
635 }
636}
637
638} //namespace vulkan_display
struct video_frame * frame
static bool is_format_supported(void *data, size_t *len)
Definition pipewire.cpp:163
vulkan_display_detail::TransferImageImpl * get_transfer_image()
detail::ConversionPipeline conversion_pipeline
detail::VulkanContext context
TransferImageImpl & acquire_transfer_image()
detail::RenderPipeline render_pipeline
std::array< detail::PerFrameResources, 3 > frame_resources
std::queue< RenderedImage > rendered_images
detail::ConcurrentQueue< TransferImageImpl * > available_img_queue
available_img_queue - producer is the render thread, consumer is the provided thread
bool queue_image(TransferImage img, bool discardable)
void copy_and_queue_image(unsigned char *frame, ImageDescription description)
vk::DescriptorPool descriptor_pool
ImageDescription current_image_description
void reconfigure(const TransferImageImpl &transfer_image)
std::vector< detail::PerFrameResources * > free_frame_resources
bool is_image_description_supported(ImageDescription description)
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)
void bind_transfer_image(TransferImageImpl &image, detail::PerFrameResources &resources)
std::vector< TransferImageImpl * > available_images
local to provider thread
detail::ConcurrentQueue< TransferImageImpl *, detail::filled_img_max_count > filled_img_queue
filled_img_queue - producer is the provider thread, consumer is the render thread
std::deque< TransferImageImpl > transfer_images
void record_graphics_commands(detail::PerFrameResources &commands, TransferImageImpl &transfer_image, uint32_t swapchain_image_id)
TransferImage acquire_image(ImageDescription description)
WindowChangedCallback * window
virtual WindowParameters get_window_parameters()=0
vk::SamplerYcbcrConversion get_yCbCr_conversion()
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()
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)
void update_render_area(vk::Extent2D render_area_siza, vk::Extent2D image_size)
vk::DescriptorSetLayout get_image_desc_set_layout()
void create(VulkanContext &context, const std::string &path_to_shaders)
vk::SamplerYcbcrConversion get_yCbCr_conversion()
void reconfigure(vk::Device device, vk::Format sampler)
void recreate(VulkanContext &context, vulkan_display::ImageDescription description)
vk::ImageView get_image_view(vk::Device device, vk::SamplerYcbcrConversion conversion)
vulkan_display::ImageDescription get_image_description() const
vk::Framebuffer get_framebuffer(uint32_t framebuffer_id)
void recreate_swapchain(vulkan_display::WindowParameters parameters, vk::RenderPass render_pass)
uint32_t acquire_next_swapchain_image(vk::Semaphore acquire_semaphore) const
vulkan_display::WindowParameters get_window_parameters() const
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)
int count
Definition hd-rum.c:44
constexpr bool is_yCbCr_format(vk::Format format)
std::function< void(vulkan_display::LogLevel, std::string_view)> vulkan_log_msg
vk::Extent2D get_buffer_size(const vulkan_display::ImageDescription &description)
constexpr uint32_t swapchain_image_out_of_date
const FormatInfo & format_info(vulkan_display::Format format)
constexpr uint32_t swapchain_image_timeout
const detail::FormatInfo & format_info() const
constexpr bool is_minimized() const
static ImageSize fromExtent2D(vk::Extent2D extent)
const char * description
Definition cineform.cpp:126
static class worker_pool instance
Definition worker.cpp:250