145 lines
5.5 KiB
C
145 lines
5.5 KiB
C
|
// Copyright 2022 Dolphin Emulator Project
|
||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <array>
|
||
|
#include <list>
|
||
|
#include <map>
|
||
|
#include <memory>
|
||
|
#include <optional>
|
||
|
#include <string>
|
||
|
#include <string_view>
|
||
|
|
||
|
#include "VideoCommon/AbstractPipeline.h"
|
||
|
#include "VideoCommon/AbstractShader.h"
|
||
|
#include "VideoCommon/AsyncShaderCompiler.h"
|
||
|
#include "VideoCommon/GXPipelineTypes.h"
|
||
|
#include "VideoCommon/PixelShaderGen.h"
|
||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||
|
#include "VideoCommon/UberShaderPixel.h"
|
||
|
#include "VideoCommon/VideoEvents.h"
|
||
|
|
||
|
struct CustomShaderInstance
|
||
|
{
|
||
|
CustomPixelShaderContents pixel_contents;
|
||
|
|
||
|
bool operator==(const CustomShaderInstance& other) const = default;
|
||
|
};
|
||
|
|
||
|
class CustomShaderCache
|
||
|
{
|
||
|
public:
|
||
|
CustomShaderCache();
|
||
|
~CustomShaderCache();
|
||
|
CustomShaderCache(const CustomShaderCache&) = delete;
|
||
|
CustomShaderCache(CustomShaderCache&&) = delete;
|
||
|
CustomShaderCache& operator=(const CustomShaderCache&) = delete;
|
||
|
CustomShaderCache& operator=(CustomShaderCache&&) = delete;
|
||
|
|
||
|
// Changes the shader host config. Shaders should be reloaded afterwards.
|
||
|
void SetHostConfig(const ShaderHostConfig& host_config) { m_host_config.bits = host_config.bits; }
|
||
|
|
||
|
// Retrieves all pending shaders/pipelines from the async compiler.
|
||
|
void RetrieveAsyncShaders();
|
||
|
|
||
|
// Reloads/recreates all shaders and pipelines.
|
||
|
void Reload();
|
||
|
|
||
|
// The optional will be empty if this pipeline is now background compiling.
|
||
|
std::optional<const AbstractPipeline*>
|
||
|
GetPipelineAsync(const VideoCommon::GXPipelineUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders,
|
||
|
const AbstractPipelineConfig& pipeline_config);
|
||
|
std::optional<const AbstractPipeline*>
|
||
|
GetPipelineAsync(const VideoCommon::GXUberPipelineUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders,
|
||
|
const AbstractPipelineConfig& pipeline_config);
|
||
|
|
||
|
private:
|
||
|
// Configuration bits.
|
||
|
APIType m_api_type = APIType::Nothing;
|
||
|
ShaderHostConfig m_host_config = {};
|
||
|
std::unique_ptr<VideoCommon::AsyncShaderCompiler> m_async_shader_compiler;
|
||
|
std::unique_ptr<VideoCommon::AsyncShaderCompiler> m_async_uber_shader_compiler;
|
||
|
|
||
|
void AsyncCreatePipeline(const VideoCommon::GXPipelineUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders,
|
||
|
const AbstractPipelineConfig& pipeline_config);
|
||
|
void AsyncCreatePipeline(const VideoCommon::GXUberPipelineUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders,
|
||
|
const AbstractPipelineConfig& pipeline_config);
|
||
|
|
||
|
// Shader/Pipeline cache helper
|
||
|
template <typename Uid, typename ValueType>
|
||
|
struct Cache
|
||
|
{
|
||
|
struct CacheHolder
|
||
|
{
|
||
|
std::unique_ptr<ValueType> value = nullptr;
|
||
|
bool pending = true;
|
||
|
};
|
||
|
using CacheElement = std::pair<CustomShaderInstance, CacheHolder>;
|
||
|
using CacheList = std::list<CacheElement>;
|
||
|
std::map<Uid, CacheList> uid_to_cachelist;
|
||
|
|
||
|
const CacheHolder* GetHolder(const Uid& uid, const CustomShaderInstance& custom_shaders) const
|
||
|
{
|
||
|
if (auto uuid_it = uid_to_cachelist.find(uid); uuid_it != uid_to_cachelist.end())
|
||
|
{
|
||
|
for (const auto& [custom_shader_val, holder] : uuid_it->second)
|
||
|
{
|
||
|
if (custom_shaders == custom_shader_val)
|
||
|
{
|
||
|
return &holder;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
typename CacheList::iterator InsertElement(const Uid& uid,
|
||
|
const CustomShaderInstance& custom_shaders)
|
||
|
{
|
||
|
CacheList& cachelist = uid_to_cachelist[uid];
|
||
|
CacheElement e{custom_shaders, CacheHolder{}};
|
||
|
return cachelist.emplace(cachelist.begin(), std::move(e));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Cache<PixelShaderUid, AbstractShader> m_ps_cache;
|
||
|
Cache<UberShader::PixelShaderUid, AbstractShader> m_uber_ps_cache;
|
||
|
Cache<VideoCommon::GXPipelineUid, AbstractPipeline> m_pipeline_cache;
|
||
|
Cache<VideoCommon::GXUberPipelineUid, AbstractPipeline> m_uber_pipeline_cache;
|
||
|
|
||
|
using PipelineIterator = Cache<VideoCommon::GXPipelineUid, AbstractPipeline>::CacheList::iterator;
|
||
|
using UberPipelineIterator =
|
||
|
Cache<VideoCommon::GXUberPipelineUid, AbstractPipeline>::CacheList::iterator;
|
||
|
using PixelShaderIterator = Cache<PixelShaderUid, AbstractShader>::CacheList::iterator;
|
||
|
using UberPixelShaderIterator =
|
||
|
Cache<UberShader::PixelShaderUid, AbstractShader>::CacheList::iterator;
|
||
|
|
||
|
void NotifyPipelineFinished(PipelineIterator iterator,
|
||
|
std::unique_ptr<AbstractPipeline> pipeline);
|
||
|
void NotifyPipelineFinished(UberPipelineIterator iterator,
|
||
|
std::unique_ptr<AbstractPipeline> pipeline);
|
||
|
|
||
|
std::unique_ptr<AbstractShader>
|
||
|
CompilePixelShader(const PixelShaderUid& uid, const CustomShaderInstance& custom_shaders) const;
|
||
|
void NotifyPixelShaderFinished(PixelShaderIterator iterator,
|
||
|
std::unique_ptr<AbstractShader> shader);
|
||
|
std::unique_ptr<AbstractShader>
|
||
|
CompilePixelShader(const UberShader::PixelShaderUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders) const;
|
||
|
void NotifyPixelShaderFinished(UberPixelShaderIterator iterator,
|
||
|
std::unique_ptr<AbstractShader> shader);
|
||
|
|
||
|
void QueuePixelShaderCompile(const PixelShaderUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders);
|
||
|
void QueuePixelShaderCompile(const UberShader::PixelShaderUid& uid,
|
||
|
const CustomShaderInstance& custom_shaders);
|
||
|
|
||
|
Common::EventHook m_frame_end_handler;
|
||
|
};
|