diff --git a/DDrawCompat/Config/Settings/DisplayFilter.cpp b/DDrawCompat/Config/Settings/DisplayFilter.cpp index 6c1e0dd..b69fc62 100644 --- a/DDrawCompat/Config/Settings/DisplayFilter.cpp +++ b/DDrawCompat/Config/Settings/DisplayFilter.cpp @@ -8,6 +8,7 @@ namespace Config : MappedSetting("DisplayFilter", "bilinear", { {"point", POINT}, {"bilinear", BILINEAR}, + {"bicubic", BICUBIC}, {"lanczos", LANCZOS}, }) { @@ -18,6 +19,7 @@ namespace Config switch (m_value) { case BILINEAR: + case BICUBIC: return { "Blur", 0, 100, 0, m_param }; case LANCZOS: return { "Lobes", 2, 4, 2, m_param }; diff --git a/DDrawCompat/Config/Settings/DisplayFilter.h b/DDrawCompat/Config/Settings/DisplayFilter.h index e6f8cdb..28648e5 100644 --- a/DDrawCompat/Config/Settings/DisplayFilter.h +++ b/DDrawCompat/Config/Settings/DisplayFilter.h @@ -11,7 +11,8 @@ namespace Config public: static const UINT POINT = 0; static const UINT BILINEAR = 1; - static const UINT LANCZOS = 2; + static const UINT BICUBIC = 2; + static const UINT LANCZOS = 3; DisplayFilter(); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 39e95cc..be5691b 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ namespace D3dDdi { ShaderBlitter::ShaderBlitter(Device& device) : m_device(device) + , m_psBicubic(createPixelShader(g_psBicubic)) , m_psColorKey(createPixelShader(g_psColorKey)) , m_psColorKeyBlend(createPixelShader(g_psColorKeyBlend)) , m_psDepthBlt(createPixelShader(g_psDepthBlt)) @@ -68,6 +70,8 @@ namespace D3dDdi , m_psPaletteLookup(createPixelShader(g_psPaletteLookup)) , m_psTextureSampler(createPixelShader(g_psTextureSampler)) , m_vertexShaderDecl(createVertexShaderDecl()) + , m_convolutionBaseParams{} + , m_convolutionExtraParams{} , m_vertices{} { for (std::size_t i = 0; i < m_vertices.size(); ++i) @@ -76,6 +80,22 @@ namespace D3dDdi } } + void ShaderBlitter::bicubicBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT blurPercent) + { + LOG_FUNC("ShaderBlitter::bicubicBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcSubResourceIndex, srcRect, blurPercent); + + const float B = blurPercent / 100.0f; + const float C = (1 - B) / 2; + + m_convolutionExtraParams[0] = { (12 - 9 * B - 6 * C) / 6, (-18 + 12 * B + 6 * C) / 6, 0, (6 - 2 * B) / 6 }; + m_convolutionExtraParams[1] = { (-B - 6 * C) / 6, (6 * B + 30 * C) / 6, (-12 * B - 48 * C) / 6, (8 * B + 24 * C) / 6 }; + + convolutionBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + 2, m_psBicubic.get()); + } + void ShaderBlitter::blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, HANDLE pixelShader, UINT filter, UINT flags, const BYTE* alpha, const Gdi::Region& srcRgn) @@ -192,23 +212,23 @@ namespace D3dDdi const float firstKernelOffset = firstSampleOffset * kernelStep; const float firstTextureOffset = firstSampleOffset * textureStep; - std::array reg = {}; - reg[0] = { textureSize.x, textureSize.y, textureSizeRcp.x, textureSizeRcp.y }; + m_convolutionBaseParams[0] = { textureSize.x, textureSize.y, textureSizeRcp.x, textureSizeRcp.y }; if (isHorizontal) { - reg[1] = { firstTextureOffset, 0, firstKernelOffset, 0 }; - reg[2] = { textureStep, 0, kernelStep, 0 }; - reg[3] = { -0.5f, 0, 0.5f * textureSizeRcp.x, 0.5f * textureSizeRcp.y }; + m_convolutionBaseParams[1] = { firstTextureOffset, 0, firstKernelOffset, 0 }; + m_convolutionBaseParams[2] = { textureStep, 0, kernelStep, 0 }; + m_convolutionBaseParams[3] = { -0.5f, 0, 0.5f * textureSizeRcp.x, 0.5f * textureSizeRcp.y }; } else { - reg[1] = { 0, firstTextureOffset, 0, firstKernelOffset }; - reg[2] = { 0, textureStep, 0, kernelStep }; - reg[3] = { 0, -0.5f, 0.5f * textureSizeRcp.x, 0.5f * textureSizeRcp.y }; + m_convolutionBaseParams[1] = { 0, firstTextureOffset, 0, firstKernelOffset }; + m_convolutionBaseParams[2] = { 0, textureStep, 0, kernelStep }; + m_convolutionBaseParams[3] = { 0, -0.5f, 0.5f * textureSizeRcp.x, 0.5f * textureSizeRcp.y }; } - reg[4] = { support, 1.0f / support, 0, 0 }; + m_convolutionBaseParams[4] = { support, 1.0f / support, 0, 0 }; - DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), { 0, reg.size() }, reg.data()); + DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), + { 0, m_convolutionBaseParams.size() + m_convolutionExtraParams.size()}, m_convolutionBaseParams.data()); blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, pixelShader, D3DTEXF_LINEAR | D3DTEXF_SRGB); } @@ -470,6 +490,11 @@ namespace D3dDdi srcResource, srcSubResourceIndex, srcRect, Config::displayFilter.getParam()); break; + case Config::Settings::DisplayFilter::BICUBIC: + m_device.getShaderBlitter().bicubicBlt(rt, rtIndex, rtRect, + srcResource, srcSubResourceIndex, srcRect, Config::displayFilter.getParam()); + break; + case Config::Settings::DisplayFilter::LANCZOS: m_device.getShaderBlitter().lanczosBlt(rt, rtIndex, rtRect, srcResource, srcSubResourceIndex, srcRect, Config::displayFilter.getParam()); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index 2442821..f578bf4 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -25,6 +25,8 @@ namespace D3dDdi ShaderBlitter& operator=(const ShaderBlitter&) = delete; ShaderBlitter& operator=(ShaderBlitter&&) = delete; + void bicubicBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT blurPercent); void colorKeyBlt(const Resource& dstResource, UINT dstSubResourceIndex, const Resource& srcResource, UINT srcSubResourceIndex, DeviceState::ShaderConstF srcColorKey); void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -86,6 +88,7 @@ namespace D3dDdi void setTextureCoords(UINT stage, const RECT& rect, UINT width, UINT height); Device& m_device; + std::unique_ptr m_psBicubic; std::unique_ptr m_psColorKey; std::unique_ptr m_psColorKeyBlend; std::unique_ptr m_psDepthBlt; @@ -97,6 +100,8 @@ namespace D3dDdi std::unique_ptr m_psPaletteLookup; std::unique_ptr m_psTextureSampler; std::unique_ptr m_vertexShaderDecl; + std::array m_convolutionBaseParams; + std::array m_convolutionExtraParams; std::array m_vertices; }; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 461b935..c98a678 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -460,6 +460,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 5f5cc09..94b4300 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -1103,6 +1103,9 @@ Shaders + + Shaders + diff --git a/DDrawCompat/Shaders/Bicubic.hlsl b/DDrawCompat/Shaders/Bicubic.hlsl new file mode 100644 index 0000000..5a912b0 --- /dev/null +++ b/DDrawCompat/Shaders/Bicubic.hlsl @@ -0,0 +1,9 @@ +#include "Convolution.hlsli" + +float kernel(float x) +{ + x = min(abs(x), g_support); + const float4 weights = x < 1 ? g_extraParams[0] : g_extraParams[1]; + const float4 powers = float4(pow(x, 3), pow(x, 2), x, 1); + return dot(weights, powers); +} diff --git a/DDrawCompat/Shaders/Convolution.hlsli b/DDrawCompat/Shaders/Convolution.hlsli index 31902fc..3c9d836 100644 --- a/DDrawCompat/Shaders/Convolution.hlsli +++ b/DDrawCompat/Shaders/Convolution.hlsli @@ -3,6 +3,8 @@ int g_sampleCountX : register(i0); int g_sampleCountY : register(i1); float4 c[32] : register(c0); +float4 g_extraParams[2] : register(c5); + static const float2 g_textureSize = c[0].xy; static const float2 g_textureSizeRcp = c[0].zw; static const float4 g_firstCoordOffset = c[1];