diff --git a/DDrawCompat/Config/Settings/DisplayFilter.cpp b/DDrawCompat/Config/Settings/DisplayFilter.cpp index c215530..6c1e0dd 100644 --- a/DDrawCompat/Config/Settings/DisplayFilter.cpp +++ b/DDrawCompat/Config/Settings/DisplayFilter.cpp @@ -5,17 +5,25 @@ namespace Config namespace Settings { DisplayFilter::DisplayFilter() - : MappedSetting("DisplayFilter", "bilinear", { {"point", POINT}, {"bilinear", BILINEAR} }) + : MappedSetting("DisplayFilter", "bilinear", { + {"point", POINT}, + {"bilinear", BILINEAR}, + {"lanczos", LANCZOS}, + }) { } Setting::ParamInfo DisplayFilter::getParamInfo() const { - if (BILINEAR == m_value) + switch (m_value) { + case BILINEAR: return { "Blur", 0, 100, 0, m_param }; + case LANCZOS: + return { "Lobes", 2, 4, 2, m_param }; + default: + return {}; } - return {}; } } } diff --git a/DDrawCompat/Config/Settings/DisplayFilter.h b/DDrawCompat/Config/Settings/DisplayFilter.h index 342d059..e6f8cdb 100644 --- a/DDrawCompat/Config/Settings/DisplayFilter.h +++ b/DDrawCompat/Config/Settings/DisplayFilter.h @@ -11,6 +11,7 @@ namespace Config public: static const UINT POINT = 0; static const UINT BILINEAR = 1; + static const UINT LANCZOS = 2; DisplayFilter(); diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index cbd060a..efb4d22 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace D3dDdi { @@ -56,6 +57,7 @@ namespace D3dDdi DrawPrimitive& getDrawPrimitive() { return m_drawPrimitive; } const D3DDDI_DEVICEFUNCS& getOrigVtable() const { return m_origVtable; } RGBQUAD* getPalette(UINT paletteHandle) { return m_palettes[paletteHandle].data(); } + SurfaceRepository& getRepo() const { return SurfaceRepository::get(m_adapter); } Resource* getResource(HANDLE resource); DeviceState& getState() { return m_state; } ShaderBlitter& getShaderBlitter() { return m_shaderBlitter; } diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 1fd61b7..d345a6d 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -48,6 +48,20 @@ namespace D3dDdi m_state.m_device, &m_data, &m_state.m_pixelShaderConst[m_data.Register][0]); } + DeviceState::TempPixelShaderConstI::TempPixelShaderConstI( + DeviceState& state, const D3DDDIARG_SETPIXELSHADERCONSTI& data, const ShaderConstI* registers) + : m_state(state) + , m_data(data) + { + state.m_device.getOrigVtable().pfnSetPixelShaderConstI(state.m_device, &data, ®isters[0][0]); + } + + DeviceState::TempPixelShaderConstI::~TempPixelShaderConstI() + { + m_state.m_device.getOrigVtable().pfnSetPixelShaderConstI( + m_state.m_device, &m_data, &m_state.m_pixelShaderConstI[m_data.Register][0]); + } + DeviceState::DeviceState(Device& device) : m_device(device) , m_app{} diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index d098e26..d2737a8 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -59,6 +59,17 @@ namespace D3dDdi D3DDDIARG_SETPIXELSHADERCONST m_data; }; + class TempPixelShaderConstI + { + public: + TempPixelShaderConstI(DeviceState& state, const D3DDDIARG_SETPIXELSHADERCONSTI& data, const ShaderConstI* registers); + ~TempPixelShaderConstI(); + + private: + DeviceState& m_state; + D3DDDIARG_SETPIXELSHADERCONSTI m_data; + }; + class TempStateLock { public: diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index dd4cc19..d817600 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -212,7 +211,7 @@ namespace D3dDdi if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface) { - auto& repo = SurfaceRepository::get(m_device.getAdapter()); + auto& repo = m_device.getRepo(); repo.release(m_msaaSurface); repo.release(m_msaaResolvedSurface); repo.release(m_lockRefSurface); @@ -669,11 +668,12 @@ namespace D3dDdi void Resource::downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight) { + auto& repo = m_device.getRepo(); while (srcWidth > 2 * dstWidth || srcHeight > 2 * dstHeight) { const LONG newSrcWidth = std::max(dstWidth, (srcWidth + 1) / 2); const LONG newSrcHeight = std::max(dstHeight, (srcHeight + 1) / 2); - auto& nextRt = getNextRenderTarget(rt, newSrcWidth, newSrcHeight); + auto& nextRt = repo.getNextRenderTarget(newSrcWidth, newSrcHeight, rt); if (!nextRt.resource) { return; @@ -808,17 +808,6 @@ namespace D3dDdi return { D3DDDIMULTISAMPLE_NONE, 0 }; } - const SurfaceRepository::Surface& Resource::getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height) - { - auto& repo = SurfaceRepository::get(m_device.getAdapter()); - auto nextRt = &repo.getTempRenderTarget(width, height, 0); - if (nextRt->resource == currentRt) - { - nextRt = &repo.getTempRenderTarget(width, height, 1); - } - return *nextRt; - } - RECT Resource::getRect(UINT subResourceIndex) const { const auto& si = m_fixedData.pSurfList[subResourceIndex]; @@ -855,8 +844,7 @@ namespace D3dDdi const RECT srcRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; if (!m_fixedData.Flags.Texture) { - auto& repo = SurfaceRepository::get(m_device.getAdapter()); - auto& texture = repo.getTempTexture(si.Width, si.Height, m_fixedData.Format); + auto& texture = m_device.getRepo().getTempTexture(si.Width, si.Height, m_fixedData.Format); if (!texture.resource) { return; @@ -1193,8 +1181,8 @@ namespace D3dDdi if (!m_colorKeyedSurface.surface) { - auto& repo = SurfaceRepository::get(m_device.getAdapter()); - repo.getSurface(m_colorKeyedSurface, m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, + m_device.getRepo().getSurface(m_colorKeyedSurface, + m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, D3DDDIFMT_A8R8G8B8, DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | (m_fixedData.MipLevels > 1 ? DDSCAPS_MIPMAP : 0), m_fixedData.SurfCount, @@ -1244,8 +1232,8 @@ namespace D3dDdi data.DstRect = g_presentationRect; } - auto& repo = SurfaceRepository::get(m_device.getAdapter()); - const auto& rtSurface = repo.getTempRenderTarget(srcWidth, srcHeight); + auto& repo = m_device.getRepo(); + const auto& rtSurface = repo.getNextRenderTarget(srcWidth, srcHeight); auto rt = rtSurface.resource ? rtSurface.resource : this; auto rtIndex = rtSurface.resource ? 0 : data.DstSubResourceIndex; auto rtRect = rtSurface.resource ? data.SrcRect : data.DstRect; @@ -1300,39 +1288,7 @@ namespace D3dDdi const LONG dstHeight = data.DstRect.bottom - data.DstRect.top; downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight); - const SurfaceRepository::Surface* rtGamma = nullptr; - if (!ShaderBlitter::isGammaRampDefault() && - SurfaceRepository::get(m_device.getAdapter()).getGammaRampTexture()) - { - rtGamma = &getNextRenderTarget(rt, dstWidth, dstHeight); - } - const bool useGamma = rtGamma && rtGamma->resource; - auto& rtNext = useGamma ? *rtGamma->resource : *this; - auto rtNextIndex = useGamma ? 0 : data.DstSubResourceIndex; - auto rtNextRect = useGamma ? RECT{ 0, 0, dstWidth, dstHeight } : data.DstRect; - - if (Config::Settings::DisplayFilter::BILINEAR == Config::displayFilter.get()) - { - m_device.getShaderBlitter().genBilinearBlt(rtNext, rtNextIndex, rtNextRect, - *rt, data.SrcRect, Config::displayFilter.getParam()); - } - else - { - D3DDDIARG_BLT blt = {}; - blt.hSrcResource = *rt; - blt.SrcSubResourceIndex = 0; - blt.SrcRect = data.SrcRect; - blt.hDstResource = rtNext; - blt.DstSubResourceIndex = rtNextIndex; - blt.DstRect = rtNextRect; - blt.Flags.Point = 1; - m_device.getOrigVtable().pfnBlt(m_device, &blt); - } - - if (useGamma) - { - m_device.getShaderBlitter().gammaBlt(*this, data.DstSubResourceIndex, data.DstRect, rtNext, rtNextRect); - } + m_device.getShaderBlitter().displayBlt(*this, data.DstSubResourceIndex, data.DstRect, *rt, 0, data.SrcRect); clearRectExterior(data.DstSubResourceIndex, data.DstRect); @@ -1351,7 +1307,7 @@ namespace D3dDdi std::vector layeredWindows, const RECT& monitorRect) { auto& blitter = m_device.getShaderBlitter(); - auto& repo = SurfaceRepository::get(m_device.getAdapter()); + auto& repo = m_device.getRepo(); for (auto& layeredWindow : layeredWindows) { @@ -1513,7 +1469,7 @@ namespace D3dDdi return LOG_RESULT(m_device.getOrigVtable().pfnBlt(m_device, &data)); } - auto& repo = SurfaceRepository::get(m_device.getAdapter()); + auto& repo = m_device.getRepo(); Resource* srcRes = &srcResource; UINT srcIndex = data.SrcSubResourceIndex; @@ -1574,7 +1530,7 @@ namespace D3dDdi { LONG width = data.DstRect.right - data.DstRect.left; LONG height = data.DstRect.bottom - data.DstRect.top; - auto& rt = getNextRenderTarget(srcRes, width, height); + auto& rt = repo.getNextRenderTarget(width, height, srcRes); if (!rt.resource) { return LOG_RESULT(E_OUTOFMEMORY); @@ -1716,39 +1672,36 @@ namespace D3dDdi static_cast(m_fixedData.pSurfList[0].Height) != m_scaledSize.cy; if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig || isScaled) { + auto& repo = m_device.getRepo(); const DWORD caps = (m_fixedData.Flags.ZBuffer ? DDSCAPS_ZBUFFER : DDSCAPS_3DDEVICE) | DDSCAPS_VIDEOMEMORY; if (D3DDDIMULTISAMPLE_NONE != msaa.first) { g_msaaOverride = msaa; - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaSurface, - scaledSize.cx, scaledSize.cy, formatConfig, caps, m_fixedData.SurfCount); + repo.getSurface(m_msaaSurface, scaledSize.cx, scaledSize.cy, formatConfig, caps, m_fixedData.SurfCount); g_msaaOverride = {}; } if (m_fixedData.Flags.ZBuffer && m_msaaSurface.resource) { g_msaaOverride = msaa; - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_nullSurface, - scaledSize.cx, scaledSize.cy, FOURCC_NULL, + repo.getSurface(m_nullSurface, scaledSize.cx, scaledSize.cy, FOURCC_NULL, DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); g_msaaOverride = {}; } - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, - scaledSize.cx, scaledSize.cy, m_nullSurface.resource ? FOURCC_INTZ : formatConfig, - caps, m_fixedData.SurfCount); + repo.getSurface(m_msaaResolvedSurface, scaledSize.cx, scaledSize.cy, + m_nullSurface.resource ? FOURCC_INTZ : formatConfig, caps, m_fixedData.SurfCount); if (!m_msaaResolvedSurface.resource && m_msaaSurface.resource) { m_msaaSurface = {}; - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, - scaledSize.cx, scaledSize.cy, formatConfig, caps, m_fixedData.SurfCount); + repo.getSurface(m_msaaResolvedSurface, scaledSize.cx, scaledSize.cy, + formatConfig, caps, m_fixedData.SurfCount); } if (!m_fixedData.Flags.ZBuffer && m_msaaResolvedSurface.resource) { - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_lockRefSurface, - m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, m_fixedData.Format, - DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); + repo.getSurface(m_lockRefSurface, m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, + m_fixedData.Format, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); if (isScaled && m_device.getGdiResource() == this) { diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index c2fe734..5cf973d 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -114,7 +114,6 @@ namespace D3dDdi void fixResourceData(); D3DDDIFORMAT getFormatConfig(); std::pair getMultisampleConfig(); - const SurfaceRepository::Surface& getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height); SIZE getScaledSize(); bool isValidRect(UINT subResourceIndex, const RECT& rect); void loadFromLockRefResource(UINT subResourceIndex); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index c82f3cc..39e95cc 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +63,7 @@ namespace D3dDdi , m_psDrawCursor(createPixelShader(g_psDrawCursor)) , m_psGamma(createPixelShader(g_psGamma)) , m_psGenBilinear(createPixelShader(g_psGenBilinear)) + , m_psLanczos(createPixelShader(g_psLanczos)) , m_psLockRef(createPixelShader(g_psLockRef)) , m_psPaletteLookup(createPixelShader(g_psPaletteLookup)) , m_psTextureSampler(createPixelShader(g_psTextureSampler)) @@ -172,6 +175,108 @@ namespace D3dDdi m_psColorKeyBlend.get(), D3DTEXF_POINT); } + void ShaderBlitter::convolution(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, + bool isHorizontal, float kernelStep, int sampleCount, float support, HANDLE pixelShader) + { + LOG_FUNC("ShaderBlitter::convolution", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcSubResourceIndex, srcRect, + isHorizontal, kernelStep, sampleCount, support, pixelShader); + + const auto& srcDesc = srcResource.getFixedDesc().pSurfList[0]; + const Float2 textureSize(srcDesc.Width, srcDesc.Height); + const Float2 textureSizeRcp = Float2(1) / textureSize; + const float textureStep = isHorizontal ? textureSizeRcp.x : textureSizeRcp.y; + + const int firstSampleOffset = -sampleCount / 2 + 1; + const float firstKernelOffset = firstSampleOffset * kernelStep; + const float firstTextureOffset = firstSampleOffset * textureStep; + + std::array reg = {}; + reg[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 }; + } + 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 }; + } + reg[4] = { support, 1.0f / support, 0, 0 }; + + DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), { 0, reg.size() }, reg.data()); + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + pixelShader, D3DTEXF_LINEAR | D3DTEXF_SRGB); + } + + void ShaderBlitter::convolutionBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, + Float2 support, HANDLE pixelShader) + { + LOG_FUNC("ShaderBlitter::convolutionBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcSubResourceIndex, srcRect, support, pixelShader); + + const Int2 dstSize(dstRect.right - dstRect.left, dstRect.bottom - dstRect.top); + const Int2 srcSize(srcRect.right - srcRect.left, srcRect.bottom - srcRect.top); + const Float2 scale = Float2(dstSize) / Float2(srcSize); + const Float2 kernelStep = min(scale, Float2(1)); + const Int2 sampleCount = min(Float2(2) * ceil(support / kernelStep), Float2(255)); + + if (srcSize.y == dstSize.y) + { + return convolution(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + true, kernelStep.x, sampleCount.x, support.x, pixelShader); + } + else if (srcSize.x == dstSize.x) + { + return convolution(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + false, kernelStep.y, sampleCount.y, support.y, pixelShader); + } + + const bool isHorizontalFirst = dstSize.x * srcSize.y <= srcSize.x * dstSize.y; + RECT rect = { 0, 0, srcSize.x, srcSize.y }; + if (dstSize.x * srcSize.y <= srcSize.x * dstSize.y) + { + rect.right = dstSize.x; + } + else + { + rect.bottom = dstSize.y; + } + + auto rt = m_device.getRepo().getNextRenderTarget(rect.right, rect.bottom, &srcResource, &dstResource).resource; + if (!rt) + { + return; + } + + const std::array reg = { { + { sampleCount.x }, + { sampleCount.y } + } }; + + DeviceState::TempPixelShaderConstI tempPsConstI(m_device.getState(), { 0, reg.size()}, reg.data()); + + if (isHorizontalFirst) + { + convolution(*rt, 0, rect, srcResource, srcSubResourceIndex, srcRect, + true, kernelStep.x, sampleCount.x, support.x, pixelShader); + convolution(dstResource, dstSubResourceIndex, dstRect, *rt, 0, rect, + false, kernelStep.y, sampleCount.y, support.y, pixelShader); + } + else + { + convolution(*rt, 0, rect, srcResource, srcSubResourceIndex, srcRect, + false, kernelStep.y, sampleCount.y, support.y, pixelShader); + convolution(dstResource, dstSubResourceIndex, dstRect, *rt, 0, rect, + true, kernelStep.x, sampleCount.x, support.x, pixelShader); + } + } + std::unique_ptr ShaderBlitter::createPixelShader(const BYTE* code, UINT size) { D3DDDIARG_CREATEPIXELSHADER data = {}; @@ -214,7 +319,7 @@ namespace D3dDdi { LOG_FUNC("ShaderBlitter::cursorBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, cursor, pt); - auto& repo = SurfaceRepository::get(m_device.getAdapter()); + auto& repo = m_device.getRepo(); auto cur = repo.getCursor(cursor); if (!cur.colorTexture) { @@ -316,6 +421,67 @@ namespace D3dDdi m_device.flushPrimitives(); } + void ShaderBlitter::displayBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect) + { + auto& repo = m_device.getRepo(); + const bool useGamma = !g_isGammaRampDefault && repo.getGammaRampTexture(); + + if (Rect::isEqualSize(dstRect, srcRect)) + { + if (useGamma) + { + gammaBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect); + return; + } + + D3DDDIARG_BLT data = {}; + data.hSrcResource = srcResource; + data.SrcSubResourceIndex = srcSubResourceIndex; + data.SrcRect = srcRect; + data.hDstResource = dstResource; + data.DstSubResourceIndex = dstSubResourceIndex; + data.DstRect = dstRect; + data.Flags.Point = 1; + m_device.getOrigVtable().pfnBlt(m_device, &data); + return; + } + + RECT r = { 0, 0, dstRect.right - dstRect.left, dstRect.bottom - dstRect.top }; + Resource* rtGamma = nullptr; + if (useGamma) + { + rtGamma = repo.getNextRenderTarget(r.right, r.bottom, &srcResource).resource; + } + + const auto& rt = rtGamma ? *rtGamma : dstResource; + const auto rtIndex = rtGamma ? 0 : dstSubResourceIndex; + const auto& rtRect = rtGamma ? r : dstRect; + + switch (Config::displayFilter.get()) + { + case Config::Settings::DisplayFilter::POINT: + m_device.getShaderBlitter().textureBlt(rt, rtIndex, rtRect, + srcResource, srcSubResourceIndex, srcRect, D3DTEXF_POINT); + break; + + case Config::Settings::DisplayFilter::BILINEAR: + m_device.getShaderBlitter().genBilinearBlt(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()); + break; + } + + if (rtGamma) + { + gammaBlt(dstResource, dstSubResourceIndex, dstRect, rt, rtIndex, rtRect); + } + } + void ShaderBlitter::drawRect(const RECT& srcRect, const RectF& dstRect, UINT srcWidth, UINT srcHeight) { m_vertices[0].xy = { dstRect.left - 0.5f, dstRect.top - 0.5f }; @@ -333,12 +499,12 @@ namespace D3dDdi } void ShaderBlitter::gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, - const Resource& srcResource, const RECT& srcRect) + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect) { LOG_FUNC("ShaderBlitter::gammaBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, - static_cast(srcResource), srcRect); + static_cast(srcResource), srcSubResourceIndex, srcRect); - auto gammaRampTexture(SurfaceRepository::get(m_device.getAdapter()).getGammaRampTexture()); + auto gammaRampTexture(m_device.getRepo().getGammaRampTexture()); if (!gammaRampTexture) { return; @@ -371,13 +537,13 @@ namespace D3dDdi } void ShaderBlitter::genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, - const Resource& srcResource, const RECT& srcRect, UINT blurPercent) + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT blurPercent) { LOG_FUNC("ShaderBlitter::genBilinearBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, - static_cast(srcResource), srcRect, blurPercent); + static_cast(srcResource), srcSubResourceIndex, srcRect, blurPercent); if (100 == blurPercent) { - blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, m_psTextureSampler.get(), D3DTEXF_LINEAR | D3DTEXF_SRGB); return; } @@ -396,13 +562,18 @@ namespace D3dDdi } }; DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), { 0, registers.size() }, registers.data()); - blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR | D3DTEXF_SRGB); } - bool ShaderBlitter::isGammaRampDefault() + void ShaderBlitter::lanczosBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT lobes) { - return g_isGammaRampDefault; + LOG_FUNC("ShaderBlitter::lanczosBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcSubResourceIndex, srcRect, lobes); + + convolutionBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + lobes, m_psLanczos.get()); } void ShaderBlitter::lockRefBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -425,7 +596,7 @@ namespace D3dDdi static_cast(srcResource), srcSubResourceIndex, srcRect, Compat::array(reinterpret_cast(palette), 256)); - auto paletteTexture(SurfaceRepository::get(m_device.getAdapter()).getPaletteTexture()); + auto paletteTexture(m_device.getRepo().getPaletteTexture()); if (!paletteTexture) { return; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index 77925a6..2442821 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -5,6 +5,7 @@ #include +#include #include #include @@ -30,10 +31,14 @@ namespace D3dDdi HCURSOR cursor, POINT pt); void depthBlt(const Resource& dstResource, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect, HANDLE nullResource); + void displayBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect); void gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, - const Resource& srcResource, const RECT& srcRect); + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect); void genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, - const Resource& srcResource, const RECT& srcRect, UINT blurPercent); + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT blurPercent); + void lanczosBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT lobes); void lockRefBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, const Resource& lockRefResource); @@ -44,7 +49,6 @@ namespace D3dDdi UINT filter, const DeviceState::ShaderConstF* srcColorKey = nullptr, const BYTE* alpha = nullptr, const Gdi::Region& srcRgn = nullptr); - static bool isGammaRampDefault(); static void resetGammaRamp(); static void setGammaRamp(const D3DDDI_GAMMA_RAMP_RGB256x3x16& ramp); @@ -62,6 +66,12 @@ namespace D3dDdi void blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, HANDLE pixelShader, UINT filter, UINT flags = 0, const BYTE* alpha = nullptr, const Gdi::Region& srcRgn = nullptr); + void convolution(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, + bool isHorizontal, float kernelStep, int sampleCount, float support, HANDLE pixelShader); + void convolutionBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, + Float2 support, HANDLE pixelShader); template std::unique_ptr createPixelShader(const BYTE(&code)[N]) @@ -82,6 +92,7 @@ namespace D3dDdi std::unique_ptr m_psDrawCursor; std::unique_ptr m_psGamma; std::unique_ptr m_psGenBilinear; + std::unique_ptr m_psLanczos; std::unique_ptr m_psLockRef; std::unique_ptr m_psPaletteLookup; std::unique_ptr m_psTextureSampler; diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 6141fbd..9dafed4 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -229,6 +229,23 @@ namespace D3dDdi return surface.resource; } + const SurfaceRepository::Surface& SurfaceRepository::getNextRenderTarget( + DWORD width, DWORD height, const Resource* currentSrcRt, const Resource* currentDstRt) + { + std::size_t index = 0; + while (index < m_renderTargets.size()) + { + auto rt = m_renderTargets[index].resource; + if (!rt || rt != currentSrcRt && rt != currentDstRt) + { + break; + } + ++index; + } + return getTempSurface(m_renderTargets[index], width, height, D3DDDIFMT_A8R8G8B8, + DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY); + } + Resource* SurfaceRepository::getPaletteTexture() { return getSurface(m_paletteTexture, 256, 1, D3DDDIFMT_A8R8G8B8, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource; @@ -263,16 +280,6 @@ namespace D3dDdi return surface; } - const SurfaceRepository::Surface& SurfaceRepository::getTempRenderTarget(DWORD width, DWORD height, UINT index) - { - if (index >= m_renderTargets.size()) - { - m_renderTargets.resize(index + 1); - } - return getTempSurface(m_renderTargets[index], width, height, D3DDDIFMT_A8R8G8B8, - DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY); - } - SurfaceRepository::Surface& SurfaceRepository::getTempSurface(Surface& surface, DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps, UINT surfaceCount) { diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index b0b651c..e9c69fd 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include @@ -41,9 +43,10 @@ namespace D3dDdi Resource* getLogicalXorTexture(); Resource* getPaletteTexture(); Resource* getGammaRampTexture(); + const Surface& getNextRenderTarget(DWORD width, DWORD height, + const Resource* currentSrcRt = nullptr, const Resource* currentDstRt = nullptr); Surface& getSurface(Surface& surface, DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1, DWORD caps2 = 0); - const Surface& getTempRenderTarget(DWORD width, DWORD height, UINT index = 0); Surface& getTempSysMemSurface(DWORD width, DWORD height); Surface& getTempSurface(Surface& surface, DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1); @@ -74,7 +77,7 @@ namespace D3dDdi Surface m_gammaRampTexture; Surface m_logicalXorTexture; Surface m_paletteTexture; - std::vector m_renderTargets; + std::array m_renderTargets; std::map m_textures; std::vector m_releasedSurfaces; Surface m_sysMemSurface; diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index cad4865..04f8dba 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -194,7 +194,7 @@ namespace return nullptr; } - auto& repo = D3dDdi::SurfaceRepository::get(device->getAdapter()); + auto& repo = device->getRepo(); D3dDdi::SurfaceRepository::Surface surface = {}; repo.getSurface(surface, width, height, D3DDDIFMT_X8R8G8B8, DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY); diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index ba2f5ca..fe2b9cd 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -51,7 +51,7 @@ namespace return LOG_RESULT(nullptr); } - auto& repo = D3dDdi::SurfaceRepository::get(device->getAdapter()); + auto& repo = device->getRepo(); D3dDdi::SurfaceRepository::Surface surface = {}; repo.getSurface(surface, 1, 1, D3DDDIFMT_X8R8G8B8, DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY); diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index ecc816e..19335f2 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -80,7 +80,7 @@ namespace return bltFunc(This, lpDDSrcSurface, lpSrcRect); } - auto& repo = D3dDdi::SurfaceRepository::get(srcResource->getDevice().getAdapter()); + auto& repo = srcResource->getDevice().getRepo(); RECT srcRect = getRect(lpSrcRect, srcDesc); auto& tex = repo.getTempTexture(srcRect.right - srcRect.left, srcRect.bottom - srcRect.top, srcResource->getOrigDesc().Format); diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index fe9ec88..461b935 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -91,7 +91,7 @@ $(IntDir)%(RelativeDir)%(Filename).h - 2.0 + 3.0 Pixel false @@ -128,7 +128,7 @@ $(IntDir)%(RelativeDir)%(Filename).h - 2.0 + 3.0 Pixel @@ -457,6 +457,7 @@ + @@ -465,6 +466,7 @@ + @@ -473,6 +475,8 @@ Vertex g_vs%(Filename) g_vs%(Filename) + 2.0 + 2.0 diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 46b82da..5f5cc09 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -665,7 +665,7 @@ Header Files\Config\Settings - + @@ -1055,7 +1055,7 @@ Source Files\Config\Settings - + Resource Files @@ -1065,6 +1065,9 @@ Resource Files + + Shaders + @@ -1097,10 +1100,13 @@ Shaders + + Shaders + Resource Files - + \ No newline at end of file diff --git a/DDrawCompat/Shaders/Convolution.hlsli b/DDrawCompat/Shaders/Convolution.hlsli new file mode 100644 index 0000000..31902fc --- /dev/null +++ b/DDrawCompat/Shaders/Convolution.hlsli @@ -0,0 +1,50 @@ +sampler2D s_texture : register(s0); +int g_sampleCountX : register(i0); +int g_sampleCountY : register(i1); + +float4 c[32] : register(c0); +static const float2 g_textureSize = c[0].xy; +static const float2 g_textureSizeRcp = c[0].zw; +static const float4 g_firstCoordOffset = c[1]; +static const float4 g_coordStep = c[2]; +static const float2 g_sampleCoordOffset = c[3].xy; +static const float2 g_halfTexelOffset = c[3].zw; +static const float g_support = c[4].x; +static const float g_supportRcp = c[4].y; + +float kernel(float x); + +float4 main(float2 texCoord : TEXCOORD0) : COLOR0 +{ + const float2 sampleCoord = texCoord * g_textureSize + g_sampleCoordOffset; + const float2 sampleCoordFrac = frac(sampleCoord); + const float2 sampleCoordInt = sampleCoord - sampleCoordFrac; + const float2 centeredTexCoord = sampleCoordInt * g_textureSizeRcp + g_halfTexelOffset; + + float4 coord = float4(centeredTexCoord, -sampleCoordFrac * g_coordStep.zw) + g_firstCoordOffset; + float4 coordStep = g_coordStep; + float4 colorSum = 0; + + if (0 != coordStep.x) + { + for (int i = 0; i < g_sampleCountX; ++i) + { + coordStep.w = kernel(coord.z); + float4 color = tex2Dlod(s_texture, coord); + colorSum += coordStep.w * color; + coord += coordStep; + } + return colorSum / coord.w; + } + else + { + for (int i = 0; i < g_sampleCountY; ++i) + { + coordStep.z = kernel(coord.w); + float4 color = tex2Dlod(s_texture, coord); + colorSum += coordStep.z * color; + coord += coordStep; + } + return colorSum / coord.z; + } +} diff --git a/DDrawCompat/Shaders/Lanczos.hlsl b/DDrawCompat/Shaders/Lanczos.hlsl new file mode 100644 index 0000000..577255b --- /dev/null +++ b/DDrawCompat/Shaders/Lanczos.hlsl @@ -0,0 +1,10 @@ +#include "Convolution.hlsli" + +float kernel(float x) +{ + x = min(abs(x), g_support); + const float PI = radians(180); + const float pi_x = PI * x; + const float pi_x_2 = pi_x * pi_x; + return 0 == pi_x_2 ? 1 : (g_support * sin(pi_x) * sin(pi_x * g_supportRcp) / pi_x_2); +}