diff --git a/DDrawCompat/Common/Rect.cpp b/DDrawCompat/Common/Rect.cpp index e4bbe49..9a1962e 100644 --- a/DDrawCompat/Common/Rect.cpp +++ b/DDrawCompat/Common/Rect.cpp @@ -21,6 +21,12 @@ namespace namespace Rect { + bool isEqualSize(const RECT& rect1, const RECT& rect2) + { + return rect1.right - rect1.left == rect2.right - rect2.left && + rect1.bottom - rect1.top == rect2.bottom - rect2.top; + } + RectF toRectF(const RECT& rect) { return { diff --git a/DDrawCompat/Common/Rect.h b/DDrawCompat/Common/Rect.h index 24ff8a9..f3d0549 100644 --- a/DDrawCompat/Common/Rect.h +++ b/DDrawCompat/Common/Rect.h @@ -13,6 +13,7 @@ struct RectF namespace Rect { RectF toRectF(const RECT& rect); + bool isEqualSize(const RECT& rect1, const RECT& rect2); void transform(RECT& rect, const RECT& srcView, const RECT& dstView); void transform(RectF& rect, const RECT& srcView, const RECT& dstView); } diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index c70cda6..d098e26 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -15,6 +15,7 @@ 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; namespace D3dDdi { diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 840d636..dd4cc19 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -117,6 +117,8 @@ namespace D3dDdi , m_handle(nullptr) , m_origData(data) , m_fixedData(data) + , m_formatInfo{} + , m_formatOp{} , m_lockBuffer(nullptr, &heapFree) , m_lockResource(nullptr, ResourceDeleter(device, device.getOrigVtable().pfnDestroyResource)) , m_lockRefSurface{} @@ -155,6 +157,13 @@ namespace D3dDdi m_formatConfig = m_fixedData.Format; m_scaledSize = { static_cast(m_fixedData.pSurfList[0].Width), static_cast(m_fixedData.pSurfList[0].Height) }; + const auto& formatOps = m_device.getAdapter().getInfo().formatOps; + auto it = formatOps.find(m_fixedData.Format); + if (it != formatOps.end()) + { + m_formatOp = it->second; + } + HRESULT result = m_device.createPrivateResource(m_fixedData); if (FAILED(result)) { @@ -392,55 +401,40 @@ namespace D3dDdi srcResource.prepareForBltSrc(data); } + if (!m_fixedData.Flags.ZBuffer && + (0 == m_formatInfo.bytesPerPixel || 0 == srcResource.m_formatInfo.bytesPerPixel)) + { + if (m_lockResource) + { + loadVidMemResource(data.DstSubResourceIndex); + clearUpToDateFlags(data.DstSubResourceIndex); + m_lockData[data.DstSubResourceIndex].isVidMemUpToDate = true; + } + return m_device.getOrigVtable().pfnBlt(m_device, &data); + } + Resource& dstRes = prepareForBltDst(data); + return shaderBlt(data, dstRes, *srcRes, + Config::Settings::BltFilter::BILINEAR == Config::bltFilter.get() ? D3DTEXF_LINEAR : D3DTEXF_POINT); + } - if (!m_fixedData.Flags.ZBuffer) + bool Resource::canCopySubResource(const D3DDDIARG_BLT& data, Resource& srcResource) + { + if (data.Flags.SrcColorKey || + data.Flags.MirrorLeftRight || + data.Flags.MirrorUpDown || + D3DDDIMULTISAMPLE_NONE != m_fixedData.MultisampleType) { - if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && - D3DDDIPOOL_SYSTEMMEM != srcResource.m_fixedData.Pool && - Config::Settings::BltFilter::BILINEAR == Config::bltFilter.get()) - { - data.Flags.Linear = 1; - } - else - { - data.Flags.Point = 1; - } + return false; } - if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && - (m_fixedData.Flags.ZBuffer && - (m_nullSurface.resource && &dstRes == m_msaaSurface.resource || m_device.getAdapter().getInfo().isD3D9On12) || - dstRes.m_fixedData.Flags.RenderTarget || - !m_fixedData.Flags.ZBuffer && ( - data.Flags.SrcColorKey || - data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown || - data.DstRect.right - data.DstRect.left != data.SrcRect.right - data.SrcRect.left || - data.DstRect.bottom - data.DstRect.top != data.SrcRect.bottom - data.SrcRect.top)) && - SUCCEEDED(shaderBlt(data, dstRes, *srcRes))) + if (m_fixedData.Flags.ZBuffer) { - return S_OK; + return !m_device.getAdapter().getInfo().isD3D9On12 || + m_fixedData.Format == srcResource.m_fixedData.Format && Rect::isEqualSize(data.SrcRect, data.DstRect); } - if (&dstRes != this && D3DDDIPOOL_SYSTEMMEM == srcRes->m_fixedData.Pool) - { - RECT r = { 0, 0, data.SrcRect.right - data.SrcRect.left, data.SrcRect.bottom - data.SrcRect.top }; - copySubResourceRegion(*this, data.DstSubResourceIndex, r, *srcRes, data.SrcSubResourceIndex, data.SrcRect); - data.hSrcResource = *this; - data.SrcSubResourceIndex = data.DstSubResourceIndex; - data.SrcRect = r; - } - - HRESULT result = m_device.getOrigVtable().pfnBlt(m_device, &data); - if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool) - { - notifyLock(data.DstSubResourceIndex); - } - else if (D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool) - { - srcResource.notifyLock(data.SrcSubResourceIndex); - } - return result; + return Rect::isEqualSize(data.SrcRect, data.DstRect); } void Resource::clearRectExterior(UINT subResourceIndex, const RECT& rect) @@ -686,7 +680,7 @@ namespace D3dDdi } m_device.getShaderBlitter().textureBlt(*nextRt.resource, 0, { 0, 0, newSrcWidth, newSrcHeight }, - *rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR); + *rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR | D3DTEXF_SRGB); rt = nextRt.resource; srcWidth = newSrcWidth; srcHeight = newSrcHeight; @@ -941,23 +935,14 @@ namespace D3dDdi else { loadVidMemResource(subResourceIndex); - const bool isScaled = static_cast(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || - static_cast(m_fixedData.pSurfList[0].Height) != m_scaledSize.cy; - if ((m_fixedData.Flags.ZBuffer || !isScaled) && !m_device.getAdapter().getInfo().isD3D9On12) - { - copySubResource(*m_msaaResolvedSurface.resource, *this, subResourceIndex); - } - else - { - D3DDDIARG_BLT blt = {}; - blt.hSrcResource = *this; - blt.SrcSubResourceIndex = subResourceIndex; - blt.SrcRect = getRect(subResourceIndex); - blt.hDstResource = *m_msaaResolvedSurface.resource; - blt.DstSubResourceIndex = subResourceIndex; - blt.DstRect = m_msaaResolvedSurface.resource->getRect(subResourceIndex); - shaderBlt(blt, *m_msaaResolvedSurface.resource , *this); - } + D3DDDIARG_BLT blt = {}; + blt.hSrcResource = *this; + blt.SrcSubResourceIndex = subResourceIndex; + blt.SrcRect = getRect(subResourceIndex); + blt.hDstResource = *m_msaaResolvedSurface.resource; + blt.DstSubResourceIndex = subResourceIndex; + blt.DstRect = m_msaaResolvedSurface.resource->getRect(subResourceIndex); + shaderBlt(blt, *m_msaaResolvedSurface.resource, *this, D3DTEXF_POINT); } m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true; } @@ -984,60 +969,18 @@ namespace D3dDdi if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate) { loadMsaaResolvedResource(subResourceIndex); - if (!m_origData.Flags.RenderTarget || - Config::Settings::ResolutionScaleFilter::POINT == Config::resolutionScaleFilter.get()) - { - const bool isScaled = static_cast(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || - static_cast(m_fixedData.pSurfList[0].Height) != m_scaledSize.cy; - if ((m_fixedData.Flags.ZBuffer || !isScaled) && !m_device.getAdapter().getInfo().isD3D9On12) - { - copySubResource(*this, *m_msaaResolvedSurface.resource, subResourceIndex); - } - else - { - D3DDDIARG_BLT blt = {}; - blt.hSrcResource = *m_msaaResolvedSurface.resource; - blt.SrcSubResourceIndex = subResourceIndex; - blt.SrcRect = m_msaaResolvedSurface.resource->getRect(subResourceIndex); - blt.hDstResource = *this; - blt.DstSubResourceIndex = subResourceIndex; - blt.DstRect = getRect(subResourceIndex); - shaderBlt(blt, *this, *m_msaaResolvedSurface.resource); - } - m_lockData[subResourceIndex].isVidMemUpToDate = true; - return; - } - auto src = m_msaaResolvedSurface.resource; - auto srcRect = src->getRect(subResourceIndex); - auto dstRect = getRect(subResourceIndex); - - downscale(src, srcRect.right, srcRect.bottom, dstRect.right, dstRect.bottom); - auto srcIndex = src == m_msaaResolvedSurface.resource ? subResourceIndex : 0; - - if (dstRect != srcRect && - !(m_device.getAdapter().getInfo().formatOps.at(m_fixedData.Format).Operations & FORMATOP_SRGBWRITE)) - { - auto nextRt = getNextRenderTarget(src, dstRect.right, dstRect.bottom).resource; - if (nextRt) - { - m_device.getShaderBlitter().textureBlt(*nextRt, 0, dstRect, - *src, srcIndex, srcRect, D3DTEXF_LINEAR); - src = nextRt; - srcRect = dstRect; - srcIndex = 0; - } - } - - if (dstRect == srcRect) - { - copySubResourceRegion(m_handle, subResourceIndex, dstRect, *src, srcIndex, srcRect); - } - else - { - m_device.getShaderBlitter().textureBlt(*this, subResourceIndex, dstRect, - *src, srcIndex, srcRect, D3DTEXF_LINEAR); - } + D3DDDIARG_BLT blt = {}; + blt.hSrcResource = *m_msaaResolvedSurface.resource; + blt.SrcSubResourceIndex = subResourceIndex; + blt.SrcRect = m_msaaResolvedSurface.resource->getRect(subResourceIndex); + blt.hDstResource = *this; + blt.DstSubResourceIndex = subResourceIndex; + blt.DstRect = getRect(subResourceIndex); + shaderBlt(blt, *this, *m_msaaResolvedSurface.resource, + Config::Settings::ResolutionScaleFilter::BILINEAR == Config::resolutionScaleFilter.get() + ? D3DTEXF_LINEAR | D3DTEXF_SRGB + : D3DTEXF_POINT); } else { @@ -1560,9 +1503,16 @@ namespace D3dDdi resource.m_isPalettizedTextureUpToDate = false; } - HRESULT Resource::shaderBlt(D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource) + HRESULT Resource::shaderBlt(const D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource, UINT filter) { - LOG_FUNC("Resource::shaderBlt", data, srcResource); + LOG_FUNC("Resource::shaderBlt", data, dstResource, srcResource); + + if (D3DDDIPOOL_SYSTEMMEM == dstResource.m_fixedData.Pool || + dstResource.canCopySubResource(data, srcResource)) + { + return LOG_RESULT(m_device.getOrigVtable().pfnBlt(m_device, &data)); + } + auto& repo = SurfaceRepository::get(m_device.getAdapter()); Resource* srcRes = &srcResource; @@ -1573,7 +1523,15 @@ namespace D3dDdi UINT dstIndex = data.DstSubResourceIndex; RECT dstRect = data.DstRect; - if (!srcResource.m_fixedData.Flags.Texture || D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool) + if (D3DTEXF_POINT != filter && + (dstResource.m_fixedData.Flags.ZBuffer || Rect::isEqualSize(srcRect, dstRect))) + { + filter = D3DTEXF_POINT; + } + + if (!srcResource.m_fixedData.Flags.Texture || + D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool || + (filter & D3DTEXF_SRGB) && !(srcResource.m_formatOp.Operations & FORMATOP_SRGBREAD)) { DWORD width = data.SrcRect.right - data.SrcRect.left; DWORD height = data.SrcRect.bottom - data.SrcRect.top; @@ -1602,11 +1560,21 @@ namespace D3dDdi } } - if (!dstResource.m_fixedData.Flags.RenderTarget && !dstResource.m_fixedData.Flags.ZBuffer) + if (filter & D3DTEXF_SRGB) + { + downscale(srcRes, srcRect.right, srcRect.bottom, dstRect.right, dstRect.bottom); + if (Rect::isEqualSize(srcRect, dstRect)) + { + filter = D3DTEXF_POINT; + } + } + + if (!dstResource.m_fixedData.Flags.RenderTarget && !dstResource.m_fixedData.Flags.ZBuffer || + (filter & D3DTEXF_SRGB) && !(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.getTempRenderTarget(width, height); + auto& rt = getNextRenderTarget(srcRes, width, height); if (!rt.resource) { return LOG_RESULT(E_OUTOFMEMORY); @@ -1642,16 +1610,20 @@ namespace D3dDdi : DeviceState::ShaderConstF{}; if (m_fixedData.Flags.ZBuffer) { - m_device.getShaderBlitter().depthBlt(*dstRes, dstRect, *srcRes, srcRect, - m_device.getAdapter().getInfo().isD3D9On12 ? nullptr : static_cast(*m_nullSurface.resource)); + const bool isD3D9On12 = m_device.getAdapter().getInfo().isD3D9On12; + if (m_nullSurface.resource || isD3D9On12) + { + m_device.getShaderBlitter().depthBlt(*dstRes, dstRect, *srcRes, srcRect, + isD3D9On12 ? nullptr : static_cast(*m_nullSurface.resource)); + } } else { m_device.getShaderBlitter().textureBlt(*dstRes, dstIndex, dstRect, *srcRes, srcIndex, srcRect, - data.Flags.Linear ? D3DTEXF_LINEAR : D3DTEXF_POINT, data.Flags.SrcColorKey ? &ck : nullptr); + filter, data.Flags.SrcColorKey ? &ck : nullptr); } - if (!dstResource.m_fixedData.Flags.RenderTarget && !dstResource.m_fixedData.Flags.ZBuffer) + if (*dstRes != data.hDstResource) { HRESULT result = copySubResourceRegion(data.hDstResource, data.DstSubResourceIndex, data.DstRect, *dstRes, dstIndex, dstRect); @@ -1691,9 +1663,7 @@ namespace D3dDdi return false; } - return Config::Settings::BltFilter::POINT == Config::bltFilter.get() || - data.SrcRect.right - data.SrcRect.left == data.DstRect.right - data.DstRect.left && - data.SrcRect.bottom - data.SrcRect.top == data.DstRect.bottom - data.DstRect.top; + return Config::Settings::BltFilter::POINT == Config::bltFilter.get() || Rect::isEqualSize(data.SrcRect, data.DstRect); } HRESULT Resource::unlock(const D3DDDIARG_UNLOCK& data) @@ -1755,8 +1725,7 @@ namespace D3dDdi g_msaaOverride = {}; } - auto& adapterInfo = m_device.getAdapter().getInfo(); - if (m_fixedData.Flags.ZBuffer && m_msaaSurface.resource && adapterInfo.isMsaaDepthResolveSupported) + if (m_fixedData.Flags.ZBuffer && m_msaaSurface.resource) { g_msaaOverride = msaa; SurfaceRepository::get(m_device.getAdapter()).getSurface(m_nullSurface, diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 975dfb3..c2fe734 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -30,6 +30,7 @@ namespace D3dDdi Resource* getCustomResource() const { return m_msaaSurface.resource ? m_msaaSurface.resource : m_msaaResolvedSurface.resource; } Device& getDevice() const { return m_device; } const D3DDDIARG_CREATERESOURCE2& getFixedDesc() const { return m_fixedData; } + FORMATOP getFormatOp() const { return m_formatOp; } const D3DDDIARG_CREATERESOURCE2& getOrigDesc() const { return m_origData; } UINT getPaletteHandle() const { return m_paletteHandle; } Resource* getPalettizedTexture() { return m_palettizedTexture; } @@ -97,6 +98,7 @@ namespace D3dDdi HRESULT bltLock(D3DDDIARG_LOCK& data); HRESULT bltViaCpu(D3DDDIARG_BLT data, Resource& srcResource); HRESULT bltViaGpu(D3DDDIARG_BLT data, Resource& srcResource); + bool canCopySubResource(const D3DDDIARG_BLT& data, Resource& srcResource); void clearRectExterior(UINT subResourceIndex, const RECT& rect); void clearRectInterior(UINT subResourceIndex, const RECT& rect); void clearUpToDateFlags(UINT subResourceIndex); @@ -124,7 +126,7 @@ namespace D3dDdi void presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect, std::vector layeredWindows, const RECT& monitorRect); void resolveMsaaDepthBuffer(); - HRESULT shaderBlt(D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource); + HRESULT shaderBlt(const D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource, UINT filter); bool shouldBltViaCpu(const D3DDDIARG_BLT &data, Resource& srcResource); Device& m_device; @@ -132,6 +134,7 @@ namespace D3dDdi Data m_origData; Data m_fixedData; FormatInfo m_formatInfo; + FORMATOP m_formatOp; std::unique_ptr m_lockBuffer; std::vector m_lockData; std::unique_ptr m_lockResource; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 2ca41ca..c82f3cc 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -89,13 +89,9 @@ namespace D3dDdi const auto& srcSurface = srcResource.getFixedDesc().pSurfList[srcSubResourceIndex]; const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex]; - bool srgb = false; - if (D3DTEXF_LINEAR == filter) - { - const auto& formatOps = m_device.getAdapter().getInfo().formatOps; - srgb = (formatOps.at(srcResource.getFixedDesc().Format).Operations & FORMATOP_SRGBREAD) && - (formatOps.at(dstResource.getFixedDesc().Format).Operations & FORMATOP_SRGBWRITE); - } + const bool srgb = (filter & D3DTEXF_SRGB) && + (srcResource.getFormatOp().Operations & FORMATOP_SRGBREAD) && + (dstResource.getFormatOp().Operations & FORMATOP_SRGBWRITE); auto& state = m_device.getState(); state.setSpriteMode(false); @@ -142,7 +138,7 @@ namespace D3dDdi state.setTempRenderState({ D3DDDIRS_DESTBLEND, D3DBLEND_INVSRCALPHA }); } - setTempTextureStage(0, srcResource, srcRect, filter); + setTempTextureStage(0, srcResource, srcRect, LOWORD(filter)); state.setTempTextureStageState({ 0, D3DDDITSS_SRGBTEXTURE, srgb }); state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, m_vertices.data()); @@ -382,7 +378,7 @@ namespace D3dDdi if (100 == blurPercent) { blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, - m_psTextureSampler.get(), D3DTEXF_LINEAR); + m_psTextureSampler.get(), D3DTEXF_LINEAR | D3DTEXF_SRGB); return; } @@ -400,7 +396,8 @@ namespace D3dDdi } }; DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), { 0, registers.size() }, registers.data()); - blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR); + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), + D3DTEXF_LINEAR | D3DTEXF_SRGB); } bool ShaderBlitter::isGammaRampDefault()