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

Aggregate render target locks

This commit is contained in:
narzoul 2018-02-03 17:02:32 +01:00
parent 60c3c4f153
commit 39d148e3ba
11 changed files with 620 additions and 585 deletions

View File

@ -0,0 +1,347 @@
#include "D3dDdi/AdapterFuncs.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/KernelModeThunks.h"
namespace
{
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
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.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;
}
bool isVidMemPool(D3DDDI_POOL pool)
{
return D3DDDIPOOL_VIDEOMEMORY == pool ||
D3DDDIPOOL_LOCALVIDMEM == pool ||
D3DDDIPOOL_NONLOCALVIDMEM == pool;
}
}
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)
, m_device(device)
, m_sharedPrimary(nullptr)
{
}
HRESULT Device::blt(const D3DDDIARG_BLT& data)
{
prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex);
prepareForRendering(data.hDstResource, data.DstSubResourceIndex);
auto it = m_oversizedResources.find(data.hSrcResource);
if (it != m_oversizedResources.end())
{
return it->second.bltFrom(data);
}
it = m_oversizedResources.find(data.hDstResource);
if (it != m_oversizedResources.end())
{
return it->second.bltTo(data);
}
return m_origVtable->pfnBlt(m_device, &data);
}
HRESULT Device::clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect)
{
prepareForRendering();
return m_origVtable->pfnClear(m_device, &data, numRect, rect);
}
HRESULT Device::colorFill(const D3DDDIARG_COLORFILL& data)
{
prepareForRendering(data.hResource, data.SubResourceIndex);
return m_origVtable->pfnColorFill(m_device, &data);
}
template <typename CreateResourceArg, typename CreateResourceFunc>
HRESULT Device::createOversizedResource(
CreateResourceArg& data,
CreateResourceFunc origCreateResource,
const D3DNTHAL_D3DEXTENDEDCAPS& caps)
{
D3DDDI_SURFACEINFO compatSurfaceInfo = data.pSurfList[0];
if (0 != caps.dwMaxTextureWidth && compatSurfaceInfo.Width > caps.dwMaxTextureWidth)
{
compatSurfaceInfo.Width = caps.dwMaxTextureWidth;
}
if (0 != caps.dwMaxTextureHeight && compatSurfaceInfo.Height > caps.dwMaxTextureHeight)
{
compatSurfaceInfo.Height = caps.dwMaxTextureHeight;
}
const D3DDDI_SURFACEINFO* origSurfList = data.pSurfList;
data.pSurfList = &compatSurfaceInfo;
HRESULT result = origCreateResource(m_device, &data);
data.pSurfList = origSurfList;
if (SUCCEEDED(result))
{
m_oversizedResources.emplace(data.hResource,
OversizedResource(m_adapter, m_device, data.Format, origSurfList[0]));
}
return result;
}
template <typename CreateResourceArg, typename CreateResourceFunc>
HRESULT Device::createResourceImpl(CreateResourceArg& data, CreateResourceFunc origCreateResource)
{
const bool isOffScreenPlain = 0 == (data.Flags.Value & g_resourceTypeFlags);
if (D3DDDIPOOL_SYSTEMMEM == data.Pool &&
(isOffScreenPlain || data.Flags.Texture) &&
OversizedResource::isSupportedFormat(data.Format) &&
1 == data.SurfCount &&
m_adapter)
{
const auto& caps = AdapterFuncs::getD3dExtendedCaps(m_adapter);
const auto& surfaceInfo = data.pSurfList[0];
if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth ||
0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight)
{
return createOversizedResource(data, origCreateResource, caps);
}
}
HRESULT result = origCreateResource(m_device, &data);
if (SUCCEEDED(result) && data.Flags.RenderTarget && !data.Flags.Primary && isVidMemPool(data.Pool))
{
m_renderTargetResources.emplace(data.hResource,
RenderTargetResource(m_device, data.hResource, data.Format, data.SurfCount));
}
return result;
}
HRESULT Device::createResource(D3DDDIARG_CREATERESOURCE& data)
{
return createResourceImpl(data, m_origVtable->pfnCreateResource);
}
HRESULT Device::createResource2(D3DDDIARG_CREATERESOURCE2& data)
{
return createResourceImpl(data, m_origVtable->pfnCreateResource2);
}
HRESULT Device::destroyResource(HANDLE resource)
{
if (resource == m_sharedPrimary)
{
KernelModeThunks::releaseVidPnSources();
}
HRESULT result = m_origVtable->pfnDestroyResource(m_device, resource);
if (SUCCEEDED(result))
{
m_oversizedResources.erase(resource);
m_renderTargetResources.erase(resource);
m_lockedRenderTargetResources.erase(resource);
if (resource == m_sharedPrimary)
{
m_sharedPrimary = nullptr;
}
}
return result;
}
HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data)
{
prepareForRendering();
return m_origVtable->pfnDrawIndexedPrimitive(m_device, &data);
}
HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer)
{
prepareForRendering();
return m_origVtable->pfnDrawIndexedPrimitive2(m_device, &data, indicesSize, indexBuffer, flagBuffer);
}
HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer)
{
prepareForRendering();
return m_origVtable->pfnDrawPrimitive(m_device, &data, flagBuffer);
}
HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data)
{
prepareForRendering();
return m_origVtable->pfnDrawPrimitive2(m_device, &data);
}
HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
const FLOAT* patch)
{
prepareForRendering();
return m_origVtable->pfnDrawRectPatch(m_device, &data, info, patch);
}
HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
const FLOAT* patch)
{
prepareForRendering();
return m_origVtable->pfnDrawTriPatch(m_device, &data, info, patch);
}
HRESULT Device::lock(D3DDDIARG_LOCK& data)
{
auto it = m_renderTargetResources.find(data.hResource);
if (it != m_renderTargetResources.end())
{
HRESULT result = it->second.lock(data);
if (SUCCEEDED(result))
{
m_lockedRenderTargetResources.emplace(it->first, it->second);
}
return result;
}
return m_origVtable->pfnLock(m_device, &data);
}
HRESULT Device::openResource(D3DDDIARG_OPENRESOURCE& data)
{
HRESULT result = m_origVtable->pfnOpenResource(m_device, &data);
if (SUCCEEDED(result) && data.Flags.Fullscreen)
{
m_sharedPrimary = data.hResource;
}
return result;
}
HRESULT Device::present(const D3DDDIARG_PRESENT& data)
{
prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex);
return m_origVtable->pfnPresent(m_device, &data);
}
HRESULT Device::present1(D3DDDIARG_PRESENT1& data)
{
for (UINT i = 0; i < data.SrcResources; ++i)
{
prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex);
}
return m_origVtable->pfnPresent1(m_device, &data);
}
HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data)
{
prepareForRendering(data.hDstResource);
prepareForRendering(data.hSrcResource);
return m_origVtable->pfnTexBlt(m_device, &data);
}
HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data)
{
prepareForRendering(data.hDstResource);
prepareForRendering(data.hSrcResource);
return m_origVtable->pfnTexBlt1(m_device, &data);
}
HRESULT Device::unlock(const D3DDDIARG_UNLOCK& data)
{
auto it = m_renderTargetResources.find(data.hResource);
if (it != m_renderTargetResources.end())
{
return it->second.unlock(data);
}
return m_origVtable->pfnUnlock(m_device, &data);
}
HRESULT Device::updateWInfo(const D3DDDIARG_WINFO& data)
{
if (1.0f == data.WNear && 1.0f == data.WFar)
{
D3DDDIARG_WINFO wInfo = {};
wInfo.WNear = 0.0f;
wInfo.WFar = 1.0f;
return m_origVtable->pfnUpdateWInfo(m_device, &wInfo);
}
return m_origVtable->pfnUpdateWInfo(m_device, &data);
}
void Device::prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex)
{
resource.prepareForRendering(subResourceIndex);
if (!resource.hasLockedSubResources())
{
m_lockedRenderTargetResources.erase(resource.getHandle());
}
}
void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex)
{
auto it = m_lockedRenderTargetResources.find(resource);
if (it != m_lockedRenderTargetResources.end())
{
prepareForRendering(it->second, subResourceIndex);
}
}
void Device::prepareForRendering()
{
auto it = m_lockedRenderTargetResources.begin();
while (it != m_lockedRenderTargetResources.end())
{
prepareForRendering((it++)->second);
}
}
}

