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

Perform sysmem to vidmem render target blits via Direct3D

This commit is contained in:
narzoul 2021-12-19 00:07:06 +01:00
parent 436a8184bb
commit 075287b16a
12 changed files with 163 additions and 25 deletions

View File

@ -62,6 +62,18 @@ namespace D3dDdi
return result; return result;
} }
Device* Device::findDeviceByResource(HANDLE resource)
{
for (auto& device : s_devices)
{
if (device.second.m_resources.find(resource) != device.second.m_resources.end())
{
return &device.second;
}
}
return nullptr;
}
Resource* Device::findResource(HANDLE resource) Resource* Device::findResource(HANDLE resource)
{ {
for (auto& device : s_devices) for (auto& device : s_devices)
@ -206,15 +218,9 @@ namespace D3dDdi
HRESULT Device::pfnDestroyResource(HANDLE resource) HRESULT Device::pfnDestroyResource(HANDLE resource)
{ {
flushPrimitives(); flushPrimitives();
if (g_gdiResource && resource == *g_gdiResource) if (g_gdiResource)
{ {
D3DDDIARG_LOCK lock = {}; g_gdiResource->onDestroyResource(resource);
lock.hResource = *g_gdiResource;
g_gdiResource->lock(lock);
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = *g_gdiResource;
g_gdiResource->unlock(unlock);
} }
if (resource == m_sharedPrimary) if (resource == m_sharedPrimary)

View File

@ -63,6 +63,7 @@ namespace D3dDdi
static Device& get(HANDLE device) { return s_devices.find(device)->second; } static Device& get(HANDLE device) { return s_devices.find(device)->second; }
static void enableFlush(bool enable) { s_isFlushEnabled = enable; } static void enableFlush(bool enable) { s_isFlushEnabled = enable; }
static Device* findDeviceByResource(HANDLE resource);
static Resource* findResource(HANDLE resource); static Resource* findResource(HANDLE resource);
static Resource* getGdiResource(); static Resource* getGdiResource();
static void setGdiResourceHandle(HANDLE resource); static void setGdiResourceHandle(HANDLE resource);

View File

@ -593,9 +593,21 @@ namespace D3dDdi
m_changedStates |= CS_STREAM_SOURCE; m_changedStates |= CS_STREAM_SOURCE;
} }
void DeviceState::setTempTexture(UINT stage, HANDLE texture) void DeviceState::setTempTexture(UINT stage, HANDLE texture, const UINT* srcColorKey)
{ {
setTexture(stage, texture); if (srcColorKey)
{
m_current.textures[stage] = nullptr;
m_current.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = 0;
m_current.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL] = *srcColorKey + 1;
setTexture(stage, texture);
setTextureStageState({ stage, D3DDDITSS_TEXTURECOLORKEYVAL, *srcColorKey });
}
else
{
setTexture(stage, texture);
}
m_changedStates |= CS_TEXTURE_STAGE; m_changedStates |= CS_TEXTURE_STAGE;
m_maxChangedTextureStage = max(stage, m_maxChangedTextureStage); m_maxChangedTextureStage = max(stage, m_maxChangedTextureStage);
} }
@ -820,6 +832,7 @@ namespace D3dDdi
m_device.getOrigVtable().pfnSetTextureStageState(m_device, &tss); m_device.getOrigVtable().pfnSetTextureStageState(m_device, &tss);
m_changedTextureStageStates[stage].reset(D3DDDITSS_DISABLETEXTURECOLORKEY); m_changedTextureStageStates[stage].reset(D3DDDITSS_DISABLETEXTURECOLORKEY);
m_changedTextureStageStates[stage].reset(D3DDDITSS_TEXTURECOLORKEYVAL); m_changedTextureStageStates[stage].reset(D3DDDITSS_TEXTURECOLORKEYVAL);
LOG_DS << tss;
} }
void DeviceState::updateTextureStages() void DeviceState::updateTextureStages()

View File

