diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index 0add54d626..1160965add 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -19,6 +19,7 @@ #include #include +#include // DbgNew is not compatible with Glslang #ifdef DBG_NEW @@ -26,6 +27,8 @@ #endif #include "base/logging.h" +#include "base/basictypes.h" +#include "base/stringutil.h" #include "ShaderTranslation.h" #include "ext/glslang/SPIRV/GlslangToSpv.h" #include "thin3d/thin3d.h" @@ -58,13 +61,105 @@ void ShaderTranslationShutdown() { glslang::FinalizeProcess(); } -std::string Preprocess(std::string code, ShaderLanguage lang) { +std::string Preprocess(std::string code, ShaderLanguage lang, Draw::ShaderStage stage) { // This takes GL up to the version we need. return code; } -std::string Postprocess(std::string code, ShaderLanguage lang) { - return code; +struct Builtin { + const char *needle; + const char *replacement; +}; + +// Workaround for deficiency in SPIRV-Cross +static const Builtin builtins[] = { + {"lessThan", + R"( + bool2 lessThan(float2 a, float2 b) { return bool2(a.x < b.x, a.y < b.y); } + bool3 lessThan(float3 a, float3 b) { return bool3(a.x < b.x, a.y < b.y, a.z < b.z); } + bool4 lessThan(float4 a, float4 b) { return bool4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w); } + )"}, + { "lessThanEqual", + R"( + bool2 lessThanEqual(float2 a, float2 b) { return bool2(a.x <= b.x, a.y <= b.y); } + bool3 lessThanEqual(float3 a, float3 b) { return bool3(a.x <= b.x, a.y <= b.y, a.z <= b.z); } + bool4 lessThanEqual(float4 a, float4 b) { return bool4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w); } + )" }, + { "greaterThan", + R"( + bool2 greaterThan(float2 a, float2 b) { return bool2(a.x > b.x, a.y > b.y); } + bool3 greaterThan(float3 a, float3 b) { return bool3(a.x > b.x, a.y > b.y, a.z > b.z); } + bool4 greaterThan(float4 a, float4 b) { return bool4(a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w); } + )" }, + { "greaterThanEqual", + R"( + bool2 greaterThanEqual(float2 a, float2 b) { return bool2(a.x >= b.x, a.y >= b.y); } + bool3 greaterThanEqual(float3 a, float3 b) { return bool3(a.x >= b.x, a.y >= b.y, a.z >= b.z); } + bool4 greaterThanEqual(float4 a, float4 b) { return bool4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w); } + )" }, + { "equal", + R"( + bool2 equal(float2 a, float2 b) { return bool2(a.x == b.x, a.y == b.y); } + bool3 equal(float3 a, float3 b) { return bool3(a.x == b.x, a.y == b.y, a.z == b.z); } + bool4 equal(float4 a, float4 b) { return bool4(a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w); } + )" }, + { "notEqual", + R"( + bool2 notEqual(float2 a, float2 b) { return bool2(a.x != b.x, a.y != b.y); } + bool3 notEqual(float3 a, float3 b) { return bool3(a.x != b.x, a.y != b.y, a.z != b.z); } + bool4 notEqual(float4 a, float4 b) { return bool4(a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w); } + )" }, +}; + +static const Builtin replacements[] = { + { "mix(", "lerp(" }, +}; + +static const char *cbufferDecl = R"( +cbuffer data : register(b0) { + float2 u_texelDelta; + float2 u_pixelDelta; + float4 u_time; +}; +)"; + +// SPIRV-Cross' HLSL output has some deficiencies we need to work around. +// Also we need to rip out single uniforms and replace them with blocks. +// Should probably do it in the source shader instead and then back translate to old style GLSL, but +// SPIRV-Cross currently won't compile with the Android NDK so I can't be bothered. +std::string Postprocess(std::string code, ShaderLanguage lang, Draw::ShaderStage stage) { + if (lang != HLSL_D3D11) + return code; + + std::stringstream out; + + // Output the uniform buffer. + out << cbufferDecl; + + // Add the builtins if required. + for (int i = 0; i < ARRAY_SIZE(builtins); i++) { + if (!builtins[i].needle) + continue; + if (code.find(builtins[i].needle) != std::string::npos) { + out << builtins[i].replacement; + } + } + + // Perform some replacements + for (int i = 0; i < ARRAY_SIZE(replacements); i++) { + code = ReplaceAll(code, replacements[i].needle, replacements[i].replacement); + } + + // Alright, now let's go through it line by line and zap the single uniforms. + std::string line; + std::stringstream instream(code); + while (std::getline(instream, line)) { + if (line.find("uniform float") != std::string::npos) + continue; + out << line << "\n"; + } + std::string output = out.str(); + return output; } bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShaderMetadata *destMetadata, std::string src, ShaderLanguage srcLang, Draw::ShaderStage stage, std::string *errorMessage) { @@ -83,7 +178,7 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade EShLanguage shaderStage = GetLanguage(stage); glslang::TShader shader(shaderStage); - std::string preprocessed = Preprocess(src, srcLang); + std::string preprocessed = Preprocess(src, srcLang, stage); shaderStrings[0] = src.c_str(); shader.setStrings(shaderStrings, 1); @@ -146,7 +241,7 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade options.shader_model = 50; hlsl.set_options(options); std::string raw = hlsl.compile(); - *dest = Postprocess(raw, destLang); + *dest = Postprocess(raw, destLang, stage); return true; } #endif diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 53ef030983..2595fe1b93 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -125,6 +125,7 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) device_->CreateBuffer(&vb, nullptr, &quadBuffer_); vb.ByteWidth = ROUND_UP(sizeof(PostShaderUniforms), 16); vb.Usage = D3D11_USAGE_DYNAMIC; + vb.BindFlags = D3D11_BIND_CONSTANT_BUFFER; device_->CreateBuffer(&vb, nullptr, &postConstants_); ShaderTranslationInit(); @@ -156,6 +157,7 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { quadInputLayout_->Release(); quadBuffer_->Release(); fsQuadBuffer_->Release(); + postConstants_->Release(); if (drawPixelsTex_) drawPixelsTex_->Release(); @@ -454,6 +456,13 @@ void FramebufferManagerD3D11::BindPostShader(const PostShaderUniforms &uniforms) context_->IASetInputLayout(postInputLayout_); context_->PSSetShader(postPixelShader_, 0, 0); context_->VSSetShader(postVertexShader_, 0, 0); + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(postConstants_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &uniforms, sizeof(uniforms)); + context_->Unmap(postConstants_, 0); + context_->VSSetConstantBuffers(0, 1, &postConstants_); // Probably not necessary + context_->PSSetConstantBuffers(0, 1, &postConstants_); } void FramebufferManagerD3D11::RebindFramebuffer() { @@ -877,7 +886,7 @@ void FramebufferManagerD3D11::EndFrame() { zoom = (PSP_CoreParameter().pixelHeight + 479) / 480; } } - if (zoom <= 1) + if (zoom <= 1 || postShaderIsUpscalingFilter_) zoom = 1; if (g_Config.IsPortrait()) {