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;
}
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)
{
for (auto& device : s_devices)
@ -206,15 +218,9 @@ namespace D3dDdi
HRESULT Device::pfnDestroyResource(HANDLE resource)
{
flushPrimitives();
if (g_gdiResource && resource == *g_gdiResource)
if (g_gdiResource)
{
D3DDDIARG_LOCK lock = {};
lock.hResource = *g_gdiResource;
g_gdiResource->lock(lock);
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = *g_gdiResource;
g_gdiResource->unlock(unlock);
g_gdiResource->onDestroyResource(resource);
}
if (resource == m_sharedPrimary)

View File

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

View File

@ -593,9 +593,21 @@ namespace D3dDdi
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_maxChangedTextureStage = max(stage, m_maxChangedTextureStage);
}
@ -820,6 +832,7 @@ namespace D3dDdi
m_device.getOrigVtable().pfnSetTextureStageState(m_device, &tss);
m_changedTextureStageStates[stage].reset(D3DDDITSS_DISABLETEXTURECOLORKEY);
m_changedTextureStageStates[stage].reset(D3DDDITSS_TEXTURECOLORKEYVAL);
LOG_DS << tss;
}
void DeviceState::updateTextureStages()

View File

@ -88,7 +88,7 @@ namespace D3dDdi
void setTempRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget);
void setTempStreamSource(const D3DDDIARG_SETSTREAMSOURCE& streamSource);
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 setTempVertexShaderDecl(HANDLE decl);
void setTempViewport(const D3DDDIARG_VIEWPORTINFO& viewport);

View File

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

View File

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

View File

@ -65,11 +65,7 @@ namespace D3dDdi
state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0xF });
state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, D3DTEXF_LINEAR == filter });
setTempTextureStage(0, srcResource, filter);
if (srcColorKey)
{
state.setTempTextureStageState({ 0, D3DDDITSS_TEXTURECOLORKEYVAL, *srcColorKey });
}
setTempTextureStage(0, srcResource, filter, srcColorKey);
struct Vertex
{
@ -241,10 +237,10 @@ namespace D3dDdi
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();
state.setTempTexture(stage, texture);
state.setTempTexture(stage, texture, srcColorKey);
state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSU, D3DTADDRESS_CLAMP });
state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSV, D3DTADDRESS_CLAMP });
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> createVertexShaderDecl();
void setTempTextureStage(UINT stage, HANDLE texture, UINT filter);
void setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey = nullptr);
Device& m_device;
std::unique_ptr<void, ResourceDeleter> m_psDrawCursor;

View File

@ -22,7 +22,13 @@ namespace DDraw
template <typename TSurface>
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>

View File

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

View File

@ -1,6 +1,11 @@
#include <set>
#include <d3d.h>
#include <d3dumddi.h>
#include <Common/CompatPtr.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/DirectDrawClipper.h>
#include <DDraw/DirectDrawSurface.h>
#include <DDraw/RealPrimarySurface.h>
@ -9,6 +14,83 @@
#include <DDraw/Surfaces/SurfaceImpl.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
{
template <typename TSurface>
@ -29,7 +111,8 @@ namespace DDraw
{
RealPrimarySurface::waitForFlip(m_data);
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>
@ -37,7 +120,8 @@ namespace DDraw
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{
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>
@ -191,4 +275,14 @@ namespace DDraw
template SurfaceImpl<IDirectDrawSurface3>;
template SurfaceImpl<IDirectDrawSurface4>;
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 <DDraw/Types.h>
struct _D3DDDIARG_BLT;
namespace DDraw
{
class Surface;
@ -46,4 +48,6 @@ namespace DDraw
private:
void restoreOrigCaps(DWORD& caps);
};
void setBltSrc(_D3DDDIARG_BLT& data);
}