mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
1733 lines
51 KiB
C++
1733 lines
51 KiB
C++
#include <type_traits>
|
|
|
|
#include <Common/Comparison.h>
|
|
#include <Common/HResultException.h>
|
|
#include <Common/Log.h>
|
|
#include <Common/Rect.h>
|
|
#include <Common/Time.h>
|
|
#include <Config/Settings/BltFilter.h>
|
|
#include <Config/Settings/ColorKeyMethod.h>
|
|
#include <Config/Settings/DepthFormat.h>
|
|
#include <Config/Settings/RenderColorDepth.h>
|
|
#include <Config/Settings/ResolutionScaleFilter.h>
|
|
#include <D3dDdi/Adapter.h>
|
|
#include <D3dDdi/Device.h>
|
|
#include <D3dDdi/KernelModeThunks.h>
|
|
#include <D3dDdi/Log/DeviceFuncsLog.h>
|
|
#include <D3dDdi/Resource.h>
|
|
#include <D3dDdi/ScopedCriticalSection.h>
|
|
#include <D3dDdi/SurfaceRepository.h>
|
|
#include <DDraw/Blitter.h>
|
|
#include <DDraw/RealPrimarySurface.h>
|
|
#include <DDraw/Surfaces/PrimarySurface.h>
|
|
#include <DDraw/Surfaces/SurfaceImpl.h>
|
|
#include <Dll/Dll.h>
|
|
#include <Gdi/Cursor.h>
|
|
#include <Gdi/Palette.h>
|
|
#include <Gdi/VirtualScreen.h>
|
|
#include <Gdi/Window.h>
|
|
#include <Win32/DisplayMode.h>
|
|
|
|
namespace
|
|
{
|
|
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
|
|
|
|
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
|
|
RECT g_presentationRect = {};
|
|
|
|
bool g_enableConfig = true;
|
|
D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN;
|
|
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> g_msaaOverride = {};
|
|
|
|
RECT calculateScaledRect(const RECT& srcRect, const RECT& dstRect)
|
|
{
|
|
const int srcWidth = srcRect.right - srcRect.left;
|
|
const int srcHeight = srcRect.bottom - srcRect.top;
|
|
const int dstWidth = dstRect.right - dstRect.left;
|
|
const int dstHeight = dstRect.bottom - dstRect.top;
|
|
|
|
RECT rect = { 0, 0, dstWidth, dstHeight };
|
|
if (dstWidth * srcHeight > dstHeight * srcWidth)
|
|
{
|
|
rect.right = dstHeight * srcWidth / srcHeight;
|
|
}
|
|
else
|
|
{
|
|
rect.bottom = dstWidth * srcHeight / srcWidth;
|
|
}
|
|
|
|
OffsetRect(&rect, (dstWidth - rect.right) / 2, (dstHeight - rect.bottom) / 2);
|
|
return rect;
|
|
}
|
|
|
|
LONG divCeil(LONG n, LONG d)
|
|
{
|
|
return (n + d - 1) / d;
|
|
}
|
|
|
|
D3DDDI_RESOURCEFLAGS getResourceTypeFlags()
|
|
{
|
|
D3DDDI_RESOURCEFLAGS flags = {};
|
|
flags.RenderTarget = 1;
|
|
flags.ZBuffer = 1;
|
|
flags.DMap = 1;
|
|
flags.Points = 1;
|
|
flags.RtPatches = 1;
|
|
flags.NPatches = 1;
|
|
flags.Video = 1;
|
|
flags.CaptureBuffer = 1;
|
|
flags.MatchGdiPrimary = 1;
|
|
flags.Primary = 1;
|
|
flags.Texture = 1;
|
|
flags.CubeMap = 1;
|
|
flags.VertexBuffer = 1;
|
|
flags.IndexBuffer = 1;
|
|
flags.DecodeRenderTarget = 1;
|
|
flags.DecodeCompressedBuffer = 1;
|
|
flags.VideoProcessRenderTarget = 1;
|
|
flags.Overlay = 1;
|
|
flags.TextApi = 1;
|
|
return flags;
|
|
}
|
|
|
|
void heapFree(void* p)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, p);
|
|
}
|
|
|
|
void logUnsupportedMsaaDepthBufferResolve()
|
|
{
|
|
LOG_ONCE("Warning: Resolving multisampled depth buffers is not supported by the GPU driver. "
|
|
"Disable antialiasing if experiencing visual glitches.");
|
|
}
|
|
}
|
|
|
|
namespace D3dDdi
|
|
{
|
|
Resource::Data::Data(const D3DDDIARG_CREATERESOURCE2& data)
|
|
: D3DDDIARG_CREATERESOURCE2(data)
|
|
, surfaceData(data.pSurfList, data.pSurfList + data.SurfCount)
|
|
{
|
|
pSurfList = surfaceData.data();
|
|
}
|
|
|
|
Resource::Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data)
|
|
: m_device(device)
|
|
, 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{}
|
|
, m_msaaSurface{}
|
|
, m_msaaResolvedSurface{}
|
|
, m_nullSurface{}
|
|
, m_colorKeyedSurface{}
|
|
, m_colorKey(0)
|
|
, m_formatConfig(D3DDDIFMT_UNKNOWN)
|
|
, m_multiSampleConfig{ D3DDDIMULTISAMPLE_NONE, 0 }
|
|
, m_scaledSize{}
|
|
, m_palettizedTexture(nullptr)
|
|
, m_paletteHandle(0)
|
|
, m_paletteColorKeyIndex(-1)
|
|
, m_isOversized(false)
|
|
, m_isSurfaceRepoResource(SurfaceRepository::inCreateSurface() || !g_enableConfig)
|
|
, m_isClampable(true)
|
|
, m_isPrimary(false)
|
|
, m_isPalettizedTextureUpToDate(false)
|
|
, m_isColorKeyedSurfaceUpToDate(false)
|
|
{
|
|
if (m_origData.Flags.VertexBuffer &&
|
|
m_origData.Flags.MightDrawFromLocked &&
|
|
D3DDDIPOOL_SYSTEMMEM != m_origData.Pool)
|
|
{
|
|
throw HResultException(E_FAIL);
|
|
}
|
|
|
|
if (m_origData.Flags.MatchGdiPrimary)
|
|
{
|
|
setFullscreenMode(true);
|
|
}
|
|
|
|
fixResourceData();
|
|
m_formatInfo = getFormatInfo(m_fixedData.Format);
|
|
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))
|
|
{
|
|
throw HResultException(result);
|
|
}
|
|
m_handle = m_fixedData.hResource;
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && m_origData.Flags.ZBuffer &&
|
|
!m_device.getAdapter().getInfo().isD3D9On12)
|
|
{
|
|
m_lockData.resize(m_origData.SurfCount);
|
|
for (UINT i = 0; i < m_origData.SurfCount; ++i)
|
|
{
|
|
m_lockData[i].isSysMemUpToDate = true;
|
|
m_lockData[i].isVidMemUpToDate = true;
|
|
m_lockData[i].isMsaaUpToDate = m_msaaSurface.resource;
|
|
m_lockData[i].isMsaaResolvedUpToDate = m_msaaResolvedSurface.resource;
|
|
m_lockData[i].qpcLastCpuAccess = Time::queryPerformanceCounter();
|
|
}
|
|
}
|
|
else if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool && 0 != m_formatInfo.bytesPerPixel)
|
|
{
|
|
m_lockData.resize(m_origData.SurfCount);
|
|
for (UINT i = 0; i < m_origData.SurfCount; ++i)
|
|
{
|
|
m_lockData[i].data = const_cast<void*>(m_origData.pSurfList[i].pSysMem);
|
|
m_lockData[i].pitch = m_origData.pSurfList[i].SysMemPitch;
|
|
m_lockData[i].isSysMemUpToDate = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
createLockResource();
|
|
}
|
|
|
|
data.hResource = m_fixedData.hResource;
|
|
updateConfig();
|
|
}
|
|
|
|
Resource::~Resource()
|
|
{
|
|
if (m_origData.Flags.MatchGdiPrimary)
|
|
{
|
|
setFullscreenMode(false);
|
|
}
|
|
|
|
if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface)
|
|
{
|
|
auto& repo = m_device.getRepo();
|
|
repo.release(m_msaaSurface);
|
|
repo.release(m_msaaResolvedSurface);
|
|
repo.release(m_lockRefSurface);
|
|
}
|
|
}
|
|
|
|
HRESULT Resource::blt(D3DDDIARG_BLT data)
|
|
{
|
|
if (!m_fixedData.Flags.MatchGdiPrimary && !isValidRect(data.DstSubResourceIndex, data.DstRect))
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
DDraw::setBltSrc(data);
|
|
auto srcResource = m_device.getResource(data.hSrcResource);
|
|
if (!srcResource)
|
|
{
|
|
prepareForBltDst(data);
|
|
return m_device.getOrigVtable().pfnBlt(m_device, &data);
|
|
}
|
|
|
|
if (!srcResource->isValidRect(data.SrcSubResourceIndex, data.SrcRect))
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if (m_fixedData.Flags.MatchGdiPrimary)
|
|
{
|
|
return presentationBlt(data, srcResource);
|
|
}
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
|
|
D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool)
|
|
{
|
|
return m_device.getOrigVtable().pfnBlt(m_device, &data);
|
|
}
|
|
|
|
if (srcResource->m_fixedData.Flags.ZBuffer && srcResource->m_msaaSurface.resource &&
|
|
!m_device.getAdapter().getInfo().isMsaaDepthResolveSupported)
|
|
{
|
|
logUnsupportedMsaaDepthBufferResolve();
|
|
return S_OK;
|
|
}
|
|
|
|
if (shouldBltViaCpu(data, *srcResource))
|
|
{
|
|
return bltViaCpu(data, *srcResource);
|
|
}
|
|
|
|
return bltViaGpu(data, *srcResource);
|
|
}
|
|
|
|
HRESULT Resource::bltLock(D3DDDIARG_LOCK& data)
|
|
{
|
|
LOG_FUNC("Resource::bltLock", data);
|
|
|
|
if (m_lockResource)
|
|
{
|
|
if (data.Flags.ReadOnly)
|
|
{
|
|
prepareForCpuRead(data.SubResourceIndex);
|
|
}
|
|
else
|
|
{
|
|
prepareForCpuWrite(data.SubResourceIndex);
|
|
}
|
|
}
|
|
|
|
auto& lockData = m_lockData[data.SubResourceIndex];
|
|
unsigned char* ptr = static_cast<unsigned char*>(lockData.data);
|
|
if (data.Flags.AreaValid)
|
|
{
|
|
ptr += data.Area.top * lockData.pitch + data.Area.left * m_formatInfo.bytesPerPixel;
|
|
}
|
|
|
|
data.pSurfData = ptr;
|
|
data.Pitch = lockData.pitch;
|
|
return LOG_RESULT(S_OK);
|
|
}
|
|
|
|
HRESULT Resource::bltViaCpu(D3DDDIARG_BLT data, Resource& srcResource)
|
|
{
|
|
D3DDDIARG_LOCK srcLock = {};
|
|
srcLock.hResource = data.hSrcResource;
|
|
srcLock.SubResourceIndex = data.SrcSubResourceIndex;
|
|
if (D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool)
|
|
{
|
|
srcLock.Flags.NotifyOnly = 1;
|
|
}
|
|
else
|
|
{
|
|
srcLock.Area = data.SrcRect;
|
|
srcLock.Flags.AreaValid = 1;
|
|
srcLock.Flags.ReadOnly = 1;
|
|
}
|
|
|
|
HRESULT result = srcResource.lock(srcLock);
|
|
if (FAILED(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
D3DDDIARG_LOCK dstLock = {};
|
|
dstLock.hResource = data.hDstResource;
|
|
dstLock.SubResourceIndex = data.DstSubResourceIndex;
|
|
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool)
|
|
{
|
|
dstLock.Flags.NotifyOnly = 1;
|
|
}
|
|
else
|
|
{
|
|
dstLock.Area = data.DstRect;
|
|
dstLock.Flags.AreaValid = 1;
|
|
}
|
|
|
|
result = lock(dstLock);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
if (D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool)
|
|
{
|
|
auto& lockData = srcResource.m_lockData[data.SrcSubResourceIndex];
|
|
srcLock.pSurfData = static_cast<BYTE*>(lockData.data) + data.SrcRect.top * lockData.pitch +
|
|
data.SrcRect.left * m_formatInfo.bytesPerPixel;
|
|
srcLock.Pitch = lockData.pitch;
|
|
}
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool)
|
|
{
|
|
auto& lockData = m_lockData[data.DstSubResourceIndex];
|
|
dstLock.pSurfData = static_cast<BYTE*>(lockData.data) + data.DstRect.top * lockData.pitch +
|
|
data.DstRect.left * m_formatInfo.bytesPerPixel;
|
|
dstLock.Pitch = lockData.pitch;
|
|
}
|
|
|
|
DDraw::Blitter::blt(
|
|
dstLock.pSurfData,
|
|
dstLock.Pitch,
|
|
data.DstRect.right - data.DstRect.left,
|
|
data.DstRect.bottom - data.DstRect.top,
|
|
srcLock.pSurfData,
|
|
srcLock.Pitch,
|
|
(1 - 2 * data.Flags.MirrorLeftRight) * (data.SrcRect.right - data.SrcRect.left),
|
|
(1 - 2 * data.Flags.MirrorUpDown) * (data.SrcRect.bottom - data.SrcRect.top),
|
|
m_formatInfo.bytesPerPixel,
|
|
data.Flags.DstColorKey ? reinterpret_cast<const DWORD*>(&data.ColorKey) : nullptr,
|
|
data.Flags.SrcColorKey ? reinterpret_cast<const DWORD*>(&data.ColorKey) : nullptr);
|
|
|
|
D3DDDIARG_UNLOCK dstUnlock = {};
|
|
dstUnlock.hResource = dstLock.hResource;
|
|
dstUnlock.SubResourceIndex = dstLock.SubResourceIndex;
|
|
dstUnlock.Flags.NotifyOnly = dstLock.Flags.NotifyOnly;
|
|
unlock(dstUnlock);
|
|
}
|
|
|
|
D3DDDIARG_UNLOCK srcUnlock = {};
|
|
srcUnlock.hResource = srcLock.hResource;
|
|
srcUnlock.SubResourceIndex = srcLock.SubResourceIndex;
|
|
srcUnlock.Flags.NotifyOnly = srcLock.Flags.NotifyOnly;
|
|
srcResource.unlock(srcUnlock);
|
|
return result;
|
|
}
|
|
|
|
HRESULT Resource::bltViaGpu(D3DDDIARG_BLT data, Resource& srcResource)
|
|
{
|
|
if (srcResource.m_lockResource)
|
|
{
|
|
srcResource.loadFromLockRefResource(data.SrcSubResourceIndex);
|
|
}
|
|
|
|
Resource* srcRes = &srcResource;
|
|
if (m_msaaResolvedSurface.resource && srcResource.m_msaaResolvedSurface.resource &&
|
|
(srcResource.m_lockData[data.SrcSubResourceIndex].isMsaaResolvedUpToDate ||
|
|
srcResource.m_lockData[data.SrcSubResourceIndex].isMsaaUpToDate))
|
|
{
|
|
srcResource.loadMsaaResolvedResource(data.SrcSubResourceIndex);
|
|
srcRes = srcResource.m_msaaResolvedSurface.resource;
|
|
data.hSrcResource = *srcRes;
|
|
srcResource.scaleRect(data.SrcRect);
|
|
if (!m_lockData[data.DstSubResourceIndex].isMsaaUpToDate)
|
|
{
|
|
loadMsaaResolvedResource(data.DstSubResourceIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
}
|
|
|
|
bool Resource::canCopySubResource(const D3DDDIARG_BLT& data, Resource& srcResource)
|
|
{
|
|
if (data.Flags.SrcColorKey ||
|
|
data.Flags.MirrorLeftRight ||
|
|
data.Flags.MirrorUpDown ||
|
|
D3DDDIMULTISAMPLE_NONE != m_fixedData.MultisampleType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_fixedData.Flags.ZBuffer)
|
|
{
|
|
return !m_device.getAdapter().getInfo().isD3D9On12 ||
|
|
m_fixedData.Format == srcResource.m_fixedData.Format && Rect::isEqualSize(data.SrcRect, data.DstRect);
|
|
}
|
|
|
|
return Rect::isEqualSize(data.SrcRect, data.DstRect);
|
|
}
|
|
|
|
void Resource::clearRectExterior(UINT subResourceIndex, const RECT& rect)
|
|
{
|
|
const LONG width = m_fixedData.pSurfList[subResourceIndex].Width;
|
|
const LONG height = m_fixedData.pSurfList[subResourceIndex].Height;
|
|
if (rect.left > 0)
|
|
{
|
|
clearRectInterior(subResourceIndex, { 0, 0, rect.left, height });
|
|
}
|
|
if (rect.right < width)
|
|
{
|
|
clearRectInterior(subResourceIndex, { rect.right, 0, width, height });
|
|
}
|
|
if (rect.top > 0)
|
|
{
|
|
clearRectInterior(subResourceIndex, { rect.left, 0, rect.right, rect.top });
|
|
}
|
|
if (rect.bottom < height)
|
|
{
|
|
clearRectInterior(subResourceIndex, { rect.left, rect.bottom, rect.right, height });
|
|
}
|
|
}
|
|
|
|
void Resource::clearRectInterior(UINT subResourceIndex, const RECT& rect)
|
|
{
|
|
D3DDDIARG_COLORFILL data = {};
|
|
data.hResource = m_handle;
|
|
data.SubResourceIndex = subResourceIndex;
|
|
data.DstRect = rect;
|
|
m_device.getOrigVtable().pfnColorFill(m_device, &data);
|
|
}
|
|
|
|
void Resource::clearUpToDateFlags(UINT subResourceIndex)
|
|
{
|
|
m_lockData[subResourceIndex].isMsaaUpToDate = false;
|
|
m_lockData[subResourceIndex].isMsaaResolvedUpToDate = false;
|
|
m_lockData[subResourceIndex].isVidMemUpToDate = false;
|
|
m_lockData[subResourceIndex].isSysMemUpToDate = false;
|
|
}
|
|
|
|
void Resource::clipRect(UINT subResourceIndex, RECT& rect)
|
|
{
|
|
rect.left = std::max<LONG>(rect.left, 0);
|
|
rect.top = std::max<LONG>(rect.top, 0);
|
|
rect.right = std::min<LONG>(rect.right, m_fixedData.pSurfList[subResourceIndex].Width);
|
|
rect.bottom = std::min<LONG>(rect.bottom, m_fixedData.pSurfList[subResourceIndex].Height);
|
|
}
|
|
|
|
HRESULT Resource::colorFill(D3DDDIARG_COLORFILL data)
|
|
{
|
|
LOG_FUNC("Resource::colorFill", data);
|
|
clipRect(data.SubResourceIndex, data.DstRect);
|
|
if (data.DstRect.left >= data.DstRect.right || data.DstRect.top >= data.DstRect.bottom)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if (m_lockResource)
|
|
{
|
|
auto& lockData = m_lockData[data.SubResourceIndex];
|
|
if (lockData.isSysMemUpToDate && !lockData.isVidMemUpToDate)
|
|
{
|
|
auto dstBuf = static_cast<BYTE*>(lockData.data) +
|
|
data.DstRect.top * lockData.pitch + data.DstRect.left * m_formatInfo.bytesPerPixel;
|
|
|
|
DDraw::Blitter::colorFill(dstBuf, lockData.pitch,
|
|
data.DstRect.right - data.DstRect.left, data.DstRect.bottom - data.DstRect.top,
|
|
m_formatInfo.bytesPerPixel, convertFrom32Bit(m_formatInfo, data.Color));
|
|
|
|
return LOG_RESULT(S_OK);
|
|
}
|
|
}
|
|
|
|
if (D3DDDIFMT_P8 == m_fixedData.Format)
|
|
{
|
|
data.Color |= data.Color << 16;
|
|
}
|
|
|
|
prepareForBltDst(data.hResource, data.SubResourceIndex, data.DstRect);
|
|
return LOG_RESULT(m_device.getOrigVtable().pfnColorFill(m_device, &data));
|
|
}
|
|
|
|
HRESULT Resource::copySubResource(Resource& dstResource, Resource& srcResource, UINT subResourceIndex)
|
|
{
|
|
return copySubResourceRegion(dstResource, subResourceIndex, dstResource.getRect(subResourceIndex),
|
|
srcResource, subResourceIndex, srcResource.getRect(subResourceIndex));
|
|
}
|
|
|
|
HRESULT Resource::copySubResource(HANDLE dstResource, HANDLE srcResource, UINT subResourceIndex)
|
|
{
|
|
return copySubResourceRegion(dstResource, subResourceIndex, getRect(subResourceIndex),
|
|
srcResource, subResourceIndex, getRect(subResourceIndex));
|
|
}
|
|
|
|
HRESULT Resource::copySubResourceRegion(HANDLE dst, UINT dstIndex, const RECT& dstRect,
|
|
HANDLE src, UINT srcIndex, const RECT& srcRect)
|
|
{
|
|
LOG_FUNC("Resource::copySubResourceRegion", dst, dstIndex, dstRect, src, srcIndex, srcRect);
|
|
D3DDDIARG_BLT data = {};
|
|
data.hDstResource = dst;
|
|
data.DstSubResourceIndex = dstIndex;
|
|
data.DstRect = dstRect;
|
|
data.hSrcResource = src;
|
|
data.SrcSubResourceIndex = srcIndex;
|
|
data.SrcRect = srcRect;
|
|
data.Flags.Point = 1;
|
|
|
|
HRESULT result = LOG_RESULT(m_device.getOrigVtable().pfnBlt(m_device, &data));
|
|
if (FAILED(result))
|
|
{
|
|
LOG_ONCE("ERROR: Resource::copySubResourceRegion failed: " << Compat::hex(result));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void Resource::createGdiLockResource()
|
|
{
|
|
LOG_FUNC("Resource::createGdiLockResource");
|
|
auto gdiSurfaceDesc(Gdi::VirtualScreen::getSurfaceDesc(DDraw::PrimarySurface::getMonitorRect()));
|
|
if (!gdiSurfaceDesc.lpSurface)
|
|
{
|
|
return;
|
|
}
|
|
|
|
D3DDDI_SURFACEINFO surfaceInfo = {};
|
|
surfaceInfo.Width = gdiSurfaceDesc.dwWidth;
|
|
surfaceInfo.Height = gdiSurfaceDesc.dwHeight;
|
|
surfaceInfo.pSysMem = gdiSurfaceDesc.lpSurface;
|
|
surfaceInfo.SysMemPitch = gdiSurfaceDesc.lPitch;
|
|
|
|
m_lockData.resize(m_fixedData.SurfCount);
|
|
createSysMemResource({ surfaceInfo });
|
|
if (m_lockResource)
|
|
{
|
|
clearUpToDateFlags(0);
|
|
m_lockData[0].isSysMemUpToDate = true;
|
|
}
|
|
else
|
|
{
|
|
m_lockData.clear();
|
|
}
|
|
}
|
|
|
|
void Resource::createLockResource()
|
|
{
|
|
D3DDDI_RESOURCEFLAGS flags = {};
|
|
flags.Value = g_resourceTypeFlags;
|
|
flags.RenderTarget = 0;
|
|
flags.Texture = 0;
|
|
if (m_device.getAdapter().getInfo().isD3D9On12)
|
|
{
|
|
flags.ZBuffer = 0;
|
|
}
|
|
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool ||
|
|
m_isSurfaceRepoResource ||
|
|
0 == m_formatInfo.bytesPerPixel ||
|
|
0 != (m_fixedData.Flags.Value & flags.Value) ||
|
|
m_fixedData.Flags.Texture && !m_origData.Flags.RenderTarget && !m_origData.Flags.ZBuffer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const auto ALIGNMENT = DDraw::Surface::ALIGNMENT;
|
|
std::vector<D3DDDI_SURFACEINFO> surfaceInfo(m_fixedData.SurfCount);
|
|
for (UINT i = 0; i < m_fixedData.SurfCount; ++i)
|
|
{
|
|
surfaceInfo[i].Width = m_fixedData.pSurfList[i].Width;
|
|
surfaceInfo[i].Height = m_fixedData.pSurfList[i].Height;
|
|
surfaceInfo[i].SysMemPitch = (surfaceInfo[i].Width * m_formatInfo.bytesPerPixel + 3) & ~3;
|
|
if (i != 0)
|
|
{
|
|
std::uintptr_t offset = reinterpret_cast<std::uintptr_t>(surfaceInfo[i - 1].pSysMem) +
|
|
((surfaceInfo[i - 1].SysMemPitch * surfaceInfo[i - 1].Height + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT);
|
|
surfaceInfo[i].pSysMem = reinterpret_cast<void*>(offset);
|
|
}
|
|
}
|
|
|
|
std::uintptr_t bufferSize = reinterpret_cast<std::uintptr_t>(surfaceInfo.back().pSysMem) +
|
|
surfaceInfo.back().SysMemPitch * surfaceInfo.back().Height + ALIGNMENT;
|
|
m_lockBuffer.reset(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufferSize));
|
|
|
|
BYTE* bufferStart = static_cast<BYTE*>(DDraw::Surface::alignBuffer(m_lockBuffer.get()));
|
|
for (UINT i = 0; i < m_fixedData.SurfCount; ++i)
|
|
{
|
|
surfaceInfo[i].pSysMem = bufferStart + reinterpret_cast<uintptr_t>(surfaceInfo[i].pSysMem);
|
|
}
|
|
|
|
createSysMemResource(surfaceInfo);
|
|
if (!m_lockResource)
|
|
{
|
|
m_lockBuffer.reset();
|
|
m_lockData.clear();
|
|
}
|
|
}
|
|
|
|
void Resource::createSysMemResource(const std::vector<D3DDDI_SURFACEINFO>& surfaceInfo)
|
|
{
|
|
LOG_FUNC("Resource::createSysMemResource", Compat::array(surfaceInfo.data(), surfaceInfo.size()));
|
|
D3DDDIARG_CREATERESOURCE2 data = {};
|
|
data.Format = m_fixedData.Format;
|
|
data.Pool = D3DDDIPOOL_SYSTEMMEM;
|
|
data.pSurfList = surfaceInfo.data();
|
|
data.SurfCount = surfaceInfo.size();
|
|
data.Rotation = D3DDDI_ROTATION_IDENTITY;
|
|
|
|
HRESULT result = m_device.createPrivateResource(data);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
m_lockResource.reset(data.hResource);
|
|
m_lockData.resize(surfaceInfo.size());
|
|
for (std::size_t i = 0; i < surfaceInfo.size(); ++i)
|
|
{
|
|
m_lockData[i].data = const_cast<void*>(surfaceInfo[i].pSysMem);
|
|
m_lockData[i].pitch = surfaceInfo[i].SysMemPitch;
|
|
m_lockData[i].isSysMemUpToDate = true;
|
|
m_lockData[i].isVidMemUpToDate = true;
|
|
m_lockData[i].isMsaaUpToDate = m_msaaSurface.resource;
|
|
m_lockData[i].isMsaaResolvedUpToDate = m_msaaResolvedSurface.resource;
|
|
m_lockData[i].isRefLocked = false;
|
|
m_lockData[i].qpcLastCpuAccess = Time::queryPerformanceCounter();
|
|
}
|
|
}
|
|
|
|
LOG_RESULT(m_lockResource.get());
|
|
}
|
|
|
|
void Resource::disableClamp()
|
|
{
|
|
m_isClampable = false;
|
|
}
|
|
|
|
void Resource::enableConfig(bool enable)
|
|
{
|
|
g_enableConfig = enable;
|
|
}
|
|
|
|
void Resource::fixResourceData()
|
|
{
|
|
if (m_fixedData.Flags.MatchGdiPrimary)
|
|
{
|
|
RECT r = DDraw::RealPrimarySurface::getMonitorRect();
|
|
if (!IsRectEmpty(&r))
|
|
{
|
|
for (auto& surface : m_fixedData.surfaceData)
|
|
{
|
|
surface.Width = r.right - r.left;
|
|
surface.Height = r.bottom - r.top;
|
|
}
|
|
}
|
|
m_fixedData.Format = D3DDDIFMT_X8R8G8B8;
|
|
}
|
|
else if (D3DDDIFMT_UNKNOWN != g_formatOverride)
|
|
{
|
|
m_fixedData.Format = g_formatOverride;
|
|
}
|
|
else if (m_fixedData.Flags.RenderTarget && m_device.getAdapter().isEmulatedRenderTargetFormat(m_fixedData.Format))
|
|
{
|
|
m_fixedData.Flags.RenderTarget = 0;
|
|
}
|
|
|
|
if (D3DDDIMULTISAMPLE_NONE != g_msaaOverride.first)
|
|
{
|
|
m_fixedData.MultisampleType = g_msaaOverride.first;
|
|
m_fixedData.MultisampleQuality = g_msaaOverride.second;
|
|
}
|
|
else if (!m_fixedData.Flags.Texture &&
|
|
!m_fixedData.Flags.MatchGdiPrimary &&
|
|
D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool &&
|
|
(m_origData.Flags.RenderTarget || m_fixedData.Flags.ZBuffer))
|
|
{
|
|
const auto& formatOps = m_device.getAdapter().getInfo().fixedFormatOps;
|
|
auto it = formatOps.find(m_fixedData.Format);
|
|
if (it != formatOps.end() && (it->second.Operations & FORMATOP_TEXTURE))
|
|
{
|
|
m_fixedData.Flags.Texture = 1;
|
|
m_fixedData.MipLevels = 1;
|
|
}
|
|
}
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
|
|
1 == m_fixedData.SurfCount &&
|
|
0 == m_fixedData.pSurfList[0].Depth &&
|
|
0 != D3dDdi::getFormatInfo(m_fixedData.Format).bytesPerPixel)
|
|
{
|
|
const auto& caps = m_device.getAdapter().getInfo().d3dExtendedCaps;
|
|
auto& surfaceInfo = m_fixedData.surfaceData[0];
|
|
if (surfaceInfo.Width > caps.dwMaxTextureWidth)
|
|
{
|
|
surfaceInfo.Width = caps.dwMaxTextureWidth;
|
|
m_isOversized = true;
|
|
}
|
|
if (surfaceInfo.Height > caps.dwMaxTextureHeight)
|
|
{
|
|
surfaceInfo.Height = caps.dwMaxTextureHeight;
|
|
m_isOversized = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
D3DDDIFORMAT Resource::getFormatConfig()
|
|
{
|
|
if (m_origData.Flags.RenderTarget && !m_fixedData.Flags.RenderTarget)
|
|
{
|
|
return 0 != m_formatInfo.alpha.bitCount ? D3DDDIFMT_A8R8G8B8 : D3DDDIFMT_X8R8G8B8;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
else if (m_fixedData.Flags.ZBuffer && Config::Settings::DepthFormat::APP != Config::depthFormat.get() &&
|
|
getFormatInfo(m_fixedData.Format).depth.bitCount != Config::depthFormat.get())
|
|
{
|
|
auto& formatOps = m_device.getAdapter().getInfo().fixedFormatOps;
|
|
switch (Config::depthFormat.get())
|
|
{
|
|
#define USE_FORMAT(format) if (formatOps.find(format) != formatOps.end()) return format
|
|
case 32:
|
|
USE_FORMAT(D3DDDIFMT_D32);
|
|
USE_FORMAT(D3DDDIFMT_D32_LOCKABLE);
|
|
USE_FORMAT(D3DDDIFMT_D32F_LOCKABLE);
|
|
case 24:
|
|
USE_FORMAT(D3DDDIFMT_S8D24);
|
|
USE_FORMAT(D3DDDIFMT_D24S8);
|
|
USE_FORMAT(D3DDDIFMT_X8D24);
|
|
USE_FORMAT(D3DDDIFMT_D24X8);
|
|
case 16:
|
|
USE_FORMAT(D3DDDIFMT_D16);
|
|
#undef USE_FORMAT
|
|
}
|
|
}
|
|
return m_fixedData.Format;
|
|
}
|
|
|
|
void* Resource::getLockPtr(UINT subResourceIndex)
|
|
{
|
|
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
|
|
}
|
|
|
|
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> Resource::getMultisampleConfig()
|
|
{
|
|
if (!m_isPrimary || m_origData.Flags.RenderTarget)
|
|
{
|
|
return m_device.getAdapter().getMultisampleConfig(m_fixedData.Format);
|
|
}
|
|
return { D3DDDIMULTISAMPLE_NONE, 0 };
|
|
}
|
|
|
|
RECT Resource::getRect(UINT subResourceIndex) const
|
|
{
|
|
const auto& si = m_fixedData.pSurfList[subResourceIndex];
|
|
return { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
|
|
}
|
|
|
|
SIZE Resource::getScaledSize()
|
|
{
|
|
SIZE size = { static_cast<LONG>(m_fixedData.pSurfList[0].Width), static_cast<LONG>(m_fixedData.pSurfList[0].Height) };
|
|
if (m_origData.Flags.RenderTarget || m_fixedData.Flags.ZBuffer)
|
|
{
|
|
return m_device.getAdapter().getScaledSize(size);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
bool Resource::isValidRect(UINT subResourceIndex, const RECT& rect)
|
|
{
|
|
return rect.left >= 0 && rect.top >= 0 && rect.left < rect.right && rect.top < rect.bottom &&
|
|
rect.right <= static_cast<LONG>(m_fixedData.pSurfList[subResourceIndex].Width) &&
|
|
rect.bottom <= static_cast<LONG>(m_fixedData.pSurfList[subResourceIndex].Height);
|
|
}
|
|
|
|
void Resource::loadFromLockRefResource(UINT subResourceIndex)
|
|
{
|
|
if (m_lockData[subResourceIndex].isRefLocked)
|
|
{
|
|
m_lockData[subResourceIndex].isRefLocked = false;
|
|
loadVidMemResource(subResourceIndex);
|
|
|
|
auto srcResource = this;
|
|
auto srcIndex = subResourceIndex;
|
|
auto& si = m_fixedData.pSurfList[subResourceIndex];
|
|
const RECT srcRect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
|
|
if (!m_fixedData.Flags.Texture)
|
|
{
|
|
auto& texture = m_device.getRepo().getTempTexture(si.Width, si.Height, m_fixedData.Format);
|
|
if (!texture.resource)
|
|
{
|
|
return;
|
|
}
|
|
srcResource = texture.resource;
|
|
srcIndex = 0;
|
|
copySubResourceRegion(*srcResource, 0, srcRect, m_handle, subResourceIndex, srcRect);
|
|
}
|
|
|
|
const RECT dstRect = { 0, 0, static_cast<LONG>(m_msaaResolvedSurface.width),
|
|
static_cast<LONG>(m_msaaResolvedSurface.height) };
|
|
m_device.getShaderBlitter().lockRefBlt(*m_msaaResolvedSurface.resource, subResourceIndex, dstRect,
|
|
*srcResource, srcIndex, srcRect, *m_lockRefSurface.resource);
|
|
m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true;
|
|
}
|
|
}
|
|
|
|
void Resource::loadMsaaResource(UINT subResourceIndex)
|
|
{
|
|
if (!m_lockData[subResourceIndex].isMsaaUpToDate)
|
|
{
|
|
if (m_msaaResolvedSurface.resource)
|
|
{
|
|
loadMsaaResolvedResource(subResourceIndex);
|
|
if (m_fixedData.Flags.ZBuffer)
|
|
{
|
|
bool isD3D9On12 = m_device.getAdapter().getInfo().isD3D9On12;
|
|
if (m_nullSurface.resource || isD3D9On12)
|
|
{
|
|
RECT r = m_msaaResolvedSurface.resource->getRect(0);
|
|
m_device.getShaderBlitter().depthBlt(
|
|
*m_msaaSurface.resource, r, *m_msaaResolvedSurface.resource, r,
|
|
isD3D9On12 ? nullptr : static_cast<HANDLE>(*m_nullSurface.resource));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
copySubResource(*m_msaaSurface.resource, *m_msaaResolvedSurface.resource, subResourceIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
copySubResource(*m_msaaSurface.resource, *this, subResourceIndex);
|
|
}
|
|
m_lockData[subResourceIndex].isMsaaUpToDate = true;
|
|
}
|
|
}
|
|
|
|
void Resource::loadMsaaResolvedResource(UINT subResourceIndex)
|
|
{
|
|
loadFromLockRefResource(subResourceIndex);
|
|
if (m_lockData[subResourceIndex].isMsaaResolvedUpToDate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_lockData[subResourceIndex].isMsaaUpToDate)
|
|
{
|
|
if (m_fixedData.Flags.ZBuffer)
|
|
{
|
|
if (m_device.getAdapter().getInfo().isMsaaDepthResolveSupported)
|
|
{
|
|
resolveMsaaDepthBuffer();
|
|
}
|
|
else
|
|
{
|
|
logUnsupportedMsaaDepthBufferResolve();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
copySubResource(*m_msaaResolvedSurface.resource, *m_msaaSurface.resource, subResourceIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
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;
|
|
}
|
|
|
|
void Resource::loadSysMemResource(UINT subResourceIndex)
|
|
{
|
|
if (!m_lockData[subResourceIndex].isSysMemUpToDate)
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
copySubResource(m_lockResource.get(), *this, subResourceIndex);
|
|
notifyLock(subResourceIndex);
|
|
m_lockData[subResourceIndex].isSysMemUpToDate = true;
|
|
}
|
|
m_lockData[subResourceIndex].qpcLastCpuAccess = Time::queryPerformanceCounter();
|
|
}
|
|
|
|
void Resource::loadVidMemResource(UINT subResourceIndex)
|
|
{
|
|
if (m_lockData[subResourceIndex].isVidMemUpToDate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate)
|
|
{
|
|
loadMsaaResolvedResource(subResourceIndex);
|
|
|
|
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
|
|
{
|
|
copySubResource(*this, m_lockResource.get(), subResourceIndex);
|
|
notifyLock(subResourceIndex);
|
|
m_lockData[subResourceIndex].isRefLocked = false;
|
|
}
|
|
m_lockData[subResourceIndex].isVidMemUpToDate = true;
|
|
}
|
|
|
|
HRESULT Resource::lock(D3DDDIARG_LOCK& data)
|
|
{
|
|
if (D3DDDIMULTISAMPLE_NONE != m_fixedData.MultisampleType)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
D3DDDIARG_BLT blt = {};
|
|
DDraw::setBltSrc(blt);
|
|
if (blt.hSrcResource)
|
|
{
|
|
return E_ABORT;
|
|
}
|
|
|
|
if (m_lockResource || m_isOversized)
|
|
{
|
|
return bltLock(data);
|
|
}
|
|
|
|
if (!data.Flags.ReadOnly)
|
|
{
|
|
m_isPalettizedTextureUpToDate = false;
|
|
m_isColorKeyedSurfaceUpToDate = false;
|
|
}
|
|
|
|
if (m_fixedData.Flags.ZBuffer && m_msaaResolvedSurface.resource)
|
|
{
|
|
loadVidMemResource(0);
|
|
if (!data.Flags.ReadOnly)
|
|
{
|
|
m_lockData[0].isMsaaUpToDate = false;
|
|
m_lockData[0].isMsaaResolvedUpToDate = false;
|
|
}
|
|
}
|
|
return m_device.getOrigVtable().pfnLock(m_device, &data);
|
|
}
|
|
|
|
void Resource::notifyLock(UINT subResourceIndex)
|
|
{
|
|
D3DDDIARG_LOCK lock = {};
|
|
lock.hResource = D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool ? m_handle : m_lockResource.get();
|
|
lock.SubResourceIndex = subResourceIndex;
|
|
lock.Flags.NotifyOnly = 1;
|
|
m_device.getOrigVtable().pfnLock(m_device, &lock);
|
|
|
|
D3DDDIARG_UNLOCK unlock = {};
|
|
unlock.hResource = lock.hResource;
|
|
unlock.SubResourceIndex = lock.SubResourceIndex;
|
|
unlock.Flags.NotifyOnly = 1;
|
|
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
|
|
}
|
|
|
|
void Resource::onDestroyResource(HANDLE resource)
|
|
{
|
|
if (resource == m_handle ||
|
|
m_msaaSurface.resource && *m_msaaSurface.resource == resource ||
|
|
m_msaaResolvedSurface.resource && *m_msaaResolvedSurface.resource == resource)
|
|
{
|
|
loadSysMemResource(0);
|
|
}
|
|
}
|
|
|
|
Resource& Resource::prepareForBltSrc(const D3DDDIARG_BLT& data)
|
|
{
|
|
if (m_lockResource || m_msaaResolvedSurface.resource)
|
|
{
|
|
loadVidMemResource(data.SrcSubResourceIndex);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Resource& Resource::prepareForBltDst(D3DDDIARG_BLT& data)
|
|
{
|
|
return prepareForBltDst(data.hDstResource, data.DstSubResourceIndex, data.DstRect);
|
|
}
|
|
|
|
Resource& Resource::prepareForBltDst(HANDLE& resource, UINT subResourceIndex, RECT& rect)
|
|
{
|
|
m_isPalettizedTextureUpToDate = false;
|
|
m_isColorKeyedSurfaceUpToDate = false;
|
|
if (m_lockResource || m_msaaResolvedSurface.resource)
|
|
{
|
|
loadFromLockRefResource(subResourceIndex);
|
|
if (m_lockData[subResourceIndex].isMsaaUpToDate)
|
|
{
|
|
resource = *m_msaaSurface.resource;
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isMsaaUpToDate = true;
|
|
scaleRect(rect);
|
|
return *m_msaaSurface.resource;
|
|
}
|
|
else if (m_lockData[subResourceIndex].isMsaaResolvedUpToDate)
|
|
{
|
|
resource = *m_msaaResolvedSurface.resource;
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true;
|
|
scaleRect(rect);
|
|
return *m_msaaResolvedSurface.resource;
|
|
}
|
|
else
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isVidMemUpToDate = true;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void Resource::prepareForCpuRead(UINT subResourceIndex)
|
|
{
|
|
if (m_lockResource)
|
|
{
|
|
loadSysMemResource(subResourceIndex);
|
|
}
|
|
}
|
|
|
|
void Resource::prepareForCpuWrite(UINT subResourceIndex)
|
|
{
|
|
m_isPalettizedTextureUpToDate = false;
|
|
m_isColorKeyedSurfaceUpToDate = false;
|
|
if (m_lockResource)
|
|
{
|
|
if (m_lockRefSurface.resource &&
|
|
(m_lockData[subResourceIndex].isMsaaResolvedUpToDate || m_lockData[subResourceIndex].isMsaaUpToDate))
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
copySubResource(*m_lockRefSurface.resource, m_handle, subResourceIndex);
|
|
m_lockData[subResourceIndex].isRefLocked = true;
|
|
}
|
|
|
|
loadSysMemResource(subResourceIndex);
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isSysMemUpToDate = true;
|
|
}
|
|
}
|
|
|
|
Resource& Resource::prepareForGpuRead(UINT subResourceIndex)
|
|
{
|
|
if (m_lockResource)
|
|
{
|
|
loadFromLockRefResource(subResourceIndex);
|
|
if (m_msaaResolvedSurface.resource)
|
|
{
|
|
loadMsaaResolvedResource(subResourceIndex);
|
|
return *m_msaaResolvedSurface.resource;
|
|
}
|
|
else
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void Resource::prepareForGpuWrite(UINT subResourceIndex)
|
|
{
|
|
m_isColorKeyedSurfaceUpToDate = false;
|
|
if (m_lockResource || m_msaaResolvedSurface.resource)
|
|
{
|
|
if (m_msaaSurface.resource)
|
|
{
|
|
loadMsaaResource(subResourceIndex);
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isMsaaUpToDate = true;
|
|
}
|
|
else if (m_msaaResolvedSurface.resource)
|
|
{
|
|
loadMsaaResolvedResource(subResourceIndex);
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true;
|
|
}
|
|
else
|
|
{
|
|
loadVidMemResource(subResourceIndex);
|
|
clearUpToDateFlags(subResourceIndex);
|
|
m_lockData[subResourceIndex].isVidMemUpToDate = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Resource& Resource::prepareForTextureRead(UINT stage)
|
|
{
|
|
if (m_lockResource)
|
|
{
|
|
for (UINT i = 0; i < m_lockData.size(); ++i)
|
|
{
|
|
prepareForGpuRead(i);
|
|
}
|
|
}
|
|
|
|
auto& defaultResource = m_msaaResolvedSurface.resource ? *m_msaaResolvedSurface.resource : *this;
|
|
const auto& appState = m_device.getState().getAppState();
|
|
if (Config::Settings::ColorKeyMethod::ALPHATEST != Config::colorKeyMethod.get() ||
|
|
!appState.renderState[D3DDDIRS_COLORKEYENABLE] ||
|
|
appState.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY])
|
|
{
|
|
return defaultResource;
|
|
}
|
|
|
|
if (!m_colorKeyedSurface.surface)
|
|
{
|
|
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,
|
|
m_fixedData.Flags.CubeMap ? DDSCAPS2_CUBEMAP : 0);
|
|
if (!m_colorKeyedSurface.surface)
|
|
{
|
|
return defaultResource;
|
|
}
|
|
m_colorKey = appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL] + 1;
|
|
}
|
|
|
|
if (!m_isColorKeyedSurfaceUpToDate ||
|
|
m_colorKey != appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL])
|
|
{
|
|
m_isColorKeyedSurfaceUpToDate = true;
|
|
m_colorKey = appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL];
|
|
auto ck = convertToShaderConst(m_formatInfo, m_colorKey);
|
|
for (UINT i = 0; i < m_fixedData.SurfCount; ++i)
|
|
{
|
|
m_device.getShaderBlitter().colorKeyBlt(*m_colorKeyedSurface.resource, i, defaultResource, i, ck);
|
|
}
|
|
}
|
|
|
|
return *m_colorKeyedSurface.resource;
|
|
}
|
|
|
|
HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource)
|
|
{
|
|
LOG_FUNC("Resource::presentationBlt", data, *srcResource);
|
|
if (srcResource->m_lockResource)
|
|
{
|
|
if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate &&
|
|
!srcResource->m_origData.Flags.RenderTarget)
|
|
{
|
|
srcResource->m_lockData[data.SrcSubResourceIndex].isVidMemUpToDate = false;
|
|
srcResource->m_lockData[data.SrcSubResourceIndex].isMsaaResolvedUpToDate = false;
|
|
}
|
|
|
|
srcResource = &srcResource->prepareForGpuRead(data.SrcSubResourceIndex);
|
|
}
|
|
|
|
LONG srcWidth = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Width;
|
|
LONG srcHeight = srcResource->m_fixedData.pSurfList[data.SrcSubResourceIndex].Height;
|
|
data.SrcRect = { 0, 0, srcWidth, srcHeight };
|
|
if (!IsRectEmpty(&g_presentationRect))
|
|
{
|
|
data.DstRect = g_presentationRect;
|
|
}
|
|
|
|
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;
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool)
|
|
{
|
|
srcResource = repo.getTempTexture(srcWidth, srcHeight, srcResource->m_fixedData.Format).resource;
|
|
if (!srcResource)
|
|
{
|
|
return LOG_RESULT(E_OUTOFMEMORY);
|
|
}
|
|
copySubResourceRegion(*srcResource, 0, data.SrcRect, data.hSrcResource, data.SrcSubResourceIndex, data.SrcRect);
|
|
}
|
|
|
|
if (D3DDDIFMT_P8 == srcResource->m_origData.Format)
|
|
{
|
|
auto entries(Gdi::Palette::getHardwarePalette());
|
|
RGBQUAD pal[256] = {};
|
|
for (UINT i = 0; i < 256; ++i)
|
|
{
|
|
pal[i].rgbRed = entries[i].peRed;
|
|
pal[i].rgbGreen = entries[i].peGreen;
|
|
pal[i].rgbBlue = entries[i].peBlue;
|
|
pal[i].rgbReserved = 0xFF;
|
|
}
|
|
m_device.getShaderBlitter().palettizedBlt(
|
|
*rt, rtIndex, rtRect, *srcResource, data.SrcSubResourceIndex, data.SrcRect, pal);
|
|
}
|
|
else
|
|
{
|
|
copySubResourceRegion(*rt, rtIndex, rtRect, *srcResource, data.SrcSubResourceIndex, data.SrcRect);
|
|
}
|
|
|
|
if (!IsRectEmpty(&g_presentationRect))
|
|
{
|
|
presentLayeredWindows(*rt, rtIndex, rtRect,
|
|
Gdi::Window::getVisibleLayeredWindows(), DDraw::PrimarySurface::getMonitorRect());
|
|
}
|
|
|
|
const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo();
|
|
const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor;
|
|
if (isCursorEmulated)
|
|
{
|
|
m_device.getShaderBlitter().cursorBlt(*rt, rtIndex, rtRect, cursorInfo.hCursor, cursorInfo.ptScreenPos);
|
|
}
|
|
|
|
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);
|
|
|
|
if (!IsRectEmpty(&g_presentationRect))
|
|
{
|
|
auto dstRect = DDraw::RealPrimarySurface::getMonitorRect();
|
|
OffsetRect(&dstRect, -dstRect.left, -dstRect.top);
|
|
presentLayeredWindows(*this, data.DstSubResourceIndex, dstRect,
|
|
Gdi::Window::getVisibleOverlayWindows(), dstRect);
|
|
}
|
|
|
|
return LOG_RESULT(S_OK);
|
|
}
|
|
|
|
void Resource::presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect,
|
|
std::vector<Gdi::Window::LayeredWindow> layeredWindows, const RECT& monitorRect)
|
|
{
|
|
auto& blitter = m_device.getShaderBlitter();
|
|
auto& repo = m_device.getRepo();
|
|
|
|
for (auto& layeredWindow : layeredWindows)
|
|
{
|
|
RECT visibleRect = {};
|
|
IntersectRect(&visibleRect, &layeredWindow.rect, &monitorRect);
|
|
if (IsRectEmpty(&visibleRect))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left, visibleRect.bottom - visibleRect.top };
|
|
auto& windowSurface = repo.getTempSysMemSurface(srcRect.right, srcRect.bottom);
|
|
auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, D3DDDIFMT_A8R8G8B8);
|
|
if (!windowSurface.resource || !texture.resource)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
HDC srcDc = GetWindowDC(layeredWindow.hwnd);
|
|
HDC dstDc = nullptr;
|
|
windowSurface.surface->GetDC(windowSurface.surface, &dstDc);
|
|
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right, srcRect.bottom, srcDc,
|
|
visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top, SRCCOPY);
|
|
windowSurface.surface->ReleaseDC(windowSurface.surface, dstDc);
|
|
ReleaseDC(layeredWindow.hwnd, srcDc);
|
|
|
|
copySubResourceRegion(*texture.resource, 0, srcRect, *windowSurface.resource, 0, srcRect);
|
|
windowSurface.resource->notifyLock(0);
|
|
|
|
DeviceState::ShaderConstF ck = {};
|
|
COLORREF colorKey = 0;
|
|
BYTE alpha = 0;
|
|
DWORD flags = 0;
|
|
GetLayeredWindowAttributes(layeredWindow.hwnd, &colorKey, &alpha, &flags);
|
|
if (flags & ULW_COLORKEY)
|
|
{
|
|
ck = convertToShaderConst(getFormatInfo(D3DDDIFMT_X8B8G8R8), colorKey);
|
|
}
|
|
|
|
if (layeredWindow.region)
|
|
{
|
|
layeredWindow.region &= monitorRect;
|
|
layeredWindow.region.offset(-visibleRect.left, -visibleRect.top);
|
|
}
|
|
Rect::transform(visibleRect, monitorRect, dstRect);
|
|
|
|
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect, D3DTEXF_POINT,
|
|
(flags & ULW_COLORKEY) ? &ck : nullptr,
|
|
(flags & ULW_ALPHA) ? &alpha : nullptr,
|
|
layeredWindow.region);
|
|
}
|
|
}
|
|
|
|
void Resource::resolveMsaaDepthBuffer()
|
|
{
|
|
LOG_FUNC("Resource::resolveMsaaDepthBuffer");
|
|
auto& state = m_device.getState();
|
|
state.setTempDepthStencil({ *m_msaaSurface.resource });
|
|
state.setTempTexture(0, *m_msaaResolvedSurface.resource);
|
|
|
|
const UINT RESZ_CODE = 0x7fa05000;
|
|
state.setTempRenderState({ D3DDDIRS_POINTSIZE, RESZ_CODE });
|
|
}
|
|
|
|
void Resource::scaleRect(RECT& rect)
|
|
{
|
|
const LONG origWidth = m_fixedData.pSurfList[0].Width;
|
|
const LONG origHeight = m_fixedData.pSurfList[0].Height;
|
|
|
|
rect.left = rect.left * m_scaledSize.cx / origWidth;
|
|
rect.top = rect.top * m_scaledSize.cy / origHeight;
|
|
rect.right = rect.right * m_scaledSize.cx / origWidth;
|
|
rect.bottom = rect.bottom * m_scaledSize.cy / origHeight;
|
|
}
|
|
|
|
void Resource::setAsGdiResource(bool isGdiResource)
|
|
{
|
|
m_lockResource.reset();
|
|
m_lockData.clear();
|
|
m_lockBuffer.reset();
|
|
if (isGdiResource)
|
|
{
|
|
createGdiLockResource();
|
|
}
|
|
else
|
|
{
|
|
createLockResource();
|
|
}
|
|
}
|
|
|
|
void Resource::setAsPrimary()
|
|
{
|
|
D3dDdi::ScopedCriticalSection lock;
|
|
if (!m_isPrimary)
|
|
{
|
|
m_isPrimary = true;
|
|
updateConfig();
|
|
}
|
|
}
|
|
|
|
void Resource::setFormatOverride(D3DDDIFORMAT format)
|
|
{
|
|
g_formatOverride = format;
|
|
}
|
|
|
|
void Resource::setFullscreenMode(bool isFullscreen)
|
|
{
|
|
if (!IsRectEmpty(&g_presentationRect) == isFullscreen)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isFullscreen)
|
|
{
|
|
DDraw::PrimarySurface::updatePalette();
|
|
|
|
const Int2 ar = m_device.getAdapter().getAspectRatio();
|
|
g_presentationRect = calculateScaledRect({ 0, 0, ar.x, ar.y }, DDraw::RealPrimarySurface::getMonitorRect());
|
|
auto& si = m_origData.pSurfList[0];
|
|
RECT primaryRect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
|
|
|
|
Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect());
|
|
if (!EqualRect(&g_presentationRect, &primaryRect))
|
|
{
|
|
Gdi::Cursor::setEmulated(true);
|
|
}
|
|
Gdi::VirtualScreen::setFullscreenMode(m_origData.Flags.MatchGdiPrimary);
|
|
}
|
|
else
|
|
{
|
|
Gdi::Palette::setHardwarePalette(Gdi::Palette::getSystemPalette().data());
|
|
|
|
g_presentationRect = {};
|
|
Gdi::VirtualScreen::setFullscreenMode(false);
|
|
Gdi::Cursor::setEmulated(false);
|
|
Gdi::Cursor::setMonitorClipRect({});
|
|
}
|
|
}
|
|
|
|
void Resource::setPaletteHandle(UINT paletteHandle)
|
|
{
|
|
m_paletteHandle = paletteHandle;
|
|
m_isPalettizedTextureUpToDate = false;
|
|
}
|
|
|
|
void Resource::setPalettizedTexture(Resource& resource)
|
|
{
|
|
m_palettizedTexture = &resource;
|
|
resource.m_isPalettizedTextureUpToDate = false;
|
|
}
|
|
|
|
HRESULT Resource::shaderBlt(const D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource, UINT filter)
|
|
{
|
|
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 = m_device.getRepo();
|
|
|
|
Resource* srcRes = &srcResource;
|
|
UINT srcIndex = data.SrcSubResourceIndex;
|
|
RECT srcRect = data.SrcRect;
|
|
|
|
Resource* dstRes = &dstResource;
|
|
UINT dstIndex = data.DstSubResourceIndex;
|
|
RECT dstRect = data.DstRect;
|
|
|
|
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;
|
|
auto texture = m_fixedData.Flags.ZBuffer
|
|
? m_msaaResolvedSurface.resource
|
|
: repo.getTempTexture(width, height, srcResource.m_fixedData.Format).resource;
|
|
if (!texture)
|
|
{
|
|
return LOG_RESULT(E_OUTOFMEMORY);
|
|
}
|
|
|
|
srcRes = texture;
|
|
srcIndex = 0;
|
|
srcRect = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
|
|
|
|
HRESULT result = copySubResourceRegion(*srcRes, srcIndex, srcRect,
|
|
data.hSrcResource, data.SrcSubResourceIndex, data.SrcRect);
|
|
if (FAILED(result))
|
|
{
|
|
return LOG_RESULT(result);
|
|
}
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool)
|
|
{
|
|
srcResource.notifyLock(data.SrcSubResourceIndex);
|
|
}
|
|
}
|
|
|
|
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.getNextRenderTarget(width, height, srcRes);
|
|
if (!rt.resource)
|
|
{
|
|
return LOG_RESULT(E_OUTOFMEMORY);
|
|
}
|
|
|
|
dstRes = rt.resource;
|
|
dstIndex = 0;
|
|
dstRect = { 0, 0, width, height };
|
|
|
|
if (data.Flags.SrcColorKey)
|
|
{
|
|
HRESULT result = copySubResourceRegion(*dstRes, dstIndex, dstRect,
|
|
data.hDstResource, data.DstSubResourceIndex, data.DstRect);
|
|
if (FAILED(result))
|
|
{
|
|
return LOG_RESULT(result);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data.Flags.MirrorLeftRight)
|
|
{
|
|
std::swap(srcRect.left, srcRect.right);
|
|
}
|
|
|
|
if (data.Flags.MirrorUpDown)
|
|
{
|
|
std::swap(srcRect.top, srcRect.bottom);
|
|
}
|
|
|
|
auto ck = data.Flags.SrcColorKey
|
|
? convertToShaderConst(srcResource.m_formatInfo, data.ColorKey)
|
|
: DeviceState::ShaderConstF{};
|
|
if (m_fixedData.Flags.ZBuffer)
|
|
{
|
|
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
|
|
{
|
|
if ((D3DTEXF_LINEAR | D3DTEXF_SRGB) == filter)
|
|
{
|
|
m_device.getShaderBlitter().bilinearBlt(*dstRes, dstIndex, dstRect, *srcRes, srcIndex, srcRect, 0);
|
|
}
|
|
else
|
|
{
|
|
m_device.getShaderBlitter().textureBlt(*dstRes, dstIndex, dstRect, *srcRes, srcIndex, srcRect,
|
|
filter, data.Flags.SrcColorKey ? &ck : nullptr);
|
|
}
|
|
}
|
|
|
|
if (*dstRes != data.hDstResource)
|
|
{
|
|
HRESULT result = copySubResourceRegion(data.hDstResource, data.DstSubResourceIndex, data.DstRect,
|
|
*dstRes, dstIndex, dstRect);
|
|
if (FAILED(result))
|
|
{
|
|
return LOG_RESULT(result);
|
|
}
|
|
}
|
|
|
|
return LOG_RESULT(S_OK);
|
|
}
|
|
|
|
bool Resource::shouldBltViaCpu(const D3DDDIARG_BLT& data, Resource& srcResource)
|
|
{
|
|
if (m_fixedData.Format != srcResource.m_fixedData.Format ||
|
|
0 == m_formatInfo.bytesPerPixel ||
|
|
m_fixedData.Flags.ZBuffer ||
|
|
D3DDDIPOOL_SYSTEMMEM != srcResource.m_fixedData.Pool && !srcResource.m_lockResource)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
D3DDDIARG_BLT blt = {};
|
|
DDraw::setBltSrc(blt);
|
|
|
|
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool ||
|
|
D3DDDIFMT_P8 == m_fixedData.Format ||
|
|
m_isOversized || srcResource.m_isOversized)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (m_lockData.empty() ||
|
|
!m_lockData[data.DstSubResourceIndex].isSysMemUpToDate ||
|
|
Time::qpcToMs(Time::queryPerformanceCounter() - m_lockData[data.DstSubResourceIndex].qpcLastCpuAccess) > 200)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Config::Settings::BltFilter::POINT == Config::bltFilter.get() || Rect::isEqualSize(data.SrcRect, data.DstRect);
|
|
}
|
|
|
|
HRESULT Resource::unlock(const D3DDDIARG_UNLOCK& data)
|
|
{
|
|
return (m_lockResource || m_isOversized) ? S_OK : m_device.getOrigVtable().pfnUnlock(m_device, &data);
|
|
}
|
|
|
|
void Resource::updateConfig()
|
|
{
|
|
if (m_isSurfaceRepoResource || D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || D3DDDIFMT_P8 == m_fixedData.Format ||
|
|
m_fixedData.Flags.MatchGdiPrimary ||
|
|
!m_isPrimary && !m_origData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer ||
|
|
!m_fixedData.Flags.ZBuffer && !m_lockResource)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const auto msaa = getMultisampleConfig();
|
|
const auto formatConfig = getFormatConfig();
|
|
const auto scaledSize = getScaledSize();
|
|
if (m_multiSampleConfig == msaa && m_formatConfig == formatConfig && m_scaledSize == scaledSize)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_msaaSurface.resource || m_msaaResolvedSurface.resource)
|
|
{
|
|
for (UINT i = 0; i < m_lockData.size(); ++i)
|
|
{
|
|
if (m_lockData[i].isMsaaUpToDate || m_lockData[i].isMsaaResolvedUpToDate)
|
|
{
|
|
loadVidMemResource(i);
|
|
}
|
|
m_lockData[i].isMsaaUpToDate = false;
|
|
m_lockData[i].isMsaaResolvedUpToDate = false;
|
|
m_lockData[i].isRefLocked = false;
|
|
}
|
|
}
|
|
|
|
m_multiSampleConfig = msaa;
|
|
m_formatConfig = formatConfig;
|
|
m_scaledSize = scaledSize;
|
|
|
|
m_msaaSurface = {};
|
|
m_msaaResolvedSurface = {};
|
|
m_nullSurface = {};
|
|
m_lockRefSurface = {};
|
|
|
|
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 (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;
|
|
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;
|
|
repo.getSurface(m_nullSurface, scaledSize.cx, scaledSize.cy, FOURCC_NULL,
|
|
DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount);
|
|
g_msaaOverride = {};
|
|
}
|
|
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 = {};
|
|
repo.getSurface(m_msaaResolvedSurface, scaledSize.cx, scaledSize.cy,
|
|
formatConfig, caps, m_fixedData.SurfCount);
|
|
}
|
|
|
|
if (!m_fixedData.Flags.ZBuffer && m_msaaResolvedSurface.resource)
|
|
{
|
|
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)
|
|
{
|
|
loadMsaaResolvedResource(0);
|
|
m_lockData[0].isVidMemUpToDate = false;
|
|
loadVidMemResource(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Resource::updatePalettizedTexture(UINT stage)
|
|
{
|
|
if (!m_palettizedTexture)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto& appState = m_device.getState().getAppState();
|
|
int paletteColorKeyIndex = appState.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY]
|
|
? -1 : appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL];
|
|
|
|
if (m_palettizedTexture->m_isPalettizedTextureUpToDate &&
|
|
(-1 == paletteColorKeyIndex || paletteColorKeyIndex == m_paletteColorKeyIndex))
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto palettePtr = m_device.getPalette(m_palettizedTexture->m_paletteHandle);
|
|
if (paletteColorKeyIndex >= 0)
|
|
{
|
|
static RGBQUAD palette[256] = {};
|
|
memcpy(palette, m_device.getPalette(m_palettizedTexture->m_paletteHandle), sizeof(palette));
|
|
for (int i = 0; i < 256; ++i)
|
|
{
|
|
if (i == paletteColorKeyIndex)
|
|
{
|
|
palette[i].rgbReserved = 0;
|
|
}
|
|
else if (palette[i] == palette[paletteColorKeyIndex])
|
|
{
|
|
palette[i].rgbBlue += 0xFF == palette[i].rgbBlue ? -1 : 1;
|
|
}
|
|
}
|
|
palettePtr = palette;
|
|
}
|
|
|
|
auto rect = getRect(0);
|
|
m_device.getShaderBlitter().palettizedBlt(*this, 0, rect, *m_palettizedTexture, 0, rect, palettePtr);
|
|
|
|
m_palettizedTexture->m_isPalettizedTextureUpToDate = true;
|
|
m_paletteColorKeyIndex = paletteColorKeyIndex;
|
|
}
|
|
}
|