mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
Move most backend functionality to VideoCommon
This commit is contained in:
@ -5,74 +5,44 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileSearch.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/PostProcessing.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/ShaderCache.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
static const char s_default_shader[] = "void main() { SetOutput(Sample()); }\n";
|
||||
|
||||
PostProcessingShaderImplementation::PostProcessingShaderImplementation()
|
||||
{
|
||||
m_timer.Start();
|
||||
}
|
||||
PostProcessingConfiguration::PostProcessingConfiguration() = default;
|
||||
|
||||
PostProcessingShaderImplementation::~PostProcessingShaderImplementation()
|
||||
{
|
||||
m_timer.Stop();
|
||||
}
|
||||
PostProcessingConfiguration::~PostProcessingConfiguration() = default;
|
||||
|
||||
static std::vector<std::string> GetShaders(const std::string& sub_dir = "")
|
||||
{
|
||||
std::vector<std::string> paths =
|
||||
Common::DoFileSearch({File::GetUserPath(D_SHADERS_IDX) + sub_dir,
|
||||
File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir},
|
||||
{".glsl"});
|
||||
std::vector<std::string> result;
|
||||
for (std::string path : paths)
|
||||
{
|
||||
std::string name;
|
||||
SplitPath(path, nullptr, &name, nullptr);
|
||||
result.push_back(name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> PostProcessingShaderImplementation::GetShaderList(APIType api_type)
|
||||
{
|
||||
// Currently there is no differentiation between API types and shader languages.
|
||||
// This could change in the future, hence the api_type parameter, but ideally,
|
||||
// shaders should be compatible across backends.
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
return GetShaders();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> PostProcessingShaderImplementation::GetAnaglyphShaderList(APIType api_type)
|
||||
{
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
return GetShaders(ANAGLYPH_DIR DIR_SEP);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
PostProcessingShaderConfiguration::PostProcessingShaderConfiguration() = default;
|
||||
|
||||
PostProcessingShaderConfiguration::~PostProcessingShaderConfiguration() = default;
|
||||
|
||||
std::string PostProcessingShaderConfiguration::LoadShader(std::string shader)
|
||||
void PostProcessingConfiguration::LoadShader(const std::string& shader)
|
||||
{
|
||||
// Load the shader from the configuration if there isn't one sent to us.
|
||||
if (shader.empty())
|
||||
shader = g_ActiveConfig.sPostProcessingShader;
|
||||
m_current_shader = shader;
|
||||
if (shader.empty())
|
||||
{
|
||||
LoadDefaultShader();
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string sub_dir =
|
||||
(g_Config.stereo_mode == StereoMode::Anaglyph) ? ANAGLYPH_DIR DIR_SEP : "";
|
||||
@ -81,32 +51,32 @@ std::string PostProcessingShaderConfiguration::LoadShader(std::string shader)
|
||||
std::string code;
|
||||
std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl";
|
||||
|
||||
if (shader.empty())
|
||||
if (!File::Exists(path))
|
||||
{
|
||||
code = s_default_shader;
|
||||
// Fallback to shared user dir
|
||||
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File::Exists(path))
|
||||
{
|
||||
// Fallback to shared user dir
|
||||
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl";
|
||||
}
|
||||
|
||||
if (!File::ReadFileToString(path, code))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
|
||||
code = s_default_shader;
|
||||
}
|
||||
if (!File::ReadFileToString(path, code))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
|
||||
LoadDefaultShader();
|
||||
return;
|
||||
}
|
||||
|
||||
LoadOptions(code);
|
||||
LoadOptionsConfiguration();
|
||||
|
||||
return code;
|
||||
m_current_shader_code = code;
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::LoadOptions(const std::string& code)
|
||||
void PostProcessingConfiguration::LoadDefaultShader()
|
||||
{
|
||||
m_options.clear();
|
||||
m_any_options_dirty = false;
|
||||
m_current_shader_code = s_default_shader;
|
||||
}
|
||||
|
||||
void PostProcessingConfiguration::LoadOptions(const std::string& code)
|
||||
{
|
||||
const std::string config_start_delimiter = "[configuration]";
|
||||
const std::string config_end_delimiter = "[/configuration]";
|
||||
@ -254,7 +224,7 @@ void PostProcessingShaderConfiguration::LoadOptions(const std::string& code)
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::LoadOptionsConfiguration()
|
||||
void PostProcessingConfiguration::LoadOptionsConfiguration()
|
||||
{
|
||||
IniFile ini;
|
||||
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||
@ -288,7 +258,7 @@ void PostProcessingShaderConfiguration::LoadOptionsConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::SaveOptionsConfiguration()
|
||||
void PostProcessingConfiguration::SaveOptionsConfiguration()
|
||||
{
|
||||
IniFile ini;
|
||||
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||
@ -331,13 +301,7 @@ void PostProcessingShaderConfiguration::SaveOptionsConfiguration()
|
||||
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::ReloadShader()
|
||||
{
|
||||
m_current_shader = "";
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::SetOptionf(const std::string& option, int index,
|
||||
float value)
|
||||
void PostProcessingConfiguration::SetOptionf(const std::string& option, int index, float value)
|
||||
{
|
||||
auto it = m_options.find(option);
|
||||
|
||||
@ -346,7 +310,7 @@ void PostProcessingShaderConfiguration::SetOptionf(const std::string& option, in
|
||||
m_any_options_dirty = true;
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::SetOptioni(const std::string& option, int index, s32 value)
|
||||
void PostProcessingConfiguration::SetOptioni(const std::string& option, int index, s32 value)
|
||||
{
|
||||
auto it = m_options.find(option);
|
||||
|
||||
@ -355,7 +319,7 @@ void PostProcessingShaderConfiguration::SetOptioni(const std::string& option, in
|
||||
m_any_options_dirty = true;
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfiguration::SetOptionb(const std::string& option, bool value)
|
||||
void PostProcessingConfiguration::SetOptionb(const std::string& option, bool value)
|
||||
{
|
||||
auto it = m_options.find(option);
|
||||
|
||||
@ -363,3 +327,384 @@ void PostProcessingShaderConfiguration::SetOptionb(const std::string& option, bo
|
||||
it->second.m_dirty = true;
|
||||
m_any_options_dirty = true;
|
||||
}
|
||||
|
||||
PostProcessing::PostProcessing()
|
||||
{
|
||||
m_timer.Start();
|
||||
}
|
||||
|
||||
PostProcessing::~PostProcessing()
|
||||
{
|
||||
m_timer.Stop();
|
||||
}
|
||||
|
||||
static std::vector<std::string> GetShaders(const std::string& sub_dir = "")
|
||||
{
|
||||
std::vector<std::string> paths =
|
||||
Common::DoFileSearch({File::GetUserPath(D_SHADERS_IDX) + sub_dir,
|
||||
File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir},
|
||||
{".glsl"});
|
||||
std::vector<std::string> result;
|
||||
for (std::string path : paths)
|
||||
{
|
||||
std::string name;
|
||||
SplitPath(path, nullptr, &name, nullptr);
|
||||
result.push_back(name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> PostProcessing::GetShaderList()
|
||||
{
|
||||
return GetShaders();
|
||||
}
|
||||
|
||||
std::vector<std::string> PostProcessing::GetAnaglyphShaderList()
|
||||
{
|
||||
return GetShaders(ANAGLYPH_DIR DIR_SEP);
|
||||
}
|
||||
|
||||
bool PostProcessing::Initialize(AbstractTextureFormat format)
|
||||
{
|
||||
m_framebuffer_format = format;
|
||||
if (!CompileVertexShader() || !CompilePixelShader() || !CompilePipeline())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostProcessing::RecompileShader()
|
||||
{
|
||||
m_pipeline.reset();
|
||||
m_pixel_shader.reset();
|
||||
if (!CompilePixelShader())
|
||||
return;
|
||||
|
||||
CompilePipeline();
|
||||
}
|
||||
|
||||
void PostProcessing::RecompilePipeline()
|
||||
{
|
||||
m_pipeline.reset();
|
||||
CompilePipeline();
|
||||
}
|
||||
|
||||
void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||
const MathUtil::Rectangle<int>& src,
|
||||
const AbstractTexture* src_tex, int src_layer)
|
||||
{
|
||||
if (g_renderer->GetCurrentFramebuffer()->GetColorFormat() != m_framebuffer_format)
|
||||
{
|
||||
m_framebuffer_format = g_renderer->GetCurrentFramebuffer()->GetColorFormat();
|
||||
RecompilePipeline();
|
||||
}
|
||||
|
||||
if (!m_pipeline)
|
||||
return;
|
||||
|
||||
FillUniformBuffer(src, src_tex, src_layer);
|
||||
g_vertex_manager->UploadUtilityUniforms(m_uniform_staging_buffer.data(),
|
||||
static_cast<u32>(m_uniform_staging_buffer.size()));
|
||||
|
||||
g_renderer->SetViewportAndScissor(
|
||||
g_renderer->ConvertFramebufferRectangle(dst, g_renderer->GetCurrentFramebuffer()));
|
||||
g_renderer->SetPipeline(m_pipeline.get());
|
||||
g_renderer->SetTexture(0, src_tex);
|
||||
g_renderer->SetSamplerState(0, RenderState::GetLinearSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
}
|
||||
|
||||
std::string PostProcessing::GetUniformBufferHeader() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
u32 unused_counter = 1;
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
ss << "cbuffer PSBlock : register(b0) {\n";
|
||||
else
|
||||
ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n";
|
||||
|
||||
// Builtin uniforms
|
||||
ss << " float4 resolution;\n";
|
||||
ss << " float4 src_rect;\n";
|
||||
ss << " uint time;\n";
|
||||
ss << " int layer;\n";
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
ss << " uint ubo_align_" << unused_counter++ << "_;\n";
|
||||
ss << "\n";
|
||||
|
||||
// Custom options/uniforms
|
||||
for (const auto& it : m_config.GetOptions())
|
||||
{
|
||||
if (it.second.m_type ==
|
||||
PostProcessingConfiguration::ConfigurationOption::OptionType::OPTION_BOOL)
|
||||
{
|
||||
ss << StringFromFormat(" int %s;\n", it.first.c_str());
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
ss << " int ubo_align_" << unused_counter++ << "_;\n";
|
||||
}
|
||||
else if (it.second.m_type ==
|
||||
PostProcessingConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
|
||||
{
|
||||
u32 count = static_cast<u32>(it.second.m_integer_values.size());
|
||||
if (count == 1)
|
||||
ss << StringFromFormat(" int %s;\n", it.first.c_str());
|
||||
else
|
||||
ss << StringFromFormat(" int%u %s;\n", count, it.first.c_str());
|
||||
|
||||
for (u32 i = count; i < 4; i++)
|
||||
ss << " int ubo_align_" << unused_counter++ << "_;\n";
|
||||
}
|
||||
else if (it.second.m_type ==
|
||||
PostProcessingConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT)
|
||||
{
|
||||
u32 count = static_cast<u32>(it.second.m_float_values.size());
|
||||
if (count == 1)
|
||||
ss << StringFromFormat(" float %s;\n", it.first.c_str());
|
||||
else
|
||||
ss << StringFromFormat(" float%u %s;\n", count, it.first.c_str());
|
||||
|
||||
for (u32 i = count; i < 4; i++)
|
||||
ss << " float ubo_align_" << unused_counter++ << "_;\n";
|
||||
}
|
||||
}
|
||||
|
||||
ss << "};\n\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string PostProcessing::GetHeader() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << GetUniformBufferHeader();
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
ss << "Texture2DArray samp0 : register(t0);\n";
|
||||
ss << "SamplerState samp0_ss : register(s0);\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n";
|
||||
ss << "VARYING_LOCATION(0) in float3 v_tex0;\n";
|
||||
ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n";
|
||||
}
|
||||
|
||||
// Rename main, since we need to set up globals
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
ss << R"(
|
||||
#define main real_main
|
||||
static float3 v_tex0;
|
||||
static float4 ocol0;
|
||||
|
||||
// Wrappers for sampling functions.
|
||||
#define texture(sampler, coords) sampler.Sample(sampler##_ss, coords)
|
||||
#define textureOffset(sampler, coords, offset) sampler.Sample(sampler##_ss, coords, offset)
|
||||
)";
|
||||
}
|
||||
|
||||
ss << R"(
|
||||
float4 Sample() { return texture(samp0, float3(v_tex0.xy, float(layer))); }
|
||||
float4 SampleLocation(float2 location) { return texture(samp0, float3(location, float(layer))); }
|
||||
float4 SampleLayer(int layer) { return texture(samp0, float3(v_tex0.xy, float(layer))); }
|
||||
#define SampleOffset(offset) textureOffset(samp0, float3(v_tex0.xy, float(layer)), offset)
|
||||
|
||||
float2 GetResolution()
|
||||
{
|
||||
return resolution.xy;
|
||||
}
|
||||
|
||||
float2 GetInvResolution()
|
||||
{
|
||||
return resolution.zw;
|
||||
}
|
||||
|
||||
float2 GetCoordinates()
|
||||
{
|
||||
return v_tex0.xy;
|
||||
}
|
||||
|
||||
uint GetTime()
|
||||
{
|
||||
return time;
|
||||
}
|
||||
|
||||
void SetOutput(float4 color)
|
||||
{
|
||||
ocol0 = color;
|
||||
}
|
||||
|
||||
#define GetOption(x) (x)
|
||||
#define OptionEnabled(x) ((x) != 0)
|
||||
|
||||
)";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string PostProcessing::GetFooter() const
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
return R"(
|
||||
|
||||
#undef main
|
||||
void main(in float3 v_tex0_ : TEXCOORD0, out float4 ocol0_ : SV_Target)
|
||||
{
|
||||
v_tex0 = v_tex0_;
|
||||
real_main();
|
||||
ocol0_ = ocol0;
|
||||
})";
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool PostProcessing::CompileVertexShader()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << GetUniformBufferHeader();
|
||||
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
ss << "void main(in uint id : SV_VertexID, out float3 v_tex0 : TEXCOORD0,\n";
|
||||
ss << " out float4 opos : SV_Position) {\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) out float3 v_tex0;\n";
|
||||
ss << "#define id gl_VertexID\n";
|
||||
ss << "#define opos gl_Position\n";
|
||||
ss << "void main() {\n";
|
||||
}
|
||||
ss << " v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n";
|
||||
ss << " opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n";
|
||||
ss << " v_tex0 = float3(src_rect.xy + (src_rect.zw * v_tex0.xy), 0.0f);\n";
|
||||
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::Vulkan)
|
||||
ss << " opos.y = -opos.y;\n";
|
||||
|
||||
ss << "}\n";
|
||||
|
||||
m_vertex_shader = g_renderer->CreateShaderFromSource(ShaderStage::Vertex, ss.str());
|
||||
if (!m_vertex_shader)
|
||||
{
|
||||
PanicAlert("Failed to compile post-processing vertex shader");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct BuiltinUniforms
|
||||
{
|
||||
float resolution[4];
|
||||
float src_rect[4];
|
||||
s32 time;
|
||||
u32 layer;
|
||||
u32 padding[2];
|
||||
};
|
||||
|
||||
size_t PostProcessing::CalculateUniformsSize() const
|
||||
{
|
||||
// Allocate a vec4 for each uniform to simplify allocation.
|
||||
return sizeof(BuiltinUniforms) + m_config.GetOptions().size() * sizeof(float) * 4;
|
||||
}
|
||||
|
||||
void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle<int>& src,
|
||||
const AbstractTexture* src_tex, int src_layer)
|
||||
{
|
||||
const float rcp_src_width = 1.0f / src_tex->GetWidth();
|
||||
const float rcp_src_height = 1.0f / src_tex->GetHeight();
|
||||
BuiltinUniforms builtin_uniforms = {
|
||||
{static_cast<float>(src_tex->GetWidth()), static_cast<float>(src_tex->GetHeight()),
|
||||
rcp_src_width, rcp_src_height},
|
||||
{static_cast<float>(src.left) * rcp_src_width, static_cast<float>(src.top) * rcp_src_height,
|
||||
static_cast<float>(src.GetWidth()) * rcp_src_width,
|
||||
static_cast<float>(src.GetHeight()) * rcp_src_height},
|
||||
static_cast<s32>(m_timer.GetTimeElapsed()),
|
||||
static_cast<u32>(src_layer),
|
||||
};
|
||||
|
||||
u8* buf = m_uniform_staging_buffer.data();
|
||||
std::memcpy(buf, &builtin_uniforms, sizeof(builtin_uniforms));
|
||||
buf += sizeof(builtin_uniforms);
|
||||
|
||||
for (const auto& it : m_config.GetOptions())
|
||||
{
|
||||
union
|
||||
{
|
||||
u32 as_bool[4];
|
||||
s32 as_int[4];
|
||||
float as_float[4];
|
||||
} value = {};
|
||||
|
||||
switch (it.second.m_type)
|
||||
{
|
||||
case PostProcessingConfiguration::ConfigurationOption::OptionType::OPTION_BOOL:
|
||||
value.as_bool[0] = it.second.m_bool_value ? 1 : 0;
|
||||
break;
|
||||
|
||||
case PostProcessingConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER:
|
||||
ASSERT(it.second.m_integer_values.size() < 4);
|
||||
std::copy_n(it.second.m_integer_values.begin(), it.second.m_integer_values.size(),
|
||||
value.as_int);
|
||||
break;
|
||||
|
||||
case PostProcessingConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT:
|
||||
ASSERT(it.second.m_float_values.size() < 4);
|
||||
std::copy_n(it.second.m_float_values.begin(), it.second.m_float_values.size(),
|
||||
value.as_float);
|
||||
break;
|
||||
}
|
||||
|
||||
std::memcpy(buf, &value, sizeof(value));
|
||||
buf += sizeof(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool PostProcessing::CompilePixelShader()
|
||||
{
|
||||
m_pipeline.reset();
|
||||
m_pixel_shader.reset();
|
||||
|
||||
// Generate GLSL and compile the new shader.
|
||||
m_config.LoadShader(g_ActiveConfig.sPostProcessingShader);
|
||||
m_pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, GetHeader() + m_config.GetShaderCode() + GetFooter());
|
||||
if (!m_pixel_shader)
|
||||
{
|
||||
PanicAlert("Failed to compile post-processing shader %s", m_config.GetShader().c_str());
|
||||
|
||||
// Use default shader.
|
||||
m_config.LoadDefaultShader();
|
||||
m_pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, GetHeader() + m_config.GetShaderCode() + GetFooter());
|
||||
if (!m_pixel_shader)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_uniform_staging_buffer.resize(CalculateUniformsSize());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PostProcessing::CompilePipeline()
|
||||
{
|
||||
AbstractPipelineConfig config = {};
|
||||
config.vertex_shader = m_vertex_shader.get();
|
||||
config.geometry_shader = g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer ?
|
||||
g_shader_cache->GetTexcoordGeometryShader() :
|
||||
nullptr;
|
||||
config.pixel_shader = m_pixel_shader.get();
|
||||
config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
|
||||
config.depth_state = RenderState::GetNoDepthTestingDepthState();
|
||||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetColorFramebufferState(m_framebuffer_format);
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
m_pipeline = g_renderer->CreatePipeline(config);
|
||||
if (!m_pipeline)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace VideoCommon
|
||||
|
Reference in New Issue
Block a user