diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index abbf218f5..47290cbcb 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -176,7 +176,9 @@ if (ENABLE_VULKAN) renderer_vulkan/vk_stream_buffer.cpp renderer_vulkan/vk_stream_buffer.h renderer_vulkan/vk_swapchain.cpp - renderer_vulkan/vk_swapchain.h) + renderer_vulkan/vk_swapchain.h + renderer_vulkan/vk_update_descriptor.cpp + renderer_vulkan/vk_update_descriptor.h) target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) target_compile_definitions(video_core PRIVATE HAS_VULKAN) diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp new file mode 100644 index 000000000..0e577b9ff --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp @@ -0,0 +1,57 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/assert.h" +#include "common/logging/log.h" +#include "video_core/renderer_vulkan/declarations.h" +#include "video_core/renderer_vulkan/vk_device.h" +#include "video_core/renderer_vulkan/vk_scheduler.h" +#include "video_core/renderer_vulkan/vk_update_descriptor.h" + +namespace Vulkan { + +VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler) + : device{device}, scheduler{scheduler} {} + +VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default; + +void VKUpdateDescriptorQueue::TickFrame() { + payload.clear(); +} + +void VKUpdateDescriptorQueue::Acquire() { + entries.clear(); +} + +void VKUpdateDescriptorQueue::Send(vk::DescriptorUpdateTemplate update_template, + vk::DescriptorSet set) { + if (payload.size() + entries.size() >= payload.max_size()) { + LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread"); + scheduler.WaitWorker(); + payload.clear(); + } + + const auto payload_start = payload.data() + payload.size(); + for (const auto& entry : entries) { + if (const auto image = std::get_if(&entry)) { + payload.push_back(*image); + } else if (const auto buffer = std::get_if(&entry)) { + payload.emplace_back(*buffer->buffer, buffer->offset, buffer->size); + } else if (const auto texel = std::get_if(&entry)) { + payload.push_back(*texel); + } else { + UNREACHABLE(); + } + } + + scheduler.Record([dev = device.GetLogical(), payload_start, set, + update_template]([[maybe_unused]] auto cmdbuf, auto& dld) { + dev.updateDescriptorSetWithTemplate(set, update_template, payload_start, dld); + }); +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h new file mode 100644 index 000000000..8c825aa29 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h @@ -0,0 +1,86 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/common_types.h" +#include "video_core/renderer_vulkan/declarations.h" + +namespace Vulkan { + +class VKDevice; +class VKScheduler; + +class DescriptorUpdateEntry { +public: + explicit DescriptorUpdateEntry() : image{} {} + + DescriptorUpdateEntry(vk::DescriptorImageInfo image) : image{image} {} + + DescriptorUpdateEntry(vk::Buffer buffer, vk::DeviceSize offset, vk::DeviceSize size) + : buffer{buffer, offset, size} {} + + DescriptorUpdateEntry(vk::BufferView texel_buffer) : texel_buffer{texel_buffer} {} + +private: + union { + vk::DescriptorImageInfo image; + vk::DescriptorBufferInfo buffer; + vk::BufferView texel_buffer; + }; +}; + +class VKUpdateDescriptorQueue final { +public: + explicit VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler); + ~VKUpdateDescriptorQueue(); + + void TickFrame(); + + void Acquire(); + + void Send(vk::DescriptorUpdateTemplate update_template, vk::DescriptorSet set); + + void AddSampledImage(vk::Sampler sampler, vk::ImageView image_view) { + entries.emplace_back(vk::DescriptorImageInfo{sampler, image_view, {}}); + } + + void AddImage(vk::ImageView image_view) { + entries.emplace_back(vk::DescriptorImageInfo{{}, image_view, {}}); + } + + void AddBuffer(const vk::Buffer* buffer, u64 offset, std::size_t size) { + entries.push_back(Buffer{buffer, offset, size}); + } + + void AddTexelBuffer(vk::BufferView texel_buffer) { + entries.emplace_back(texel_buffer); + } + + vk::ImageLayout* GetLastImageLayout() { + return &std::get(entries.back()).imageLayout; + } + +private: + struct Buffer { + const vk::Buffer* buffer{}; + u64 offset{}; + std::size_t size{}; + }; + using Variant = std::variant; + // Old gcc versions don't consider this trivially copyable. + // static_assert(std::is_trivially_copyable_v); + + const VKDevice& device; + VKScheduler& scheduler; + + boost::container::static_vector entries; + boost::container::static_vector payload; +}; + +} // namespace Vulkan