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

Prefer locks and blits in system memory

This commit is contained in:
narzoul 2019-07-25 22:51:11 +02:00
parent 545b08c55b
commit c526cc2506
19 changed files with 1376 additions and 301 deletions

View File

@ -63,7 +63,13 @@ std::ostream& operator<<(std::ostream& os, const WCHAR* wstr)
return os << static_cast<const void*>(wstr);
}
return os << std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().to_bytes(wstr);
while (*wstr)
{
os.put(static_cast<char>(*wstr));
++wstr;
}
return os;
}
std::ostream& operator<<(std::ostream& os, const DEVMODEA& dm)

View File

@ -37,7 +37,8 @@ namespace
HRESULT result = D3dDdi::AdapterFuncs::s_origVtables.at(hAdapter).pfnGetCaps(hAdapter, pData);
if (SUCCEEDED(result) && D3DDDICAPS_DDRAW == pData->Type)
{
static_cast<DDRAW_CAPS*>(pData->pData)->FxCaps = 0;
static_cast<DDRAW_CAPS*>(pData->pData)->FxCaps =
DDRAW_FXCAPS_BLTMIRRORLEFTRIGHT | DDRAW_FXCAPS_BLTMIRRORUPDOWN;
}
return result;
}

View File

@ -5,7 +5,6 @@
#include "D3dDdi/Adapter.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/KernelModeThunks.h"
#include "D3dDdi/Resource.h"
#include "Gdi/AccessGuard.h"
@ -28,44 +27,33 @@ namespace
: Gdi::DDrawAccessGuard(access, g_gdiResourceHandle == resource)
, m_device(device)
{
device.prepareForRendering(resource, subResourceIndex);
device.prepareForRendering(resource, subResourceIndex, Gdi::ACCESS_READ == access);
}
private:
D3dDdi::Device & m_device;
D3dDdi::Device& m_device;
};
template <typename Container, typename Predicate>
void erase_if(Container& container, Predicate pred)
{
auto it = container.begin();
while (it != container.end())
{
if (pred(*it))
{
it = container.erase(it);
}
else
{
++it;
}
}
}
}
namespace D3dDdi
{
UINT getBytesPerPixel(D3DDDIFORMAT format)
{
switch (format)
{
case D3DDDIFMT_A8:
case D3DDDIFMT_P8:
return 1;
case D3DDDIFMT_R5G6B5:
case D3DDDIFMT_X1R5G5B5:
case D3DDDIFMT_A1R5G5B5:
case D3DDDIFMT_A8P8:
return 2;
case D3DDDIFMT_R8G8B8:
return 3;
case D3DDDIFMT_A8R8G8B8:
case D3DDDIFMT_X8R8G8B8:
case D3DDDIFMT_A8B8G8R8:
case D3DDDIFMT_X8B8G8R8:
return 4;
default:
return 0;
}
}
Device::Device(HANDLE adapter, HANDLE device)
: m_origVtable(DeviceFuncs::s_origVtables.at(device))
, m_adapter(Adapter::get(adapter))
@ -76,13 +64,13 @@ namespace D3dDdi
HRESULT Device::blt(const D3DDDIARG_BLT& data)
{
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex);
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex);
auto it = m_resources.find(data.hDstResource);
if (it != m_resources.end())
{
return it->second.blt(data);
}
RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex);
RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex);
return m_origVtable.pfnBlt(m_device, &data);
}
@ -104,7 +92,7 @@ namespace D3dDdi
try
{
Resource resource(Resource::create(*this, data));
m_resources.emplace(resource, resource);
m_resources.emplace(resource, std::move(resource));
return S_OK;
}
catch (const HResultException& e)
@ -133,9 +121,17 @@ namespace D3dDdi
HRESULT result = m_origVtable.pfnDestroyResource(m_device, resource);
if (SUCCEEDED(result))
{
m_resources.erase(resource);
m_renderTargetResources.erase(resource);
m_lockedRenderTargetResources.erase(resource);
erase_if(m_dirtyRenderTargets,
[=](const decltype(m_dirtyRenderTargets)::value_type& v) { return v.first.first == resource; });
erase_if(m_dirtyTextures,
[=](const decltype(m_dirtyTextures)::value_type& v) { return v.first.first == resource; });
auto it = m_resources.find(resource);
if (it != m_resources.end())
{
it->second.destroy();
m_resources.erase(it);
}
if (resource == m_sharedPrimary)
{
@ -195,21 +191,10 @@ namespace D3dDdi
(data.Flags.ReadOnly || g_isReadOnlyGdiLockEnabled) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
data.hResource == g_gdiResourceHandle);
auto it = m_renderTargetResources.find(data.hResource);
if (it != m_renderTargetResources.end())
auto it = m_resources.find(data.hResource);
if (it != m_resources.end())
{
HRESULT result = it->second.lock(data);
if (SUCCEEDED(result))
{
m_lockedRenderTargetResources.emplace(it->first, it->second);
}
return result;
}
auto resourceIter = m_resources.find(data.hResource);
if (resourceIter != m_resources.end())
{
return resourceIter->second.lock(data);
return it->second.lock(data);
}
return m_origVtable.pfnLock(m_device, &data);
@ -243,7 +228,8 @@ namespace D3dDdi
for (UINT i = 0; i < data.SrcResources; ++i)
{
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex);
const bool isReadOnly = true;
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex, isReadOnly);
}
return m_origVtable.pfnPresent1(m_device, &data);
@ -266,18 +252,13 @@ namespace D3dDdi
HRESULT Device::unlock(const D3DDDIARG_UNLOCK& data)
{
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, data.hResource == g_gdiResourceHandle);
auto it = m_renderTargetResources.find(data.hResource);
if (it != m_renderTargetResources.end())
auto it = m_resources.find(data.hResource);
if (it != m_resources.end())
{
return it->second.unlock(data);
}
auto resourceIter = m_resources.find(data.hResource);
if (resourceIter != m_resources.end())
{
return resourceIter->second.unlock(data);
}
return m_origVtable.pfnUnlock(m_device, &data);
}
@ -293,37 +274,52 @@ namespace D3dDdi
return m_origVtable.pfnUpdateWInfo(m_device, &data);
}
void Device::addRenderTargetResource(const D3DDDIARG_CREATERESOURCE& data)
void Device::addDirtyRenderTarget(Resource& resource, UINT subResourceIndex)
{
m_renderTargetResources.emplace(data.hResource,
RenderTargetResource(*this, data.hResource, data.Format, data.SurfCount));
m_dirtyRenderTargets.emplace(std::make_pair(resource, subResourceIndex), resource);
}
void Device::prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex)
void Device::addDirtyTexture(Resource& resource, UINT subResourceIndex)
{
resource.prepareForRendering(subResourceIndex);
if (!resource.hasLockedSubResources())
m_dirtyTextures.emplace(std::make_pair(resource, subResourceIndex), resource);
}
void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly)
{
auto it = m_resources.find(resource);
if (it != m_resources.end())
{
m_lockedRenderTargetResources.erase(resource.getHandle());
it->second.prepareForRendering(subResourceIndex, isReadOnly);
}
}
void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex)
void Device::prepareForRendering(std::map<std::pair<HANDLE, UINT>, Resource&>& resources, bool isReadOnly)
{
auto it = m_lockedRenderTargetResources.find(resource);
if (it != m_lockedRenderTargetResources.end())
auto it = resources.begin();
while (it != resources.end())
{
prepareForRendering(it->second, subResourceIndex);
auto& resource = it->second;
auto subResourceIndex = it->first.second;
++it;
resource.prepareForRendering(subResourceIndex, isReadOnly);
}
}
void Device::prepareForRendering()
{
auto it = m_lockedRenderTargetResources.begin();
while (it != m_lockedRenderTargetResources.end())
{
prepareForRendering((it++)->second);
}
const bool isReadOnly = true;
prepareForRendering(m_dirtyRenderTargets, !isReadOnly);
prepareForRendering(m_dirtyTextures, isReadOnly);
}
void Device::removeDirtyRenderTarget(Resource& resource, UINT subResourceIndex)
{
m_dirtyRenderTargets.erase(std::make_pair(resource, subResourceIndex));
}
void Device::removeDirtyTexture(Resource& resource, UINT subResourceIndex)
{
m_dirtyTextures.erase(std::make_pair(resource, subResourceIndex));
}
void Device::add(HANDLE adapter, HANDLE device)
@ -347,6 +343,21 @@ namespace D3dDdi
s_devices.erase(device);
}
Resource* Device::getResource(HANDLE resource)
{
for (auto& device : s_devices)
{
for (auto& res : device.second.getResources())
{
if (resource == res.second)
{
return &res.second;
}
}
}
return nullptr;
}
void Device::setGdiResourceHandle(HANDLE resource)
{
g_gdiResourceHandle = resource;

View File

@ -1,17 +1,14 @@
#pragma once
#include <map>
#include <unordered_map>
#include <d3d.h>
#include <d3dnthal.h>
#include <d3dumddi.h>
#include "D3dDdi/RenderTargetResource.h"
namespace D3dDdi
{
UINT getBytesPerPixel(D3DDDIFORMAT format);
class Adapter;
class Resource;
@ -46,16 +43,20 @@ namespace D3dDdi
Adapter& getAdapter() const { return m_adapter; }
const D3DDDI_DEVICEFUNCS& getOrigVtable() const { return m_origVtable; }
std::map<HANDLE, Resource>& getResources() { return m_resources; }
std::unordered_map<HANDLE, Resource>& getResources() { return m_resources; }
void addRenderTargetResource(const D3DDDIARG_CREATERESOURCE& data);
void prepareForRendering(HANDLE resource, UINT subResourceIndex = UINT_MAX);
void addDirtyRenderTarget(Resource& resource, UINT subResourceIndex);
void addDirtyTexture(Resource& resource, UINT subResourceIndex);
void prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly);
void prepareForRendering();
void removeDirtyRenderTarget(Resource& resource, UINT subResourceIndex);
void removeDirtyTexture(Resource& resource, UINT subResourceIndex);
static void add(HANDLE adapter, HANDLE device);
static Device& get(HANDLE device);
static void remove(HANDLE device);
static Resource* getResource(HANDLE resource);
static void setGdiResourceHandle(HANDLE resource);
static void setReadOnlyGdiLock(bool enable);
@ -65,14 +66,14 @@ namespace D3dDdi
template <typename Arg>
HRESULT createResourceImpl(Arg& data);
void prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex = UINT_MAX);
void prepareForRendering(std::map<std::pair<HANDLE, UINT>, Resource&>& resources, bool isReadOnly);
const D3DDDI_DEVICEFUNCS& m_origVtable;
Adapter& m_adapter;
HANDLE m_device;
std::map<HANDLE, Resource> m_resources;
std::map<HANDLE, RenderTargetResource> m_renderTargetResources;
std::map<HANDLE, RenderTargetResource&> m_lockedRenderTargetResources;
std::unordered_map<HANDLE, Resource> m_resources;
std::map<std::pair<HANDLE, UINT>, Resource&> m_dirtyRenderTargets;
std::map<std::pair<HANDLE, UINT>, Resource&> m_dirtyTextures;
HANDLE m_sharedPrimary;
static std::map<HANDLE, Device> s_devices;