@ -88,7 +88,7 @@ namespace D3dDdi
void setTempRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget); void setTempRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget);
void setTempStreamSource(const D3DDDIARG_SETSTREAMSOURCE& streamSource); void setTempStreamSource(const D3DDDIARG_SETSTREAMSOURCE& streamSource);
void setTempStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& streamSourceUm, const void* umBuffer); void setTempStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& streamSourceUm, const void* umBuffer);
void setTempTexture(UINT stage, HANDLE texture); void setTempTexture(UINT stage, HANDLE texture, const UINT* srcColorKey = nullptr);
void setTempTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE& tss); void setTempTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE& tss);
void setTempVertexShaderDecl(HANDLE decl); void setTempVertexShaderDecl(HANDLE decl);
void setTempViewport(const D3DDDIARG_VIEWPORTINFO& viewport); void setTempViewport(const D3DDDIARG_VIEWPORTINFO& viewport);

View File

@ -13,6 +13,7 @@
#include <DDraw/Blitter.h> #include <DDraw/Blitter.h>
#include <DDraw/RealPrimarySurface.h> #include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h> #include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Surfaces/SurfaceImpl.h>
#include <Gdi/Cursor.h> #include <Gdi/Cursor.h>
#include <Gdi/Palette.h> #include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
@ -188,6 +189,7 @@ namespace D3dDdi
return S_OK; return S_OK;
} }
DDraw::setBltSrc(data);
auto srcResource = m_device.getResource(data.hSrcResource); auto srcResource = m_device.getResource(data.hSrcResource);
if (srcResource) if (srcResource)
{ {
@ -623,6 +625,13 @@ namespace D3dDdi
HRESULT Resource::lock(D3DDDIARG_LOCK& data) HRESULT Resource::lock(D3DDDIARG_LOCK& data)
{ {
D3DDDIARG_BLT blt = {};
DDraw::setBltSrc(blt);
if (blt.hSrcResource)
{
return E_ABORT;
}
if (isOversized()) if (isOversized())
{ {
if (0 != data.SubResourceIndex || if (0 != data.SubResourceIndex ||
@ -657,6 +666,16 @@ namespace D3dDdi
m_device.getOrigVtable().pfnUnlock(m_device, &unlock); m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
} }
void Resource::onDestroyResource(HANDLE resource)
{
if (resource == m_handle ||
m_msaaSurface.resource && *m_msaaSurface.resource == resource ||
m_msaaResolvedSurface.resource && *m_msaaResolvedSurface.resource == resource)
{
loadSysMemResource(0);
}
}
Resource& Resource::prepareForBltSrc(const D3DDDIARG_BLT& data) Resource& Resource::prepareForBltSrc(const D3DDDIARG_BLT& data)
{ {
if (m_lockResource) if (m_lockResource)
@ -868,7 +887,7 @@ namespace D3dDdi
UINT dstIndex = data.DstSubResourceIndex; UINT dstIndex = data.DstSubResourceIndex;
RECT dstRect = data.DstRect; RECT dstRect = data.DstRect;
if (!srcResource.m_fixedData.Flags.Texture) if (!srcResource.m_fixedData.Flags.Texture || D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool)
{ {
DWORD width = data.SrcRect.right - data.SrcRect.left; DWORD width = data.SrcRect.right - data.SrcRect.left;
DWORD height = data.SrcRect.bottom - data.SrcRect.top; DWORD height = data.SrcRect.bottom - data.SrcRect.top;

View File

@ -34,6 +34,7 @@ namespace D3dDdi
HRESULT colorFill(D3DDDIARG_COLORFILL data); HRESULT colorFill(D3DDDIARG_COLORFILL data);
void* getLockPtr(UINT subResourceIndex); void* getLockPtr(UINT subResourceIndex);
HRESULT lock(D3DDDIARG_LOCK& data); HRESULT lock(D3DDDIARG_LOCK& data);
void onDestroyResource(HANDLE resource);
Resource& prepareForBltSrc(const D3DDDIARG_BLT& data); Resource& prepareForBltSrc(const D3DDDIARG_BLT& data);
Resource& prepareForBltDst(D3DDDIARG_BLT& data); Resource& prepareForBltDst(D3DDDIARG_BLT& data);
void prepareForCpuRead(UINT subResourceIndex); void prepareForCpuRead(UINT subResourceIndex);

View File

@ -65,11 +65,7 @@ namespace D3dDdi
state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0xF }); state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0xF });
state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, D3DTEXF_LINEAR == filter }); state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, D3DTEXF_LINEAR == filter });
setTempTextureStage(0, srcResource, filter); setTempTextureStage(0, srcResource, filter, srcColorKey);
if (srcColorKey)
{
state.setTempTextureStageState({ 0, D3DDDITSS_TEXTURECOLORKEYVAL, *srcColorKey });
}
struct Vertex struct Vertex
{ {
@ -241,10 +237,10 @@ namespace D3dDdi
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT); blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT);
} }
void ShaderBlitter::setTempTextureStage(UINT stage, HANDLE texture, UINT filter) void ShaderBlitter::setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey)
{ {
auto& state = m_device.getState(); auto& state = m_device.getState();
state.setTempTexture(stage, texture); state.setTempTexture(stage, texture, srcColorKey);
state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSU, D3DTADDRESS_CLAMP }); state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSU, D3DTADDRESS_CLAMP });
state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSV, D3DTADDRESS_CLAMP }); state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSV, D3DTADDRESS_CLAMP });
state.setTempTextureStageState({ stage, D3DDDITSS_MAGFILTER, filter }); state.setTempTextureStageState({ stage, D3DDDITSS_MAGFILTER, filter });

