vk_update_descriptor: Initial implementation
The update descriptor is used to store in flat memory a large chunk of staging data used to update descriptor sets through templates. It provides a push interface to easily insert descriptors following the current pipeline. The order used in the descriptor update template has to be implicitly followed. We can catch bugs here using validation layers.
This commit is contained in:
parent
89fc75d769
commit
322d6a0311
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <variant>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#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<vk::DescriptorImageInfo>(&entry)) {
|
||||
payload.push_back(*image);
|
||||
} else if (const auto buffer = std::get_if<Buffer>(&entry)) {
|
||||
payload.emplace_back(*buffer->buffer, buffer->offset, buffer->size);
|
||||
} else if (const auto texel = std::get_if<vk::BufferView>(&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
|
|
@ -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 <type_traits>
|
||||
#include <variant>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#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<vk::DescriptorImageInfo>(entries.back()).imageLayout;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Buffer {
|
||||
const vk::Buffer* buffer{};
|
||||
u64 offset{};
|
||||
std::size_t size{};
|
||||
};
|
||||
using Variant = std::variant<vk::DescriptorImageInfo, Buffer, vk::BufferView>;
|
||||
// Old gcc versions don't consider this trivially copyable.
|
||||
// static_assert(std::is_trivially_copyable_v<Variant>);
|
||||
|
||||
const VKDevice& device;
|
||||
VKScheduler& scheduler;
|
||||
|
||||
boost::container::static_vector<Variant, 0x400> entries;
|
||||
boost::container::static_vector<DescriptorUpdateEntry, 0x10000> payload;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
Loading…
Reference in New Issue