summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_vulkan/pipeline_helper.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_vulkan/pipeline_helper.h')
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
new file mode 100644
index 000000000..4847db6b6
--- /dev/null
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -0,0 +1,154 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstddef>
+
+#include <boost/container/small_vector.hpp>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "shader_recompiler/shader_info.h"
+#include "video_core/renderer_vulkan/vk_texture_cache.h"
+#include "video_core/renderer_vulkan/vk_update_descriptor.h"
+#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/types.h"
+#include "video_core/textures/texture.h"
+#include "video_core/vulkan_common/vulkan_device.h"
+
+namespace Vulkan {
+
+class DescriptorLayoutBuilder {
+public:
+ DescriptorLayoutBuilder(const Device& device_) : device{&device_} {}
+
+ bool CanUsePushDescriptor() const noexcept {
+ return device->IsKhrPushDescriptorSupported() &&
+ num_descriptors <= device->MaxPushDescriptors();
+ }
+
+ vk::DescriptorSetLayout CreateDescriptorSetLayout(bool use_push_descriptor) const {
+ if (bindings.empty()) {
+ return nullptr;
+ }
+ const VkDescriptorSetLayoutCreateFlags flags =
+ use_push_descriptor ? VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR : 0;
+ return device->GetLogical().CreateDescriptorSetLayout({
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = flags,
+ .bindingCount = static_cast<u32>(bindings.size()),
+ .pBindings = bindings.data(),
+ });
+ }
+
+ vk::DescriptorUpdateTemplateKHR CreateTemplate(VkDescriptorSetLayout descriptor_set_layout,
+ VkPipelineLayout pipeline_layout,
+ bool use_push_descriptor) const {
+ if (entries.empty()) {
+ return nullptr;
+ }
+ const VkDescriptorUpdateTemplateType type =
+ use_push_descriptor ? VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR
+ : VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR;
+ return device->GetLogical().CreateDescriptorUpdateTemplateKHR({
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .flags = 0,
+ .descriptorUpdateEntryCount = static_cast<u32>(entries.size()),
+ .pDescriptorUpdateEntries = entries.data(),
+ .templateType = type,
+ .descriptorSetLayout = descriptor_set_layout,
+ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+ .pipelineLayout = pipeline_layout,
+ .set = 0,
+ });
+ }
+
+ vk::PipelineLayout CreatePipelineLayout(VkDescriptorSetLayout descriptor_set_layout) const {
+ return device->GetLogical().CreatePipelineLayout({
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .setLayoutCount = descriptor_set_layout ? 1U : 0U,
+ .pSetLayouts = bindings.empty() ? nullptr : &descriptor_set_layout,
+ .pushConstantRangeCount = 0,
+ .pPushConstantRanges = nullptr,
+ });
+ }
+
+ void Add(const Shader::Info& info, VkShaderStageFlags stage) {
+ Add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stage, info.constant_buffer_descriptors);
+ Add(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stage, info.storage_buffers_descriptors);
+ Add(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, stage, info.texture_buffer_descriptors);
+ Add(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, stage, info.image_buffer_descriptors);
+ Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage, info.texture_descriptors);
+ Add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stage, info.image_descriptors);
+ }
+
+private:
+ template <typename Descriptors>
+ void Add(VkDescriptorType type, VkShaderStageFlags stage, const Descriptors& descriptors) {
+ const size_t num{descriptors.size()};
+ for (size_t i = 0; i < num; ++i) {
+ bindings.push_back({
+ .binding = binding,
+ .descriptorType = type,
+ .descriptorCount = descriptors[i].count,
+ .stageFlags = stage,
+ .pImmutableSamplers = nullptr,
+ });
+ entries.push_back({
+ .dstBinding = binding,
+ .dstArrayElement = 0,
+ .descriptorCount = descriptors[i].count,
+ .descriptorType = type,
+ .offset = offset,
+ .stride = sizeof(DescriptorUpdateEntry),
+ });
+ ++binding;
+ num_descriptors += descriptors[i].count;
+ offset += sizeof(DescriptorUpdateEntry);
+ }
+ }
+
+ const Device* device{};
+ boost::container::small_vector<VkDescriptorSetLayoutBinding, 32> bindings;
+ boost::container::small_vector<VkDescriptorUpdateTemplateEntryKHR, 32> entries;
+ u32 binding{};
+ u32 num_descriptors{};
+ size_t offset{};
+};
+
+inline void PushImageDescriptors(const Shader::Info& info, const VkSampler*& samplers,
+ const ImageId*& image_view_ids, TextureCache& texture_cache,
+ VKUpdateDescriptorQueue& update_descriptor_queue) {
+ for (const auto& desc : info.texture_buffer_descriptors) {
+ image_view_ids += desc.count;
+ }
+ for (const auto& desc : info.image_buffer_descriptors) {
+ image_view_ids += desc.count;
+ }
+ for (const auto& desc : info.texture_descriptors) {
+ for (u32 index = 0; index < desc.count; ++index) {
+ const VkSampler sampler{*(samplers++)};
+ ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))};
+ const VkImageView vk_image_view{image_view.Handle(desc.type)};
+ update_descriptor_queue.AddSampledImage(vk_image_view, sampler);
+ }
+ }
+ for (const auto& desc : info.image_descriptors) {
+ for (u32 index = 0; index < desc.count; ++index) {
+ ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))};
+ if (desc.is_written) {
+ texture_cache.MarkModification(image_view.image_id);
+ }
+ const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)};
+ update_descriptor_queue.AddImage(vk_image_view);
+ }
+ }
+}
+
+} // namespace Vulkan