View File

@ -0,0 +1,71 @@
#pragma once
#define CINTERFACE
#include <map>
#include <set>
#include <d3d.h>
#include <d3dnthal.h>
#include <d3dumddi.h>
#include "D3dDdi/OversizedResource.h"
#include "D3dDdi/RenderTargetResource.h"
namespace D3dDdi
{
UINT getBytesPerPixel(D3DDDIFORMAT format);
class Device
{
public:
Device(HANDLE adapter, HANDLE device);
HRESULT blt(const D3DDDIARG_BLT& data);
HRESULT clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect);
HRESULT colorFill(const D3DDDIARG_COLORFILL& data);
HRESULT createResource(D3DDDIARG_CREATERESOURCE& data);
HRESULT createResource2(D3DDDIARG_CREATERESOURCE2& data);
HRESULT destroyResource(HANDLE resource);
HRESULT drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data);
HRESULT drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data,
UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer);
HRESULT drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer);
HRESULT drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data);
HRESULT drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info,
const FLOAT* patch);
HRESULT drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info,
const FLOAT* patch);
HRESULT lock(D3DDDIARG_LOCK& data);
HRESULT openResource(D3DDDIARG_OPENRESOURCE& data);
HRESULT present(const D3DDDIARG_PRESENT& data);
HRESULT present1(D3DDDIARG_PRESENT1& data);
HRESULT texBlt(const D3DDDIARG_TEXBLT& data);
HRESULT texBlt1(const D3DDDIARG_TEXBLT1& data);
HRESULT unlock(const D3DDDIARG_UNLOCK& data);
HRESULT updateWInfo(const D3DDDIARG_WINFO& data);
void prepareForRendering(HANDLE resource, UINT subResourceIndex = UINT_MAX);
void prepareForRendering();
private:
template <typename CreateResourceArg, typename CreateResourceFunc>
HRESULT createOversizedResource(
CreateResourceArg& data,
CreateResourceFunc origCreateResource,
const D3DNTHAL_D3DEXTENDEDCAPS& caps);
template <typename CreateResourceArg, typename CreateResourceFunc>
HRESULT createResourceImpl(CreateResourceArg& data, CreateResourceFunc origCreateResource);
void prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex = UINT_MAX);
const D3DDDI_DEVICEFUNCS* m_origVtable;
HANDLE m_adapter;
HANDLE m_device;
std::map<HANDLE, OversizedResource> m_oversizedResources;
std::map<HANDLE, RenderTargetResource> m_renderTargetResources;
std::map<HANDLE, RenderTargetResource&> m_lockedRenderTargetResources;
HANDLE m_sharedPrimary;
};
}

