vk_compute_pipeline: Initial implementation
This abstraction represents a Vulkan compute pipeline.
This commit is contained in:
		@@ -155,6 +155,8 @@ if (ENABLE_VULKAN)
 | 
			
		||||
        renderer_vulkan/maxwell_to_vk.h
 | 
			
		||||
        renderer_vulkan/vk_buffer_cache.cpp
 | 
			
		||||
        renderer_vulkan/vk_buffer_cache.h
 | 
			
		||||
        renderer_vulkan/vk_compute_pipeline.cpp
 | 
			
		||||
        renderer_vulkan/vk_compute_pipeline.h
 | 
			
		||||
        renderer_vulkan/vk_descriptor_pool.cpp
 | 
			
		||||
        renderer_vulkan/vk_descriptor_pool.h
 | 
			
		||||
        renderer_vulkan/vk_device.cpp
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										112
									
								
								src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
// Copyright 2019 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "video_core/renderer_vulkan/declarations.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_device.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_resource_manager.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
 | 
			
		||||
 | 
			
		||||
namespace Vulkan {
 | 
			
		||||
 | 
			
		||||
VKComputePipeline::VKComputePipeline(const VKDevice& device, VKScheduler& scheduler,
 | 
			
		||||
                                     VKDescriptorPool& descriptor_pool,
 | 
			
		||||
                                     VKUpdateDescriptorQueue& update_descriptor_queue,
 | 
			
		||||
                                     const SPIRVShader& shader)
 | 
			
		||||
    : device{device}, scheduler{scheduler}, entries{shader.entries},
 | 
			
		||||
      descriptor_set_layout{CreateDescriptorSetLayout()},
 | 
			
		||||
      descriptor_allocator{descriptor_pool, *descriptor_set_layout},
 | 
			
		||||
      update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()},
 | 
			
		||||
      descriptor_template{CreateDescriptorUpdateTemplate()},
 | 
			
		||||
      shader_module{CreateShaderModule(shader.code)}, pipeline{CreatePipeline()} {}
 | 
			
		||||
 | 
			
		||||
VKComputePipeline::~VKComputePipeline() = default;
 | 
			
		||||
 | 
			
		||||
