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

Added timeout for sysmem preference of blits

Improves performance in Dungeon Keeper 2.
This commit is contained in:
narzoul 2019-08-22 20:47:24 +02:00
parent a45e5768ae
commit 898c7e819c
5 changed files with 104 additions and 145 deletions

View File

@ -5,6 +5,7 @@ typedef unsigned long DWORD;
namespace Config
{
const int delayedFlipModeTimeout = 200;
const int evictionTimeout = 200;
const int maxPaletteUpdatesPerMs = 5;
const int maxUserModeDisplayDrivers = 3;
}

View File

@ -63,7 +63,7 @@ namespace D3dDdi
{
try
{
Resource resource(Resource::create(*this, data));
Resource resource(*this, data);
m_resources.emplace(resource, std::move(resource));
return S_OK;
}

View File

@ -2,6 +2,8 @@
#include <Common/HResultException.h>
#include <Common/Log.h>
#include <Common/Time.h>
#include <Config/Config.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/KernelModeThunks.h>
@ -132,53 +134,57 @@ namespace D3dDdi
pSurfList = surfaceData.data();
}
Resource::Data::Data(const Data& other)
: D3DDDIARG_CREATERESOURCE2(other)
, surfaceData(other.surfaceData)
{
pSurfList = surfaceData.data();
}
Resource::Data& Resource::Data::operator=(const Data& other)
{
static_cast<D3DDDIARG_CREATERESOURCE2&>(*this) = other;
surfaceData = other.surfaceData;
pSurfList = surfaceData.data();
return *this;
}
Resource::SysMemBltGuard::SysMemBltGuard(Resource& resource, UINT subResourceIndex, bool isReadOnly)
: data(nullptr)
, pitch(0)
{
if (D3DDDIPOOL_SYSTEMMEM == resource.m_fixedData.Pool)
{
data = const_cast<void*>(resource.m_fixedData.pSurfList[subResourceIndex].pSysMem);
pitch = resource.m_fixedData.pSurfList[subResourceIndex].SysMemPitch;
}
else if (resource.m_lockResource)
{
if (!resource.m_lockData[subResourceIndex].isSysMemUpToDate)
{
resource.copyToSysMem(subResourceIndex);
}
resource.m_lockData[subResourceIndex].isVidMemUpToDate &= isReadOnly;
data = resource.m_lockData[subResourceIndex].data;
pitch = resource.m_lockData[subResourceIndex].pitch;
}
}
Resource::Resource(Device& device, const D3DDDIARG_CREATERESOURCE& data)
: Resource(device, upgradeResourceData(data))
{
}
Resource::Resource(Device& device, const D3DDDIARG_CREATERESOURCE2& data)
template <typename Arg>
Resource::Resource(Device& device, Arg& data, HRESULT(APIENTRY* createResourceFunc)(HANDLE, Arg*))
: m_device(device)
, m_handle(nullptr)
, m_origData(data)
, m_fixedData(data)
, m_lockBuffer(nullptr, &heapFree)
, m_lockResource(nullptr, ResourceDeleter(device))
{
if (D3DDDIFMT_VERTEXDATA == data.Format &&
data.Flags.VertexBuffer &&
data.Flags.MightDrawFromLocked &&
D3DDDIPOOL_SYSTEMMEM != data.Pool)
{
const HRESULT D3DERR_NOTAVAILABLE = 0x8876086A;
throw HResultException(D3DERR_NOTAVAILABLE);
}
fixResourceData(device, reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(m_fixedData));
m_formatInfo = getFormatInfo(m_fixedData.Format);
HRESULT result = createResourceFunc(device, reinterpret_cast<Arg*>(&m_fixedData));
if (FAILED(result))
{
throw HResultException(result);
}
m_handle = m_fixedData.hResource;
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
0 != m_formatInfo.bytesPerPixel)
{
m_lockData.resize(m_fixedData.SurfCount);
for (UINT i = 0; i < m_fixedData.SurfCount; ++i)
{
m_lockData[i].data = const_cast<void*>(m_fixedData.pSurfList[i].pSysMem);
m_lockData[i].pitch = m_fixedData.pSurfList[i].SysMemPitch;
m_lockData[i].isSysMemUpToDate = true;
}
}
createLockResource();
data.hResource = m_fixedData.hResource;
}
Resource::Resource(Device& device, D3DDDIARG_CREATERESOURCE& data)
: Resource(device, data, device.getOrigVtable().pfnCreateResource)
{
}
Resource::Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data)
: Resource(device, data, device.getOrigVtable().pfnCreateResource2)
{
}
@ -227,6 +233,7 @@ namespace D3dDdi
copyToSysMem(data.SubResourceIndex);
}
lockData.isVidMemUpToDate &= data.Flags.ReadOnly;
lockData.qpcLastForcedLock = Time::queryPerformanceCounter();
unsigned char* ptr = static_cast<unsigned char*>(lockData.data);
if (data.Flags.AreaValid)
@ -408,10 +415,12 @@ namespace D3dDdi
{
m_lockResource.reset(data.hResource);
m_lockData.resize(surfaceInfo.size());
auto qpcLastForcedLock = Time::queryPerformanceCounter() - Time::msToQpc(Config::evictionTimeout);
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].qpcLastForcedLock = qpcLastForcedLock;
m_lockData[i].isSysMemUpToDate = true;
m_lockData[i].isVidMemUpToDate = true;
}
@ -420,48 +429,6 @@ namespace D3dDdi
LOG_RESULT(m_lockResource.get());
}
template <typename Arg>
Resource Resource::create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*))
{
if (D3DDDIFMT_VERTEXDATA == data.Format &&
data.Flags.VertexBuffer &&
data.Flags.MightDrawFromLocked &&
D3DDDIPOOL_SYSTEMMEM != data.Pool)
{
const HRESULT D3DERR_NOTAVAILABLE = 0x8876086A;
throw HResultException(D3DERR_NOTAVAILABLE);
}
Resource resource(device, data);
Arg origData = data;
fixResourceData(device, reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(data));
resource.m_fixedData = data;
resource.m_formatInfo = getFormatInfo(data.Format);
HRESULT result = createResourceFunc(device, &data);
if (FAILED(result))
{
data = origData;
throw HResultException(result);
}
resource.m_handle = data.hResource;
resource.createLockResource();
data = origData;
data.hResource = resource.m_handle;
return resource;
}
Resource Resource::create(Device& device, D3DDDIARG_CREATERESOURCE& data)
{
return create(device, data, device.getOrigVtable().pfnCreateResource);
}
Resource Resource::create(Device& device, D3DDDIARG_CREATERESOURCE2& data)
{
return create(device, data, device.getOrigVtable().pfnCreateResource2);
}
void Resource::fixVertexData(UINT offset, UINT count, UINT stride)
{
if (!m_fixedData.Flags.MightDrawFromLocked ||
@ -489,14 +456,7 @@ namespace D3dDdi
void* Resource::getLockPtr(UINT subResourceIndex)
{
return m_lockResource ? m_lockData[subResourceIndex].data
: const_cast<void*>(m_fixedData.pSurfList[subResourceIndex].pSysMem);
}
bool Resource::isInSysMem(UINT subResourceIndex) const
{
return D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool ||
(m_lockResource && m_lockData[subResourceIndex].isSysMemUpToDate);
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
}
bool Resource::isOversized() const
@ -622,37 +582,52 @@ namespace D3dDdi
HRESULT Resource::sysMemPreferredBlt(const D3DDDIARG_BLT& data, Resource& srcResource)
{
if (m_fixedData.Format == srcResource.m_fixedData.Format &&
0 != m_formatInfo.bytesPerPixel &&
(data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown ||
(isInSysMem(data.DstSubResourceIndex) &&
(!srcResource.m_fixedData.Flags.RenderTarget || srcResource.isInSysMem(data.SrcSubResourceIndex)))))
!m_lockData.empty() &&
!srcResource.m_lockData.empty())
{
SysMemBltGuard srcGuard(srcResource, data.SrcSubResourceIndex, true);
if (srcGuard.data)
auto& dstLockData = m_lockData[data.DstSubResourceIndex];
auto& srcLockData = srcResource.m_lockData[data.SrcSubResourceIndex];
bool isSysMemBltPreferred = true;
auto now = Time::queryPerformanceCounter();
if (data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown)
{
SysMemBltGuard dstGuard(*this, data.DstSubResourceIndex, false);
if (dstGuard.data)
dstLockData.qpcLastForcedLock = now;
srcLockData.qpcLastForcedLock = now;
}
else if (m_lockResource)
{
isSysMemBltPreferred = dstLockData.isSysMemUpToDate &&
Time::qpcToMs(now - dstLockData.qpcLastForcedLock) <= Config::evictionTimeout;
}
if (isSysMemBltPreferred)
{
dstLockData.isVidMemUpToDate = false;
if (!srcLockData.isSysMemUpToDate)
{
auto dstBuf = static_cast<BYTE*>(dstGuard.data) +
data.DstRect.top * dstGuard.pitch + data.DstRect.left * m_formatInfo.bytesPerPixel;
auto srcBuf = static_cast<const BYTE*>(srcGuard.data) +
data.SrcRect.top * srcGuard.pitch + data.SrcRect.left * m_formatInfo.bytesPerPixel;
DDraw::Blitter::blt(
dstBuf,
dstGuard.pitch,
data.DstRect.right - data.DstRect.left,
data.DstRect.bottom - data.DstRect.top,
srcBuf,
srcGuard.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);
return S_OK;
srcResource.copyToSysMem(data.SrcSubResourceIndex);
}
auto dstBuf = static_cast<BYTE*>(dstLockData.data) +
data.DstRect.top * dstLockData.pitch + data.DstRect.left * m_formatInfo.bytesPerPixel;
auto srcBuf = static_cast<const BYTE*>(srcLockData.data) +
data.SrcRect.top * srcLockData.pitch + data.SrcRect.left * m_formatInfo.bytesPerPixel;
DDraw::Blitter::blt(
dstBuf,
dstLockData.pitch,
data.DstRect.right - data.DstRect.left,
data.DstRect.bottom - data.DstRect.top,
srcBuf,
srcLockData.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);
return S_OK;
}
}

View File

@ -15,8 +15,8 @@ namespace D3dDdi
class Resource
{
public:
static Resource create(Device& device, D3DDDIARG_CREATERESOURCE& data);
static Resource create(Device& device, D3DDDIARG_CREATERESOURCE2& data);
Resource(Device& device, D3DDDIARG_CREATERESOURCE& data);
Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data);
Resource(const Resource&) = delete;
Resource& operator=(const Resource&) = delete;
@ -42,8 +42,10 @@ namespace D3dDdi
Data();
Data(const D3DDDIARG_CREATERESOURCE& data);
Data(const D3DDDIARG_CREATERESOURCE2& data);
Data(const Data& other);
Data& operator=(const Data& other);
Data(const Data&) = delete;
Data& operator=(const Data&) = delete;
Data(Data&&) = default;
Data& operator=(Data&&) = default;
@ -55,6 +57,7 @@ namespace D3dDdi
void* data;
UINT pitch;
UINT lockCount;
long long qpcLastForcedLock;
bool isSysMemUpToDate;
bool isVidMemUpToDate;
};
@ -69,19 +72,8 @@ namespace D3dDdi
Device& m_device;
};
struct SysMemBltGuard
{
void* data;
UINT pitch;
SysMemBltGuard(Resource& resource, UINT subResourceIndex, bool isReadOnly);
};
Resource(Device& device, const D3DDDIARG_CREATERESOURCE& data);
Resource(Device& device, const D3DDDIARG_CREATERESOURCE2& data);
template <typename Arg>
static Resource create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*));
Resource(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*));
HRESULT bltLock(D3DDDIARG_LOCK& data);
HRESULT bltUnlock(const D3DDDIARG_UNLOCK& data);
@ -92,7 +84,6 @@ namespace D3dDdi
void createLockResource();
void createSysMemResource(const std::vector<D3DDDI_SURFACEINFO>& surfaceInfo);
bool isOversized() const;
bool isInSysMem(UINT subResourceIndex) const;
HRESULT presentationBlt(const D3DDDIARG_BLT& data, Resource& srcResource);
HRESULT splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect);

View File

@ -64,14 +64,6 @@ namespace DDraw
}
auto surface7(CompatPtr<IDirectDrawSurface7>::from(surface));
if (!(desc.dwFlags & DDSD_PIXELFORMAT))
{
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = {};
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
surface7->GetPixelFormat(surface7, &desc.ddpfPixelFormat);
}
if (desc.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
{
auto attachedSurfaces(getAllAttachedSurfaces(*surface7));