// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include "common/thread_worker.h" #include "shader_recompiler/shader_info.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace VideoCore { class ShaderNotify; } namespace Vulkan { struct GraphicsPipelineCacheKey { std::array unique_hashes; FixedPipelineState state; size_t Hash() const noexcept; bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept; bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept { return !operator==(rhs); } size_t Size() const noexcept { return sizeof(unique_hashes) + state.Size(); } }; static_assert(std::has_unique_object_representations_v); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_constructible_v); } // namespace Vulkan namespace std { template <> struct hash { size_t operator()(const Vulkan::GraphicsPipelineCacheKey& k) const noexcept { return k.Hash(); } }; } // namespace std namespace Vulkan { class Device; class PipelineStatistics; class RenderPassCache; class RescalingPushConstant; class RenderAreaPushConstant; class Scheduler; class UpdateDescriptorQueue; class GraphicsPipeline { static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; public: explicit GraphicsPipeline(Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, VideoCore::ShaderNotify* shader_notify, const Device& device, DescriptorPool& descriptor_pool, UpdateDescriptorQueue& update_descriptor_queue, Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key, std::array stages, const std::array& infos); GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; GraphicsPipeline& operator=(const GraphicsPipeline&) = delete; GraphicsPipeline(const GraphicsPipeline&) = delete; void AddTransition(GraphicsPipeline* transition); void Configure(bool is_indexed) { configure_func(this, is_indexed); } [[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept { if (key == current_key) { return this; } const auto it{std::find(transition_keys.begin(), transition_keys.end(), current_key)}; return it != transition_keys.end() ? transitions[std::distance(transition_keys.begin(), it)] : nullptr; } [[nodiscard]] bool IsBuilt() const noexcept { return is_built.load(std::memory_order::relaxed); } template static auto MakeConfigureSpecFunc() { return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl(is_indexed); }; } void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) { maxwell3d = maxwell3d_; gpu_memory = gpu_memory_; } private: template void ConfigureImpl(bool is_indexed); void ConfigureDraw(const RescalingPushConstant& rescaling, const RenderAreaPushConstant& render_are); void MakePipeline(VkRenderPass render_pass); void Validate(); const GraphicsPipelineCacheKey key; Tegra::Engines::Maxwell3D* maxwell3d; Tegra::MemoryManager* gpu_memory; const Device& device; TextureCache& texture_cache; BufferCache& buffer_cache; Scheduler& scheduler; UpdateDescriptorQueue& update_descriptor_queue; void (*configure_func)(GraphicsPipeline*, bool){}; std::vector transition_keys; std::vector transitions; std::array spv_modules; std::array stage_infos; std::array enabled_uniform_buffer_masks{}; VideoCommon::UniformBufferSizes uniform_buffer_sizes{}; u32 num_textures{}; vk::DescriptorSetLayout descriptor_set_layout; DescriptorAllocator descriptor_allocator; vk::PipelineLayout pipeline_layout; vk::DescriptorUpdateTemplateKHR descriptor_update_template; vk::Pipeline pipeline; std::condition_variable build_condvar; std::mutex build_mutex; std::atomic_bool is_built{false}; bool uses_push_descriptor{false}; }; } // namespace Vulkan