wip
This commit is contained in:
parent
cbaca5d788
commit
b8eee191fa
|
@ -20,6 +20,7 @@ public:
|
||||||
ALWAYS_INLINE ID3D11RenderTargetView* GetD3DRTV() const { return m_rtv.Get(); }
|
ALWAYS_INLINE ID3D11RenderTargetView* GetD3DRTV() const { return m_rtv.Get(); }
|
||||||
ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); }
|
ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); }
|
||||||
ALWAYS_INLINE ID3D11RenderTargetView* const* GetD3DRTVArray() const { return m_rtv.GetAddressOf(); }
|
ALWAYS_INLINE ID3D11RenderTargetView* const* GetD3DRTVArray() const { return m_rtv.GetAddressOf(); }
|
||||||
|
ALWAYS_INLINE bool IsValid() const { return static_cast<bool>(m_texture); }
|
||||||
|
|
||||||
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
||||||
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
||||||
|
|
|
@ -960,6 +960,10 @@ bool D3D11HostDisplay::SetPostProcessingChain(const std::string_view& config)
|
||||||
|
|
||||||
PostProcessingStage stage;
|
PostProcessingStage stage;
|
||||||
stage.uniforms_size = shader.GetUniformsSize();
|
stage.uniforms_size = shader.GetUniformsSize();
|
||||||
|
stage.output_texture_scale = shader.GetOutputScale();
|
||||||
|
stage.sampler_state = (shader.GetTextureFilter() == PostProcessingShader::TextureFilter::Linear) ?
|
||||||
|
m_linear_sampler.Get() :
|
||||||
|
m_point_sampler.Get();
|
||||||
stage.vertex_shader = shader_cache.GetVertexShader(m_device.Get(), vs);
|
stage.vertex_shader = shader_cache.GetVertexShader(m_device.Get(), vs);
|
||||||
stage.pixel_shader = shader_cache.GetPixelShader(m_device.Get(), ps);
|
stage.pixel_shader = shader_cache.GetPixelShader(m_device.Get(), ps);
|
||||||
if (!stage.vertex_shader || !stage.pixel_shader)
|
if (!stage.vertex_shader || !stage.pixel_shader)
|
||||||
|
@ -1000,13 +1004,17 @@ bool D3D11HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 ta
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 target_count = (static_cast<u32>(m_post_processing_stages.size()) - 1);
|
for (u32 i = 0; i < static_cast<u32>(m_post_processing_stages.size()); i++)
|
||||||
for (u32 i = 0; i < target_count; i++)
|
|
||||||
{
|
{
|
||||||
PostProcessingStage& pps = m_post_processing_stages[i];
|
PostProcessingStage& pps = m_post_processing_stages[i];
|
||||||
if (pps.output_texture.GetWidth() != target_width || pps.output_texture.GetHeight() != target_height)
|
if (i == static_cast<u32>(m_post_processing_stages.size() - 1) && pps.output_texture_scale == 1.0f)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const u32 stage_width = static_cast<u32>(static_cast<float>(target_width) * pps.output_texture_scale);
|
||||||
|
const u32 stage_height = static_cast<u32>(static_cast<float>(target_height) * pps.output_texture_scale);
|
||||||
|
if (pps.output_texture.GetWidth() != stage_width || pps.output_texture.GetHeight() != stage_height)
|
||||||
{
|
{
|
||||||
if (!pps.output_texture.Create(m_device.Get(), target_width, target_height, 1, format, bind_flags))
|
if (!pps.output_texture.Create(m_device.Get(), stage_width, stage_height, 1, format, bind_flags))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1042,25 +1050,32 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||||
texture_view_width = final_width;
|
texture_view_width = final_width;
|
||||||
texture_view_height = final_height;
|
texture_view_height = final_height;
|
||||||
|
|
||||||
const u32 final_stage = static_cast<u32>(m_post_processing_stages.size()) - 1u;
|
|
||||||
for (u32 i = 0; i < static_cast<u32>(m_post_processing_stages.size()); i++)
|
for (u32 i = 0; i < static_cast<u32>(m_post_processing_stages.size()); i++)
|
||||||
{
|
{
|
||||||
PostProcessingStage& pps = m_post_processing_stages[i];
|
PostProcessingStage& pps = m_post_processing_stages[i];
|
||||||
if (i == final_stage)
|
if (pps.output_texture.IsValid())
|
||||||
{
|
|
||||||
m_context->OMSetRenderTargets(1, &final_target, nullptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
m_context->ClearRenderTargetView(pps.output_texture.GetD3DRTV(), clear_color.data());
|
m_context->ClearRenderTargetView(pps.output_texture.GetD3DRTV(), clear_color.data());
|
||||||
m_context->OMSetRenderTargets(1, pps.output_texture.GetD3DRTVArray(), nullptr);
|
m_context->OMSetRenderTargets(1, pps.output_texture.GetD3DRTVArray(), nullptr);
|
||||||
|
|
||||||
|
CD3D11_VIEWPORT vp(0.0f, 0.0f, static_cast<float>(pps.output_texture.GetWidth()),
|
||||||
|
static_cast<float>(pps.output_texture.GetHeight()), 0.0f, 1.0f);
|
||||||
|
m_context->RSSetViewports(1, &vp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_context->OMSetRenderTargets(1, &final_target, nullptr);
|
||||||
|
|
||||||
|
CD3D11_VIEWPORT vp(0.0f, 0.0f, static_cast<float>(GetWindowWidth()), static_cast<float>(GetWindowHeight()), 0.0f,
|
||||||
|
1.0f);
|
||||||
|
m_context->RSSetViewports(1, &vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0);
|
m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0);
|
||||||
m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0);
|
m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0);
|
||||||
m_context->PSSetShaderResources(0, 1, reinterpret_cast<ID3D11ShaderResourceView**>(&texture_handle));
|
m_context->PSSetShaderResources(0, 1, reinterpret_cast<ID3D11ShaderResourceView**>(&texture_handle));
|
||||||
m_context->PSSetSamplers(0, 1, m_point_sampler.GetAddressOf());
|
m_context->PSSetSamplers(0, 1, &pps.sampler_state);
|
||||||
|
|
||||||
const auto map =
|
const auto map =
|
||||||
m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), pps.uniforms_size);
|
m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), pps.uniforms_size);
|
||||||
|
@ -1073,10 +1088,28 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||||
|
|
||||||
m_context->Draw(3, 0);
|
m_context->Draw(3, 0);
|
||||||
|
|
||||||
if (i != final_stage)
|
if (pps.output_texture.IsValid())
|
||||||
texture_handle = pps.output_texture.GetD3DSRV();
|
texture_handle = pps.output_texture.GetD3DSRV();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// final blit when upscaling shaders are used
|
||||||
|
const PostProcessingStage& final_stage = m_post_processing_stages.back();
|
||||||
|
if (final_stage.output_texture.IsValid())
|
||||||
|
{
|
||||||
|
m_context->OMSetRenderTargets(1, &final_target, nullptr);
|
||||||
|
|
||||||
|
CD3D11_VIEWPORT vp(0.0f, 0.0f, static_cast<float>(GetWindowWidth()), static_cast<float>(GetWindowHeight()), 0.0f,
|
||||||
|
1.0f);
|
||||||
|
m_context->RSSetViewports(1, &vp);
|
||||||
|
|
||||||
|
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
|
||||||
|
m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0);
|
||||||
|
m_context->PSSetShaderResources(0, 1, final_stage.output_texture.GetD3DSRVArray());
|
||||||
|
m_context->PSSetSamplers(0, 1, m_linear_sampler.GetAddressOf());
|
||||||
|
m_context->Draw(3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
ID3D11ShaderResourceView* null_srv = nullptr;
|
ID3D11ShaderResourceView* null_srv = nullptr;
|
||||||
m_context->PSSetShaderResources(0, 1, &null_srv);
|
m_context->PSSetShaderResources(0, 1, &null_srv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,9 @@ protected:
|
||||||
{
|
{
|
||||||
ComPtr<ID3D11VertexShader> vertex_shader;
|
ComPtr<ID3D11VertexShader> vertex_shader;
|
||||||
ComPtr<ID3D11PixelShader> pixel_shader;
|
ComPtr<ID3D11PixelShader> pixel_shader;
|
||||||
|
ID3D11SamplerState* sampler_state;
|
||||||
D3D11::Texture output_texture;
|
D3D11::Texture output_texture;
|
||||||
|
float output_texture_scale;
|
||||||
u32 uniforms_size;
|
u32 uniforms_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -87,39 +87,54 @@ u32 ParseVector(const std::string_view& line, PostProcessingShader::Option::Valu
|
||||||
|
|
||||||
PostProcessingShader::PostProcessingShader() = default;
|
PostProcessingShader::PostProcessingShader() = default;
|
||||||
|
|
||||||
PostProcessingShader::PostProcessingShader(std::string name, std::string code) : m_name(name), m_code(code)
|
PostProcessingShader::PostProcessingShader(std::string name, std::string code) : m_name(name)
|
||||||
{
|
{
|
||||||
LoadOptions();
|
Pass pass;
|
||||||
|
pass.code = std::move(code);
|
||||||
|
m_passes.push_back(std::move(pass));
|
||||||
|
LoadLegacyOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
PostProcessingShader::PostProcessingShader(const PostProcessingShader& copy)
|
PostProcessingShader::PostProcessingShader(const PostProcessingShader& copy)
|
||||||
: m_name(copy.m_name), m_code(copy.m_code), m_options(copy.m_options)
|
: m_name(copy.m_name), m_passes(copy.m_passes), m_options(copy.m_options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PostProcessingShader::PostProcessingShader(PostProcessingShader& move)
|
PostProcessingShader::PostProcessingShader(PostProcessingShader& move)
|
||||||
: m_name(std::move(move.m_name)), m_code(std::move(move.m_code)), m_options(std::move(move.m_options))
|
: m_name(std::move(move.m_name)), m_passes(std::move(move.m_passes)), m_options(std::move(move.m_options))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PostProcessingShader::~PostProcessingShader() = default;
|
PostProcessingShader::~PostProcessingShader() = default;
|
||||||
|
|
||||||
bool PostProcessingShader::LoadFromFile(std::string name, const char* filename)
|
bool PostProcessingShader::LoadFromFile(std::string name, const char* filename)
|
||||||
|
{
|
||||||
|
const char* extension = std::strrchr(filename, '.');
|
||||||
|
if (extension && StringUtil::Strcasecmp(extension, ".glslp") == 0)
|
||||||
|
return LoadFromPassFile(std::move(name), filename);
|
||||||
|
else
|
||||||
|
return LoadFromLegacyFile(std::move(name), filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PostProcessingShader::LoadFromLegacyFile(std::string name, const char* filename)
|
||||||
{
|
{
|
||||||
std::optional<std::string> code = FileSystem::ReadFileToString(filename);
|
std::optional<std::string> code = FileSystem::ReadFileToString(filename);
|
||||||
if (!code.has_value() || code->empty())
|
if (!code.has_value() || code->empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_name = std::move(name);
|
m_name = std::move(name);
|
||||||
m_code = std::move(code.value());
|
|
||||||
|
Pass pass;
|
||||||
|
pass.code = std::move(code.value());
|
||||||
|
m_passes.push_back(std::move(pass));
|
||||||
m_options.clear();
|
m_options.clear();
|
||||||
LoadOptions();
|
LoadLegacyOptions();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PostProcessingShader::IsValid() const
|
bool PostProcessingShader::IsValid() const
|
||||||
{
|
{
|
||||||
return !m_name.empty() && !m_code.empty();
|
return !m_name.empty() && !m_passes.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
const PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const std::string_view& name) const
|
const PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const std::string_view& name) const
|
||||||
|
@ -277,7 +292,7 @@ void PostProcessingShader::FillUniformBuffer(void* buffer, u32 texture_width, s3
|
||||||
FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const PostProcessingShader& copy)
|
FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const PostProcessingShader& copy)
|
||||||
{
|
{
|
||||||
m_name = copy.m_name;
|
m_name = copy.m_name;
|
||||||
m_code = copy.m_code;
|
m_passes = copy.m_passes;
|
||||||
m_options = copy.m_options;
|
m_options = copy.m_options;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -285,18 +300,18 @@ FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const Post
|
||||||
FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(PostProcessingShader& move)
|
FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(PostProcessingShader& move)
|
||||||
{
|
{
|
||||||
m_name = std::move(move.m_name);
|
m_name = std::move(move.m_name);
|
||||||
m_code = std::move(move.m_code);
|
m_passes = std::move(move.m_passes);
|
||||||
m_options = std::move(move.m_options);
|
m_options = std::move(move.m_options);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessingShader::LoadOptions()
|
void PostProcessingShader::LoadLegacyOptions()
|
||||||
{
|
{
|
||||||
// Adapted from Dolphin's PostProcessingConfiguration::LoadOptions().
|
// Adapted from Dolphin's PostProcessingConfiguration::LoadOptions().
|
||||||
constexpr char config_start_delimiter[] = "[configuration]";
|
constexpr char config_start_delimiter[] = "[configuration]";
|
||||||
constexpr char config_end_delimiter[] = "[/configuration]";
|
constexpr char config_end_delimiter[] = "[/configuration]";
|
||||||
size_t configuration_start = m_code.find(config_start_delimiter);
|
size_t configuration_start = m_passes.front().code.find(config_start_delimiter);
|
||||||
size_t configuration_end = m_code.find(config_end_delimiter);
|
size_t configuration_end = m_passes.front().code.find(config_end_delimiter);
|
||||||
if (configuration_start == std::string::npos || configuration_end == std::string::npos)
|
if (configuration_start == std::string::npos || configuration_end == std::string::npos)
|
||||||
{
|
{
|
||||||
// Issue loading configuration or there isn't one.
|
// Issue loading configuration or there isn't one.
|
||||||
|
@ -304,8 +319,8 @@ void PostProcessingShader::LoadOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string configuration_string =
|
std::string configuration_string =
|
||||||
m_code.substr(configuration_start + std::strlen(config_start_delimiter),
|
m_passes.front().code.substr(configuration_start + std::strlen(config_start_delimiter),
|
||||||
configuration_end - configuration_start - std::strlen(config_start_delimiter));
|
configuration_end - configuration_start - std::strlen(config_start_delimiter));
|
||||||
|
|
||||||
std::istringstream in(configuration_string);
|
std::istringstream in(configuration_string);
|
||||||
|
|
||||||
|
@ -416,4 +431,181 @@ void PostProcessingShader::LoadOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PostProcessingShader::LoadFromPassFile(std::string name, const char* filename)
|
||||||
|
{
|
||||||
|
std::optional<std::string> code = FileSystem::ReadFileToString(filename);
|
||||||
|
if (!code.has_value() || code->empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::istringstream in(code.value());
|
||||||
|
|
||||||
|
std::string current_section;
|
||||||
|
Option current_option = {};
|
||||||
|
Pass current_pass;
|
||||||
|
|
||||||
|
auto CompleteSection = [&]() {
|
||||||
|
if (current_option.type != Option::Type::Invalid)
|
||||||
|
{
|
||||||
|
current_option.value = current_option.default_value;
|
||||||
|
if (current_option.ui_name.empty())
|
||||||
|
current_option.ui_name = current_option.name;
|
||||||
|
|
||||||
|
if (!current_option.name.empty() && current_option.vector_size > 0)
|
||||||
|
m_options.push_back(std::move(current_option));
|
||||||
|
|
||||||
|
current_option = {};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (current_section == "Pass")
|
||||||
|
{
|
||||||
|
if (current_pass.code.empty())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Pass %zu has no code", m_passes.size() + 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!in.eof())
|
||||||
|
{
|
||||||
|
std::string line_str;
|
||||||
|
if (std::getline(in, line_str))
|
||||||
|
{
|
||||||
|
std::string_view line_view = line_str;
|
||||||
|
|
||||||
|
// Check for CRLF eol and convert it to LF
|
||||||
|
if (!line_view.empty() && line_view.at(line_view.size() - 1) == '\r')
|
||||||
|
line_view.remove_suffix(1);
|
||||||
|
|
||||||
|
if (line_view.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line_view[0] == '[')
|
||||||
|
{
|
||||||
|
size_t endpos = line_view.find("]");
|
||||||
|
if (endpos != std::string::npos)
|
||||||
|
{
|
||||||
|
if (!CompleteSection())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// New section!
|
||||||
|
current_section = line_view.substr(1, endpos - 1);
|
||||||
|
if (current_section == "OptionBool")
|
||||||
|
current_option.type = Option::Type::Bool;
|
||||||
|
else if (current_section == "OptionRangeFloat")
|
||||||
|
current_option.type = Option::Type::Float;
|
||||||
|
else if (current_section == "OptionRangeInteger")
|
||||||
|
current_option.type = Option::Type::Int;
|
||||||
|
else if (current_section != "Pass")
|
||||||
|
Log_ErrorPrintf("Invalid option type: '%s'", line_str.c_str());
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view key, value;
|
||||||
|
ParseKeyValue(line_view, &key, &value);
|
||||||
|
if (!key.empty() && !value.empty())
|
||||||
|
{
|
||||||
|
if (current_option.type != Option::Type::Invalid)
|
||||||
|
{
|
||||||
|
if (key == "GUIName")
|
||||||
|
{
|
||||||
|
current_option.ui_name = value;
|
||||||
|
}
|
||||||
|
else if (key == "OptionName")
|
||||||
|
{
|
||||||
|
current_option.name = value;
|
||||||
|
}
|
||||||
|
else if (key == "DependentOption")
|
||||||
|
{
|
||||||
|
current_option.dependent_option = value;
|
||||||
|
}
|
||||||
|
else if (key == "MinValue" || key == "MaxValue" || key == "DefaultValue" || key == "StepAmount")
|
||||||
|
{
|
||||||
|
Option::ValueVector* dst_array;
|
||||||
|
if (key == "MinValue")
|
||||||
|
dst_array = ¤t_option.min_value;
|
||||||
|
else if (key == "MaxValue")
|
||||||
|
dst_array = ¤t_option.max_value;
|
||||||
|
else if (key == "DefaultValue")
|
||||||
|
dst_array = ¤t_option.default_value;
|
||||||
|
else // if (key == "StepAmount")
|
||||||
|
dst_array = ¤t_option.step_value;
|
||||||
|
|
||||||
|
u32 size = 0;
|
||||||
|
if (current_option.type == Option::Type::Bool)
|
||||||
|
(*dst_array)[size++].int_value = StringUtil::FromChars<bool>(value).value_or(false) ? 1 : 0;
|
||||||
|
else if (current_option.type == Option::Type::Float)
|
||||||
|
size = ParseVector<float>(value, dst_array);
|
||||||
|
else if (current_option.type == Option::Type::Int)
|
||||||
|
size = ParseVector<s32>(value, dst_array);
|
||||||
|
|
||||||
|
current_option.vector_size =
|
||||||
|
(current_option.vector_size == 0) ? size : std::min(current_option.vector_size, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Invalid option key: '%s'", line_str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (current_section == "Pass")
|
||||||
|
{
|
||||||
|
if (key == "OutputScale")
|
||||||
|
{
|
||||||
|
current_pass.output_scale = StringUtil::FromChars<float>(value).value_or(1.0f);
|
||||||
|
if (current_pass.output_scale <= 0.0f)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Invalid output scale: %f", current_pass.output_scale);
|
||||||
|
current_pass.output_scale = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key == "TextureFilter")
|
||||||
|
{
|
||||||
|
if (value == "Nearest")
|
||||||
|
current_pass.texture_filter = TextureFilter::Nearest;
|
||||||
|
else if (value == "Linear")
|
||||||
|
current_pass.texture_filter = TextureFilter::Linear;
|
||||||
|
else
|
||||||
|
Log_ErrorPrintf("Invalid texture filter: '%s'", line_str.c_str());
|
||||||
|
}
|
||||||
|
else if (key == "File")
|
||||||
|
{
|
||||||
|
const String source_file(FileSystem::BuildPathRelativeToFile(filename, SmallString(value)));
|
||||||
|
std::optional<std::string> source_code(FileSystem::ReadFileToString(source_file));
|
||||||
|
if (!source_code.has_value() || source_code->empty())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to load shader source from '%s'", source_file.GetCharArray());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_pass.code = std::move(source_code.value());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Invalid pass setting: '%s'", line_str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CompleteSection())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_passes.empty())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("No passes defined in %s", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace FrontendCommon
|
} // namespace FrontendCommon
|
||||||
|
|
|
@ -16,6 +16,12 @@ public:
|
||||||
PUSH_CONSTANT_SIZE_THRESHOLD = 128
|
PUSH_CONSTANT_SIZE_THRESHOLD = 128
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TextureFilter
|
||||||
|
{
|
||||||
|
Nearest,
|
||||||
|
Linear
|
||||||
|
};
|
||||||
|
|
||||||
struct Option
|
struct Option
|
||||||
{
|
{
|
||||||
enum : u32
|
enum : u32
|
||||||
|
@ -53,6 +59,13 @@ public:
|
||||||
ValueVector value;
|
ValueVector value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Pass
|
||||||
|
{
|
||||||
|
std::string code;
|
||||||
|
float output_scale = 1.0f;
|
||||||
|
TextureFilter texture_filter = TextureFilter::Linear;
|
||||||
|
};
|
||||||
|
|
||||||
PostProcessingShader();
|
PostProcessingShader();
|
||||||
PostProcessingShader(std::string name, std::string code);
|
PostProcessingShader(std::string name, std::string code);
|
||||||
PostProcessingShader(const PostProcessingShader& copy);
|
PostProcessingShader(const PostProcessingShader& copy);
|
||||||
|
@ -63,10 +76,14 @@ public:
|
||||||
PostProcessingShader& operator=(PostProcessingShader& move);
|
PostProcessingShader& operator=(PostProcessingShader& move);
|
||||||
|
|
||||||
ALWAYS_INLINE const std::string& GetName() const { return m_name; }
|
ALWAYS_INLINE const std::string& GetName() const { return m_name; }
|
||||||
ALWAYS_INLINE const std::string& GetCode() const { return m_code; }
|
ALWAYS_INLINE const std::string& GetCode(u32 pass) const { return m_passes[pass].code; }
|
||||||
|
ALWAYS_INLINE float GetOutputScale(u32 pass) const { return m_passes[pass].output_scale; }
|
||||||
|
ALWAYS_INLINE TextureFilter GetTextureFilter(u32 pass) const { return m_passes[pass].texture_filter; }
|
||||||
|
ALWAYS_INLINE u32 GetNumPasses() const { return static_cast<u32>(m_passes.size()); }
|
||||||
ALWAYS_INLINE const std::vector<Option>& GetOptions() const { return m_options; }
|
ALWAYS_INLINE const std::vector<Option>& GetOptions() const { return m_options; }
|
||||||
ALWAYS_INLINE std::vector<Option>& GetOptions() { return m_options; }
|
ALWAYS_INLINE std::vector<Option>& GetOptions() { return m_options; }
|
||||||
ALWAYS_INLINE bool HasOptions() const { return !m_options.empty(); }
|
ALWAYS_INLINE bool HasOptions() const { return !m_options.empty(); }
|
||||||
|
ALWAYS_INLINE bool IsLegacy() const { return m_is_legacy; }
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
|
@ -97,11 +114,14 @@ private:
|
||||||
float padding[1];
|
float padding[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoadOptions();
|
bool LoadFromLegacyFile(std::string name, const char* filename);
|
||||||
|
bool LoadFromPassFile(std::string name, const char* filename);
|
||||||
|
void LoadLegacyOptions();
|
||||||
|
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_code;
|
std::vector<Pass> m_passes;
|
||||||
std::vector<Option> m_options;
|
std::vector<Option> m_options;
|
||||||
|
bool m_is_legacy = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FrontendCommon
|
} // namespace FrontendCommon
|
|
@ -9,11 +9,23 @@ PostProcessingShaderGen::PostProcessingShaderGen(HostDisplay::RenderAPI render_a
|
||||||
|
|
||||||
PostProcessingShaderGen::~PostProcessingShaderGen() = default;
|
PostProcessingShaderGen::~PostProcessingShaderGen() = default;
|
||||||
|
|
||||||
std::string PostProcessingShaderGen::GeneratePostProcessingVertexShader(const PostProcessingShader& shader)
|
std::string PostProcessingShaderGen::GeneratePostProcessingVertexShader(const PostProcessingShader& shader, u32 pass)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PostProcessingShaderGen::GeneratePostProcessingFragmentShader(const PostProcessingShader& shader, u32 pass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PostProcessingShaderGen::GenerateLegacyPostProcessingVertexShader(const PostProcessingShader& shader,
|
||||||
|
u32 pass)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
WriteHeader(ss);
|
WriteHeader(ss);
|
||||||
|
DefineMacro(ss, "VERTEX", true);
|
||||||
|
DefineMacro(ss, "FRAGMENT", false);
|
||||||
DeclareTexture(ss, "samp0", 0);
|
DeclareTexture(ss, "samp0", 0);
|
||||||
WriteUniformBuffer(ss, shader, shader.UsePushConstants());
|
WriteUniformBuffer(ss, shader, shader.UsePushConstants());
|
||||||
|
|
||||||
|
@ -32,11 +44,14 @@ std::string PostProcessingShaderGen::GeneratePostProcessingVertexShader(const Po
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PostProcessingShaderGen::GeneratePostProcessingFragmentShader(const PostProcessingShader& shader)
|
std::string PostProcessingShaderGen::GenerateLegacyPostProcessingFragmentShader(const PostProcessingShader& shader,
|
||||||
|
u32 pass)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
WriteHeader(ss);
|
WriteHeader(ss);
|
||||||
|
DefineMacro(ss, "VERTEX", false);
|
||||||
|
DefineMacro(ss, "FRAGMENT", true);
|
||||||
DeclareTexture(ss, "samp0", 0);
|
DeclareTexture(ss, "samp0", 0);
|
||||||
WriteUniformBuffer(ss, shader, shader.UsePushConstants());
|
WriteUniformBuffer(ss, shader, shader.UsePushConstants());
|
||||||
|
|
||||||
|
@ -118,7 +133,7 @@ void SetOutput(float4 color)
|
||||||
#define OptionEnabled(x) ((x) != 0)
|
#define OptionEnabled(x) ((x) != 0)
|
||||||
)";
|
)";
|
||||||
|
|
||||||
ss << shader.GetCode();
|
ss << shader.GetCode(pass);
|
||||||
|
|
||||||
if (!m_glsl)
|
if (!m_glsl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,11 +11,14 @@ public:
|
||||||
PostProcessingShaderGen(HostDisplay::RenderAPI render_api, bool supports_dual_source_blend);
|
PostProcessingShaderGen(HostDisplay::RenderAPI render_api, bool supports_dual_source_blend);
|
||||||
~PostProcessingShaderGen();
|
~PostProcessingShaderGen();
|
||||||
|
|
||||||
std::string GeneratePostProcessingVertexShader(const PostProcessingShader& shader);
|
std::string GeneratePostProcessingVertexShader(const PostProcessingShader& shader, u32 pass);
|
||||||
std::string GeneratePostProcessingFragmentShader(const PostProcessingShader& shader);
|
std::string GeneratePostProcessingFragmentShader(const PostProcessingShader& shader, u32 pass);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteUniformBuffer(std::stringstream& ss, const PostProcessingShader& shader, bool use_push_constants);
|
void WriteUniformBuffer(std::stringstream& ss, const PostProcessingShader& shader, bool use_push_constants);
|
||||||
|
|
||||||
|
std::string GenerateLegacyPostProcessingVertexShader(const PostProcessingShader& shader, u32 pass);
|
||||||
|
std::string GenerateLegacyPostProcessingFragmentShader(const PostProcessingShader& shader, u32 pass);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FrontendCommon
|
} // namespace FrontendCommon
|
Loading…
Reference in New Issue