diff --git a/DDrawCompat/Config/Settings/RenderColorDepth.h b/DDrawCompat/Config/Settings/RenderColorDepth.h index 2269d98..d7d4b50 100644 --- a/DDrawCompat/Config/Settings/RenderColorDepth.h +++ b/DDrawCompat/Config/Settings/RenderColorDepth.h @@ -6,11 +6,20 @@ namespace Config { namespace Settings { - class RenderColorDepth : public MappedSetting + class RenderColorDepth : public MappedSetting> { public: RenderColorDepth() - : MappedSetting("RenderColorDepth", "app", { {"app", 0}, {"16", 16}, {"32", 32} }) + : MappedSetting("RenderColorDepth", "appd8", { + { "app", { 0, 8 } }, + { "appd8", { 8, 0 } }, + { "appd10", { 10, 0 } }, + { "16", { 6, 8 } }, + { "16d8", { 8, 6 } }, + { "16d10", { 10, 6 } }, + { "32", { 8, 8 } }, + { "32d10", { 10, 8 } }, + }) { } }; diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index 0a2d46c..40dde0e 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -226,6 +227,41 @@ namespace D3dDdi return { levels.MsType, std::min(static_cast(Config::antialiasing.getParam()), levels.QualityLevels - 1) }; } + D3DDDIFORMAT Adapter::getRenderColorDepthSrcFormat(D3DDDIFORMAT appFormat) const + { + switch (Config::renderColorDepth.get().first) + { + case 10: + if (isSupportedRttFormat(D3DDDIFMT_A2B10G10R10)) + { + return D3DDDIFMT_A2B10G10R10; + } + if (isSupportedRttFormat(D3DDDIFMT_A2R10G10B10)) + { + return D3DDDIFMT_A2R10G10B10; + } + [[fallthrough]]; + + case 8: + return D3DDDIFMT_X8R8G8B8; + + case 6: + return D3DDDIFMT_R5G6B5; + } + + return appFormat; + } + + D3DDDIFORMAT Adapter::getRenderColorDepthDstFormat() const + { + switch (Config::renderColorDepth.get().second) + { + case 6: return D3DDDIFMT_R5G6B5; + case 8: return D3DDDIFMT_X8R8G8B8; + } + return 16 == Win32::DisplayMode::getBpp() ? D3DDDIFMT_R5G6B5 : D3DDDIFMT_X8R8G8B8; + } + SIZE Adapter::getScaledSize(Int2 size) const { const auto scaleFactor = getScaleFactor(); @@ -349,6 +385,14 @@ namespace D3dDdi return it != formatOps.end() && (it->second.Operations & FORMATOP_OFFSCREEN_RENDERTARGET); } + bool Adapter::isSupportedRttFormat(D3DDDIFORMAT format) const + { + auto it = m_info.formatOps.find(format); + return it != m_info.formatOps.end() && + (it->second.Format & FORMATOP_OFFSCREEN_RENDERTARGET) && + (it->second.Format & FORMATOP_TEXTURE); + } + HRESULT Adapter::pfnCloseAdapter() { auto adapter = m_adapter; diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index 8f2c39f..21c9664 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -41,6 +41,8 @@ namespace D3dDdi const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); } std::pair getMultisampleConfig(D3DDDIFORMAT format) const; const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; } + D3DDDIFORMAT getRenderColorDepthSrcFormat(D3DDDIFORMAT appFormat) const; + D3DDDIFORMAT getRenderColorDepthDstFormat() const; CompatWeakPtr getRepository() const { return m_repository; } SIZE getScaledSize(Int2 size) const; bool isEmulatedRenderTargetFormat(D3DDDIFORMAT format) const; @@ -66,6 +68,7 @@ namespace D3dDdi std::string getSupportedMsaaModes(const std::map& formatOps) const; DWORD getSupportedZBufferBitDepths(const std::map& formatOps) const; bool isEmulatedRenderTargetFormat(D3DDDIFORMAT format, const std::map& formatOps) const; + bool isSupportedRttFormat(D3DDDIFORMAT format) const; HANDLE m_adapter; D3DDDI_ADAPTERFUNCS m_origVtable; diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index d345a6d..a0968c2 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::TempPixelShaderConstB::TempPixelShaderConstB( + DeviceState& state, const D3DDDIARG_SETPIXELSHADERCONSTB& data, const BOOL* registers) + : m_state(state) + , m_data(data) + { + state.m_device.getOrigVtable().pfnSetPixelShaderConstB(state.m_device, &data, registers); + } + + DeviceState::TempPixelShaderConstB::~TempPixelShaderConstB() + { + m_state.m_device.getOrigVtable().pfnSetPixelShaderConstB( + m_state.m_device, &m_data, &m_state.m_pixelShaderConstB[m_data.Register][0]); + } + DeviceState::TempPixelShaderConstI::TempPixelShaderConstI( DeviceState& state, const D3DDDIARG_SETPIXELSHADERCONSTI& data, const ShaderConstI* registers) : m_state(state) diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index d2737a8..6c7ad88 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -15,7 +15,9 @@ const UINT D3DTEXF_NONE = 0; const UINT D3DTEXF_POINT = 1; const UINT D3DTEXF_LINEAR = 2; const UINT D3DTEXF_ANISOTROPIC = 3; -const UINT D3DTEXF_SRGB = 0x10000; +const UINT D3DTEXF_SRGBREAD = 0x10000; +const UINT D3DTEXF_SRGBWRITE = 0x20000; +const UINT D3DTEXF_SRGB = D3DTEXF_SRGBREAD | D3DTEXF_SRGBWRITE; namespace D3dDdi { @@ -59,6 +61,17 @@ namespace D3dDdi D3DDDIARG_SETPIXELSHADERCONST m_data; }; + class TempPixelShaderConstB + { + public: + TempPixelShaderConstB(DeviceState& state, const D3DDDIARG_SETPIXELSHADERCONSTB& data, const BOOL* registers); + ~TempPixelShaderConstB(); + + private: + DeviceState& m_state; + D3DDDIARG_SETPIXELSHADERCONSTB m_data; + }; + class TempPixelShaderConstI { public: diff --git a/DDrawCompat/D3dDdi/FormatInfo.cpp b/DDrawCompat/D3dDdi/FormatInfo.cpp index 939384d..3988187 100644 --- a/DDrawCompat/D3dDdi/FormatInfo.cpp +++ b/DDrawCompat/D3dDdi/FormatInfo.cpp @@ -109,8 +109,10 @@ namespace { D3DDDIFMT_A8R3G3B2, FormatInfoXARGB(0, 8, 3, 3, 2) }, { D3DDDIFMT_X4R4G4B4, FormatInfoXARGB(4, 0, 4, 4, 4) }, - { D3DDDIFMT_A8B8G8R8, FormatInfoXABGR(0, 8, 8, 8, 8) }, - { D3DDDIFMT_X8B8G8R8, FormatInfoXABGR(8, 0, 8, 8, 8) }, + { D3DDDIFMT_A2B10G10R10, FormatInfoXABGR(0, 2, 10, 10, 10) }, + { D3DDDIFMT_A8B8G8R8, FormatInfoXABGR(0, 8, 8, 8, 8) }, + { D3DDDIFMT_X8B8G8R8, FormatInfoXABGR(8, 0, 8, 8, 8) }, + { D3DDDIFMT_A2R10G10B10, FormatInfoXARGB(0, 2, 10, 10, 10) }, { D3DDDIFMT_A8P8, FormatInfoAP(8, 8) }, { D3DDDIFMT_P8, FormatInfoAP(0, 8) }, @@ -141,6 +143,11 @@ namespace DDPIXELFORMAT getPixelFormat(const D3dDdi::FormatInfo& info) { + if (info.red.bitCount > 8) + { + return {}; + } + DDPIXELFORMAT pf = {}; pf.dwSize = sizeof(pf); pf.dwFlags = diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index b17bc7b..8932206 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -529,6 +528,12 @@ namespace D3dDdi srcResource, subResourceIndex, getRect(subResourceIndex)); } + HRESULT Resource::copySubResourceRegion(UINT dstIndex, const RECT& dstRect, + HANDLE src, UINT srcIndex, const RECT& srcRect) + { + return copySubResourceRegion(*this, dstIndex, dstRect, src, srcIndex, srcRect); + } + HRESULT Resource::copySubResourceRegion(HANDLE dst, UINT dstIndex, const RECT& dstRect, HANDLE src, UINT srcIndex, const RECT& srcRect) { @@ -743,11 +748,7 @@ namespace D3dDdi if (D3DDDIFMT_X8R8G8B8 == m_fixedData.Format || D3DDDIFMT_R5G6B5 == m_fixedData.Format) { - switch (Config::renderColorDepth.get()) - { - case 16: return D3DDDIFMT_R5G6B5; - case 32: return D3DDDIFMT_X8R8G8B8; - } + return m_device.getAdapter().getRenderColorDepthSrcFormat(m_fixedData.Format); } else if (m_fixedData.Flags.ZBuffer && Config::Settings::DepthFormat::APP != Config::depthFormat.get() && getFormatInfo(m_fixedData.Format).depth.bitCount != Config::depthFormat.get()) @@ -1212,7 +1213,7 @@ namespace D3dDdi } auto& repo = m_device.getRepo(); - const auto& rtSurface = repo.getNextRenderTarget(srcWidth, srcHeight); + const auto& rtSurface = repo.getNextRenderTarget(srcWidth, srcHeight, srcResource->m_fixedData.Format); auto rt = rtSurface.resource ? rtSurface.resource : this; auto rtIndex = rtSurface.resource ? 0 : data.DstSubResourceIndex; auto rtRect = rtSurface.resource ? data.SrcRect : data.DstRect; @@ -1259,15 +1260,12 @@ namespace D3dDdi m_device.getShaderBlitter().cursorBlt(*rt, rtIndex, rtRect, cursorInfo.hCursor, cursorInfo.ptScreenPos); } - if (!rtSurface.resource) + if (rtSurface.resource) { - return LOG_RESULT(S_OK); + m_device.getShaderBlitter().displayBlt(*this, data.DstSubResourceIndex, data.DstRect, *rt, 0, data.SrcRect); + clearRectExterior(data.DstSubResourceIndex, data.DstRect); } - m_device.getShaderBlitter().displayBlt(*this, data.DstSubResourceIndex, data.DstRect, *rt, 0, data.SrcRect); - - clearRectExterior(data.DstSubResourceIndex, data.DstRect); - if (!IsRectEmpty(&g_presentationRect)) { presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex), @@ -1468,7 +1466,7 @@ namespace D3dDdi if (!srcResource.m_fixedData.Flags.Texture || D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool || - (filter & D3DTEXF_SRGB) && !(srcResource.m_formatOp.Operations & FORMATOP_SRGBREAD)) + (filter & D3DTEXF_SRGBREAD) && !(srcResource.m_formatOp.Operations & FORMATOP_SRGBREAD)) { DWORD width = data.SrcRect.right - data.SrcRect.left; DWORD height = data.SrcRect.bottom - data.SrcRect.top; @@ -1498,11 +1496,11 @@ namespace D3dDdi } if (!dstResource.m_fixedData.Flags.RenderTarget && !dstResource.m_fixedData.Flags.ZBuffer || - (filter & D3DTEXF_SRGB) && !(dstResource.m_formatOp.Operations & FORMATOP_SRGBWRITE)) + (filter & D3DTEXF_SRGBWRITE) && !(dstResource.m_formatOp.Operations & FORMATOP_SRGBWRITE)) { LONG width = data.DstRect.right - data.DstRect.left; LONG height = data.DstRect.bottom - data.DstRect.top; - auto& rt = repo.getNextRenderTarget(width, height, srcRes); + auto& rt = repo.getNextRenderTarget(width, height, D3DDDIFMT_X8R8G8B8, srcRes); if (!rt.resource) { return LOG_RESULT(E_OUTOFMEMORY); diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 6f3c1e8..1aa53db 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -39,6 +39,8 @@ namespace D3dDdi HRESULT blt(D3DDDIARG_BLT data); HRESULT colorFill(D3DDDIARG_COLORFILL data); + HRESULT copySubResourceRegion(UINT dstIndex, const RECT& dstRect, + HANDLE src, UINT srcIndex, const RECT& srcRect); void disableClamp(); void* getLockPtr(UINT subResourceIndex); RECT getRect(UINT subResourceIndex) const; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index c1081cb..c270366 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -15,11 +15,11 @@ #include #include #include -#include #include #include #include #include +#include #include #define CONCAT_(a, b) a##b @@ -28,6 +28,10 @@ namespace { + const UINT CF_HORIZONTAL = 1; + const UINT CF_GAMMARAMP = 2; + const UINT CF_DITHERING = 4; + D3DDDI_GAMMA_RAMP_RGB256x3x16 g_gammaRamp; bool g_isGammaRampDefault = true; bool g_isGammaRampInvalidated = false; @@ -83,11 +87,11 @@ namespace D3dDdi } , m_psDepthBlt(createPixelShader(g_psDepthBlt)) , m_psDrawCursor(createPixelShader(g_psDrawCursor)) - , m_psGamma(createPixelShader(g_psGamma)) , m_psLanczos(createPixelShader(g_psLanczos)) , m_psLockRef(createPixelShader(g_psLockRef)) , m_psPaletteLookup(createPixelShader(g_psPaletteLookup)) , m_psPoint(createPixelShader(g_psPoint)) + , m_psPointNoFilter(createPixelShader(g_psPointNoFilter)) , m_psTextureSampler(createPixelShader(g_psTextureSampler)) , m_vertexShaderDecl(createVertexShaderDecl()) , m_convolutionParams{} @@ -160,9 +164,13 @@ namespace D3dDdi const auto& srcSurface = srcResource.getFixedDesc().pSurfList[srcSubResourceIndex]; const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex]; - const bool srgb = (filter & D3DTEXF_SRGB) && - (srcResource.getFormatOp().Operations & FORMATOP_SRGBREAD) && - (dstResource.getFormatOp().Operations & FORMATOP_SRGBWRITE); + bool srgbRead = (filter & D3DTEXF_SRGBREAD) && (srcResource.getFormatOp().Operations & FORMATOP_SRGBREAD); + bool srgbWrite = (filter & D3DTEXF_SRGBWRITE) && (dstResource.getFormatOp().Operations & FORMATOP_SRGBWRITE); + if (D3DTEXF_SRGB == HIWORD(filter) && (!srgbRead || !srgbWrite)) + { + srgbRead = false; + srgbWrite = false; + } auto& state = m_device.getState(); state.setSpriteMode(false); @@ -189,7 +197,7 @@ namespace D3dDdi state.setTempRenderState({ D3DDDIRS_MULTISAMPLEANTIALIAS, FALSE }); state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0xF }); state.setTempRenderState({ D3DDDIRS_SCISSORTESTENABLE, FALSE }); - state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, srgb }); + state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, srgbWrite }); if (alpha) { @@ -209,8 +217,7 @@ namespace D3dDdi state.setTempRenderState({ D3DDDIRS_DESTBLEND, D3DBLEND_INVSRCALPHA }); } - setTempTextureStage(0, srcResource, srcRect, LOWORD(filter)); - state.setTempTextureStageState({ 0, D3DDDITSS_SRGBTEXTURE, srgb }); + setTempTextureStage(0, srcResource, srcRect, LOWORD(filter) | (srgbRead ? D3DTEXF_SRGBREAD : 0)); state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, m_vertices.data()); @@ -246,18 +253,18 @@ namespace D3dDdi void ShaderBlitter::convolution(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, - bool isHorizontal, Float2 support, HANDLE pixelShader, - const std::function setExtraParams) + Float2 support, HANDLE pixelShader, const std::function setExtraParams, DWORD flags) { LOG_FUNC("ShaderBlitter::convolution", static_cast(dstResource), dstSubResourceIndex, dstRect, static_cast(srcResource), srcSubResourceIndex, srcRect, - isHorizontal, support, pixelShader, static_cast(setExtraParams)); + support, pixelShader, static_cast(setExtraParams), flags); const auto& srcDesc = srcResource.getFixedDesc().pSurfList[0]; const Float2 dstSize(dstRect.right - dstRect.left, dstRect.bottom - dstRect.top); const Float2 srcSize(srcRect.right - srcRect.left, srcRect.bottom - srcRect.top); const Float2 scale = dstSize / srcSize; + const bool isHorizontal = flags & CF_HORIZONTAL; const bool isDual = srcSize.x != dstSize.x && srcSize.y != dstSize.y; const Float2 compMaskPri = isHorizontal ? Float2(1, 0) : Float2(0, 1); const Float2 compMaskSec = isHorizontal ? Float2(0, 1) : Float2(1, 0); @@ -291,14 +298,43 @@ namespace D3dDdi setExtraParams(isHorizontal); } + struct BoolParams + { + BOOL useSrgbRead; + BOOL useSrgbReadNeg; + BOOL useSrgbWrite; + BOOL useGammaRamp; + BOOL useDithering; + }; + + BoolParams boolParams = {}; + boolParams.useSrgbRead = !(srcResource.getFormatOp().Operations & FORMATOP_SRGBREAD); + boolParams.useSrgbReadNeg = !boolParams.useSrgbRead; + boolParams.useSrgbWrite = (flags & (CF_GAMMARAMP | CF_DITHERING)) || + !(dstResource.getFormatOp().Operations & FORMATOP_SRGBWRITE); + boolParams.useGammaRamp = flags & CF_GAMMARAMP; + boolParams.useDithering = flags & CF_DITHERING; + + DeviceState::TempPixelShaderConstB tempPsConstB(m_device.getState(), { 0, 5 }, &boolParams.useSrgbRead); + const DeviceState::ShaderConstI reg = { dot(sampleCountHalf - 1, Int2(compMaskPri)) }; DeviceState::TempPixelShaderConstI tempPsConstI(m_device.getState(), { 0, 1 }, ®); DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), { 0, sizeof(m_convolutionParams) / sizeof(DeviceState::ShaderConstF) }, reinterpret_cast(&m_convolutionParams)); - blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, - pixelShader, (p.support <= 1 ? D3DTEXF_LINEAR : D3DTEXF_POINT) | D3DTEXF_SRGB); + + UINT filter = (p.support <= 1 && !boolParams.useSrgbRead) ? D3DTEXF_LINEAR : D3DTEXF_POINT; + if (!boolParams.useSrgbRead && 0 != support.x) + { + filter |= D3DTEXF_SRGBREAD; + } + if (!boolParams.useSrgbWrite && 0 != support.x) + { + filter |= D3DTEXF_SRGBWRITE; + } + + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, pixelShader, filter); } void ShaderBlitter::convolutionBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -315,15 +351,84 @@ namespace D3dDdi const Float2 kernelCoordStep = min(scale, 1.0f); const Float2 sampleCountHalf = support / kernelCoordStep; - if (srcSize.y == dstSize.y || sampleCountHalf.y <= 1) + DWORD flags = 0; + Resource* gammaRampTexture = nullptr; + if (!g_isGammaRampDefault && nullptr != (gammaRampTexture = m_device.getRepo().getGammaRampTexture())) { - return convolution(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, - true, support, pixelShader, setExtraParams); + flags |= CF_GAMMARAMP; } - else if (srcSize.x == dstSize.x || sampleCountHalf.x <= 1) + + const auto& dstFi = getFormatInfo(m_device.getAdapter().getRenderColorDepthDstFormat()); + const auto& srcFi = getFormatInfo(srcResource.getFixedDesc().Format); + BYTE maxBpcDiff = 0; + maxBpcDiff = std::max(maxBpcDiff, srcFi.red.bitCount - dstFi.red.bitCount); + maxBpcDiff = std::max(maxBpcDiff, srcFi.green.bitCount - dstFi.green.bitCount); + maxBpcDiff = std::max(maxBpcDiff, srcFi.blue.bitCount - dstFi.blue.bitCount); + + Resource* ditherTexture = nullptr; + DWORD ditherSize = std::min(1 << maxBpcDiff, 16); + if (0 != maxBpcDiff && nullptr != (ditherTexture = m_device.getRepo().getDitherTexture(ditherSize))) + { + flags |= CF_DITHERING; + } + + if ((flags & CF_GAMMARAMP) && g_isGammaRampInvalidated) + { + D3DDDIARG_LOCK lock = {}; + lock.hResource = *gammaRampTexture; + lock.Flags.Discard = 1; + m_device.getOrigVtable().pfnLock(m_device, &lock); + if (lock.pSurfData) + { + auto ptr = static_cast(lock.pSurfData); + setGammaValues(ptr, g_gammaRamp.Red); + setGammaValues(ptr + lock.Pitch, g_gammaRamp.Green); + setGammaValues(ptr + 2 * lock.Pitch, g_gammaRamp.Blue); + + D3DDDIARG_UNLOCK unlock = {}; + unlock.hResource = *gammaRampTexture; + m_device.getOrigVtable().pfnUnlock(m_device, &unlock); + g_isGammaRampInvalidated = false; + } + else + { + flags &= ~CF_GAMMARAMP; + } + } + + if (flags & CF_GAMMARAMP) + { + setTempTextureStage(1, *gammaRampTexture, srcRect, D3DTEXF_LINEAR); + } + + if (flags & CF_DITHERING) + { + setTempTextureStage(2, *ditherTexture, dstRect, D3DTEXF_POINT, D3DTADDRESS_WRAP); + m_convolutionParams.maxRgb[0] = static_cast(1 << dstFi.red.bitCount) - 1; + m_convolutionParams.maxRgb[1] = static_cast(1 << dstFi.green.bitCount) - 1; + m_convolutionParams.maxRgb[2] = static_cast(1 << dstFi.blue.bitCount) - 1; + for (unsigned i = 0; i < 3; ++i) + { + m_convolutionParams.maxRgbRcp[i] = 1.0f / m_convolutionParams.maxRgb[i]; + } + + const float d = static_cast(ditherSize * ditherSize); + m_convolutionParams.ditherScale = (d - 1) / d; + m_convolutionParams.ditherOffset = 0.5f / d; + } + + if (srcSize.y == dstSize.y || + 0 == support.y || + sampleCountHalf.y <= 1 && (srcResource.getFormatOp().Operations & FORMATOP_SRGBREAD)) { return convolution(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, - false, support, pixelShader, setExtraParams); + support, pixelShader, setExtraParams, flags | CF_HORIZONTAL); + } + if (srcSize.x == dstSize.x || + sampleCountHalf.x <= 1 && (srcResource.getFormatOp().Operations & FORMATOP_SRGBREAD)) + { + return convolution(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + support, pixelShader, setExtraParams, flags); } const bool isHorizontalFirst = dstSize.x * srcSize.y <= srcSize.x * dstSize.y; @@ -337,16 +442,17 @@ namespace D3dDdi rect.bottom = dstSize.y; } - auto rt = m_device.getRepo().getNextRenderTarget(rect.right, rect.bottom, &srcResource, &dstResource).resource; + auto rt = m_device.getRepo().getNextRenderTarget(rect.right, rect.bottom, + srcResource.getFixedDesc().Format, &srcResource, &dstResource).resource; if (!rt) { return; } convolution(*rt, 0, rect, srcResource, srcSubResourceIndex, srcRect, - isHorizontalFirst, support, pixelShader, setExtraParams); + support, pixelShader, setExtraParams, isHorizontalFirst ? CF_HORIZONTAL : 0); convolution(dstResource, dstSubResourceIndex, dstRect, *rt, 0, rect, - !isHorizontalFirst, support, pixelShader, setExtraParams); + support, pixelShader, setExtraParams, flags | (isHorizontalFirst ? 0 : CF_HORIZONTAL)); } std::unique_ptr ShaderBlitter::createPixelShader(const BYTE* code, UINT size) @@ -427,14 +533,7 @@ namespace D3dDdi if (cur.maskTexture) { - D3DDDIARG_BLT data = {}; - data.hSrcResource = dstResource; - data.SrcSubResourceIndex = dstSubResourceIndex; - data.SrcRect = clippedDstRect; - data.hDstResource = *cur.tempTexture; - data.DstRect = clippedSrcRect; - m_device.getOrigVtable().pfnBlt(m_device, &data); - + cur.tempTexture->copySubResourceRegion(0, clippedSrcRect, dstResource, dstSubResourceIndex, clippedDstRect); setTempTextureStage(1, *cur.maskTexture, clippedSrcRect, D3DTEXF_POINT); setTempTextureStage(2, *cur.colorTexture, clippedSrcRect, D3DTEXF_POINT); setTempTextureStage(3, *xorTexture, clippedSrcRect, D3DTEXF_POINT); @@ -493,75 +592,42 @@ namespace D3dDdi m_device.flushPrimitives(); } - void ShaderBlitter::displayBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + void ShaderBlitter::displayBlt(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(); - + auto filter = Config::displayFilter.get(); 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; + filter = Config::Settings::DisplayFilter::POINT; } - 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()) + switch (filter) { case Config::Settings::DisplayFilter::POINT: - m_device.getShaderBlitter().pointBlt(rt, rtIndex, rtRect, + m_device.getShaderBlitter().pointBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect); break; case Config::Settings::DisplayFilter::BILINEAR: - m_device.getShaderBlitter().bilinearBlt(rt, rtIndex, rtRect, + m_device.getShaderBlitter().bilinearBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, Config::displayFilter.getParam()); break; case Config::Settings::DisplayFilter::BICUBIC: - m_device.getShaderBlitter().bicubicBlt(rt, rtIndex, rtRect, + m_device.getShaderBlitter().bicubicBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, Config::displayFilter.getParam()); break; case Config::Settings::DisplayFilter::LANCZOS: - m_device.getShaderBlitter().lanczosBlt(rt, rtIndex, rtRect, + m_device.getShaderBlitter().lanczosBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, Config::displayFilter.getParam()); break; case Config::Settings::DisplayFilter::SPLINE: - m_device.getShaderBlitter().splineBlt(rt, rtIndex, rtRect, + m_device.getShaderBlitter().splineBlt(dstResource, dstSubResourceIndex, dstRect, 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) @@ -580,44 +646,6 @@ namespace D3dDdi m_device.pfnDrawPrimitive(&dp, nullptr); } - void ShaderBlitter::gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, - const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect) - { - LOG_FUNC("ShaderBlitter::gammaBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, - static_cast(srcResource), srcSubResourceIndex, srcRect); - - auto gammaRampTexture(m_device.getRepo().getGammaRampTexture()); - if (!gammaRampTexture) - { - return; - } - - if (g_isGammaRampInvalidated) - { - D3DDDIARG_LOCK lock = {}; - lock.hResource = *gammaRampTexture; - lock.Flags.Discard = 1; - m_device.getOrigVtable().pfnLock(m_device, &lock); - if (!lock.pSurfData) - { - return; - } - - auto ptr = static_cast(lock.pSurfData); - setGammaValues(ptr, g_gammaRamp.Red); - setGammaValues(ptr + lock.Pitch, g_gammaRamp.Green); - setGammaValues(ptr + 2 * lock.Pitch, g_gammaRamp.Blue); - - D3DDDIARG_UNLOCK unlock = {}; - unlock.hResource = *gammaRampTexture; - m_device.getOrigVtable().pfnUnlock(m_device, &unlock); - g_isGammaRampInvalidated = false; - } - - setTempTextureStage(1, *gammaRampTexture, srcRect, D3DTEXF_POINT); - blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGamma.get(), D3DTEXF_POINT); - } - void ShaderBlitter::lanczosBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT lobes) { @@ -680,8 +708,18 @@ namespace D3dDdi LOG_FUNC("ShaderBlitter::pointBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, static_cast(srcResource), srcSubResourceIndex, srcRect); - convolutionBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, - 0.5f, m_psPoint.get()); + auto dstSize = Rect::getSize(dstRect); + auto srcSize = Rect::getSize(srcRect); + if (dstSize.cx >= srcSize.cx && dstSize.cy >= srcSize.cy) + { + convolutionBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + 0.0f, m_psPointNoFilter.get()); + } + else + { + convolutionBlt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + 0.5f, m_psPoint.get()); + } } void ShaderBlitter::resetGammaRamp() @@ -701,16 +739,18 @@ namespace D3dDdi g_isGammaRampInvalidated = !g_isGammaRampDefault; } - void ShaderBlitter::setTempTextureStage(UINT stage, const Resource& texture, const RECT& rect, UINT filter) + void ShaderBlitter::setTempTextureStage(UINT stage, const Resource& texture, const RECT& rect, UINT filter, + UINT textureAddress) { auto& state = m_device.getState(); state.setTempTexture(stage, texture); state.setTempTextureStageState({ stage, D3DDDITSS_TEXCOORDINDEX, stage }); - state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSU, D3DTADDRESS_CLAMP }); - state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSV, D3DTADDRESS_CLAMP }); - state.setTempTextureStageState({ stage, D3DDDITSS_MAGFILTER, filter }); - state.setTempTextureStageState({ stage, D3DDDITSS_MINFILTER, filter }); + state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSU, textureAddress }); + state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSV, textureAddress }); + state.setTempTextureStageState({ stage, D3DDDITSS_MAGFILTER, LOWORD(filter) }); + state.setTempTextureStageState({ stage, D3DDDITSS_MINFILTER, LOWORD(filter) }); state.setTempTextureStageState({ stage, D3DDDITSS_MIPFILTER, D3DTEXF_NONE }); + state.setTempTextureStageState({ stage, D3DDDITSS_SRGBTEXTURE, 0 != (filter & D3DTEXF_SRGBREAD) }); state.setTempRenderState({ static_cast(D3DDDIRS_WRAP0 + stage), 0 }); auto& si = texture.getFixedDesc().pSurfList[0]; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index feeedf2..7a824a8 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -41,9 +41,7 @@ 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, + void displayBlt(Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect); void lanczosBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT lobes); @@ -80,6 +78,11 @@ namespace D3dDdi Float2 kernelCoordStepPri; float support; float supportRcp; + DeviceState::ShaderConstF maxRgb; + DeviceState::ShaderConstF maxRgbRcp; + float ditherScale; + float ditherOffset; + Float2 padding; alignas(sizeof(DeviceState::ShaderConstF)) std::array extra; }; @@ -96,8 +99,7 @@ namespace D3dDdi 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, Float2 support, HANDLE pixelShader, - const std::function setExtraParams); + Float2 support, HANDLE pixelShader, const std::function setExtraParams, DWORD flags); void convolutionBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, Float2 support, HANDLE pixelShader, const std::function setExtraParams = {}); @@ -111,7 +113,8 @@ namespace D3dDdi std::unique_ptr createPixelShader(const BYTE* code, UINT size); std::unique_ptr createVertexShaderDecl(); void drawRect(const RECT& srcRect, const RectF& dstRect, UINT srcWidth, UINT srcHeight); - void setTempTextureStage(UINT stage, const Resource& texture, const RECT& rect, UINT filter); + void setTempTextureStage(UINT stage, const Resource& texture, const RECT& rect, UINT filter, + UINT textureAddress = D3DTADDRESS_CLAMP); void setTextureCoords(UINT stage, const RECT& rect, UINT width, UINT height); Device& m_device; @@ -120,12 +123,13 @@ namespace D3dDdi std::unique_ptr m_psColorKeyBlend; std::unique_ptr m_psCubicConvolution[3]; std::unique_ptr m_psDepthBlt; + std::unique_ptr m_psDitheredGammaControl; std::unique_ptr m_psDrawCursor; - std::unique_ptr m_psGamma; std::unique_ptr m_psLanczos; std::unique_ptr m_psLockRef; std::unique_ptr m_psPaletteLookup; std::unique_ptr m_psPoint; + std::unique_ptr m_psPointNoFilter; std::unique_ptr m_psTextureSampler; std::unique_ptr m_vertexShaderDecl; ConvolutionParams m_convolutionParams; diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 2d989af..e7ab9ce 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -18,6 +18,27 @@ namespace { std::map g_repositories; bool g_enableSurfaceCheck = true; + + void initDitherTexture(BYTE* tex, DWORD pitch, DWORD x, DWORD y, DWORD size, DWORD mul, DWORD value) + { + if (1 == size) + { + tex[y * pitch + x] = static_cast(value); + } + else + { + size /= 2; + initDitherTexture(tex, pitch, x, y, size, 4 * mul, value + 0 * mul); + initDitherTexture(tex, pitch, x + size, y, size, 4 * mul, value + 2 * mul); + initDitherTexture(tex, pitch, x, y + size, size, 4 * mul, value + 3 * mul); + initDitherTexture(tex, pitch, x + size, y + size, size, 4 * mul, value + 1 * mul); + } + } + + void initDitherTexture(BYTE* tex, DWORD pitch, DWORD size) + { + initDitherTexture(tex, pitch, 0, 0, size, 1, 0); + } } namespace D3dDdi @@ -201,6 +222,14 @@ namespace D3dDdi return true; } + Resource* SurfaceRepository::getDitherTexture(DWORD size) + { + return getInitializedResource(m_ditherTexture, size, size, D3DDDIFMT_L8, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, + [](const DDSURFACEDESC2& desc) { + initDitherTexture(static_cast(desc.lpSurface), desc.lPitch, 16); + }); + } + Resource* SurfaceRepository::getGammaRampTexture() { return getSurface(m_gammaRampTexture, 256, 3, D3DDDIFMT_L8, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource; @@ -245,19 +274,21 @@ namespace D3dDdi } const SurfaceRepository::Surface& SurfaceRepository::getNextRenderTarget( - DWORD width, DWORD height, const Resource* currentSrcRt, const Resource* currentDstRt) + DWORD width, DWORD height, D3DDDIFORMAT format, const Resource* currentSrcRt, const Resource* currentDstRt) { + const bool hq = getFormatInfo(format).red.bitCount > 8; + auto& renderTargets = hq ? m_hqRenderTargets : m_renderTargets; std::size_t index = 0; - while (index < m_renderTargets.size()) + while (index < renderTargets.size()) { - auto rt = m_renderTargets[index].resource; + auto rt = renderTargets[index].resource; if (!rt || rt != currentSrcRt && rt != currentDstRt) { break; } ++index; } - return getTempSurface(m_renderTargets[index], width, height, D3DDDIFMT_X8R8G8B8, + return getTempSurface(renderTargets[index], width, height, hq ? format : D3DDDIFMT_X8R8G8B8, DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY); } diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index e9c69fd..e40b814 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -40,10 +40,11 @@ namespace D3dDdi SurfaceRepository(); Cursor getCursor(HCURSOR cursor); + Resource* getDitherTexture(DWORD size); Resource* getLogicalXorTexture(); Resource* getPaletteTexture(); Resource* getGammaRampTexture(); - const Surface& getNextRenderTarget(DWORD width, DWORD height, + const Surface& getNextRenderTarget(DWORD width, DWORD height, D3DDDIFORMAT format, 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); @@ -74,10 +75,12 @@ namespace D3dDdi Surface m_cursorMaskTexture; Surface m_cursorColorTexture; Surface m_cursorTempTexture; + Surface m_ditherTexture; Surface m_gammaRampTexture; Surface m_logicalXorTexture; Surface m_paletteTexture; std::array m_renderTargets; + std::array m_hqRenderTargets; std::map m_textures; std::vector m_releasedSurfaces; Surface m_sysMemSurface; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index d798f2b..ae98ffc 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -486,11 +486,11 @@ - + Vertex diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 019bd34..d811100 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -1136,9 +1136,6 @@ Shaders - - Shaders - Shaders @@ -1169,6 +1166,9 @@ Shaders + + Shaders + diff --git a/DDrawCompat/Shaders/Convolution.hlsli b/DDrawCompat/Shaders/Convolution.hlsli index 186e77f..1d04ad8 100644 --- a/DDrawCompat/Shaders/Convolution.hlsli +++ b/DDrawCompat/Shaders/Convolution.hlsli @@ -1,8 +1,16 @@ sampler2D s_texture : register(s0); +sampler2D s_gammaRamp : register(s1); +sampler2D s_dither : register(s2); int g_sampleCountHalfMinusOne : register(i0); float4 c[32] : register(c0); -float4 g_extraParams[4] : register(c6); +float4 g_extraParams[4] : register(c9); + +bool g_useSrgbRead : register(b0); +bool g_useSrgbReadNeg : register(b1); +bool g_useSrgbWrite : register(b2); +bool g_useGammaRamp : register(b3); +bool g_useDithering : register(b4); static const float2 g_textureSize = c[0].xy; static const float2 g_sampleCoordOffset = c[0].zw; @@ -15,6 +23,10 @@ static const float2 g_textureCoordStepSec = c[4].zw; static const float2 g_kernelCoordStepPri = c[5].xy; static const float g_support = c[5].z; static const float g_supportRcp = c[5].w; +static const float4 g_maxRgb = c[6]; +static const float4 g_maxRgbRcp = c[7]; +static const float g_ditherScale = c[8].x; +static const float g_ditherOffset = c[8].y; #ifdef NONNEGATIVE float4 kernel(float4 x); @@ -22,14 +34,35 @@ float4 kernel(float4 x); float kernel(float x); #endif -void addSamples(inout float4 colorSum, float4 textureCoord, float4 weights) +float4 srgb2lin(float4 color) +{ + return float4(color.rgb < 0.04045f ? color.rgb / 12.92f : pow((abs(color.rgb) + 0.055f) / 1.055f, 2.4f), 1); +} + +void addSamples(inout float4 color, float4 textureCoord, float4 weights) { #ifdef NONNEGATIVE - const float weightSum = weights.x + weights.z; - colorSum += weightSum * tex2Dlod(s_texture, lerp(textureCoord.xyxy, textureCoord.zwzw, weights.z / weightSum)); -#else - colorSum += weights.x * tex2Dlod(s_texture, textureCoord.xyxy); - colorSum += weights.z * tex2Dlod(s_texture, textureCoord.zwzw); + [branch] + if (g_useSrgbRead) + { +#endif + float4 color1 = tex2Dlod(s_texture, textureCoord.xyxy); + float4 color2 = tex2Dlod(s_texture, textureCoord.zwzw); + [branch] + if (g_useSrgbRead) + { + color1 = srgb2lin(color1); + color2 = srgb2lin(color2); + } + color += weights.x * color1; + color += weights.z * color2; +#ifdef NONNEGATIVE + } + else + { + const float weightSum = weights.x + weights.z; + color += weightSum * tex2Dlod(s_texture, lerp(textureCoord.xyxy, textureCoord.zwzw, weights.z / weightSum)); + } #endif } @@ -42,8 +75,16 @@ float4 getWeights(float4 kernelCoord) #endif } -float4 main(float2 texCoord : TEXCOORD0) : COLOR0 +float4 normalize(float4 color) { + return color * 255.0f / 256.0f + 0.5f / 256.0f; +} + +float4 main(float2 texCoord : TEXCOORD0, float2 ditherCoord : TEXCOORD2) : COLOR0 +{ +#ifdef NOFILTER + float4 color = float4(tex2D(s_texture, texCoord).rgb, 1); +#else const float2 sampleCoord = mad(texCoord, g_textureSize, g_sampleCoordOffset); const float2 sampleCoordFrac = frac(sampleCoord); const float2 sampleCoordInt = sampleCoord - sampleCoordFrac; @@ -55,21 +96,54 @@ float4 main(float2 texCoord : TEXCOORD0) : COLOR0 const float4 weights = getWeights(kernelCoord); #ifdef NONNEGATIVE - [branch] if (g_sampleCoordOffset.x == g_sampleCoordOffset.y) + [branch] + if (g_useSrgbReadNeg) { - textureCoord = lerp(textureCoord, textureCoord + g_textureCoordStepSec.xyxy, weights.w / (weights.y + weights.w)); + [branch] + if (g_sampleCoordOffset.x == g_sampleCoordOffset.y) + { + textureCoord = lerp(textureCoord, textureCoord + g_textureCoordStepSec.xyxy, weights.w / (weights.y + weights.w)); + } } -#endif +#endif // NONNEGATIVE - float4 colorSum = 0; - addSamples(colorSum, textureCoord, weights); + float4 color = 0; + addSamples(color, textureCoord, weights); for (int i = 0; i < g_sampleCountHalfMinusOne; ++i) { textureCoord += g_textureCoordStepPri.xyxy; kernelCoord += g_kernelCoordStepPri.xyxy; - addSamples(colorSum, textureCoord, getWeights(kernelCoord)); + addSamples(color, textureCoord, getWeights(kernelCoord)); } - return colorSum / colorSum.a; + color /= color.a; + + [branch] + if (g_useSrgbWrite) + { + color = saturate(color); + color.rgb = color.rgb < 0.0031308f ? 12.92f * color.rgb : 1.055f * pow(color.rgb, 1.0f / 2.4f) - 0.055f; +#endif // NOFILTER + + [branch] + if (g_useGammaRamp) + { + color = normalize(color); + color.r = tex2Dlod(s_gammaRamp, float4(color.r, 0.0f, 0, 0)).r; + color.g = tex2Dlod(s_gammaRamp, float4(color.g, 0.5f, 0, 0)).r; + color.b = tex2Dlod(s_gammaRamp, float4(color.b, 1.0f, 0, 0)).r; + } + + [branch] + if (g_useDithering) + { + const float dither = tex2D(s_dither, ditherCoord).r * g_ditherScale + g_ditherOffset; + color = floor(color * g_maxRgb + dither) * g_maxRgbRcp; + } +#ifndef NOFILTER + } +#endif + + return color; } diff --git a/DDrawCompat/Shaders/Gamma.hlsl b/DDrawCompat/Shaders/Gamma.hlsl deleted file mode 100644 index 6865e50..0000000 --- a/DDrawCompat/Shaders/Gamma.hlsl +++ /dev/null @@ -1,12 +0,0 @@ -sampler2D s_texture : register(s0); -sampler2D s_gammaRamp : register(s1); - -float4 main(float2 texCoord : TEXCOORD0) : COLOR0 -{ - const float4 color = tex2D(s_texture, texCoord); - return float4( - tex2D(s_gammaRamp, float2(color.r, 0.0f)).r, - tex2D(s_gammaRamp, float2(color.g, 0.5f)).r, - tex2D(s_gammaRamp, float2(color.b, 1.0f)).r, - 0); -} diff --git a/DDrawCompat/Shaders/PointNoFilter.hlsl b/DDrawCompat/Shaders/PointNoFilter.hlsl new file mode 100644 index 0000000..e50458a --- /dev/null +++ b/DDrawCompat/Shaders/PointNoFilter.hlsl @@ -0,0 +1,2 @@ +#define NOFILTER +#include "Convolution.hlsli"