View File

@ -1,104 +0,0 @@
#include "D3dDdi/Device.h"
#include "D3dDdi/RenderTargetResource.h"
namespace D3dDdi
{
RenderTargetResource::RenderTargetResource(Device& device, HANDLE resource, D3DDDIFORMAT format, UINT surfaceCount)
: m_device(device)
, m_resource(resource)
, m_bytesPerPixel(getBytesPerPixel(format))
, m_subResources(surfaceCount, SubResource(*this))
{
}
HRESULT RenderTargetResource::lock(D3DDDIARG_LOCK& data)
{
if (data.SubResourceIndex >= m_subResources.size())
{
return m_device.getOrigVtable().pfnLock(m_device, &data);
}
auto& subResource = m_subResources[data.SubResourceIndex];
if (subResource.surfacePtr)
{
auto surfacePtr = static_cast<unsigned char*>(subResource.surfacePtr);
if (data.Flags.AreaValid)
{
surfacePtr += data.Area.top * subResource.pitch + data.Area.left * m_bytesPerPixel;
}
data.pSurfData = surfacePtr;
data.Pitch = subResource.pitch;
subResource.isLocked = true;
return S_OK;
}
const UINT origFlags = data.Flags.Value;
data.Flags.Value = 0;
const HRESULT result = m_device.getOrigVtable().pfnLock(m_device, &data);
data.Flags.Value = origFlags;
if (SUCCEEDED(result))
{
subResource.surfacePtr = data.pSurfData;
subResource.pitch = data.Pitch;
subResource.isLocked = true;
m_lockedSubResources.insert(data.SubResourceIndex);
}
return result;
}
HRESULT RenderTargetResource::unlock(const D3DDDIARG_UNLOCK& data)
{
if (data.SubResourceIndex >= m_subResources.size())
{
return m_device.getOrigVtable().pfnUnlock(m_device, &data);
}
m_subResources[data.SubResourceIndex].isLocked = false;
return S_OK;
}
void RenderTargetResource::prepareForRendering(UINT subResourceIndex)
{
if (UINT_MAX == subResourceIndex)
{
auto it = m_lockedSubResources.begin();
while (it != m_lockedSubResources.end())
{
prepareSubResourceForRendering(*(it++));
}
}
if (subResourceIndex >= m_subResources.size())
{
return;
}
prepareSubResourceForRendering(subResourceIndex);
}
void RenderTargetResource::prepareSubResourceForRendering(UINT subResourceIndex)
{
auto& subResource = m_subResources[subResourceIndex];
if (subResource.surfacePtr && !subResource.isLocked)
{
D3DDDIARG_UNLOCK data = {};
data.hResource = m_resource;
data.SubResourceIndex = subResourceIndex;
m_device.getOrigVtable().pfnUnlock(m_device, &data);
subResource.surfacePtr = nullptr;
subResource.pitch = 0;
m_lockedSubResources.erase(subResourceIndex);
}
}
RenderTargetResource::SubResource::SubResource(RenderTargetResource& parent)
: parent(parent)
, surfacePtr(nullptr)
, pitch(0)
, isLocked(false)
{
}
}

View File

@ -1,44 +0,0 @@
#pragma once
#include <d3d.h>
#include <d3dumddi.h>
#include <set>
#include <vector>
namespace D3dDdi
{
class Device;
class RenderTargetResource
{
public:
RenderTargetResource(Device& device, HANDLE resource, D3DDDIFORMAT format, UINT surfaceCount);
HRESULT lock(D3DDDIARG_LOCK& data);
HRESULT unlock(const D3DDDIARG_UNLOCK& data);
HANDLE getHandle() const { return m_resource; }
bool hasLockedSubResources() { return !m_lockedSubResources.empty(); }
void prepareForRendering(UINT subResourceIndex = UINT_MAX);
private:
struct SubResource
{
RenderTargetResource& parent;
void* surfacePtr;
UINT pitch;
bool isLocked;
SubResource(RenderTargetResource& parent);
};
void prepareSubResourceForRendering(UINT subResourceIndex);
Device& m_device;
HANDLE m_resource;
UINT m_bytesPerPixel;
std::vector<SubResource> m_subResources;
std::set<UINT> m_lockedSubResources;
};
}

View File

