mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 08:13:05 +00:00
233 lines
10 KiB
C++
233 lines
10 KiB
C++
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINECACHE_H_
|
|
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINECACHE_H_
|
|
|
|
#include "common/abi.h"
|
|
#include "common/assert.h"
|
|
#include "common/common.h"
|
|
#include "graphics/host_gpu/renderer/colorRenderTarget.h"
|
|
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
|
#include "graphics/host_gpu/renderer/renderTarget.h"
|
|
#include "graphics/host_gpu/vulkanCommon.h"
|
|
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
|
|
#include "graphics/shader/rectListShader.h"
|
|
#include "graphics/shader/shader.h"
|
|
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <filesystem>
|
|
#include <memory>
|
|
#include <span>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
struct GraphicContext;
|
|
struct ShaderParams;
|
|
class CommandBuffer;
|
|
|
|
namespace ShaderRecompiler {
|
|
struct CompileOptions;
|
|
struct ShaderSource;
|
|
struct TranslateResult;
|
|
} // namespace ShaderRecompiler
|
|
|
|
namespace ShaderRecompiler::IR {
|
|
class ImageHeapSource;
|
|
} // namespace ShaderRecompiler::IR
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct PipelineStaticParameters {
|
|
bool negative_one_to_one = false;
|
|
bool depth_clip_enable = true;
|
|
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
|
// 0 without tessellation, 3 for a rectangle list, else the input control points.
|
|
uint8_t patch_control_points = 0;
|
|
bool primitive_restart_enable = false;
|
|
uint32_t samples = 1;
|
|
bool sample_shading_enable = false;
|
|
bool alpha_to_coverage_enable = false;
|
|
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
bool cull_front = false;
|
|
bool cull_back = false;
|
|
bool face = false;
|
|
bool provoking_vtx_last = false;
|
|
vk::PolygonMode polygon_mode = vk::PolygonMode::eFill;
|
|
uint8_t color_srcblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
uint8_t color_comb_fcn[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
uint8_t color_destblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
uint8_t alpha_srcblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
uint8_t alpha_comb_fcn[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
uint8_t alpha_destblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
bool separate_alpha_blend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
bool blend_enable[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
};
|
|
|
|
struct PipelineRenderingState {
|
|
std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {};
|
|
vk::Format depth_format = vk::Format::eUndefined;
|
|
vk::Format stencil_format = vk::Format::eUndefined;
|
|
uint32_t color_count = 0;
|
|
};
|
|
|
|
struct PipelineVertexInputState {
|
|
struct Binding {
|
|
uint32_t stride = 0;
|
|
uint8_t instance = 0;
|
|
};
|
|
struct Attribute {
|
|
uint32_t offset = 0;
|
|
uint8_t binding = 0;
|
|
};
|
|
|
|
std::array<Binding, ShaderVertexInputInfo::RES_MAX> bindings {};
|
|
std::array<Attribute, ShaderVertexInputInfo::RES_MAX> attributes {};
|
|
uint8_t binding_count = 0;
|
|
uint8_t attribute_count = 0;
|
|
};
|
|
|
|
// Everything a graphics pipeline is made of besides the stage modules its ids name. Aligned so
|
|
// that rendering.color_formats can be passed to Vulkan.
|
|
struct alignas(4) GraphicsPipelineKey {
|
|
// VS, LS or mesh; HS; TES; PS. 0 marks an absent stage.
|
|
std::array<uint64_t, 4> stage_ids {};
|
|
PipelineRenderingState rendering;
|
|
PipelineVertexInputState vertex_input;
|
|
PipelineStaticParameters static_params;
|
|
|
|
bool operator==(const GraphicsPipelineKey& other) const;
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
// Keys are compared and hashed as bytes.
|
|
static_assert(std::has_unique_object_representations_v<GraphicsPipelineKey>);
|
|
|
|
// A compiled stage with what pipeline creation needs from it besides the key.
|
|
struct ShaderModule {
|
|
uint64_t id = 0;
|
|
vk::ShaderModule module = nullptr;
|
|
ShaderRecompiler::IR::CompiledShaderInfo info;
|
|
ShaderRecompiler::IR::ResourceSpecialization specialization;
|
|
std::vector<uint32_t> function_code;
|
|
// VS or LS: the host format of each vertex input attribute.
|
|
std::vector<vk::Format> vertex_formats;
|
|
// Rectangle-list PS: the parameters it reads.
|
|
std::vector<RectListParameter> rect_parameters;
|
|
};
|
|
|
|
// A draw's topology, shader stages (from PipelineCache::GetGraphicsPrograms) and targets.
|
|
struct DrawRenderState {
|
|
RenderDepthInfo depth_info;
|
|
RenderColorInfo color_info[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
|
uint32_t color_count = 0;
|
|
// Color targets the pixel program writes.
|
|
uint32_t mrt_mask = 0;
|
|
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
|
bool primitive_restart_enable = false;
|
|
bool ps_active = false;
|
|
std::array<ShaderVertexInputInfo, 3> vertex_info;
|
|
ShaderPixelInputInfo ps_input_info;
|
|
|
|
[[nodiscard]] std::span<const ShaderVertexInputInfo> VertexStages() const {
|
|
return {vertex_info.data(), vertex_info[1].stage ? 3u : 1u};
|
|
}
|
|
};
|
|
|
|
// The owning renderer serializes access, including saves while the GPU is running.
|
|
class PipelineCache {
|
|
public:
|
|
PipelineCache(GraphicContext& graphics, ShaderRecompiler::IR::ImageHeapSource* image_heap);
|
|
~PipelineCache();
|
|
KYTY_CLASS_NO_COPY(PipelineCache);
|
|
void Save();
|
|
|
|
struct Pipeline {
|
|
vk::PipelineLayout pipeline_layout = nullptr;
|
|
vk::Pipeline pipeline = nullptr;
|
|
vk::DescriptorSetLayout descriptor_set_layout = nullptr;
|
|
bool uses_push_descriptors = false;
|
|
bool uses_image_heap = false;
|
|
};
|
|
|
|
// Reads the shaders and registers bound in `command` into the state's shader stages.
|
|
void GetGraphicsPrograms(const CommandBuffer& command, DrawRenderState& state);
|
|
// Null skips the dispatch.
|
|
const ShaderModule* GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
|
ShaderComputeInputInfo& input_info);
|
|
|
|
Pipeline& GetGraphicsPipeline(const CommandBuffer& command, const DrawRenderState& state);
|
|
Pipeline& GetComputePipeline(const ShaderComputeInputInfo& input_info);
|
|
|
|
private:
|
|
friend struct PipelineCacheTestAccess;
|
|
|
|
struct Program {
|
|
std::unique_ptr<ShaderRecompiler::ShaderSource> call_source;
|
|
ShaderRecompiler::IR::ResourcePlan resource_plan;
|
|
ShaderRecompiler::IR::ResourceSnapshot resources;
|
|
ShaderRecompiler::IR::ResourceSpecialization specialization;
|
|
std::vector<ShaderModule> modules;
|
|
bool skip_dispatch = false;
|
|
|
|
[[nodiscard]] std::span<const uint32_t> FunctionCode() const;
|
|
bool RefreshCallSource(const ShaderRecompiler::IR::SrtRuntime& runtime);
|
|
template <bool HasCalls>
|
|
ShaderModule* FindModule(const ShaderRecompiler::IR::SrtRuntime& runtime,
|
|
uint32_t push_data_cursor);
|
|
};
|
|
|
|
struct ProgramKey {
|
|
ShaderType stage = ShaderType::Unknown;
|
|
uint64_t hash = 0;
|
|
uint32_t user_data_count = 0;
|
|
std::vector<uint32_t> static_state;
|
|
|
|
bool operator==(const ProgramKey&) const = default;
|
|
};
|
|
|
|
// Variants of one source share a bucket; ProgramKey equality compares the state.
|
|
struct ProgramKeyHash {
|
|
std::size_t operator()(const ProgramKey& key) const { return key.hash; }
|
|
};
|
|
|
|
struct GraphicsPipelineKeyHash {
|
|
std::size_t operator()(const GraphicsPipelineKey& key) const;
|
|
};
|
|
|
|
GraphicContext& m_graphics;
|
|
ShaderRecompiler::IR::ImageHeapSource* m_image_heap;
|
|
std::unordered_map<ProgramKey, Program, ProgramKeyHash> m_program_cache;
|
|
ProgramKey m_lookup_key;
|
|
vk::PipelineCache m_driver_cache = nullptr;
|
|
std::filesystem::path m_driver_cache_path;
|
|
std::chrono::steady_clock::time_point m_next_driver_cache_save;
|
|
bool m_driver_cache_dirty = false;
|
|
std::unordered_map<GraphicsPipelineKey, Pipeline, GraphicsPipelineKeyHash> m_graphics_pipelines;
|
|
std::unordered_map<uint64_t, Pipeline> m_compute_pipelines;
|
|
|
|
template <typename InputInfo>
|
|
const ShaderModule* GetProgram(const ShaderParams& params, InputInfo& input_info,
|
|
uint32_t& push_data_cursor);
|
|
ShaderModule& CompileModule(Program& program, const ProgramKey& key,
|
|
ShaderRecompiler::CompileOptions options,
|
|
ShaderRecompiler::TranslateResult translated,
|
|
uint32_t push_data_cursor);
|
|
void InitializeDriverCache();
|
|
void CheckpointDriverCache();
|
|
};
|
|
|
|
// Stages are indexed like GraphicsPipelineKey::stage_ids.
|
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
|
const GraphicsPipelineKey& key,
|
|
const std::array<const ShaderModule*, 4>& stages,
|
|
vk::PipelineCache driver_cache);
|
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
|
const ShaderModule& module, vk::PipelineCache driver_cache);
|
|
|
|
} // namespace Libs::Graphics
|
|
|
|
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINECACHE_H_
|