View File

@ -42,7 +42,7 @@ namespace D3dDdi
std::unique_ptr<void, ResourceDeleter> createPixelShader(const BYTE* code, UINT size); std::unique_ptr<void, ResourceDeleter> createPixelShader(const BYTE* code, UINT size);
std::unique_ptr<void, ResourceDeleter> createVertexShaderDecl(); std::unique_ptr<void, ResourceDeleter> createVertexShaderDecl();
void setTempTextureStage(UINT stage, HANDLE texture, UINT filter); void setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey = nullptr);
Device& m_device; Device& m_device;
std::unique_ptr<void, ResourceDeleter> m_psDrawCursor; std::unique_ptr<void, ResourceDeleter> m_psDrawCursor;

View File

@ -22,7 +22,13 @@ namespace DDraw
template <typename TSurface> template <typename TSurface>
HANDLE getDriverResourceHandle(TSurface& surface) HANDLE getDriverResourceHandle(TSurface& surface)
{ {
return *reinterpret_cast<HANDLE*>(getRuntimeResourceHandle(surface)); return reinterpret_cast<HANDLE*>(getRuntimeResourceHandle(surface))[0];
}
template <typename TSurface>
UINT getSubResourceIndex(TSurface& surface)
{
return reinterpret_cast<UINT*>(getRuntimeResourceHandle(surface))[1];
} }
template <typename Vtable> template <typename Vtable>

View File

@ -1,8 +1,6 @@
#include <initguid.h> #include <initguid.h>
#include <Common/CompatPtr.h> #include <Common/CompatPtr.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/Resource.h>
#include <DDraw/DirectDrawClipper.h> #include <DDraw/DirectDrawClipper.h>
#include <DDraw/DirectDrawSurface.h> #include <DDraw/DirectDrawSurface.h>
#include <DDraw/Surfaces/Surface.h> #include <DDraw/Surfaces/Surface.h>

View File