@ -6,11 +6,13 @@
#include "D3dDdi/Device.h"
#include "D3dDdi/Log/DeviceFuncsLog.h"
#include "D3dDdi/Resource.h"
#include "DDraw/Blitter.h"
#include "DDraw/Surfaces/Surface.h"
namespace
{
UINT getBytesPerPixel(D3DDDIFORMAT format);
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
bool isVidMemPool(D3DDDI_POOL pool);
void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight);
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
@ -32,7 +34,7 @@ namespace
(isOffScreenPlain || data.Flags.Texture) &&
1 == data.SurfCount &&
0 == data.pSurfList[0].Depth &&
0 != D3dDdi::getBytesPerPixel(data.Format))
0 != getBytesPerPixel(data.Format))
{
const auto& caps = device.getAdapter().getD3dExtendedCaps();
const auto& surfaceInfo = data.pSurfList[0];
@ -44,6 +46,40 @@ namespace
}
}
UINT getBytesPerPixel(D3DDDIFORMAT format)
{
switch (format)
{
case D3DDDIFMT_R3G3B2:
case D3DDDIFMT_A8:
case D3DDDIFMT_P8:
case D3DDDIFMT_R8:
return 1;
case D3DDDIFMT_R5G6B5:
case D3DDDIFMT_X1R5G5B5:
case D3DDDIFMT_A1R5G5B5:
case D3DDDIFMT_A4R4G4B4:
case D3DDDIFMT_A8R3G3B2:
case D3DDDIFMT_X4R4G4B4:
case D3DDDIFMT_A8P8:
case D3DDDIFMT_G8R8:
return 2;
case D3DDDIFMT_R8G8B8:
return 3;
case D3DDDIFMT_A8R8G8B8:
case D3DDDIFMT_X8R8G8B8:
case D3DDDIFMT_A8B8G8R8:
case D3DDDIFMT_X8B8G8R8:
return 4;
default:
return 0;
}
}
D3DDDI_RESOURCEFLAGS getResourceTypeFlags()
{
D3DDDI_RESOURCEFLAGS flags = {};
@ -68,19 +104,12 @@ namespace
return flags;
}
bool isVidMemPool(D3DDDI_POOL pool)
{
return D3DDDIPOOL_VIDEOMEMORY == pool ||
D3DDDIPOOL_LOCALVIDMEM == pool ||
D3DDDIPOOL_NONLOCALVIDMEM == pool;
}
void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight)
{
static std::vector<D3DDDI_SURFACEINFO> tiles;
tiles.clear();
const UINT bytesPerPixel = D3dDdi::getBytesPerPixel(data.Format);
const UINT bytesPerPixel = getBytesPerPixel(data.Format);
for (UINT y = 0; y < data.pSurfList[0].Height; y += tileHeight)
{
@ -147,6 +176,37 @@ namespace D3dDdi
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 (subResourceIndex < resource.m_lockData.size())
{
if (!resource.m_lockData[subResourceIndex].isSysMemUpToDate)
{
if (isReadOnly)
{
resource.copyToSysMem(subResourceIndex);
}
else
{
resource.moveToSysMem(subResourceIndex);
}
}
else if (!isReadOnly && resource.m_lockData[subResourceIndex].isVidMemUpToDate)
{
resource.setVidMemUpToDate(subResourceIndex, false);
}
data = resource.m_lockData[subResourceIndex].data;
pitch = resource.m_lockData[subResourceIndex].pitch;
}
}
Resource::Resource(Device& device, const D3DDDIARG_CREATERESOURCE& data)
: Resource(device, upgradeResourceData(data))
{
@ -156,6 +216,9 @@ namespace D3dDdi
: m_device(device)
, m_handle(nullptr)
, m_origData(data)
, m_bytesPerPixel(0)
, m_rootSurface(nullptr)
, m_lockResource(nullptr)
{
}
@ -163,28 +226,125 @@ namespace D3dDdi
{
if (isOversized())
{
m_device.prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex, true);
return splitBlt(data, data.DstSubResourceIndex, data.DstRect, data.SrcRect);
}
else
{
auto& resources = m_device.getResources();
auto it = resources.find(data.hSrcResource);
if (it != resources.end() && it->second.isOversized())
if (it != resources.end())
{
return it->second.splitBlt(data, data.SrcSubResourceIndex, data.SrcRect, data.DstRect);
if (it->second.isOversized())
{
prepareForRendering(data.DstSubResourceIndex, false);
return it->second.splitBlt(data, data.SrcSubResourceIndex, data.SrcRect, data.DstRect);
}
else
{
return sysMemPreferredBlt(data, it->second);
}
}
}
prepareForRendering(data.DstSubResourceIndex, false);
return m_device.getOrigVtable().pfnBlt(m_device, &data);
}
HRESULT Resource::bltLock(D3DDDIARG_LOCK& data)
{
LOG_FUNC("Resource::bltLock", data);
if (data.SubResourceIndex >= m_lockData.size())
{
return LOG_RESULT(m_device.getOrigVtable().pfnLock(m_device, &data));
}
auto& lockData = m_lockData[data.SubResourceIndex];
if (!lockData.isSysMemUpToDate)
{
if (data.Flags.ReadOnly)
{
copyToSysMem(data.SubResourceIndex);
}
else
{
moveToSysMem(data.SubResourceIndex);
}
}
else if (!data.Flags.ReadOnly && lockData.isVidMemUpToDate)
{
setVidMemUpToDate(data.SubResourceIndex, false);
}
unsigned char* ptr = static_cast<unsigned char*>(lockData.data);
if (data.Flags.AreaValid)
{
ptr += data.Area.top * lockData.pitch + data.Area.left * m_bytesPerPixel;
}
data.pSurfData = ptr;
data.Pitch = lockData.pitch;
++lockData.lockCount;
return LOG_RESULT(S_OK);
}
HRESULT Resource::bltUnlock(const D3DDDIARG_UNLOCK& data)
{
LOG_FUNC("Resource::bltUnlock", data);
if (data.SubResourceIndex >= m_lockData.size())
{
return LOG_RESULT(m_device.getOrigVtable().pfnUnlock(m_device, &data));
}
if (0 != m_lockData[data.SubResourceIndex].lockCount)
{
--m_lockData[data.SubResourceIndex].lockCount;
}
return LOG_RESULT(S_OK);
}
HRESULT Resource::copySubResource(Resource& dstResource, Resource& srcResource, UINT subResourceIndex)
{
RECT rect = {};
rect.right = dstResource.m_fixedData.pSurfList[subResourceIndex].Width;
rect.bottom = dstResource.m_fixedData.pSurfList[subResourceIndex].Height;
D3DDDIARG_BLT data = {};
data.hSrcResource = srcResource;
data.SrcSubResourceIndex = subResourceIndex;
data.SrcRect = rect;
data.hDstResource = dstResource;
data.DstSubResourceIndex = subResourceIndex;
data.DstRect = rect;
HRESULT result = dstResource.m_device.getOrigVtable().pfnBlt(dstResource.m_device, &data);
if (FAILED(result))
{
LOG_ONCE("ERROR: Resource::copySubResource failed: " << Compat::hex(result));
}
return result;
}
void Resource::copyToSysMem(UINT subResourceIndex)
{
copySubResource(*m_lockResource, *this, subResourceIndex);
setSysMemUpToDate(subResourceIndex, true);
}
void Resource::copyToVidMem(UINT subResourceIndex)
{
copySubResource(*this, *m_lockResource, subResourceIndex);
setVidMemUpToDate(subResourceIndex, true);
}
template <typename Arg>
Resource Resource::create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*))
{
Resource resource(device, data);
Arg origData = data;
auto& baseData = reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(data);
fixResourceData(device, baseData);
fixResourceData(device, reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(data));
resource.m_fixedData = data;
resource.m_bytesPerPixel = getBytesPerPixel(data.Format);
HRESULT result = createResourceFunc(device, &data);
if (FAILED(result))
@ -193,11 +353,6 @@ namespace D3dDdi
throw HResultException(result);
}
if (data.Flags.RenderTarget && !data.Flags.Primary && isVidMemPool(data.Pool))
{
device.addRenderTargetResource(baseData);
}
resource.m_handle = data.hResource;
data = origData;
data.hResource = resource.m_handle;
@ -214,6 +369,14 @@ namespace D3dDdi
return create(device, data, device.getOrigVtable().pfnCreateResource2);
}
void Resource::destroy()
{
if (m_rootSurface)
{
m_rootSurface->clearResources();
}
}
bool Resource::isOversized() const
{
return m_fixedData.SurfCount != m_origData.SurfCount;
@ -231,9 +394,163 @@ namespace D3dDdi
}
return splitLock(data, m_device.getOrigVtable().pfnLock);
}
else if (m_lockResource)
{
return bltLock(data);
}
return m_device.getOrigVtable().pfnLock(m_device, &data);
}
void Resource::moveToSysMem(UINT subResourceIndex)
{
copySubResource(*m_lockResource, *this, subResourceIndex);
setSysMemUpToDate(subResourceIndex, true);
setVidMemUpToDate(subResourceIndex, false);
}
void Resource::moveToVidMem(UINT subResourceIndex)
{
copySubResource(*this, *m_lockResource, subResourceIndex);
setVidMemUpToDate(subResourceIndex, true);
setSysMemUpToDate(subResourceIndex, false);
}
void Resource::prepareForRendering(UINT subResourceIndex, bool isReadOnly)
{
if (subResourceIndex < m_lockData.size())
{
prepareSubResourceForRendering(subResourceIndex, isReadOnly);
}
else if (UINT_MAX == subResourceIndex)
{
for (UINT i = 0; i < m_lockData.size(); ++i)
{
prepareSubResourceForRendering(i, isReadOnly);
}
}
}
void Resource::prepareSubResourceForRendering(UINT subResourceIndex, bool isReadOnly)
{
auto& lockData = m_lockData[subResourceIndex];
if (0 == lockData.lockCount)
{
if (isReadOnly)
{
if (!lockData.isVidMemUpToDate)
{
copyToVidMem(subResourceIndex);
}
}
else if (lockData.isVidMemUpToDate)
{
setSysMemUpToDate(subResourceIndex, false);
}
else
{
moveToVidMem(subResourceIndex);
}
}
}
void Resource::setLockResource(Resource* lockResource)
{
if (!m_lockResource == !lockResource)
{
return;
}
if (lockResource)
{
if (lockResource->m_fixedData.SurfCount != m_fixedData.SurfCount)
{
LOG_ONCE("ERROR: Lock surface count mismatch: " <<
m_fixedData.surfaceData << " vs " << lockResource->m_fixedData.SurfCount);
return;
}
m_lockData.resize(m_fixedData.SurfCount);
for (UINT i = 0; i < m_fixedData.SurfCount; ++i)
{
m_lockData[i].data = const_cast<void*>(lockResource->m_fixedData.pSurfList[i].pSysMem);
m_lockData[i].pitch = lockResource->m_fixedData.pSurfList[i].SysMemPitch;
m_lockData[i].isSysMemUpToDate = true;
m_lockData[i].isVidMemUpToDate = true;
}
m_lockResource = lockResource;
if (m_fixedData.Flags.RenderTarget)
{
for (std::size_t i = 0; i < m_lockData.size(); ++i)
{
m_device.addDirtyRenderTarget(*this, i);
}
}
}
else
{
if (m_fixedData.Flags.RenderTarget)
{
for (std::size_t i = 0; i < m_lockData.size(); ++i)
{
if (m_lockData[i].isSysMemUpToDate)
{
m_device.removeDirtyRenderTarget(*this, i);
}
}
}
if (m_fixedData.Flags.Texture)
{
for (std::size_t i = 0; i < m_lockData.size(); ++i)
{
if (!m_lockData[i].isVidMemUpToDate)
{
m_device.removeDirtyTexture(*this, i);
}
}
}
m_lockResource = nullptr;
m_lockData.clear();
}
}
void Resource::setRootSurface(DDraw::Surface* rootSurface)
{
m_rootSurface = rootSurface;
}
void Resource::setSysMemUpToDate(UINT subResourceIndex, bool upToDate)
{
m_lockData[subResourceIndex].isSysMemUpToDate = upToDate;
if (m_fixedData.Flags.RenderTarget)
{
if (upToDate)
{
m_device.addDirtyRenderTarget(*this, subResourceIndex);
}
else
{
m_device.removeDirtyRenderTarget(*this, subResourceIndex);
}
}
}
void Resource::setVidMemUpToDate(UINT subResourceIndex, bool upToDate)
{
m_lockData[subResourceIndex].isVidMemUpToDate = upToDate;
if (m_fixedData.Flags.Texture)
{
if (upToDate)
{
m_device.removeDirtyTexture(*this, subResourceIndex);
}
else
{
m_device.addDirtyTexture(*this, subResourceIndex);
}
}
}
HRESULT Resource::splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect)
{
LOG_FUNC("Resource::splitBlt", data, subResourceIndex, rect, otherRect);
@ -295,6 +612,46 @@ namespace D3dDdi
return LOG_RESULT(S_OK);
}
HRESULT Resource::sysMemPreferredBlt(const D3DDDIARG_BLT& data, Resource& srcResource)
{
if (m_fixedData.Format == srcResource.m_fixedData.Format &&
(D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown ||
(data.DstSubResourceIndex < m_lockData.size() && m_lockData[data.DstSubResourceIndex].isSysMemUpToDate)))
{
SysMemBltGuard srcGuard(srcResource, data.SrcSubResourceIndex, true);
if (srcGuard.data)
{
SysMemBltGuard dstGuard(*this, data.DstSubResourceIndex, false);
if (dstGuard.data)
{
auto dstBuf = static_cast<BYTE*>(dstGuard.data) +
data.DstRect.top * dstGuard.pitch + data.DstRect.left * m_bytesPerPixel;
auto srcBuf = static_cast<const BYTE*>(srcGuard.data) +
data.SrcRect.top * srcGuard.pitch + data.SrcRect.left * m_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_bytesPerPixel,
data.Flags.DstColorKey ? reinterpret_cast<const DWORD*>(&data.ColorKey) : nullptr,
data.Flags.SrcColorKey ? reinterpret_cast<const DWORD*>(&data.ColorKey) : nullptr);
return S_OK;
}
}
}
prepareForRendering(data.DstSubResourceIndex, false);
srcResource.prepareForRendering(data.SrcSubResourceIndex, true);
return m_device.getOrigVtable().pfnBlt(m_device, &data);
}
template <typename Arg>
HRESULT Resource::splitLock(Arg& data, HRESULT(APIENTRY *lockFunc)(HANDLE, Arg*))
{
@ -323,6 +680,11 @@ namespace D3dDdi
}
return splitLock(data, m_device.getOrigVtable().pfnUnlock);
}
else if (m_lockResource)
{
return bltUnlock(data);
}
return m_device.getOrigVtable().pfnUnlock(m_device, &data);
}
}

