mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-01-31 19:43:35 +00:00
Yellow squiggly lines begone! Done automatically on .cpp files through `run-clang-tidy`, with manual corrections to the mistakes. If an import is directly used, but is technically unnecessary since it's recursively imported by something else, it is *not* removed. The tool doesn't touch .h files, so I did some of them by hand while fixing errors due to old recursive imports. Not everything is removed, but the cleanup should be substantial enough. Because this done on Linux, code that isn't used on it is mostly untouched. (Hopefully no open PR is depending on these imports...)
384 lines
13 KiB
C++
384 lines
13 KiB
C++
// Copyright 2022 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h"
|
|
|
|
#include "VideoCommon/AbstractGfx.h"
|
|
#include "VideoCommon/VideoConfig.h"
|
|
#include "VideoCommon/VideoEvents.h"
|
|
|
|
CustomShaderCache::CustomShaderCache()
|
|
{
|
|
m_api_type = g_backend_info.api_type;
|
|
m_host_config.bits = ShaderHostConfig::GetCurrent().bits;
|
|
|
|
m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
|
m_async_shader_compiler->StartWorkerThreads(1); // TODO
|
|
|
|
m_async_uber_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
|
m_async_uber_shader_compiler->StartWorkerThreads(1); // TODO
|
|
|
|
m_frame_end_handler = GetVideoEvents().after_frame_event.Register(
|
|
[this](Core::System&) { RetrieveAsyncShaders(); });
|
|
}
|
|
|
|
CustomShaderCache::~CustomShaderCache()
|
|
{
|
|
if (m_async_shader_compiler)
|
|
{
|
|
m_async_shader_compiler->StopWorkerThreads();
|
|
m_async_shader_compiler->ClearAllWork();
|
|
}
|
|
|
|
if (m_async_uber_shader_compiler)
|
|
{
|
|
m_async_uber_shader_compiler->StopWorkerThreads();
|
|
m_async_uber_shader_compiler->ClearAllWork();
|
|
}
|
|
}
|
|
|
|
void CustomShaderCache::RetrieveAsyncShaders()
|
|
{
|
|
m_async_shader_compiler->RetrieveWorkItems();
|
|
m_async_uber_shader_compiler->RetrieveWorkItems();
|
|
}
|
|
|
|
void CustomShaderCache::Reload()
|
|
{
|
|
while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork())
|
|
{
|
|
m_async_shader_compiler->RetrieveWorkItems();
|
|
}
|
|
|
|
while (m_async_uber_shader_compiler->HasPendingWork() ||
|
|
m_async_uber_shader_compiler->HasCompletedWork())
|
|
{
|
|
m_async_uber_shader_compiler->RetrieveWorkItems();
|
|
}
|
|
|
|
m_ps_cache = {};
|
|
m_uber_ps_cache = {};
|
|
m_pipeline_cache = {};
|
|
m_uber_pipeline_cache = {};
|
|
}
|
|
|
|
std::optional<const AbstractPipeline*>
|
|
CustomShaderCache::GetPipelineAsync(const VideoCommon::GXPipelineUid& uid,
|
|
const CustomShaderInstance& custom_shaders,
|
|
const AbstractPipelineConfig& pipeline_config)
|
|
{
|
|
if (auto holder = m_pipeline_cache.GetHolder(uid, custom_shaders))
|
|
{
|
|
if (holder->pending)
|
|
return std::nullopt;
|
|
return holder->value.get();
|
|
}
|
|
AsyncCreatePipeline(uid, custom_shaders, pipeline_config);
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<const AbstractPipeline*>
|
|
CustomShaderCache::GetPipelineAsync(const VideoCommon::GXUberPipelineUid& uid,
|
|
const CustomShaderInstance& custom_shaders,
|
|
const AbstractPipelineConfig& pipeline_config)
|
|
{
|
|
if (auto holder = m_uber_pipeline_cache.GetHolder(uid, custom_shaders))
|
|
{
|
|
if (holder->pending)
|
|
return std::nullopt;
|
|
return holder->value.get();
|
|
}
|
|
AsyncCreatePipeline(uid, custom_shaders, pipeline_config);
|
|
return std::nullopt;
|
|
}
|
|
|
|
void CustomShaderCache::AsyncCreatePipeline(const VideoCommon::GXPipelineUid& uid,
|
|
|
|
const CustomShaderInstance& custom_shaders,
|
|
const AbstractPipelineConfig& pipeline_config)
|
|
{
|
|
class PipelineWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
|
{
|
|
public:
|
|
PipelineWorkItem(CustomShaderCache* shader_cache, const VideoCommon::GXPipelineUid& uid,
|
|
const CustomShaderInstance& custom_shaders, PipelineIterator iterator,
|
|
const AbstractPipelineConfig& pipeline_config)
|
|
: m_shader_cache(shader_cache), m_uid(uid), m_iterator(iterator), m_config(pipeline_config),
|
|
m_custom_shaders(custom_shaders)
|
|
{
|
|
SetStagesReady();
|
|
}
|
|
|
|
void SetStagesReady()
|
|
{
|
|
m_stages_ready = true;
|
|
|
|
PixelShaderUid ps_uid = m_uid.ps_uid;
|
|
ClearUnusedPixelShaderUidBits(m_shader_cache->m_api_type, m_shader_cache->m_host_config,
|
|
&ps_uid);
|
|
|
|
if (auto holder = m_shader_cache->m_ps_cache.GetHolder(ps_uid, m_custom_shaders))
|
|
{
|
|
// If the pixel shader is no longer pending compilation
|
|
// and the shader compilation succeeded, set
|
|
// the pipeline to use the new pixel shader.
|
|
// Otherwise, use the existing shader.
|
|
if (!holder->pending && holder->value.get())
|
|
{
|
|
m_config.pixel_shader = holder->value.get();
|
|
}
|
|
m_stages_ready &= !holder->pending;
|
|
}
|
|
else
|
|
{
|
|
m_stages_ready &= false;
|
|
m_shader_cache->QueuePixelShaderCompile(ps_uid, m_custom_shaders);
|
|
}
|
|
}
|
|
|
|
bool Compile() override
|
|
{
|
|
if (m_stages_ready)
|
|
{
|
|
m_pipeline = g_gfx->CreatePipeline(m_config);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Retrieve() override
|
|
{
|
|
if (m_stages_ready)
|
|
{
|
|
m_shader_cache->NotifyPipelineFinished(m_iterator, std::move(m_pipeline));
|
|
}
|
|
else
|
|
{
|
|
// Re-queue for next frame.
|
|
auto wi = m_shader_cache->m_async_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
|
m_shader_cache, m_uid, m_custom_shaders, m_iterator, m_config);
|
|
m_shader_cache->m_async_shader_compiler->QueueWorkItem(std::move(wi), 0);
|
|
}
|
|
}
|
|
|
|
private:
|
|
CustomShaderCache* m_shader_cache;
|
|
std::unique_ptr<AbstractPipeline> m_pipeline;
|
|
VideoCommon::GXPipelineUid m_uid;
|
|
PipelineIterator m_iterator;
|
|
AbstractPipelineConfig m_config;
|
|
CustomShaderInstance m_custom_shaders;
|
|
bool m_stages_ready;
|
|
};
|
|
|
|
auto list_iter = m_pipeline_cache.InsertElement(uid, custom_shaders);
|
|
auto work_item = m_async_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
|
this, uid, custom_shaders, list_iter, pipeline_config);
|
|
m_async_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
|
}
|
|
|
|
void CustomShaderCache::AsyncCreatePipeline(const VideoCommon::GXUberPipelineUid& uid,
|
|
|
|
const CustomShaderInstance& custom_shaders,
|
|
const AbstractPipelineConfig& pipeline_config)
|
|
{
|
|
class PipelineWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
|
{
|
|
public:
|
|
PipelineWorkItem(CustomShaderCache* shader_cache, const VideoCommon::GXUberPipelineUid& uid,
|
|
const CustomShaderInstance& custom_shaders, UberPipelineIterator iterator,
|
|
const AbstractPipelineConfig& pipeline_config)
|
|
: m_shader_cache(shader_cache), m_uid(uid), m_iterator(iterator), m_config(pipeline_config),
|
|
m_custom_shaders(custom_shaders)
|
|
{
|
|
SetStagesReady();
|
|
}
|
|
|
|
void SetStagesReady()
|
|
{
|
|
m_stages_ready = true;
|
|
|
|
UberShader::PixelShaderUid ps_uid = m_uid.ps_uid;
|
|
ClearUnusedPixelShaderUidBits(m_shader_cache->m_api_type, m_shader_cache->m_host_config,
|
|
&ps_uid);
|
|
|
|
if (auto holder = m_shader_cache->m_uber_ps_cache.GetHolder(ps_uid, m_custom_shaders))
|
|
{
|
|
if (!holder->pending && holder->value.get())
|
|
{
|
|
m_config.pixel_shader = holder->value.get();
|
|
}
|
|
m_stages_ready &= !holder->pending;
|
|
}
|
|
else
|
|
{
|
|
m_stages_ready &= false;
|
|
m_shader_cache->QueuePixelShaderCompile(ps_uid, m_custom_shaders);
|
|
}
|
|
}
|
|
|
|
bool Compile() override
|
|
{
|
|
if (m_stages_ready)
|
|
{
|
|
if (m_config.pixel_shader == nullptr || m_config.vertex_shader == nullptr)
|
|
return false;
|
|
|
|
m_pipeline = g_gfx->CreatePipeline(m_config);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Retrieve() override
|
|
{
|
|
if (m_stages_ready)
|
|
{
|
|
m_shader_cache->NotifyPipelineFinished(m_iterator, std::move(m_pipeline));
|
|
}
|
|
else
|
|
{
|
|
// Re-queue for next frame.
|
|
auto wi = m_shader_cache->m_async_uber_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
|
m_shader_cache, m_uid, m_custom_shaders, m_iterator, m_config);
|
|
m_shader_cache->m_async_uber_shader_compiler->QueueWorkItem(std::move(wi), 0);
|
|
}
|
|
}
|
|
|
|
private:
|
|
CustomShaderCache* m_shader_cache;
|
|
std::unique_ptr<AbstractPipeline> m_pipeline;
|
|
VideoCommon::GXUberPipelineUid m_uid;
|
|
UberPipelineIterator m_iterator;
|
|
AbstractPipelineConfig m_config;
|
|
CustomShaderInstance m_custom_shaders;
|
|
bool m_stages_ready;
|
|
};
|
|
|
|
auto list_iter = m_uber_pipeline_cache.InsertElement(uid, custom_shaders);
|
|
auto work_item = m_async_uber_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
|
this, uid, custom_shaders, list_iter, pipeline_config);
|
|
m_async_uber_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
|
}
|
|
|
|
void CustomShaderCache::NotifyPipelineFinished(PipelineIterator iterator,
|
|
std::unique_ptr<AbstractPipeline> pipeline)
|
|
{
|
|
iterator->second.pending = false;
|
|
iterator->second.value = std::move(pipeline);
|
|
}
|
|
|
|
void CustomShaderCache::NotifyPipelineFinished(UberPipelineIterator iterator,
|
|
std::unique_ptr<AbstractPipeline> pipeline)
|
|
{
|
|
iterator->second.pending = false;
|
|
iterator->second.value = std::move(pipeline);
|
|
}
|
|
|
|
void CustomShaderCache::QueuePixelShaderCompile(const PixelShaderUid& uid,
|
|
|
|
const CustomShaderInstance& custom_shaders)
|
|
{
|
|
class PixelShaderWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
|
{
|
|
public:
|
|
PixelShaderWorkItem(CustomShaderCache* shader_cache, const PixelShaderUid& uid,
|
|
const CustomShaderInstance& custom_shaders, PixelShaderIterator iter)
|
|
: m_shader_cache(shader_cache), m_uid(uid), m_custom_shaders(custom_shaders), m_iter(iter)
|
|
{
|
|
}
|
|
|
|
bool Compile() override
|
|
{
|
|
m_shader = m_shader_cache->CompilePixelShader(m_uid, m_custom_shaders);
|
|
return true;
|
|
}
|
|
|
|
void Retrieve() override
|
|
{
|
|
m_shader_cache->NotifyPixelShaderFinished(m_iter, std::move(m_shader));
|
|
}
|
|
|
|
private:
|
|
CustomShaderCache* m_shader_cache;
|
|
std::unique_ptr<AbstractShader> m_shader;
|
|
PixelShaderUid m_uid;
|
|
CustomShaderInstance m_custom_shaders;
|
|
PixelShaderIterator m_iter;
|
|
};
|
|
|
|
auto list_iter = m_ps_cache.InsertElement(uid, custom_shaders);
|
|
auto work_item = m_async_shader_compiler->CreateWorkItem<PixelShaderWorkItem>(
|
|
this, uid, custom_shaders, list_iter);
|
|
m_async_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
|
}
|
|
|
|
void CustomShaderCache::QueuePixelShaderCompile(const UberShader::PixelShaderUid& uid,
|
|
|
|
const CustomShaderInstance& custom_shaders)
|
|
{
|
|
class PixelShaderWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
|
{
|
|
public:
|
|
PixelShaderWorkItem(CustomShaderCache* shader_cache, const UberShader::PixelShaderUid& uid,
|
|
const CustomShaderInstance& custom_shaders, UberPixelShaderIterator iter)
|
|
: m_shader_cache(shader_cache), m_uid(uid), m_custom_shaders(custom_shaders), m_iter(iter)
|
|
{
|
|
}
|
|
|
|
bool Compile() override
|
|
{
|
|
m_shader = m_shader_cache->CompilePixelShader(m_uid, m_custom_shaders);
|
|
return true;
|
|
}
|
|
|
|
void Retrieve() override
|
|
{
|
|
m_shader_cache->NotifyPixelShaderFinished(m_iter, std::move(m_shader));
|
|
}
|
|
|
|
private:
|
|
CustomShaderCache* m_shader_cache;
|
|
std::unique_ptr<AbstractShader> m_shader;
|
|
UberShader::PixelShaderUid m_uid;
|
|
CustomShaderInstance m_custom_shaders;
|
|
UberPixelShaderIterator m_iter;
|
|
};
|
|
|
|
auto list_iter = m_uber_ps_cache.InsertElement(uid, custom_shaders);
|
|
auto work_item = m_async_uber_shader_compiler->CreateWorkItem<PixelShaderWorkItem>(
|
|
this, uid, custom_shaders, list_iter);
|
|
m_async_uber_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
|
}
|
|
|
|
std::unique_ptr<AbstractShader>
|
|
CustomShaderCache::CompilePixelShader(const PixelShaderUid& uid,
|
|
const CustomShaderInstance& custom_shaders) const
|
|
{
|
|
const ShaderCode source_code =
|
|
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData(), {});
|
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr,
|
|
"Custom Pixel Shader");
|
|
}
|
|
|
|
std::unique_ptr<AbstractShader>
|
|
CustomShaderCache::CompilePixelShader(const UberShader::PixelShaderUid& uid,
|
|
const CustomShaderInstance& custom_shaders) const
|
|
{
|
|
const ShaderCode source_code = GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr,
|
|
"Custom Uber Pixel Shader");
|
|
}
|
|
|
|
void CustomShaderCache::NotifyPixelShaderFinished(PixelShaderIterator iterator,
|
|
std::unique_ptr<AbstractShader> shader)
|
|
{
|
|
iterator->second.pending = false;
|
|
iterator->second.value = std::move(shader);
|
|
}
|
|
|
|
void CustomShaderCache::NotifyPixelShaderFinished(UberPixelShaderIterator iterator,
|
|
std::unique_ptr<AbstractShader> shader)
|
|
{
|
|
iterator->second.pending = false;
|
|
iterator->second.value = std::move(shader);
|
|
}
|