1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Don't apply gamma correction to bilinear blits

See issue #208.
This commit is contained in:
narzoul 2023-03-04 13:26:05 +01:00
parent bbf926162b
commit 714c4f5337
6 changed files with 114 additions and 137 deletions

View File

@ -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 {

View File

@ -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);
}

View File

@ -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
{

View File

@ -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<LONG>(m_fixedData.pSurfList[0].Width), static_cast<LONG>(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<LONG>(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx ||
static_cast<LONG>(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<LONG>(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx ||
static_cast<LONG>(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<HANDLE>(*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<HANDLE>(*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,

View File

@ -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<Gdi::Window::LayeredWindow> 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<void, void(*)(void*)> m_lockBuffer;
std::vector<LockData> m_lockData;
std::unique_ptr<void, ResourceDeleter> m_lockResource;

View File

@ -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()