View File

@ -4,6 +4,12 @@
#include <d3d.h>
#include <d3dumddi.h>
#include <ddraw.h>
namespace DDraw
{
class Surface;
}
namespace D3dDdi
{
@ -18,7 +24,11 @@ namespace D3dDdi
operator HANDLE() const { return m_handle; }
HRESULT blt(D3DDDIARG_BLT data);
void destroy();
HRESULT lock(D3DDDIARG_LOCK& data);
void prepareForRendering(UINT subResourceIndex, bool isReadOnly);
void setLockResource(Resource* lockResource);
void setRootSurface(DDraw::Surface* rootSurface);
HRESULT unlock(const D3DDDIARG_UNLOCK& data);
private:
@ -36,21 +46,55 @@ namespace D3dDdi
std::vector<D3DDDI_SURFACEINFO> surfaceData;
};
struct LockData
{
void* data;
UINT pitch;
UINT lockCount;
bool isSysMemUpToDate;
bool isVidMemUpToDate;
};
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);
static HRESULT copySubResource(Resource& dstResource, Resource& srcResource, UINT subResourceIndex);
template <typename Arg>
static Resource create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*));
HRESULT bltLock(D3DDDIARG_LOCK& data);
HRESULT bltUnlock(const D3DDDIARG_UNLOCK& data);
void copyToSysMem(UINT subResourceIndex);
void copyToVidMem(UINT subResourceIndex);
bool isOversized() const;
void moveToSysMem(UINT subResourceIndex);
void moveToVidMem(UINT subResourceIndex);
void prepareSubResourceForRendering(UINT subResourceIndex, bool isReadOnly);
void setSysMemUpToDate(UINT subResourceIndex, bool upToDate);
void setVidMemUpToDate(UINT subResourceIndex, bool upToDate);
HRESULT splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect);
template <typename Arg>
HRESULT splitLock(Arg& data, HRESULT(APIENTRY *lockFunc)(HANDLE, Arg*));
HRESULT sysMemPreferredBlt(const D3DDDIARG_BLT& data, Resource& srcResource);
Device& m_device;
HANDLE m_handle;
Data m_origData;
Data m_fixedData;
UINT m_bytesPerPixel;
DDraw::Surface* m_rootSurface;
Resource* m_lockResource;
std::vector<LockData> m_lockData;
};
}

View File

