mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
959bee4799
Co-authored-by: fxpw <fxpw@outlook.com>
203 lines
8.5 KiB
C++
203 lines
8.5 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/renderTarget.h"
|
|
#include "graphics/host_gpu/vulkanCommon.h"
|
|
#include "graphics/shader/shader.h"
|
|
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <filesystem>
|
|
#include <memory>
|
|
#include <span>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
struct GraphicContext;
|
|
struct RenderColorInfo;
|
|
struct RenderDepthInfo;
|
|
class CommandBuffer;
|
|
|
|
namespace HW {
|
|
class Context;
|
|
class Shader;
|
|
class UserConfig;
|
|
struct ComputeShaderInfo;
|
|
} // namespace HW
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct PipelineStaticParameters {
|
|
bool negative_one_to_one = false;
|
|
bool depth_clip_enable = true;
|
|
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
|
bool primitive_restart_enable = false;
|
|
uint32_t samples = 1;
|
|
bool sample_shading_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] = {};
|
|
|
|
bool operator==(const PipelineStaticParameters& other) const noexcept;
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
static_assert(std::is_trivially_copyable_v<PipelineStaticParameters>);
|
|
static_assert(std::is_standard_layout_v<PipelineStaticParameters>);
|
|
static_assert(alignof(PipelineStaticParameters) == 1);
|
|
static_assert(sizeof(PipelineStaticParameters) == 116);
|
|
|
|
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;
|
|
|
|
bool operator==(const PipelineRenderingState&) const = default;
|
|
};
|
|
|
|
struct PipelineVertexInputState {
|
|
struct Binding {
|
|
uint32_t stride = 0;
|
|
bool instance = false;
|
|
bool operator==(const Binding&) const = default;
|
|
};
|
|
struct Attribute {
|
|
uint32_t offset = 0;
|
|
uint8_t binding = 0;
|
|
bool operator==(const Attribute&) const = default;
|
|
};
|
|
|
|
std::array<Binding, ShaderVertexInputInfo::RES_MAX> bindings {};
|
|
std::array<Attribute, ShaderVertexInputInfo::RES_MAX> attributes {};
|
|
uint8_t binding_count = 0;
|
|
uint8_t attribute_count = 0;
|
|
|
|
bool operator==(const PipelineVertexInputState&) const = default;
|
|
};
|
|
|
|
struct ShaderProgram {
|
|
uint64_t id = 0;
|
|
vk::ShaderModule module = nullptr;
|
|
|
|
explicit operator bool() const { return id != 0 && module != nullptr; }
|
|
};
|
|
|
|
// The owning renderer serializes access, including saves while the GPU is running.
|
|
class PipelineCache {
|
|
public:
|
|
explicit PipelineCache(GraphicContext& graphics);
|
|
~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;
|
|
};
|
|
|
|
struct GraphicsPrograms {
|
|
std::array<ShaderProgram, 3> vertex;
|
|
ShaderProgram pixel;
|
|
|
|
[[nodiscard]] uint32_t VertexStageCount() const { return vertex[1] ? 3u : 1u; }
|
|
};
|
|
|
|
GraphicsPrograms
|
|
GetGraphicsPrograms(const HW::VertexShaderInfo& vertex_regs,
|
|
const HW::PixelShaderInfo& pixel_regs, const HW::ShaderRegisters& sh,
|
|
const HW::Context& context, const HW::UserConfig& user_config,
|
|
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
|
|
bool pixel_active, std::array<ShaderVertexInputInfo, 3>& vertex_info,
|
|
ShaderPixelInputInfo& pixel_info);
|
|
ShaderProgram GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
|
const HW::ShaderRegisters& sh,
|
|
ShaderComputeInputInfo& input_info);
|
|
|
|
Pipeline& GetGraphicsPipeline(std::span<const RenderColorInfo> colors,
|
|
const RenderDepthInfo& depth,
|
|
std::span<const ShaderVertexInputInfo> vertex_info,
|
|
CommandBuffer& command, const ShaderPixelInputInfo* ps_input_info,
|
|
vk::PrimitiveTopology topology, bool primitive_restart_enable,
|
|
const GraphicsPrograms& programs);
|
|
Pipeline& GetComputePipeline(const ShaderComputeInputInfo& input_info,
|
|
const ShaderProgram& compute_program);
|
|
|
|
private:
|
|
struct ProgramCache;
|
|
|
|
struct GraphicsPipelineKey {
|
|
PipelineRenderingState rendering;
|
|
std::array<uint64_t, 3> vertex_shader_ids {};
|
|
uint64_t ps_shader_id = 0;
|
|
PipelineVertexInputState vertex_input;
|
|
PipelineStaticParameters static_params;
|
|
|
|
bool operator==(const GraphicsPipelineKey& other) const {
|
|
return rendering == other.rendering && vertex_shader_ids == other.vertex_shader_ids &&
|
|
ps_shader_id == other.ps_shader_id && vertex_input == other.vertex_input &&
|
|
static_params == other.static_params;
|
|
}
|
|
};
|
|
|
|
struct PipelineKeyHash {
|
|
static void Mix(std::size_t& hash, std::size_t value) {
|
|
hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (hash << 6u) +
|
|
(hash >> 2u);
|
|
}
|
|
};
|
|
|
|
struct GraphicsPipelineKeyHash {
|
|
std::size_t operator()(const GraphicsPipelineKey& key) const;
|
|
};
|
|
|
|
GraphicContext& m_graphics;
|
|
std::unique_ptr<ProgramCache> m_program_cache;
|
|
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, std::unique_ptr<Pipeline>, GraphicsPipelineKeyHash>
|
|
m_graphics_pipelines;
|
|
std::unordered_map<uint64_t, std::unique_ptr<Pipeline>> m_compute_pipelines;
|
|
|
|
void InitializeDriverCache();
|
|
void CheckpointDriverCache();
|
|
};
|
|
|
|
void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id);
|
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
|
const PipelineRenderingState& rendering,
|
|
const PipelineVertexInputState& vertex_input,
|
|
std::span<const ShaderVertexInputInfo> vertex_info,
|
|
const ShaderPixelInputInfo* ps_input_info,
|
|
const PipelineCache::GraphicsPrograms& programs,
|
|
const PipelineStaticParameters& static_params,
|
|
vk::PipelineCache driver_cache);
|
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
|
const ShaderComputeInputInfo& input_info,
|
|
vk::ShaderModule compute_module, vk::PipelineCache driver_cache);
|
|
|
|
} // namespace Libs::Graphics
|
|
|
|
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINECACHE_H_
|