vk::DescriptorSet VKComputePipeline::CommitDescriptorSet() {
 | 
			
		||||
    if (!descriptor_template) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    const auto set = descriptor_allocator.Commit(scheduler.GetFence());
 | 
			
		||||
    update_descriptor_queue.Send(*descriptor_template, set);
 | 
			
		||||
    return set;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UniqueDescriptorSetLayout VKComputePipeline::CreateDescriptorSetLayout() const {
 | 
			
		||||
    std::vector<vk::DescriptorSetLayoutBinding> bindings;
 | 
			
		||||
    u32 binding = 0;
 | 
			
		||||
    const auto AddBindings = [&](vk::DescriptorType descriptor_type, std::size_t num_entries) {
 | 
			
		||||
        // TODO(Rodrigo): Maybe make individual bindings here?
 | 
			
		||||
        for (u32 bindpoint = 0; bindpoint < static_cast<u32>(num_entries); ++bindpoint) {
 | 
			
		||||
            bindings.emplace_back(binding++, descriptor_type, 1, vk::ShaderStageFlagBits::eCompute,
 | 
			
		||||
                                  nullptr);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    AddBindings(vk::DescriptorType::eUniformBuffer, entries.const_buffers.size());
 | 
			
		||||
    AddBindings(vk::DescriptorType::eStorageBuffer, entries.global_buffers.size());
 | 
			
		||||
    AddBindings(vk::DescriptorType::eUniformTexelBuffer, entries.texel_buffers.size());
 | 
			
		||||
    AddBindings(vk::DescriptorType::eCombinedImageSampler, entries.samplers.size());
 | 
			
		||||
    AddBindings(vk::DescriptorType::eStorageImage, entries.images.size());
 | 
			
		||||
 | 
			
		||||
    const vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_ci(
 | 
			
		||||
        {}, static_cast<u32>(bindings.size()), bindings.data());
 | 
			
		||||
 | 
			
		||||
    const auto dev = device.GetLogical();
 | 
			
		||||
    const auto& dld = device.GetDispatchLoader();
 | 
			
		||||
    return dev.createDescriptorSetLayoutUnique(descriptor_set_layout_ci, nullptr, dld);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UniquePipelineLayout VKComputePipeline::CreatePipelineLayout() const {
 | 
			
		||||
    const vk::PipelineLayoutCreateInfo layout_ci({}, 1, &*descriptor_set_layout, 0, nullptr);
 | 
			
		||||
    const auto dev = device.GetLogical();
 | 
			
		||||
    return dev.createPipelineLayoutUnique(layout_ci, nullptr, device.GetDispatchLoader());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UniqueDescriptorUpdateTemplate VKComputePipeline::CreateDescriptorUpdateTemplate() const {
 | 
			
		||||
    std::vector<vk::DescriptorUpdateTemplateEntry> template_entries;
 | 
			
		||||
    u32 binding = 0;
 | 
			
		||||
    u32 offset = 0;
 | 
			
		||||
    FillDescriptorUpdateTemplateEntries(device, entries, binding, offset, template_entries);
 | 
			
		||||
    if (template_entries.empty()) {
 | 
			
		||||
        // If the shader doesn't use descriptor sets, skip template creation.
 | 
			
		||||
        return UniqueDescriptorUpdateTemplate{};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vk::DescriptorUpdateTemplateCreateInfo template_ci(
 | 
			
		||||
        {}, static_cast<u32>(template_entries.size()), template_entries.data(),
 | 
			
		||||
        vk::DescriptorUpdateTemplateType::eDescriptorSet, *descriptor_set_layout,
 | 
			
		||||
        vk::PipelineBindPoint::eGraphics, *layout, DESCRIPTOR_SET);
 | 
			
		||||
 | 
			
		||||
    const auto dev = device.GetLogical();
 | 
			
		||||
    const auto& dld = device.GetDispatchLoader();
 | 
			
		||||
    return dev.createDescriptorUpdateTemplateUnique(template_ci, nullptr, dld);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UniqueShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const {
 | 
			
		||||
    const vk::ShaderModuleCreateInfo module_ci({}, code.size() * sizeof(u32), code.data());
 | 
			
		||||
    const auto dev = device.GetLogical();
 | 
			
		||||
    return dev.createShaderModuleUnique(module_ci, nullptr, device.GetDispatchLoader());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UniquePipeline VKComputePipeline::CreatePipeline() const {
 | 
			
		||||
    vk::PipelineShaderStageCreateInfo shader_stage_ci({}, vk::ShaderStageFlagBits::eCompute,
 | 
			
		||||
                                                      *shader_module, "main", nullptr);
 | 
			
		||||
    vk::PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci;
 | 
			
		||||
    subgroup_size_ci.requiredSubgroupSize = GuestWarpSize;
 | 
			
		||||
    if (entries.uses_warps && device.IsGuestWarpSizeSupported(vk::ShaderStageFlagBits::eCompute)) {
 | 
			
		||||
        shader_stage_ci.pNext = &subgroup_size_ci;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vk::ComputePipelineCreateInfo create_info({}, shader_stage_ci, *layout, {}, 0);
 | 
			
		||||
    const auto dev = device.GetLogical();
 | 
			
		||||
    return dev.createComputePipelineUnique({}, create_info, nullptr, device.GetDispatchLoader());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Vulkan
 | 
			
		||||
							
								
								
									
										66
									
								
								src/video_core/renderer_vulkan/vk_compute_pipeline.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/video_core/renderer_vulkan/vk_compute_pipeline.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
// Copyright 2019 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/declarations.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
 | 
			
		||||
 | 
			
		||||
namespace Vulkan {
 | 
			
		||||
 | 
			
		||||
class VKDevice;
 | 
			
		||||
class VKScheduler;
 | 
			
		||||
class VKUpdateDescriptorQueue;
 | 
			
		||||
 | 
			
		||||
class VKComputePipeline final {
 | 
			
		||||
public:
 | 
			
		||||
    explicit VKComputePipeline(const VKDevice& device, VKScheduler& scheduler,
 | 
			
		||||
                               VKDescriptorPool& descriptor_pool,
 | 
			
		||||
                               VKUpdateDescriptorQueue& update_descriptor_queue,
 | 
			
		||||
                               const SPIRVShader& shader);
 | 
			
		||||
    ~VKComputePipeline();
 | 
			
		||||
 | 
			
		||||
    vk::DescriptorSet CommitDescriptorSet();
 | 
			
		||||
 | 
			
		||||
    vk::Pipeline GetHandle() const {
 | 
			
		||||
        return *pipeline;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vk::PipelineLayout GetLayout() const {
 | 
			
		||||
        return *layout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const ShaderEntries& GetEntries() {
 | 
			
		||||
        return entries;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    UniqueDescriptorSetLayout CreateDescriptorSetLayout() const;
 | 
			
		||||
 | 
			
		||||
    UniquePipelineLayout CreatePipelineLayout() const;
 | 
			
		||||
 | 
			
		||||
    UniqueDescriptorUpdateTemplate CreateDescriptorUpdateTemplate() const;
 | 
			
		||||
 | 
			
		||||
    UniqueShaderModule CreateShaderModule(const std::vector<u32>& code) const;
 | 
			
		||||
 | 
			
		||||
    UniquePipeline CreatePipeline() const;
 | 
			
		||||
 | 
			
		||||
    const VKDevice& device;
 | 
			
		||||
    VKScheduler& scheduler;
 | 
			
		||||
    ShaderEntries entries;
 | 
			
		||||
 | 
			
		||||
    UniqueDescriptorSetLayout descriptor_set_layout;
 | 
			
		||||
    DescriptorAllocator descriptor_allocator;
 | 
			
		||||
    VKUpdateDescriptorQueue& update_descriptor_queue;
 | 
			
		||||
    UniquePipelineLayout layout;
 | 
			
		||||
    UniqueDescriptorUpdateTemplate descriptor_template;
 | 
			
		||||
    UniqueShaderModule shader_module;
 | 
			
		||||
    UniquePipeline pipeline;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Vulkan
 | 
			
		||||
@@ -4,9 +4,12 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/engines/maxwell_3d.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/declarations.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
 | 
			
		||||
#include "video_core/shader/shader_ir.h"
 | 
			
		||||
@@ -15,6 +18,42 @@ namespace Vulkan {
 | 
			
		||||
 | 
			
		||||
class VKDevice;
 | 
			
		||||
 | 
			
		||||
struct ComputePipelineCacheKey {
 | 
			
		||||
    GPUVAddr shader{};
 | 
			
		||||
    u32 shared_memory_size{};
 | 
			
		||||
    std::array<u32, 3> workgroup_size{};
 | 
			
		||||
 | 
			
		||||
    std::size_t Hash() const noexcept {
 | 
			
		||||
        return static_cast<std::size_t>(shader) ^
 | 
			
		||||
               ((static_cast<std::size_t>(shared_memory_size) >> 7) << 40) ^
 | 
			
		||||
               static_cast<std::size_t>(workgroup_size[0]) ^
 | 
			
		||||
               (static_cast<std::size_t>(workgroup_size[1]) << 16) ^
 | 
			
		||||
               (static_cast<std::size_t>(workgroup_size[2]) << 24);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator==(const ComputePipelineCacheKey& rhs) const noexcept {
 | 
			
		||||
        return std::tie(shader, shared_memory_size, workgroup_size) ==
 | 
			
		||||
               std::tie(rhs.shader, rhs.shared_memory_size, rhs.workgroup_size);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Vulkan
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<Vulkan::ComputePipelineCacheKey> {
 | 
			
		||||
    std::size_t operator()(const Vulkan::ComputePipelineCacheKey& k) const noexcept {
 | 
			
		||||
        return k.Hash();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
namespace Vulkan {
 | 
			
		||||
 | 
			
		||||
class VKDevice;
 | 
			
		||||
 | 
			
		||||
void FillDescriptorUpdateTemplateEntries(
 | 
			
		||||
    const VKDevice& device, const ShaderEntries& entries, u32& binding, u32& offset,
 | 
			
		||||
    std::vector<vk::DescriptorUpdateTemplateEntry>& template_entries);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user