@ -0,0 +1,654 @@
#include <array>
#include <vector>
#include <intrin.h>
#include "Common/ScopedCriticalSection.h"
#include "DDraw/Blitter.h"
#pragma warning(disable : 4127)
namespace
{
Compat::CriticalSection g_overlappingBltCs;
#pragma pack(1)
class UInt24
{
public:
UInt24(DWORD value)
{
m_low16 = static_cast<WORD>(value);
m_high8 = static_cast<BYTE>((value & 0x00FF0000) >> 16);
}
private:
WORD m_low16;
BYTE m_high8;
};
#pragma pack()
template <typename Elem, std::size_t... dim>
struct MultiDimArray;
template <typename Elem, std::size_t firstDim, std::size_t... dim>
struct MultiDimArray<Elem, firstDim, dim...>
{
typedef std::array<typename MultiDimArray<Elem, dim...>::type, firstDim> type;
};
template <typename Elem, std::size_t dim>
struct MultiDimArray<Elem, dim>
{
typedef std::array<Elem, dim> type;
};
void blt(BYTE* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight,
const BYTE* src, DWORD srcPitch, LONG srcWidth, LONG srcHeight,
DWORD bytesPerPixel, const DWORD* dstColorKey, const DWORD* srcColorKey);
template <int n> __m128i _mm_cmpeq_epi(__m128i a, __m128i b);
template <> __m128i _mm_cmpeq_epi<8>(__m128i a, __m128i b) { return _mm_cmpeq_epi8(a, b); }
template <> __m128i _mm_cmpeq_epi<16>(__m128i a, __m128i b) { return _mm_cmpeq_epi16(a, b); }
template <> __m128i _mm_cmpeq_epi<32>(__m128i a, __m128i b) { return _mm_cmpeq_epi32(a, b); }
template <int n> __m128i _mm_loadu_si(const void* p);
template <> __m128i _mm_loadu_si<8>(const void* p) { return _mm_cvtsi32_si128(*static_cast<const uint8_t*>(p)); }
template <> __m128i _mm_loadu_si<16>(const void* p) { return _mm_cvtsi32_si128(*static_cast<const uint16_t*>(p)); }
template <> __m128i _mm_loadu_si<32>(const void* p) { return _mm_cvtsi32_si128(*static_cast<const uint32_t*>(p)); }
template <> __m128i _mm_loadu_si<64>(const void* p) { return _mm_loadl_epi64(static_cast<const __m128i*>(p)); }
template <> __m128i _mm_loadu_si<128>(const void* p) { return _mm_loadu_si128(static_cast<const __m128i*>(p)); }
template <int n> __m128i _mm_set1_epi(DWORD a);
template <> __m128i _mm_set1_epi<8>(DWORD a) { return _mm_set1_epi8(static_cast<uint8_t>(a)); }
template <> __m128i _mm_set1_epi<16>(DWORD a) { return _mm_set1_epi16(static_cast<uint16_t>(a)); }
template <> __m128i _mm_set1_epi<32>(DWORD a) { return _mm_set1_epi32(a); }
template <int n> void _mm_storeu_si(void* p, __m128i a);
template <> void _mm_storeu_si<8>(void* p, __m128i a) { *static_cast<uint8_t*>(p) = static_cast<uint8_t>(_mm_cvtsi128_si32(a)); }
template <> void _mm_storeu_si<16>(void* p, __m128i a) { *static_cast<uint16_t*>(p) = static_cast<uint16_t>(_mm_cvtsi128_si32(a)); }
template <> void _mm_storeu_si<32>(void* p, __m128i a) { *static_cast<uint32_t*>(p) = _mm_cvtsi128_si32(a); }
template <> void _mm_storeu_si<64>(void* p, __m128i a) { _mm_storel_epi64(static_cast<__m128i*>(p), a); }
template <> void _mm_storeu_si<128>(void* p, __m128i a) { _mm_storeu_si128(static_cast<__m128i*>(p), a); }
template <typename Pixel, int vectorSize>
__forceinline __m128i reverseVector(__m128i vec)
{
if (16 == vectorSize)
{
vec = _mm_shuffle_epi32(vec, _MM_SHUFFLE(0, 1, 2, 3));
}
else if (8 == vectorSize)
{
vec = _mm_shuffle_epi32(vec, _MM_SHUFFLE(3, 2, 0, 1));
}
if (sizeof(Pixel) <= 2)
{
if (vectorSize > 2)
{
vec = _mm_shufflelo_epi16(vec, _MM_SHUFFLE(2, 3, 0, 1));
}
if (16 == vectorSize)
{
vec = _mm_shufflehi_epi16(vec, _MM_SHUFFLE(2, 3, 0, 1));
}
}
if (1 == sizeof(Pixel) && vectorSize > 1)
{
vec = _mm_or_si128(_mm_slli_epi16(vec, 8), _mm_srli_epi16(vec, 8));
}
return vec;
}
template <int pixelsPerVector, int count>
__forceinline void loadSrcVectorRemainder(__m128i& vec1, __m128i& vec2,
const BYTE*& src, int& offset, int delta, std::integral_constant<int, count>)
{
vec1 = _mm_insert_epi16(vec1, *(src + (offset >> 16)), (pixelsPerVector - count) / 2);
offset += delta;
vec2 = _mm_insert_epi16(vec2, *(src + (offset >> 16)), (pixelsPerVector - count) / 2);
offset += delta;
loadSrcVectorRemainder<pixelsPerVector>(vec1, vec2, src, offset, delta, std::integral_constant<int, count - 2>());
}
template <int pixelsPerVector>
__forceinline void loadSrcVectorRemainder(__m128i& vec1, __m128i& vec2,
const BYTE*& src, int& offset, int delta, std::integral_constant<int, 1> /*count*/)
{
vec1 = _mm_insert_epi16(vec1, *(src + (offset >> 16)), (pixelsPerVector - 1) / 2);
offset += delta;
}
template <int pixelsPerVector>
__forceinline void loadSrcVectorRemainder(__m128i& /*vec1*/, __m128i& /*vec2*/,
const BYTE*& /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, 0> /*count*/)
{
}
template <int pixelsPerVector>
__forceinline void loadSrcVectorRemainder(__m128i& /*vec1*/, __m128i& /*vec2*/,
const BYTE*& /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, -1> /*count*/)
{
}
template <int pixelsPerVector, int count>
__forceinline void loadSrcVectorRemainder(__m128i& vec,
const BYTE* src, int& offset, int delta, std::integral_constant<int, count>)
{
__m128i vec2 = _mm_loadu_si<8>(src + (offset >> 16));
offset += delta;
loadSrcVectorRemainder<pixelsPerVector>(vec, vec2, src, offset, delta, std::integral_constant<int, count - 1>());
vec2 = _mm_slli_si128(vec2, 1);
vec = _mm_or_si128(vec, vec2);
}
template <int pixelsPerVector, int count>
__forceinline void loadSrcVectorRemainder(__m128i& vec,
const WORD* src, int& offset, int delta, std::integral_constant<int, count>)
{
vec = _mm_insert_epi16(vec, *(src + (offset >> 16)), pixelsPerVector - count);
offset += delta;
loadSrcVectorRemainder<pixelsPerVector>(vec, src, offset, delta, std::integral_constant<int, count - 1>());
}
template <int pixelsPerVector>
__forceinline void loadSrcVectorRemainder(__m128i& /*vec*/,
const WORD* /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, 0> /*count*/)
{
}
template <int pixelsPerVector, int count>
__forceinline void loadSrcVectorRemainder(__m128i& vec,
const DWORD* src, int& offset, int delta, std::integral_constant<int, count>)
{
__m128i pixel = _mm_loadu_si32(src + (offset >> 16));
pixel = _mm_slli_si128(pixel, (pixelsPerVector - count) * 4);
vec = _mm_or_si128(vec, pixel);
offset += delta;
loadSrcVectorRemainder<pixelsPerVector>(vec, src, offset, delta, std::integral_constant<int, count - 1>());
}
template <int pixelsPerVector>
__forceinline void loadSrcVectorRemainder(__m128i& /*vec*/,
const DWORD* /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, 0> /*count*/)
{
}
template <int vectorSize, bool stretch, bool mirror, typename Pixel>
__forceinline __m128i loadSrcVector(const Pixel*& src, int& offset, int delta)
{
const int pixelsPerVector = vectorSize / sizeof(Pixel);
__m128i vec = _mm_loadu_si<sizeof(Pixel) * 8>(stretch ? src + (offset >> 16) : src);
if (stretch)
{
offset += delta;
loadSrcVectorRemainder<pixelsPerVector>(vec, src, offset, delta,
std::integral_constant<int, pixelsPerVector - 1>());
}
else
{
vec = _mm_loadu_si<vectorSize * 8>(src);
if (mirror)
{
vec = reverseVector<Pixel, vectorSize>(vec);
src -= pixelsPerVector;
}
else
{
src += pixelsPerVector;
}
}
return vec;
}
template <typename Pixel>
__forceinline __m128i compareColorKey(__m128i vec, DWORD colorKey)
{
__m128i colorKeyVec = _mm_set1_epi<sizeof(Pixel) * 8>(colorKey);
if (4 == sizeof(Pixel))
{
__m128i colorKeyMask = _mm_set1_epi<sizeof(Pixel) * 8>(0x00FFFFFF);
vec = _mm_and_si128(vec, colorKeyMask);
}
return _mm_cmpeq_epi<sizeof(Pixel) * 8>(vec, colorKeyVec);
}
template <typename Pixel, bool mirror, bool useDstColorKey, bool useSrcColorKey>
__forceinline __m128i bltVector(__m128i dst, __m128i src, DWORD dstColorKey, DWORD srcColorKey)
{
if (useDstColorKey && useSrcColorKey)
{
__m128i maskDst = compareColorKey<Pixel>(dst, dstColorKey);
__m128i maskSrc = compareColorKey<Pixel>(src, srcColorKey);
__m128i mask = _mm_andnot_si128(maskSrc, maskDst);
dst = _mm_andnot_si128(mask, dst);
src = _mm_and_si128(mask, src);
return _mm_or_si128(dst, src);
}
else if (useDstColorKey)
{
__m128i mask = compareColorKey<Pixel>(dst, dstColorKey);
dst = _mm_andnot_si128(mask, dst);
src = _mm_and_si128(mask, src);
return _mm_or_si128(dst, src);
}
else if (useSrcColorKey)
{
__m128i mask = compareColorKey<Pixel>(src, srcColorKey);
dst = _mm_and_si128(mask, dst);
src = _mm_andnot_si128(mask, src);
return _mm_or_si128(dst, src);
}
else
{
return src;
}
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
__forceinline void bltVector(Pixel*& dst, const Pixel*& src, int& offset, int delta,
DWORD dstColorKey, DWORD srcColorKey)
{
__m128i s = loadSrcVector<vectorSize, stretch, mirror>(src, offset, delta);
__m128i d = _mm_loadu_si<vectorSize * 8>(dst);
d = bltVector<Pixel, mirror, useDstColorKey, useSrcColorKey>(d, s, dstColorKey, srcColorKey);
_mm_storeu_si<vectorSize * 8>(dst, d);
dst += vectorSize / sizeof(Pixel);
}
template <int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey, typename Pixel>
__forceinline void bltVectorRow(Pixel* dst, const Pixel* src, DWORD width, int offset, int delta,
DWORD dstColorKey, DWORD srcColorKey)
{
const int pixelsPerVector = vectorSize / sizeof(Pixel);
if (16 == vectorSize)
{
for (DWORD i = width / pixelsPerVector - 1; i != 0; --i)
{
bltVector<Pixel, 16, stretch, mirror, useDstColorKey, useSrcColorKey>(
dst, src, offset, delta, dstColorKey, srcColorKey);
}
}
if (sizeof(Pixel) < vectorSize)
{
const DWORD remainder = width % pixelsPerVector;
auto src1 = src;
auto offset1 = offset;
__m128i s1 = loadSrcVector<vectorSize, stretch, mirror>(src1, offset1, delta);
if (stretch)
{
offset += remainder * delta;
}
else if (mirror)
{
src -= remainder;
}
else
{
src += remainder;
}
__m128i s2 = loadSrcVector<vectorSize, stretch, mirror>(src, offset, delta);
__m128i d1 = _mm_loadu_si<vectorSize * 8>(dst);
__m128i d2 = _mm_loadu_si<vectorSize * 8>(dst + remainder);
d1 = bltVector<Pixel, mirror, useDstColorKey, useSrcColorKey>(d1, s1, dstColorKey, srcColorKey);
_mm_storeu_si<vectorSize * 8>(dst, d1);
d2 = bltVector<Pixel, mirror, useDstColorKey, useSrcColorKey>(d2, s2, dstColorKey, srcColorKey);
_mm_storeu_si<vectorSize * 8>(dst + remainder, d2);
}
else
{
bltVector<Pixel, vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>(
dst, src, offset, delta, dstColorKey, srcColorKey);
}
}
template <bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
__forceinline void bltPixel(UInt24*& dst, const UInt24*& src, int& offset, int delta,
DWORD dstColorKey, DWORD srcColorKey)
{
const UInt24* src1 = stretch ? src + (offset >> 16) : src;
if (useDstColorKey || useSrcColorKey)
{
const DWORD d = *reinterpret_cast<const WORD*>(dst) | (reinterpret_cast<const BYTE*>(dst)[2] << 16);
const DWORD s = *reinterpret_cast<const WORD*>(src1) | (reinterpret_cast<const BYTE*>(src1)[2] << 16);
const DWORD mask = static_cast<DWORD>(-static_cast<int>(
(!useDstColorKey || dstColorKey == d) &&
(!useSrcColorKey || srcColorKey != s)));
*dst = (d & ~mask) | (s & mask);
}
else
{
*dst = *src1;
}
++dst;
if (stretch)
{
offset += delta;
}
else
{
src += mirror ? -1 : 1;
}
}
template <int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
__forceinline void bltVectorRow(UInt24* dst, const UInt24* src, DWORD width, int offset, int delta,
DWORD dstColorKey, DWORD srcColorKey)
{
if (!stretch && !mirror && !useDstColorKey && !useSrcColorKey)
{
bltVectorRow<vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey, BYTE>(
reinterpret_cast<BYTE*>(dst), reinterpret_cast<const BYTE*>(src),
width * 3, offset, delta, dstColorKey, srcColorKey);
return;
}
if (2 == vectorSize)
{
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
return;
}
if (4 == vectorSize)
{
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
return;
}
for (DWORD i = width; i != 0; --i)
{
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
}
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
__forceinline std::enable_if_t<vectorSize >= sizeof(Pixel) || (2 == vectorSize && 3 == sizeof(Pixel))> vectorizedBlt(
BYTE * dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight,
const BYTE * src, DWORD srcPitch, int offsetX, int deltaX, int offsetY, int deltaY,
DWORD dstColorKey, DWORD srcColorKey)
{
if (3 != sizeof(Pixel) && !stretch && mirror)
{
src -= vectorSize - sizeof(Pixel);
}
for (DWORD i = dstHeight; i != 0; --i)
{
bltVectorRow<vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>(
reinterpret_cast<Pixel*>(dst),
reinterpret_cast<const Pixel*>(src + (offsetY >> 16) * srcPitch),
dstWidth, offsetX, deltaX, dstColorKey, srcColorKey);
dst += dstPitch;
offsetY += deltaY;
}
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
__forceinline std::enable_if_t < vectorSize < sizeof(Pixel) && (2 != vectorSize || 3 != sizeof(Pixel))> vectorizedBlt(
BYTE* /*dst*/, DWORD /*dstPitch*/, DWORD /*dstWidth*/, DWORD /*dstHeight*/,
const BYTE* /*src*/, DWORD /*srcPitch*/, int /*offsetX*/, int /*deltaX*/, int /*offsetY*/, int /*deltaY*/,
const DWORD /*dstColorKey*/, const DWORD /*srcColorKey*/)
{
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
void vectorizedBltFunc(void* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight,
const void* src, DWORD srcPitch, int offsetX, int deltaX, int offsetY, int deltaY,
DWORD dstColorKey, DWORD srcColorKey)
{
vectorizedBlt<Pixel, vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>(
static_cast<BYTE*>(dst), dstPitch, dstWidth, dstHeight,
static_cast<const BYTE*>(src), srcPitch, offsetX, deltaX, offsetY, deltaY, dstColorKey, srcColorKey);
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
auto getVectorizedBltFunc()
{
return &vectorizedBltFunc<Pixel, vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>;
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey>
auto getVectorizedBltFunc(bool useSrcColorKey)
{
return useSrcColorKey
? getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, useDstColorKey, true>()
: getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, useDstColorKey, false>();
}
template <typename Pixel, int vectorSize, bool stretch, bool mirror>
auto getVectorizedBltFunc(bool useDstColorKey, bool useSrcColorKey)
{
return useDstColorKey
? getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, true>(useSrcColorKey)
: getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, false>(useSrcColorKey);
}
template <typename Pixel, int vectorSize, bool stretch>
auto getVectorizedBltFunc(bool mirror, bool useDstColorKey, bool useSrcColorKey)
{
return mirror
? getVectorizedBltFunc<Pixel, vectorSize, stretch, true>(useDstColorKey, useSrcColorKey)
: getVectorizedBltFunc<Pixel, vectorSize, stretch, false>(useDstColorKey, useSrcColorKey);
}
template <typename Pixel, int vectorSize>
auto getVectorizedBltFunc(bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey)
{
return stretch
? getVectorizedBltFunc<Pixel, vectorSize, true>(mirror, useDstColorKey, useSrcColorKey)
: getVectorizedBltFunc<Pixel, vectorSize, false>(mirror, useDstColorKey, useSrcColorKey);
}
template <typename Pixel>
auto getVectorizedBltFunc(DWORD width, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey)
{
if (width >= 16) return getVectorizedBltFunc<Pixel, 16>(stretch, mirror, useDstColorKey, useSrcColorKey);
if (width >= 8) return getVectorizedBltFunc<Pixel, 8>(stretch, mirror, useDstColorKey, useSrcColorKey);
if (width >= 4) return getVectorizedBltFunc<Pixel, 4>(stretch, mirror, useDstColorKey, useSrcColorKey);
if (width >= 2) return getVectorizedBltFunc<Pixel, 2>(stretch, mirror, useDstColorKey, useSrcColorKey);
return getVectorizedBltFunc<Pixel, 1>(stretch, mirror, useDstColorKey, useSrcColorKey);
}
auto getVectorizedBltFunc(DWORD bytesPerPixel, DWORD width,
bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey)
{
switch (bytesPerPixel)
{
case 4: return getVectorizedBltFunc<DWORD>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
case 3: return getVectorizedBltFunc<UInt24>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
case 2: return getVectorizedBltFunc<WORD>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
default: return getVectorizedBltFunc<BYTE>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
}
}
auto getVectorizedBltFuncs()
{
typename MultiDimArray<decltype(&vectorizedBltFunc<BYTE, 1, false, false, false, false>), 4, 5, 2, 2, 2, 2>::type vectorizedBltFuncs;
for (int bytesPerPixel = 1; bytesPerPixel <= 4; ++bytesPerPixel)
{
for (int width = 0; width <= 4; ++width)
{
for (int stretch = 0; stretch <= 1; ++stretch)
{
for (int mirror = 0; mirror <= 1; ++mirror)
{
for (int useDstColorKey = 0; useDstColorKey <= 1; ++useDstColorKey)
{
for (int useSrcColorKey = 0; useSrcColorKey <= 1; ++useSrcColorKey)
{
vectorizedBltFuncs[bytesPerPixel - 1][width][stretch][mirror][useDstColorKey][useSrcColorKey] =
getVectorizedBltFunc(bytesPerPixel, static_cast<DWORD>(pow(2, width)),
stretch, mirror, useDstColorKey, useSrcColorKey);
}
}
}
}
}
}
return vectorizedBltFuncs;
}
const auto g_vectorizedBltFuncs(getVectorizedBltFuncs());
bool doOverlappingBlt(BYTE* dst, DWORD pitch, DWORD dstWidth, DWORD dstHeight,
const BYTE* src, LONG srcWidth, LONG srcHeight,
DWORD bytesPerPixel, const DWORD* dstColorKey, const DWORD* srcColorKey)
{
const bool mirrorLeftRight = srcWidth < 0;
const bool mirrorUpDown = srcHeight < 0;
const DWORD absSrcWidth = mirrorLeftRight ? -srcWidth : srcWidth;
const DWORD absSrcHeight = mirrorUpDown ? -srcHeight : srcHeight;
RECT dstRect = { 0, 0, static_cast<LONG>(dstWidth * bytesPerPixel), static_cast<LONG>(dstHeight) };
RECT srcRect = { 0, 0, static_cast<LONG>(absSrcWidth * bytesPerPixel), static_cast<LONG>(absSrcHeight) };
srcRect.top = (src - dst) / static_cast<LONG>(pitch);
srcRect.left = (src - dst) % static_cast<LONG>(pitch);
srcRect.bottom += srcRect.top;
srcRect.right += srcRect.left;
RECT r = {};
if (!IntersectRect(&r, &dstRect, &srcRect))
{
return false;
}
if (!mirrorLeftRight && !mirrorUpDown)
{
if (EqualRect(&dstRect, &srcRect))
{
return true;
}
if (dstWidth == absSrcWidth && dstHeight == absSrcHeight && !dstColorKey && !srcColorKey)
{
if (dst < src)
{
for (DWORD y = dstHeight; y != 0; --y)
{
std::memmove(dst, src, dstWidth * bytesPerPixel);
dst += pitch;
src += pitch;
}
}
else
{
dst += (dstHeight - 1) * pitch;
src += (srcHeight - 1) * pitch;
for (DWORD y = dstHeight; y != 0; --y)
{
std::memmove(dst, src, dstWidth * bytesPerPixel);
dst -= pitch;
src -= pitch;
}
}
return true;
}
}
Compat::ScopedCriticalSection lock(g_overlappingBltCs);
static std::vector<BYTE> tmpSurface;
const LONG srcByteWidth = absSrcWidth * bytesPerPixel;
if (tmpSurface.size() < absSrcHeight * srcByteWidth)
{
tmpSurface.resize(absSrcHeight * srcByteWidth);
}
BYTE* tmp = tmpSurface.data();
auto vectorizedBltFunc = g_vectorizedBltFuncs[0]
[(srcByteWidth >= 2) + (srcByteWidth >= 4) + (srcByteWidth >= 8) + (srcByteWidth >= 16)][0][0][0][0];
vectorizedBltFunc(tmp, srcByteWidth, srcByteWidth, absSrcHeight,
src, pitch, 0x8000, 0x10000, 0x8000, 0x10000, 0, 0);
blt(dst, pitch, dstWidth, dstHeight,
tmp, srcByteWidth, srcWidth, srcHeight,
bytesPerPixel, dstColorKey, srcColorKey);
return true;
}
void blt(BYTE* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight,
const BYTE* src, DWORD srcPitch, LONG srcWidth, LONG srcHeight,
DWORD bytesPerPixel, const DWORD* dstColorKey, const DWORD* srcColorKey)
{
const bool mirrorLeftRight = srcWidth < 0;
const bool mirrorUpDown = srcHeight < 0;
const DWORD absSrcWidth = mirrorLeftRight ? -srcWidth : srcWidth;
const DWORD absSrcHeight = mirrorUpDown ? -srcHeight : srcHeight;
if (dstPitch == srcPitch)
{
const BYTE* dstEnd = dst + (dstHeight - 1) * dstPitch + dstWidth * bytesPerPixel;
const BYTE* srcEnd = src + (absSrcHeight - 1) * srcPitch + absSrcWidth * bytesPerPixel;
if (dst < src ? dstEnd > src : srcEnd > dst)
{
if (doOverlappingBlt(dst, dstPitch, dstWidth, dstHeight,
src, srcWidth, srcHeight, bytesPerPixel, dstColorKey, srcColorKey))
{
return;
}
}
}
int deltaX = (absSrcWidth << 16) / dstWidth;
int deltaY = (absSrcHeight << 16) / dstHeight;
int offsetX = deltaX / 2;
int offsetY = deltaY / 2;
if (mirrorLeftRight)
{
offsetX += static_cast<int>(dstWidth - 1) * deltaX;
deltaX = -deltaX;
}
if (mirrorUpDown)
{
offsetY += static_cast<int>(dstHeight - 1) * deltaY;
deltaY = -deltaY;
}
src += (offsetY >> 16) * srcPitch + (offsetX >> 16) * bytesPerPixel;
offsetX &= 0x0000FFFF;
offsetY &= 0x0000FFFF;
const DWORD dstCk = dstColorKey ? *dstColorKey & 0x00FFFFFF : 0;
const DWORD srcCk = srcColorKey ? *srcColorKey & 0x00FFFFFF : 0;
const DWORD dstByteWidth = dstWidth * bytesPerPixel;
auto vectorizedBltFunc = g_vectorizedBltFuncs
[bytesPerPixel - 1]
[(dstByteWidth >= 2) + (dstByteWidth >= 4) + (dstByteWidth >= 8) + (dstByteWidth >= 16)]
[dstWidth != absSrcWidth]
[mirrorLeftRight]
[nullptr != dstColorKey]
[nullptr != srcColorKey];
vectorizedBltFunc(dst, dstPitch, dstWidth, dstHeight,
src, srcPitch, offsetX, deltaX, offsetY, deltaY, dstCk, srcCk);
}
}
namespace DDraw
{
namespace Blitter
{
void blt(void* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight,
const void* src, DWORD srcPitch, LONG srcWidth, LONG srcHeight,
DWORD bytesPerPixel, const DWORD* dstColorKey, const DWORD* srcColorKey)
{
::blt(static_cast<BYTE*>(dst), dstPitch, dstWidth, dstHeight,
static_cast<const BYTE*>(src), srcPitch, srcWidth, srcHeight,
bytesPerPixel, dstColorKey, srcColorKey);
}
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
namespace DDraw
{
namespace Blitter
{
void blt(void* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight,
const void* src, DWORD srcPitch, LONG srcWidth, LONG srcHeight,
DWORD bytesPerPixel, const DWORD* dstColorKey, const DWORD* srcColorKey);
}
}

View File

@ -562,7 +562,7 @@ namespace DDraw
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
if (isFlipEmulated)
{
surfaceTargetOverride->Blt(
surfaceTargetOverride.get()->lpVtbl->Blt(
surfaceTargetOverride, nullptr, PrimarySurface::getPrimary(), nullptr, DDBLT_WAIT, nullptr);
}

View File

@ -60,7 +60,7 @@ namespace
auto srcSurface(CompatPtr<IDirectDrawSurface7>::from(lpDDSrcSurface));
gdiSurface->SetClipper(gdiSurface, gdiClipper);
gdiSurface->Blt(gdiSurface, &dstRect, srcSurface, lpSrcRect, dwFlags, lpDDBltFx);
gdiSurface.get()->lpVtbl->Blt(gdiSurface, &dstRect, srcSurface, lpSrcRect, dwFlags, lpDDBltFx);
gdiSurface->SetClipper(gdiSurface, nullptr);
}

View File

@ -1,6 +1,8 @@
#include <initguid.h>
#include "Common/CompatPtr.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/Resource.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/Surfaces/Surface.h"
@ -11,23 +13,6 @@
DEFINE_GUID(IID_CompatSurfacePrivateData,
0xc62d8849, 0xdfac, 0x4454, 0xa1, 0xe8, 0xda, 0x67, 0x44, 0x64, 0x26, 0xba);
namespace
{
void fixSurfaceDesc(DWORD& flags, DWORD& caps)
{
if ((flags & DDSD_WIDTH) &&
(flags & DDSD_HEIGHT) &&
!(caps & (DDSCAPS_ALPHA | DDSCAPS_ZBUFFER)))
{
if (!(caps & (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_OVERLAY | DDSCAPS_TEXTURE |
DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER)))
{
caps |= DDSCAPS_OFFSCREENPLAIN;
}
}
}
}
namespace DDraw
{
HRESULT STDMETHODCALLTYPE Surface::QueryInterface(REFIID, LPVOID*)
@ -50,14 +35,47 @@ namespace DDraw
return refCount;
}
Surface::Surface()
Surface::Surface(Surface* rootSurface)
: m_ddObject(nullptr)
, m_refCount(0)
, m_rootSurface(rootSurface ? rootSurface : this)
{
}
Surface::~Surface()
{
clearResources();
if (m_rootSurface != this)
{
auto it = std::find(m_rootSurface->m_attachedSurfaces.begin(),
m_rootSurface->m_attachedSurfaces.end(), this);
if (it != m_rootSurface->m_attachedSurfaces.end())
{
m_rootSurface->m_attachedSurfaces.erase(it);
}
if (m_rootSurface->m_lockSurface == m_surface)
{
m_rootSurface->m_lockSurface.detach();
m_rootSurface->m_attachedLockSurfaces.clear();
}
}
else
{
for (auto attachedSurface : m_attachedSurfaces)
{
attachedSurface->m_rootSurface = attachedSurface;
}
if (m_lockSurface)
{
auto lockSurface(getSurface(*m_lockSurface));
if (lockSurface)
{
lockSurface->m_rootSurface = lockSurface;
}
}
}
}
void Surface::attach(CompatRef<IDirectDrawSurface7> dds, std::unique_ptr<Surface> privateData)
@ -65,8 +83,9 @@ namespace DDraw
if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData,
privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER)))
{
CompatPtr<IUnknown> dd;
dds.get().lpVtbl->GetDDInterface(&dds, reinterpret_cast<void**>(&dd.getRef()));
CompatPtr<IUnknown> ddUnk;
dds.get().lpVtbl->GetDDInterface(&dds, reinterpret_cast<void**>(&ddUnk.getRef()));
CompatPtr<IDirectDraw7> dd(ddUnk);
privateData->createImpl();
privateData->m_impl->m_data = privateData.get();
@ -75,17 +94,37 @@ namespace DDraw
privateData->m_impl4->m_data = privateData.get();
privateData->m_impl7->m_data = privateData.get();
privateData->m_ddObject = DDraw::getDdObject(*CompatPtr<IDirectDraw>(dd));
privateData->m_surface = &dds;
privateData->m_ddObject = DDraw::getDdObject(*dd);
privateData.release();
}
}
void Surface::clearResources()
{
if (!m_surface)
{
return;
}
auto resource = D3dDdi::Device::getResource(getDriverResourceHandle(*m_surface));
if (resource)
{
resource->setLockResource(nullptr);
resource->setRootSurface(nullptr);
}
for (auto attachedSurface : m_attachedSurfaces)
{
attachedSurface->clearResources();
}
}
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
HRESULT Surface::create(
CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface, std::unique_ptr<Surface> privateData)
{
fixSurfaceDesc(desc.dwFlags, desc.ddsCaps.dwCaps);
HRESULT result = dd->CreateSurface(&dd, &desc, &surface, nullptr);
if (FAILED(result))
{
@ -93,17 +132,41 @@ namespace DDraw
}
auto surface7(CompatPtr<IDirectDrawSurface7>::from(surface));
attach(*surface7, std::move(privateData));
if (!(desc.dwFlags & DDSD_PIXELFORMAT))
{
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = {};
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
surface7->GetPixelFormat(surface7, &desc.ddpfPixelFormat);
}
privateData->m_lockSurface = privateData->createLockSurface<TDirectDraw, TSurface>(dd, desc);
if (privateData->m_lockSurface)
{
attach(*privateData->m_lockSurface, std::make_unique<Surface>(privateData.get()));
}
if (desc.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
{
auto attachedSurfaces(getAllAttachedSurfaces(*surface7));
for (std::size_t i = 0; i < attachedSurfaces.size(); ++i)
if (privateData->m_lockSurface)
{
attach(*attachedSurfaces[i], std::make_unique<Surface>());
auto attachedLockSurfaces(getAllAttachedSurfaces(*privateData->m_lockSurface));
privateData->m_attachedLockSurfaces.assign(attachedLockSurfaces.begin(), attachedLockSurfaces.end());
}
for (DWORD i = 0; i < attachedSurfaces.size(); ++i)
{
auto data(std::make_unique<Surface>(privateData.get()));
privateData->m_attachedSurfaces.push_back(data.get());
attach(*attachedSurfaces[i], std::move(data));
}
}
Surface* rootSurface = privateData.get();
attach(*surface7, std::move(privateData));
rootSurface->restore();
return result;
}
@ -136,6 +199,30 @@ namespace DDraw
template <>
SurfaceImpl<IDirectDrawSurface7>* Surface::getImpl<IDirectDrawSurface7>() const { return m_impl7.get(); }
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
CompatPtr<IDirectDrawSurface7> Surface::createLockSurface(CompatRef<TDirectDraw> dd, TSurfaceDesc desc)
{
LOG_FUNC("Surface::createLockSurface", dd, desc);
if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ||
!(desc.ddpfPixelFormat.dwFlags & DDPF_RGB) ||
0 == desc.ddpfPixelFormat.dwRGBBitCount ||
desc.ddpfPixelFormat.dwRGBBitCount > 32 ||
0 != (desc.ddpfPixelFormat.dwRGBBitCount % 8))
{
return LOG_RESULT(nullptr);
}
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = desc.ddpfPixelFormat;
desc.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
CompatPtr<TSurface> lockSurface;
dd->CreateSurface(&dd, &desc, &lockSurface.getRef(), nullptr);
return LOG_RESULT(lockSurface);
}
template <typename TSurface>
Surface* Surface::getSurface(TSurface& dds)
{
@ -155,4 +242,30 @@ namespace DDraw
template Surface* Surface::getSurface(IDirectDrawSurface3& dds);
template Surface* Surface::getSurface(IDirectDrawSurface4& dds);
template Surface* Surface::getSurface(IDirectDrawSurface7& dds);
void Surface::restore()
{
setResources(m_lockSurface);
if (m_lockSurface)
{
for (std::size_t i = 0; i < m_attachedSurfaces.size(); ++i)
{
m_attachedSurfaces[i]->setResources(
i < m_attachedLockSurfaces.size() ? m_attachedLockSurfaces[i] : nullptr);
}
}
}
void Surface::setResources(CompatWeakPtr<IDirectDrawSurface7> lockSurface)
{
if (lockSurface)
{
auto resource = D3dDdi::Device::getResource(getDriverResourceHandle(*m_surface));
if (resource)
{
resource->setLockResource(D3dDdi::Device::getResource(getDriverResourceHandle(*lockSurface)));
resource->setRootSurface(m_rootSurface);
}
}
}
}

View File

@ -20,7 +20,7 @@ namespace DDraw
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
Surface();
Surface(Surface* rootSurface = nullptr);
virtual ~Surface();
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
@ -33,6 +33,9 @@ namespace DDraw
template <typename TSurface>
SurfaceImpl<TSurface>* getImpl() const;
void clearResources();
void restore();
protected:
static void attach(CompatRef<IDirectDrawSurface7> dds, std::unique_ptr<Surface> privateData);
@ -51,6 +54,16 @@ namespace DDraw
template <typename TDirectDrawSurface>
friend class SurfaceImpl2;
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
CompatPtr<IDirectDrawSurface7> createLockSurface(CompatRef<TDirectDraw> dd, TSurfaceDesc desc);
void setResources(CompatWeakPtr<IDirectDrawSurface7> lockSurface);
DWORD m_refCount;
Surface* m_rootSurface;
CompatWeakPtr<IDirectDrawSurface7> m_surface;
std::vector<Surface*> m_attachedSurfaces;
CompatPtr<IDirectDrawSurface7> m_lockSurface;
std::vector<CompatWeakPtr<IDirectDrawSurface7>> m_attachedLockSurfaces;
};
}

View File

@ -46,11 +46,6 @@ namespace DDraw
HRESULT SurfaceImpl<TSurface>::BltFast(
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{
if (!waitForFlip(This, dwTrans, DDBLTFAST_WAIT, DDBLTFAST_DONOTWAIT))
{
return DDERR_WASSTILLDRAWING;
}
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
return s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
@ -176,7 +171,12 @@ namespace DDraw
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::Restore(TSurface* This)
{
return s_origVtable.Restore(This);
HRESULT result = s_origVtable.Restore(This);
if (SUCCEEDED(result))
{
m_data->restore();
}
return result;
}
template <typename TSurface>

View File

@ -84,6 +84,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
@ -102,6 +103,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
@ -120,6 +122,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
@ -160,7 +163,6 @@
<ClInclude Include="D3dDdi\Log\DeviceCallbacksLog.h" />
<ClInclude Include="D3dDdi\Log\DeviceFuncsLog.h" />
<ClInclude Include="D3dDdi\Log\KernelModeThunksLog.h" />
<ClInclude Include="D3dDdi\RenderTargetResource.h" />
<ClInclude Include="D3dDdi\Resource.h" />
<ClInclude Include="D3dDdi\ScopedCriticalSection.h" />
<ClInclude Include="D3dDdi\Visitors\AdapterCallbacksVisitor.h" />
@ -168,6 +170,7 @@
<ClInclude Include="D3dDdi\Visitors\DeviceCallbacksVisitor.h" />
<ClInclude Include="D3dDdi\Visitors\DeviceFuncsVisitor.h" />
<ClInclude Include="DDraw\ActivateAppHandler.h" />
<ClInclude Include="DDraw\Blitter.h" />
<ClInclude Include="DDraw\DirectDraw.h" />
<ClInclude Include="DDraw\DirectDrawClipper.h" />
<ClInclude Include="DDraw\DirectDrawGammaControl.h" />
@ -237,10 +240,10 @@
<ClCompile Include="D3dDdi\Log\DeviceCallbacksLog.cpp" />
<ClCompile Include="D3dDdi\Log\DeviceFuncsLog.cpp" />
<ClCompile Include="D3dDdi\Log\KernelModeThunksLog.cpp" />
<ClCompile Include="D3dDdi\RenderTargetResource.cpp" />
<ClCompile Include="D3dDdi\Resource.cpp" />
<ClCompile Include="D3dDdi\ScopedCriticalSection.cpp" />
<ClCompile Include="DDraw\ActivateAppHandler.cpp" />
<ClCompile Include="DDraw\Blitter.cpp" />
<ClCompile Include="DDraw\DirectDraw.cpp" />
<ClCompile Include="DDraw\DirectDrawClipper.cpp" />
<ClCompile Include="DDraw\DirectDrawGammaControl.cpp" />

View File

@ -300,9 +300,6 @@
<ClInclude Include="DDraw\DirectDrawGammaControl.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
<ClInclude Include="D3dDdi\RenderTargetResource.h">
<Filter>Header Files\D3dDdi</Filter>
</ClInclude>
<ClInclude Include="D3dDdi\Device.h">
<Filter>Header Files\D3dDdi</Filter>
</ClInclude>
@ -351,6 +348,9 @@
<ClInclude Include="Common\HResultException.h">
<Filter>Header Files\Common</Filter>
</ClInclude>
<ClInclude Include="DDraw\Blitter.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -503,9 +503,6 @@
<ClCompile Include="DDraw\DirectDrawGammaControl.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>
<ClCompile Include="D3dDdi\RenderTargetResource.cpp">
<Filter>Source Files\D3dDdi</Filter>
</ClCompile>
<ClCompile Include="D3dDdi\Device.cpp">
<Filter>Source Files\D3dDdi</Filter>
</ClCompile>
@ -533,6 +530,9 @@
<ClCompile Include="D3dDdi\Resource.cpp">
<Filter>Source Files\D3dDdi</Filter>
</ClCompile>
<ClCompile Include="DDraw\Blitter.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Dll\DDrawCompat.def">

View File

@ -95,13 +95,13 @@ namespace
CompatPtr<IDirectDrawClipper> clipper;
ddrawSurface->GetClipper(ddrawSurface, &clipper.getRef());
ddrawSurface->SetClipper(ddrawSurface, nullptr);
result = SUCCEEDED(ddrawSurface->Blt(
result = SUCCEEDED(ddrawSurface.get()->lpVtbl->Blt(
ddrawSurface, nullptr, gdiSurface, nullptr, DDBLT_WAIT, nullptr));
ddrawSurface->SetClipper(ddrawSurface, clipper);
}
else
{
result = SUCCEEDED(gdiSurface->BltFast(
result = SUCCEEDED(gdiSurface.get()->lpVtbl->BltFast(
gdiSurface, 0, 0, ddrawSurface, nullptr, DDBLTFAST_WAIT));
}
g_isSyncing = false;

View File

@ -143,7 +143,7 @@ namespace Gdi
CompatPtr<IDirectDraw7> dd(ddUnk);
CompatPtr<IDirectDrawSurface7> surface;
dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
dd.get()->lpVtbl->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
return surface;
}