View File

@ -1,461 +1,77 @@
#include <functional>
#include <map>
#include "D3dDdi/AdapterFuncs.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/LockResource.h"
#include "D3dDdi/KernelModeThunks.h"
#include "D3dDdi/OversizedResource.h"
namespace
{
struct Resource
std::map<HANDLE, D3dDdi::Device> g_devices;
D3dDdi::Device& getDevice(HANDLE device)
{
HANDLE device;
HANDLE resource;
Resource() : device(nullptr), resource(nullptr) {}
Resource(HANDLE device, HANDLE resource) : device(device), resource(resource) {}
bool operator<(const Resource& rhs) const
auto it = g_devices.find(device);
if (it != g_devices.end())
{
return device < rhs.device || (device == rhs.device && resource < rhs.resource);
return it->second;
}
};
class ResourceReplacer
{
public:
ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex);
~ResourceReplacer();
D3dDdi::LockResource::SubResource* getSubResource() const { return m_subResource; }
private:
HANDLE& m_resource;
HANDLE m_origResource;
D3dDdi::LockResource::SubResource* m_subResource;
};
D3DDDI_DEVICEFUNCS& getOrigVtable(HANDLE device);
D3DDDI_RESOURCEFLAGS getResourceTypeFlags();
bool isVidMemPool(D3DDDI_POOL pool);
D3dDdi::LockResource::SubResource* replaceWithActiveResource(
HANDLE device, HANDLE& resource, UINT subResourceIndex);
std::map<HANDLE, HANDLE> g_deviceToAdapter;
std::map<Resource, D3dDdi::LockResource> g_lockResources;
std::map<Resource, D3dDdi::OversizedResource> g_oversizedResources;
std::map<HANDLE, D3dDdi::LockResource::SubResource*> g_renderTargets;
Resource g_sharedPrimary;
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
ResourceReplacer::ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex)
: m_resource(const_cast<HANDLE&>(resource))
, m_origResource(resource)
{
m_subResource = replaceWithActiveResource(device, m_resource, subResourceIndex);
return g_devices.emplace(device, D3dDdi::Device(nullptr, device)).first->second;
}
ResourceReplacer::~ResourceReplacer()
template <typename DeviceMethodPtr, DeviceMethodPtr deviceMethod, typename Arg, typename... Params>
HRESULT WINAPI deviceFunc(HANDLE device, Arg* data, Params... params)
{
m_resource = m_origResource;
}
template <typename CreateResourceArg, typename CreateResourceFunc>
HRESULT createOversizedResource(HANDLE device, CreateResourceArg& resourceData,
CreateResourceFunc origCreateResource, const D3DNTHAL_D3DEXTENDEDCAPS& caps)
{
D3DDDI_SURFACEINFO compatSurfaceInfo = resourceData.pSurfList[0];
if (0 != caps.dwMaxTextureWidth && compatSurfaceInfo.Width > caps.dwMaxTextureWidth)
{
compatSurfaceInfo.Width = caps.dwMaxTextureWidth;
}
if (0 != caps.dwMaxTextureHeight && compatSurfaceInfo.Height > caps.dwMaxTextureHeight)
{
compatSurfaceInfo.Height = caps.dwMaxTextureHeight;
}
const D3DDDI_SURFACEINFO* origSurfList = resourceData.pSurfList;
resourceData.pSurfList = &compatSurfaceInfo;
HRESULT result = origCreateResource(device, &resourceData);
resourceData.pSurfList = origSurfList;
if (SUCCEEDED(result))
{
auto it = g_deviceToAdapter.find(device);
if (it != g_deviceToAdapter.end())
{
D3dDdi::OversizedResource oversizedResource(
it->second, device, resourceData.Format, origSurfList[0]);
g_oversizedResources[Resource(device, resourceData.hResource)] = oversizedResource;
}
}
return result;
}
template <typename CreateResourceArg, typename CreateResourceFunc>
HRESULT createResource(HANDLE device, CreateResourceArg* resourceData,
CreateResourceFunc origCreateResource)
{
const bool isOffScreenPlain = 0 == (resourceData->Flags.Value & g_resourceTypeFlags);
if (D3DDDIPOOL_SYSTEMMEM == resourceData->Pool &&
(isOffScreenPlain || resourceData->Flags.Texture) &&
D3dDdi::OversizedResource::isSupportedFormat(resourceData->Format) &&
1 == resourceData->SurfCount)
{
auto it = g_deviceToAdapter.find(device);
if (it != g_deviceToAdapter.end())
{
const auto& caps = D3dDdi::AdapterFuncs::getD3dExtendedCaps(it->second);
const auto& surfaceInfo = resourceData->pSurfList[0];
if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth ||
0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight)
{
return createOversizedResource(device, *resourceData, origCreateResource, caps);
}
}
}
HANDLE origResourceHandle = resourceData->hResource;
HRESULT result = origCreateResource(device, resourceData);
if (SUCCEEDED(result) && resourceData->Flags.RenderTarget && !resourceData->Flags.Primary &&
isVidMemPool(resourceData->Pool))
{
CreateResourceArg lockResourceData = {};
lockResourceData.Format = resourceData->Format;
lockResourceData.Pool = resourceData->Pool;
lockResourceData.pSurfList = resourceData->pSurfList;
lockResourceData.SurfCount = resourceData->SurfCount;
lockResourceData.hResource = origResourceHandle;
lockResourceData.Flags.CpuOptimized = 1;
if (SUCCEEDED(origCreateResource(device, &lockResourceData)))
{
g_lockResources.emplace(std::piecewise_construct,
std::forward_as_tuple(device, resourceData->hResource),
std::forward_as_tuple(device, resourceData->hResource, lockResourceData.hResource,
lockResourceData.pSurfList, lockResourceData.SurfCount));
}
}
return result;
}
D3DDDI_DEVICEFUNCS& getOrigVtable(HANDLE device)
{
return D3dDdi::DeviceFuncs::s_origVtables.at(device);
}
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.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;
}
bool isVidMemPool(D3DDDI_POOL pool)
{
return D3DDDIPOOL_VIDEOMEMORY == pool ||
D3DDDIPOOL_LOCALVIDMEM == pool ||
D3DDDIPOOL_NONLOCALVIDMEM == pool;
}
HRESULT renderFunc(HANDLE device, std::function<HRESULT()> origFunc)
{
auto it = g_renderTargets.find(device);
if (it != g_renderTargets.end())
{
it->second->updateOrig();
}
HRESULT result = origFunc();
if (SUCCEEDED(result) && it != g_renderTargets.end())
{
it->second->m_isLockUpToDate = false;
}
return result;
}
D3dDdi::LockResource::SubResource* replaceWithActiveResource(
HANDLE device, HANDLE& resource, UINT subResourceIndex)
{
auto it = g_lockResources.find(Resource(device, resource));
if (it == g_lockResources.end())
{
return nullptr;
}
auto& subResource = it->second.getSubResource(subResourceIndex);
if (subResource.m_isLockUpToDate)
{
resource = it->second.getHandle();
}
return &subResource;
}
HRESULT APIENTRY blt(HANDLE hDevice, const D3DDDIARG_BLT* pData)
{
ResourceReplacer srcReplacer(hDevice, pData->hSrcResource, pData->SrcSubResourceIndex);
ResourceReplacer dstReplacer(hDevice, pData->hDstResource, pData->DstSubResourceIndex);
auto dstSubResource = dstReplacer.getSubResource();
HRESULT result = S_OK;
auto it = g_oversizedResources.find(Resource(hDevice, pData->hSrcResource));
if (it != g_oversizedResources.end())
{
result = it->second.bltFrom(*pData);
}
else
{
it = g_oversizedResources.find(Resource(hDevice, pData->hDstResource));
if (it != g_oversizedResources.end())
{
result = it->second.bltTo(*pData);
}
else
{
result = getOrigVtable(hDevice).pfnBlt(hDevice, pData);
}
}
if (SUCCEEDED(result) && dstSubResource && dstSubResource->m_isLockUpToDate)
{
dstSubResource->m_isOrigUpToDate = false;
}
return result;
}
HRESULT APIENTRY colorFill(HANDLE hDevice, const D3DDDIARG_COLORFILL* pData)
{
ResourceReplacer replacer(hDevice, pData->hResource, pData->SubResourceIndex);
auto subResource = replacer.getSubResource();
HRESULT result = getOrigVtable(hDevice).pfnColorFill(hDevice, pData);
if (SUCCEEDED(result) && subResource && subResource->m_isLockUpToDate)
{
subResource->m_isOrigUpToDate = false;
}
return result;
}
HRESULT APIENTRY createResource(HANDLE hDevice, D3DDDIARG_CREATERESOURCE* pResource)
{
return createResource(hDevice, pResource, getOrigVtable(hDevice).pfnCreateResource);
}
HRESULT APIENTRY createResource2(HANDLE hDevice, D3DDDIARG_CREATERESOURCE2* pResource2)
{
return createResource(hDevice, pResource2, getOrigVtable(hDevice).pfnCreateResource2);
return (getDevice(device).*deviceMethod)(*data, params...);
}
HRESULT APIENTRY destroyDevice(HANDLE hDevice)
{
HRESULT result = getOrigVtable(hDevice).pfnDestroyDevice(hDevice);
HRESULT result = D3dDdi::DeviceFuncs::s_origVtables.at(hDevice).pfnDestroyDevice(hDevice);
if (SUCCEEDED(result))
{
D3dDdi::DeviceFuncs::s_origVtables.erase(hDevice);
g_deviceToAdapter.erase(hDevice);
g_devices.erase(hDevice);
}
return result;
}
HRESULT APIENTRY destroyResource(HANDLE hDevice, HANDLE hResource)
{
const bool isSharedPrimary =
hDevice == g_sharedPrimary.device && hResource == g_sharedPrimary.resource;
if (isSharedPrimary)
{
D3dDdi::KernelModeThunks::releaseVidPnSources();
}
HRESULT result = getOrigVtable(hDevice).pfnDestroyResource(hDevice, hResource);
if (SUCCEEDED(result))
{
auto lockResourceIt = g_lockResources.find(Resource(hDevice, hResource));
if (lockResourceIt != g_lockResources.end())
{
auto renderTarget = g_renderTargets.find(hDevice);
if (renderTarget != g_renderTargets.end() &&
&renderTarget->second->getParent() == &lockResourceIt->second)
{
g_renderTargets.erase(hDevice);
}
getOrigVtable(hDevice).pfnDestroyResource(hDevice, lockResourceIt->second.getHandle());
g_lockResources.erase(lockResourceIt);
}
auto oversizedResourceIt = g_oversizedResources.find(Resource(hDevice, hResource));
if (oversizedResourceIt != g_oversizedResources.end())
{
g_oversizedResources.erase(oversizedResourceIt);
}
if (isSharedPrimary)
{
g_sharedPrimary = {};
}
}
return result;
}
HRESULT APIENTRY lock(HANDLE hDevice, D3DDDIARG_LOCK* pData)
{
auto it = g_lockResources.find(Resource(hDevice, pData->hResource));
if (it != g_lockResources.end())
{
auto& subResource = it->second.getSubResource(pData->SubResourceIndex);
subResource.updateLock();
HANDLE origResourceHandle = pData->hResource;
pData->hResource = it->second.getHandle();
HRESULT result = getOrigVtable(hDevice).pfnLock(hDevice, pData);
pData->hResource = origResourceHandle;
if (SUCCEEDED(result) && !pData->Flags.ReadOnly)
{
subResource.m_isOrigUpToDate = false;
}
return result;
}
return getOrigVtable(hDevice).pfnLock(hDevice, pData);
}
HRESULT APIENTRY openResource(HANDLE hDevice, D3DDDIARG_OPENRESOURCE* pResource)
{
HRESULT result = getOrigVtable(hDevice).pfnOpenResource(hDevice, pResource);
if (SUCCEEDED(result) && pResource->Flags.Fullscreen)
{
g_sharedPrimary = Resource(hDevice, pResource->hResource);
}
return result;
}
HRESULT APIENTRY present(HANDLE hDevice, const D3DDDIARG_PRESENT* pData)
{
auto it = g_lockResources.find(Resource(hDevice, pData->hSrcResource));
if (it != g_lockResources.end())
{
it->second.getSubResource(pData->SrcSubResourceIndex).updateOrig();
}
return getOrigVtable(hDevice).pfnPresent(hDevice, pData);
}
HRESULT APIENTRY present1(HANDLE hDevice, D3DDDIARG_PRESENT1* pPresentData)
{
for (UINT i = 0; i < pPresentData->SrcResources; ++i)
{
auto it = g_lockResources.find(Resource(hDevice, pPresentData->phSrcResources[i].hResource));
if (it != g_lockResources.end())
{
it->second.getSubResource(pPresentData->phSrcResources[i].SubResourceIndex).updateOrig();
}
}
return getOrigVtable(hDevice).pfnPresent1(hDevice, pPresentData);
}
template <typename DeviceFuncMemberPtr, DeviceFuncMemberPtr origFunc, typename... Params>
HRESULT WINAPI renderFunc(HANDLE device, Params... params)
{
return renderFunc(device,
[=]() { return (getOrigVtable(device).*origFunc)(device, params...); });
}
HRESULT APIENTRY setRenderTarget(HANDLE hDevice, const D3DDDIARG_SETRENDERTARGET* pData)
{
HRESULT result = getOrigVtable(hDevice).pfnSetRenderTarget(hDevice, pData);
if (SUCCEEDED(result))
{
auto it = g_lockResources.find(Resource(hDevice, pData->hRenderTarget));
if (it != g_lockResources.end())
{
g_renderTargets[hDevice] = &it->second.getSubResource(pData->SubResourceIndex);
}
else
{
g_renderTargets.erase(hDevice);
}
}
return result;
}
HRESULT APIENTRY unlock(HANDLE hDevice, const D3DDDIARG_UNLOCK* pData)
{
auto it = g_lockResources.find(Resource(hDevice, pData->hResource));
if (it != g_lockResources.end())
{
HANDLE origResource = pData->hResource;
const_cast<HANDLE&>(pData->hResource) = it->second.getHandle();
HRESULT result = getOrigVtable(hDevice).pfnUnlock(hDevice, pData);
const_cast<HANDLE&>(pData->hResource) = origResource;
return result;
}
return getOrigVtable(hDevice).pfnUnlock(hDevice, pData);
}
HRESULT APIENTRY updateWInfo(HANDLE hDevice, const D3DDDIARG_WINFO* pData)
{
if (pData && 1.0f == pData->WNear && 1.0f == pData->WFar)
{
D3DDDIARG_WINFO wInfo = {};
wInfo.WNear = 0.0f;
wInfo.WFar = 1.0f;
return getOrigVtable(hDevice).pfnUpdateWInfo(hDevice, &wInfo);
}
return getOrigVtable(hDevice).pfnUpdateWInfo(hDevice, pData);
return getDevice(hDevice).destroyResource(hResource);
}
}
#define RENDER_FUNC(func) renderFunc<decltype(&D3DDDI_DEVICEFUNCS::func), &D3DDDI_DEVICEFUNCS::func>
#define DEVICE_FUNC(func) deviceFunc<decltype(&Device::func), &Device::func>
namespace D3dDdi
{
void DeviceFuncs::onCreateDevice(HANDLE adapter, HANDLE device)
{
g_deviceToAdapter[device] = adapter;
g_devices.emplace(device, Device(adapter, device));
}
void DeviceFuncs::setCompatVtable(D3DDDI_DEVICEFUNCS& vtable)
{
vtable.pfnBlt = &blt;
vtable.pfnClear = &RENDER_FUNC(pfnClear);
vtable.pfnColorFill = &colorFill;
vtable.pfnCreateResource = &createResource;
vtable.pfnCreateResource2 = &createResource2;
vtable.pfnBlt = &DEVICE_FUNC(blt);
vtable.pfnClear = &DEVICE_FUNC(clear);
vtable.pfnColorFill = &DEVICE_FUNC(colorFill);
vtable.pfnCreateResource = &DEVICE_FUNC(createResource);
vtable.pfnCreateResource2 = &DEVICE_FUNC(createResource2);
vtable.pfnDestroyDevice = &destroyDevice;
vtable.pfnDestroyResource = &destroyResource;
vtable.pfnDrawIndexedPrimitive = &RENDER_FUNC(pfnDrawIndexedPrimitive);
vtable.pfnDrawIndexedPrimitive2 = &RENDER_FUNC(pfnDrawIndexedPrimitive2);
vtable.pfnDrawPrimitive = &RENDER_FUNC(pfnDrawPrimitive);
vtable.pfnDrawPrimitive2 = &RENDER_FUNC(pfnDrawPrimitive2);
vtable.pfnDrawRectPatch = &RENDER_FUNC(pfnDrawRectPatch);
vtable.pfnDrawTriPatch = &RENDER_FUNC(pfnDrawTriPatch);
vtable.pfnLock = &lock;
vtable.pfnOpenResource = &openResource;
vtable.pfnPresent = &present;
vtable.pfnPresent1 = &present1;
vtable.pfnSetRenderTarget = &setRenderTarget;
vtable.pfnUnlock = &unlock;
vtable.pfnUpdateWInfo = &updateWInfo;
vtable.pfnDrawIndexedPrimitive = &DEVICE_FUNC(drawIndexedPrimitive);
vtable.pfnDrawIndexedPrimitive2 = &DEVICE_FUNC(drawIndexedPrimitive2);
vtable.pfnDrawPrimitive = &DEVICE_FUNC(drawPrimitive);
vtable.pfnDrawPrimitive2 = &DEVICE_FUNC(drawPrimitive2);
vtable.pfnDrawRectPatch = &DEVICE_FUNC(drawRectPatch);
vtable.pfnDrawTriPatch = &DEVICE_FUNC(drawTriPatch);
vtable.pfnLock = &DEVICE_FUNC(lock);
vtable.pfnOpenResource = &DEVICE_FUNC(openResource);
vtable.pfnPresent = &DEVICE_FUNC(present);
vtable.pfnPresent1 = &DEVICE_FUNC(present1);
vtable.pfnTexBlt = &DEVICE_FUNC(texBlt);
vtable.pfnTexBlt1 = &DEVICE_FUNC(texBlt1);
vtable.pfnUnlock = &DEVICE_FUNC(unlock);
vtable.pfnUpdateWInfo = &DEVICE_FUNC(updateWInfo);
}
}