@ -1,6 +1,11 @@
#include <set> #include <set>
#include <d3d.h>
#include <d3dumddi.h>
#include <Common/CompatPtr.h> #include <Common/CompatPtr.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/DirectDrawClipper.h> #include <DDraw/DirectDrawClipper.h>
#include <DDraw/DirectDrawSurface.h> #include <DDraw/DirectDrawSurface.h>
#include <DDraw/RealPrimarySurface.h> #include <DDraw/RealPrimarySurface.h>
@ -9,6 +14,83 @@
#include <DDraw/Surfaces/SurfaceImpl.h> #include <DDraw/Surfaces/SurfaceImpl.h>
#include <Dll/Dll.h> #include <Dll/Dll.h>
namespace
{
HANDLE g_bltSrcResource = nullptr;
UINT g_bltSrcSubResourceIndex = 0;
RECT g_bltSrcRect = {};
template <typename TSurface>
typename DDraw::Types<TSurface>::TSurfaceDesc getDesc(TSurface* This)
{
DDraw::Types<TSurface>::TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
getOrigVtable(This).GetSurfaceDesc(This, &desc);
return desc;
}
template <typename TSurfaceDesc>
RECT getRect(LPRECT rect, const TSurfaceDesc& desc)
{
return rect ? *rect : RECT{ 0, 0, static_cast<LONG>(desc.dwWidth), static_cast<LONG>(desc.dwHeight) };
}
template <typename TSurface, typename BltFunc>
HRESULT blt(TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, BltFunc bltFunc)
{
if (!lpDDSrcSurface)
{
return bltFunc(This, lpDDSrcSurface, lpSrcRect);
}
auto dstDesc = getDesc(This);
if (!(dstDesc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) || !(dstDesc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
{
return bltFunc(This, lpDDSrcSurface, lpSrcRect);
}
auto srcDesc = getDesc(lpDDSrcSurface);
if (!(srcDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
{
return bltFunc(This, lpDDSrcSurface, lpSrcRect);
}
auto srcResource = DDraw::DirectDrawSurface::getDriverResourceHandle(*lpDDSrcSurface);
auto device = D3dDdi::Device::findDeviceByResource(srcResource);
if (!device)
{
return bltFunc(This, lpDDSrcSurface, lpSrcRect);
}
auto& repo = D3dDdi::SurfaceRepository::get(device->getAdapter());
RECT srcRect = getRect(lpSrcRect, srcDesc);
auto& tex = repo.getTempTexture(srcRect.right - srcRect.left, srcRect.bottom - srcRect.top,
srcDesc.ddpfPixelFormat);
if (!tex.resource)
{
return bltFunc(This, lpDDSrcSurface, lpSrcRect);
}
CompatPtr<TSurface> newSrcSurface(tex.surface);
DDCOLORKEY ck = {};
HRESULT result = getOrigVtable(This).GetColorKey(lpDDSrcSurface, DDCKEY_SRCBLT, &ck);
getOrigVtable(This).SetColorKey(newSrcSurface, DDCKEY_SRCBLT, SUCCEEDED(result) ? &ck : nullptr);
g_bltSrcResource = srcResource;
g_bltSrcSubResourceIndex = DDraw::DirectDrawSurface::getSubResourceIndex(*lpDDSrcSurface);
g_bltSrcRect = getRect(lpSrcRect, srcDesc);
RECT r = { 0, 0, g_bltSrcRect.right - g_bltSrcRect.left, g_bltSrcRect.bottom - g_bltSrcRect.top };
result = bltFunc(This, newSrcSurface, &r);
g_bltSrcResource = nullptr;
g_bltSrcSubResourceIndex = 0;
g_bltSrcRect = {};
return SUCCEEDED(result) ? DD_OK : bltFunc(This, lpDDSrcSurface, lpSrcRect);
}
}
namespace DDraw namespace DDraw
{ {
template <typename TSurface> template <typename TSurface>
@ -29,7 +111,8 @@ namespace DDraw
{ {
RealPrimarySurface::waitForFlip(m_data); RealPrimarySurface::waitForFlip(m_data);
DirectDrawClipper::update(); DirectDrawClipper::update();
return getOrigVtable(This).Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect)
{ return getOrigVtable(This).Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); });
} }
template <typename TSurface> template <typename TSurface>
@ -37,7 +120,8 @@ namespace DDraw
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{ {
RealPrimarySurface::waitForFlip(m_data); RealPrimarySurface::waitForFlip(m_data);
return getOrigVtable(This).BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect)
{ return getOrigVtable(This).BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); });
} }
template <typename TSurface> template <typename TSurface>
@ -191,4 +275,14 @@ namespace DDraw
template SurfaceImpl<IDirectDrawSurface3>; template SurfaceImpl<IDirectDrawSurface3>;
template SurfaceImpl<IDirectDrawSurface4>; template SurfaceImpl<IDirectDrawSurface4>;
template SurfaceImpl<IDirectDrawSurface7>; template SurfaceImpl<IDirectDrawSurface7>;
void setBltSrc(D3DDDIARG_BLT& data)
{
if (g_bltSrcResource)
{
data.hSrcResource = g_bltSrcResource;
data.SrcSubResourceIndex = g_bltSrcSubResourceIndex;
OffsetRect(&data.SrcRect, g_bltSrcRect.left, g_bltSrcRect.top);
}
}
} }

View File

@ -7,6 +7,8 @@
#include <Common/CompatVtable.h> #include <Common/CompatVtable.h>
#include <DDraw/Types.h> #include <DDraw/Types.h>
struct _D3DDDIARG_BLT;
namespace DDraw namespace DDraw
{ {
class Surface; class Surface;
@ -46,4 +48,6 @@ namespace DDraw
private: private:
void restoreOrigCaps(DWORD& caps); void restoreOrigCaps(DWORD& caps);
}; };
void setBltSrc(_D3DDDIARG_BLT& data);
} }