PostProcessing/FX: Support multiple render targets

This commit is contained in:
Stenzek 2023-12-08 16:38:11 +10:00
parent fdd3edf73a
commit ff37afef55
No known key found for this signature in database
2 changed files with 55 additions and 28 deletions

View File

@ -317,7 +317,6 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
if (!temp_module.techniques.empty())
{
u32 max_rt = 0;
bool has_passes = false;
for (const reshadefx::technique_info& tech : temp_module.techniques)
{
@ -325,6 +324,7 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
{
has_passes = true;
u32 max_rt = 0;
for (u32 i = 0; i < std::size(pi.render_target_names); i++)
{
if (pi.render_target_names[i].empty())
@ -333,6 +333,13 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
max_rt = std::max(max_rt, i);
}
if (max_rt > GPUDevice::MAX_RENDER_TARGETS)
{
Error::SetString(error, fmt::format("Too many render targets ({}) in pass {}, only {} are supported.", max_rt,
pi.name, GPUDevice::MAX_RENDER_TARGETS));
return false;
}
if (pi.samplers.size() > GPUDevice::MAX_TEXTURE_SAMPLERS)
{
Error::SetString(error, fmt::format("Too many samplers ({}) in pass {}, only {} are supported.",
@ -346,11 +353,6 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
Error::SetString(error, "No passes defined in file.");
return false;
}
else if (max_rt > 0)
{
Error::SetString(error, "Shaders with multiple render targets are currently not supported.");
return false;
}
}
// Might go invalid when creating pipelines.
@ -967,24 +969,32 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
if (is_final)
{
pass.render_target = OUTPUT_COLOR_TEXTURE;
pass.render_targets.push_back(OUTPUT_COLOR_TEXTURE);
}
else if (!pi.render_target_names[0].empty())
{
pass.render_target = static_cast<TextureID>(m_textures.size());
for (u32 i = 0; i < static_cast<u32>(m_textures.size()); i++)
for (const std::string& rtname : pi.render_target_names)
{
if (m_textures[i].reshade_name == pi.render_target_names[0])
{
pass.render_target = static_cast<TextureID>(i);
if (rtname.empty())
break;
TextureID rt = static_cast<TextureID>(m_textures.size());
for (u32 i = 0; i < static_cast<u32>(m_textures.size()); i++)
{
if (m_textures[i].reshade_name == rtname)
{
rt = static_cast<TextureID>(i);
break;
}
}
}
if (pass.render_target == static_cast<TextureID>(m_textures.size()))
{
Error::SetString(error, fmt::format("Unknown texture '{}' used as render target in pass '{}'",
pi.render_target_names[0], pi.name));
return false;
if (rt == static_cast<TextureID>(m_textures.size()))
{
Error::SetString(error,
fmt::format("Unknown texture '{}' used as render target in pass '{}'", rtname, pi.name));
return false;
}
pass.render_targets.push_back(rt);
}
}
else
@ -992,7 +1002,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
Texture new_rt;
new_rt.rt_scale = 1.0f;
new_rt.format = backbuffer_format;
pass.render_target = static_cast<TextureID>(m_textures.size());
pass.render_targets.push_back(static_cast<TextureID>(m_textures.size()));
m_textures.push_back(std::move(new_rt));
}
@ -1151,7 +1161,7 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
const std::string_view code(mod.code.data(), mod.code.size());
auto get_shader = [api, needs_main_defn, &code](const std::string& name, const std::vector<Sampler>& samplers,
auto get_shader = [api, needs_main_defn, &code](const std::string& name, const std::span<Sampler> samplers,
GPUShaderStage stage) {
std::string real_code;
if (needs_main_defn)
@ -1222,7 +1232,15 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
if (!vs || !fs)
return false;
plconfig.SetTargetFormats((pass.render_target >= 0) ? m_textures[pass.render_target].format : format);
for (size_t i = 0; i < pass.render_targets.size(); i++)
{
plconfig.color_formats[i] =
((pass.render_targets[i] >= 0) ? m_textures[pass.render_targets[i]].format : format);
}
for (size_t i = pass.render_targets.size(); i < GPUDevice::MAX_RENDER_TARGETS; i++)
plconfig.color_formats[i] = GPUTexture::Format::Unknown;
plconfig.depth_format = GPUTexture::Format::Unknown;
plconfig.blend = MapBlendState(info);
plconfig.primitive = MapPrimitive(info.topology);
plconfig.vertex_shader = vs.get();
@ -1431,12 +1449,11 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final
for (const Pass& pass : m_passes)
{
GL_SCOPE_FMT("Draw pass {}", pass.name.c_str());
GL_INS_FMT("Render Target: ID {} [{}]", pass.render_target, GetTextureNameForID(pass.render_target));
GPUTexture* output = GetTextureByID(pass.render_target, input, final_target);
DebugAssert(!pass.render_targets.empty());
if (!output)
if (pass.render_targets.size() == 1 && pass.render_targets[0] == OUTPUT_COLOR_TEXTURE && !final_target)
{
// Drawing to final buffer.
// Special case: drawing to final buffer.
if (!g_gpu_device->BeginPresent(false))
{
GL_POP();
@ -1445,7 +1462,16 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final
}
else
{
g_gpu_device->SetRenderTargets(&output, 1, nullptr);
std::array<GPUTexture*, GPUDevice::MAX_RENDER_TARGETS> render_targets;
for (size_t i = 0; i < pass.render_targets.size(); i++)
{
GL_INS_FMT("Render Target {}: ID {} [{}]", i, pass.render_targets[i],
GetTextureNameForID(pass.render_targets[i]));
render_targets[i] = GetTextureByID(pass.render_targets[i], input, final_target);
DebugAssert(render_targets[i]);
}
g_gpu_device->SetRenderTargets(render_targets.data(), static_cast<u32>(pass.render_targets.size()), nullptr);
}
g_gpu_device->SetPipeline(pass.pipeline.get());

View File

@ -5,6 +5,7 @@
#include "postprocessing_shader.h"
#include "common/thirdparty/SmallVector.h"
#include "common/timer.h"
// reshadefx
@ -103,8 +104,8 @@ private:
struct Pass
{
std::unique_ptr<GPUPipeline> pipeline;
TextureID render_target;
std::vector<Sampler> samplers;
llvm::SmallVector<TextureID, GPUDevice::MAX_RENDER_TARGETS> render_targets;
llvm::SmallVector<Sampler, GPUDevice::MAX_TEXTURE_SAMPLERS> samplers;
u32 num_vertices;
#ifdef _DEBUG