View File

@ -1,73 +0,0 @@
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/LockResource.h"
namespace
{
D3DDDI_DEVICEFUNCS& getOrigVtable(HANDLE device)
{
return D3dDdi::DeviceFuncs::s_origVtables.at(device);
}
}
namespace D3dDdi
{
LockResource::LockResource(HANDLE device, HANDLE origResource, HANDLE lockResource,
const D3DDDI_SURFACEINFO* surfaceInfo, UINT surfaceInfoCount)
: m_device(device)
, m_origResource(origResource)
, m_lockResource(lockResource)
{
for (UINT i = 0; i < surfaceInfoCount; ++i)
{
m_subResources.emplace_back(*this, i, surfaceInfo[i].Width, surfaceInfo[i].Height);
}
}
LockResource::~LockResource()
{
}
LockResource::SubResource::SubResource(LockResource& parent, UINT index, UINT width, UINT height)
: m_isOrigUpToDate(true)
, m_isLockUpToDate(true)
, m_parent(&parent)
, m_index(index)
, m_width(width)
, m_height(height)
{
}
HRESULT LockResource::SubResource::blt(HANDLE dstResource, HANDLE srcResource)
{
RECT rect = { 0, 0, static_cast<LONG>(m_width), static_cast<LONG>(m_height) };
D3DDDIARG_BLT bltData = {};
bltData.hSrcResource = srcResource;
bltData.SrcSubResourceIndex = m_index;
bltData.SrcRect = rect;
bltData.hDstResource = dstResource;
bltData.DstSubResourceIndex = m_index;
bltData.DstRect = rect;
bltData.Flags.Point = 1;
return getOrigVtable(m_parent->m_device).pfnBlt(m_parent->m_device, &bltData);
}
void LockResource::SubResource::updateLock()
{
if (!m_isLockUpToDate)
{
blt(m_parent->m_lockResource, m_parent->m_origResource);
m_isLockUpToDate = true;
}
}
void LockResource::SubResource::updateOrig()
{
if (!m_isOrigUpToDate)
{
blt(m_parent->m_origResource, m_parent->m_lockResource);
m_isOrigUpToDate = true;
}
}
}

