diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index 3cc7a09..e8177f1 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -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) diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index ee8a377..d494722 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -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); diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 73a1c7a..912b128 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -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() diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index e6b591f..75dc3f7 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -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); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 3380300..3e3df3a 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 85139e6..cc5d18a 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -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); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 89b1ad8..16058f5 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -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 }); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index 619038d..be7a103 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -42,7 +42,7 @@ namespace D3dDdi std::unique_ptr createPixelShader(const BYTE* code, UINT size); std::unique_ptr 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 m_psDrawCursor; diff --git a/DDrawCompat/DDraw/DirectDrawSurface.h b/DDrawCompat/DDraw/DirectDrawSurface.h index 85be636..614362c 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.h +++ b/DDrawCompat/DDraw/DirectDrawSurface.h @@ -22,7 +22,13 @@ namespace DDraw template HANDLE getDriverResourceHandle(TSurface& surface) { - return *reinterpret_cast(getRuntimeResourceHandle(surface)); + return reinterpret_cast(getRuntimeResourceHandle(surface))[0]; + } + + template + UINT getSubResourceIndex(TSurface& surface) + { + return reinterpret_cast(getRuntimeResourceHandle(surface))[1]; } template diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 05e9b12..7f12b44 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include #include #include #include diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index 9727dbc..07ea92e 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -1,6 +1,11 @@ #include +#include +#include + #include +#include +#include #include #include #include @@ -9,6 +14,83 @@ #include #include +namespace +{ + HANDLE g_bltSrcResource = nullptr; + UINT g_bltSrcSubResourceIndex = 0; + RECT g_bltSrcRect = {}; + + template + typename DDraw::Types::TSurfaceDesc getDesc(TSurface* This) + { + DDraw::Types::TSurfaceDesc desc = {}; + desc.dwSize = sizeof(desc); + getOrigVtable(This).GetSurfaceDesc(This, &desc); + return desc; + } + + template + RECT getRect(LPRECT rect, const TSurfaceDesc& desc) + { + return rect ? *rect : RECT{ 0, 0, static_cast(desc.dwWidth), static_cast(desc.dwHeight) }; + } + + template + 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 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 @@ -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 @@ -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 @@ -191,4 +275,14 @@ namespace DDraw template SurfaceImpl; template SurfaceImpl; template SurfaceImpl; + + 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); + } + } } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h index 34b9592..bf579b0 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -7,6 +7,8 @@ #include #include +struct _D3DDDIARG_BLT; + namespace DDraw { class Surface; @@ -46,4 +48,6 @@ namespace DDraw private: void restoreOrigCaps(DWORD& caps); }; + + void setBltSrc(_D3DDDIARG_BLT& data); }