View File

@ -1,50 +0,0 @@
#pragma once
#define CINTERFACE
#include <vector>
#include <d3d.h>
#include <d3dumddi.h>
namespace D3dDdi
{
class LockResource
{
public:
struct SubResource
{
public:
SubResource(LockResource& parent, UINT index, UINT width, UINT height);
LockResource& getParent() const { return *m_parent; }
void updateLock();
void updateOrig();
bool m_isOrigUpToDate;
bool m_isLockUpToDate;
private:
HRESULT blt(HANDLE dstResource, HANDLE srcResource);
LockResource* m_parent;
UINT m_index;
UINT m_width;
UINT m_height;
};
LockResource(HANDLE device, HANDLE origResource, HANDLE lockResource,
const D3DDDI_SURFACEINFO* surfaceInfo, UINT surfaceInfoCount);
~LockResource();
LockResource(const LockResource&) = delete;
HANDLE getHandle() const { return m_lockResource; }
SubResource& getSubResource(UINT index) { return m_subResources[index]; }
private:
HANDLE m_device;
HANDLE m_origResource;
HANDLE m_lockResource;
std::vector<SubResource> m_subResources;
};
}

View File

@ -1,43 +1,10 @@
#include "D3dDdi/AdapterFuncs.h"
#include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/OversizedResource.h"
namespace
{
UINT getBytesPerPixel(D3DDDIFORMAT format)
{
switch (format)
{
case D3DDDIFMT_R5G6B5:
case D3DDDIFMT_X1R5G5B5:
case D3DDDIFMT_A1R5G5B5:
return 2;
case D3DDDIFMT_R8G8B8:
return 3;
case D3DDDIFMT_A8R8G8B8:
case D3DDDIFMT_X8R8G8B8:
case D3DDDIFMT_A8B8G8R8:
case D3DDDIFMT_X8B8G8R8:
return 4;
default:
return 0;
}
}
}
namespace D3dDdi
{
OversizedResource::OversizedResource()
: m_adapter(nullptr)
, m_device(nullptr)
, m_format(D3DDDIFMT_UNKNOWN)
, m_surfaceInfo()
{
}
OversizedResource::OversizedResource(
HANDLE adapter, HANDLE device, D3DDDIFORMAT format, const D3DDDI_SURFACEINFO& surfaceInfo)
: m_adapter(adapter)

View File

@ -10,7 +10,6 @@ namespace D3dDdi
class OversizedResource
{
public:
OversizedResource();
OversizedResource(HANDLE adapter, HANDLE device,
D3DDDIFORMAT format, const D3DDDI_SURFACEINFO& surfaceInfo);

View File

@ -0,0 +1,106 @@
#include "D3dDdi/Device.h"
#include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/RenderTargetResource.h"
namespace D3dDdi
{
RenderTargetResource::RenderTargetResource(
HANDLE 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 D3dDdi::DeviceFuncs::s_origVtables.at(m_device).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 = D3dDdi::DeviceFuncs::s_origVtables.at(m_device).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 D3dDdi::DeviceFuncs::s_origVtables.at(m_device).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;
D3dDdi::DeviceFuncs::s_origVtables.at(m_device).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

@ -0,0 +1,44 @@
#pragma once
#define CINTERFACE
#include <d3d.h>
#include <d3dumddi.h>
#include <set>
#include <vector>
namespace D3dDdi
{
class RenderTargetResource
{
public:
RenderTargetResource(HANDLE 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);
HANDLE m_device;
HANDLE m_resource;
UINT m_bytesPerPixel;
std::vector<SubResource> m_subResources;
std::set<UINT> m_lockedSubResources;
};
}

View File

@ -164,16 +164,17 @@
<ClInclude Include="Config\Config.h" />
<ClInclude Include="D3dDdi\AdapterCallbacks.h" />
<ClInclude Include="D3dDdi\AdapterFuncs.h" />
<ClInclude Include="D3dDdi\Device.h" />
<ClInclude Include="D3dDdi\DeviceCallbacks.h" />
<ClInclude Include="D3dDdi\DeviceFuncs.h" />
<ClInclude Include="D3dDdi\Hooks.h" />
<ClInclude Include="D3dDdi\KernelModeThunks.h" />
<ClInclude Include="D3dDdi\LockResource.h" />
<ClInclude Include="D3dDdi\Log\AdapterFuncsLog.h" />
<ClInclude Include="D3dDdi\Log\DeviceCallbacksLog.h" />
<ClInclude Include="D3dDdi\Log\DeviceFuncsLog.h" />
<ClInclude Include="D3dDdi\Log\KernelModeThunksLog.h" />
<ClInclude Include="D3dDdi\OversizedResource.h" />
<ClInclude Include="D3dDdi\RenderTargetResource.h" />
<ClInclude Include="D3dDdi\Visitors\AdapterCallbacksVisitor.h" />
<ClInclude Include="D3dDdi\Visitors\AdapterFuncsVisitor.h" />
<ClInclude Include="D3dDdi\Visitors\DeviceCallbacksVisitor.h" />
@ -235,16 +236,17 @@
<ClCompile Include="Common\Time.cpp" />
<ClCompile Include="D3dDdi\AdapterCallbacks.cpp" />
<ClCompile Include="D3dDdi\AdapterFuncs.cpp" />
<ClCompile Include="D3dDdi\Device.cpp" />
<ClCompile Include="D3dDdi\DeviceCallbacks.cpp" />
<ClCompile Include="D3dDdi\DeviceFuncs.cpp" />
<ClCompile Include="D3dDdi\Hooks.cpp" />
<ClCompile Include="D3dDdi\KernelModeThunks.cpp" />
<ClCompile Include="D3dDdi\LockResource.cpp" />
<ClCompile Include="D3dDdi\Log\AdapterFuncsLog.cpp" />
<ClCompile Include="D3dDdi\Log\DeviceCallbacksLog.cpp" />
<ClCompile Include="D3dDdi\Log\DeviceFuncsLog.cpp" />
<ClCompile Include="D3dDdi\Log\KernelModeThunksLog.cpp" />
<ClCompile Include="D3dDdi\OversizedResource.cpp" />
<ClCompile Include="D3dDdi\RenderTargetResource.cpp" />
<ClCompile Include="DDraw\ActivateAppHandler.cpp" />
<ClCompile Include="DDraw\DirectDraw.cpp" />
<ClCompile Include="DDraw\DirectDrawClipper.cpp" />

View File

@ -282,9 +282,6 @@
<ClInclude Include="D3dDdi\Log\DeviceCallbacksLog.h">
<Filter>Header Files\D3dDdi\Log</Filter>
</ClInclude>
<ClInclude Include="D3dDdi\LockResource.h">
<Filter>Header Files\D3dDdi</Filter>
</ClInclude>
<ClInclude Include="D3dDdi\Log\AdapterFuncsLog.h">
<Filter>Header Files\D3dDdi\Log</Filter>
</ClInclude>
@ -312,6 +309,12 @@
<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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -452,9 +455,6 @@
<ClCompile Include="D3dDdi\Log\DeviceCallbacksLog.cpp">
<Filter>Source Files\D3dDdi\Log</Filter>
</ClCompile>
<ClCompile Include="D3dDdi\LockResource.cpp">
<Filter>Source Files\D3dDdi</Filter>
</ClCompile>
<ClCompile Include="D3dDdi\Log\AdapterFuncsLog.cpp">
<Filter>Source Files\D3dDdi\Log</Filter>
</ClCompile>
@ -476,6 +476,12 @@
<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>
</ItemGroup>
<ItemGroup>
<None Include="Dll\DDrawCompat.def">