diff --git a/DDrawCompat/Common/Log.cpp b/DDrawCompat/Common/Log.cpp index 970afa0..c6870e7 100644 --- a/DDrawCompat/Common/Log.cpp +++ b/DDrawCompat/Common/Log.cpp @@ -63,7 +63,13 @@ std::ostream& operator<<(std::ostream& os, const WCHAR* wstr) return os << static_cast(wstr); } - return os << std::wstring_convert, wchar_t>().to_bytes(wstr); + while (*wstr) + { + os.put(static_cast(*wstr)); + ++wstr; + } + + return os; } std::ostream& operator<<(std::ostream& os, const DEVMODEA& dm) diff --git a/DDrawCompat/D3dDdi/AdapterFuncs.cpp b/DDrawCompat/D3dDdi/AdapterFuncs.cpp index 8000c66..a9a56cf 100644 --- a/DDrawCompat/D3dDdi/AdapterFuncs.cpp +++ b/DDrawCompat/D3dDdi/AdapterFuncs.cpp @@ -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(pData->pData)->FxCaps = 0; + static_cast(pData->pData)->FxCaps = + DDRAW_FXCAPS_BLTMIRRORLEFTRIGHT | DDRAW_FXCAPS_BLTMIRRORUPDOWN; } return result; } diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index 99e3c95..711c6e7 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -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 + 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, 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; diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index 8904e46..fd65d12 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -1,17 +1,14 @@ #pragma once #include +#include #include #include #include -#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& getResources() { return m_resources; } + std::unordered_map& 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 HRESULT createResourceImpl(Arg& data); - void prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex = UINT_MAX); + void prepareForRendering(std::map, Resource&>& resources, bool isReadOnly); const D3DDDI_DEVICEFUNCS& m_origVtable; Adapter& m_adapter; HANDLE m_device; - std::map m_resources; - std::map m_renderTargetResources; - std::map m_lockedRenderTargetResources; + std::unordered_map m_resources; + std::map, Resource&> m_dirtyRenderTargets; + std::map, Resource&> m_dirtyTextures; HANDLE m_sharedPrimary; static std::map s_devices; diff --git a/DDrawCompat/D3dDdi/RenderTargetResource.cpp b/DDrawCompat/D3dDdi/RenderTargetResource.cpp deleted file mode 100644 index 91390d6..0000000 --- a/DDrawCompat/D3dDdi/RenderTargetResource.cpp +++ /dev/null @@ -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(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) - { - } -} diff --git a/DDrawCompat/D3dDdi/RenderTargetResource.h b/DDrawCompat/D3dDdi/RenderTargetResource.h deleted file mode 100644 index d97ff68..0000000 --- a/DDrawCompat/D3dDdi/RenderTargetResource.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -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 m_subResources; - std::set m_lockedSubResources; - }; -} diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 69f2733..7891891 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -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 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(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(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 Resource Resource::create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*)) { Resource resource(device, data); Arg origData = data; - auto& baseData = reinterpret_cast(data); - fixResourceData(device, baseData); + fixResourceData(device, reinterpret_cast(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(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(dstGuard.data) + + data.DstRect.top * dstGuard.pitch + data.DstRect.left * m_bytesPerPixel; + auto srcBuf = static_cast(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(&data.ColorKey) : nullptr, + data.Flags.SrcColorKey ? reinterpret_cast(&data.ColorKey) : nullptr); + + return S_OK; + } + } + } + + prepareForRendering(data.DstSubResourceIndex, false); + srcResource.prepareForRendering(data.SrcSubResourceIndex, true); + return m_device.getOrigVtable().pfnBlt(m_device, &data); + } + template 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); } } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 586407d..39e358c 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -4,6 +4,12 @@ #include #include +#include + +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 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 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 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 m_lockData; }; } diff --git a/DDrawCompat/DDraw/Blitter.cpp b/DDrawCompat/DDraw/Blitter.cpp new file mode 100644 index 0000000..86fc84d --- /dev/null +++ b/DDrawCompat/DDraw/Blitter.cpp @@ -0,0 +1,654 @@ +#include +#include + +#include + +#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(value); + m_high8 = static_cast((value & 0x00FF0000) >> 16); + } + + private: + WORD m_low16; + BYTE m_high8; + }; +#pragma pack() + + template + struct MultiDimArray; + + template + struct MultiDimArray + { + typedef std::array::type, firstDim> type; + }; + + template + struct MultiDimArray + { + typedef std::array 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 __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 __m128i _mm_loadu_si(const void* p); + template <> __m128i _mm_loadu_si<8>(const void* p) { return _mm_cvtsi32_si128(*static_cast(p)); } + template <> __m128i _mm_loadu_si<16>(const void* p) { return _mm_cvtsi32_si128(*static_cast(p)); } + template <> __m128i _mm_loadu_si<32>(const void* p) { return _mm_cvtsi32_si128(*static_cast(p)); } + template <> __m128i _mm_loadu_si<64>(const void* p) { return _mm_loadl_epi64(static_cast(p)); } + template <> __m128i _mm_loadu_si<128>(const void* p) { return _mm_loadu_si128(static_cast(p)); } + + template __m128i _mm_set1_epi(DWORD a); + template <> __m128i _mm_set1_epi<8>(DWORD a) { return _mm_set1_epi8(static_cast(a)); } + template <> __m128i _mm_set1_epi<16>(DWORD a) { return _mm_set1_epi16(static_cast(a)); } + template <> __m128i _mm_set1_epi<32>(DWORD a) { return _mm_set1_epi32(a); } + + template void _mm_storeu_si(void* p, __m128i a); + template <> void _mm_storeu_si<8>(void* p, __m128i a) { *static_cast(p) = static_cast(_mm_cvtsi128_si32(a)); } + template <> void _mm_storeu_si<16>(void* p, __m128i a) { *static_cast(p) = static_cast(_mm_cvtsi128_si32(a)); } + template <> void _mm_storeu_si<32>(void* p, __m128i a) { *static_cast(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 + __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 + __forceinline void loadSrcVectorRemainder(__m128i& vec1, __m128i& vec2, + const BYTE*& src, int& offset, int delta, std::integral_constant) + { + 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(vec1, vec2, src, offset, delta, std::integral_constant()); + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& vec1, __m128i& vec2, + const BYTE*& src, int& offset, int delta, std::integral_constant /*count*/) + { + vec1 = _mm_insert_epi16(vec1, *(src + (offset >> 16)), (pixelsPerVector - 1) / 2); + offset += delta; + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& /*vec1*/, __m128i& /*vec2*/, + const BYTE*& /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant /*count*/) + { + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& /*vec1*/, __m128i& /*vec2*/, + const BYTE*& /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant /*count*/) + { + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& vec, + const BYTE* src, int& offset, int delta, std::integral_constant) + { + __m128i vec2 = _mm_loadu_si<8>(src + (offset >> 16)); + offset += delta; + loadSrcVectorRemainder(vec, vec2, src, offset, delta, std::integral_constant()); + vec2 = _mm_slli_si128(vec2, 1); + vec = _mm_or_si128(vec, vec2); + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& vec, + const WORD* src, int& offset, int delta, std::integral_constant) + { + vec = _mm_insert_epi16(vec, *(src + (offset >> 16)), pixelsPerVector - count); + offset += delta; + loadSrcVectorRemainder(vec, src, offset, delta, std::integral_constant()); + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& /*vec*/, + const WORD* /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant /*count*/) + { + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& vec, + const DWORD* src, int& offset, int delta, std::integral_constant) + { + __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(vec, src, offset, delta, std::integral_constant()); + } + + template + __forceinline void loadSrcVectorRemainder(__m128i& /*vec*/, + const DWORD* /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant /*count*/) + { + } + + template + __forceinline __m128i loadSrcVector(const Pixel*& src, int& offset, int delta) + { + const int pixelsPerVector = vectorSize / sizeof(Pixel); + __m128i vec = _mm_loadu_si(stretch ? src + (offset >> 16) : src); + if (stretch) + { + offset += delta; + loadSrcVectorRemainder(vec, src, offset, delta, + std::integral_constant()); + } + else + { + vec = _mm_loadu_si(src); + if (mirror) + { + vec = reverseVector(vec); + src -= pixelsPerVector; + } + else + { + src += pixelsPerVector; + } + } + return vec; + } + + template + __forceinline __m128i compareColorKey(__m128i vec, DWORD colorKey) + { + __m128i colorKeyVec = _mm_set1_epi(colorKey); + if (4 == sizeof(Pixel)) + { + __m128i colorKeyMask = _mm_set1_epi(0x00FFFFFF); + vec = _mm_and_si128(vec, colorKeyMask); + } + return _mm_cmpeq_epi(vec, colorKeyVec); + } + + template + __forceinline __m128i bltVector(__m128i dst, __m128i src, DWORD dstColorKey, DWORD srcColorKey) + { + if (useDstColorKey && useSrcColorKey) + { + __m128i maskDst = compareColorKey(dst, dstColorKey); + __m128i maskSrc = compareColorKey(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(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(src, srcColorKey); + dst = _mm_and_si128(mask, dst); + src = _mm_andnot_si128(mask, src); + return _mm_or_si128(dst, src); + } + else + { + return src; + } + } + + template + __forceinline void bltVector(Pixel*& dst, const Pixel*& src, int& offset, int delta, + DWORD dstColorKey, DWORD srcColorKey) + { + __m128i s = loadSrcVector(src, offset, delta); + __m128i d = _mm_loadu_si(dst); + d = bltVector(d, s, dstColorKey, srcColorKey); + _mm_storeu_si(dst, d); + dst += vectorSize / sizeof(Pixel); + } + + template + __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( + dst, src, offset, delta, dstColorKey, srcColorKey); + } + } + + if (sizeof(Pixel) < vectorSize) + { + const DWORD remainder = width % pixelsPerVector; + auto src1 = src; + auto offset1 = offset; + __m128i s1 = loadSrcVector(src1, offset1, delta); + if (stretch) + { + offset += remainder * delta; + } + else if (mirror) + { + src -= remainder; + } + else + { + src += remainder; + } + __m128i s2 = loadSrcVector(src, offset, delta); + __m128i d1 = _mm_loadu_si(dst); + __m128i d2 = _mm_loadu_si(dst + remainder); + d1 = bltVector(d1, s1, dstColorKey, srcColorKey); + _mm_storeu_si(dst, d1); + d2 = bltVector(d2, s2, dstColorKey, srcColorKey); + _mm_storeu_si(dst + remainder, d2); + } + else + { + bltVector( + dst, src, offset, delta, dstColorKey, srcColorKey); + } + } + + template + __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(dst) | (reinterpret_cast(dst)[2] << 16); + const DWORD s = *reinterpret_cast(src1) | (reinterpret_cast(src1)[2] << 16); + const DWORD mask = static_cast(-static_cast( + (!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 + __forceinline void bltVectorRow(UInt24* dst, const UInt24* src, DWORD width, int offset, int delta, + DWORD dstColorKey, DWORD srcColorKey) + { + if (!stretch && !mirror && !useDstColorKey && !useSrcColorKey) + { + bltVectorRow( + reinterpret_cast(dst), reinterpret_cast(src), + width * 3, offset, delta, dstColorKey, srcColorKey); + return; + } + + if (2 == vectorSize) + { + bltPixel(dst, src, offset, delta, dstColorKey, srcColorKey); + return; + } + + if (4 == vectorSize) + { + bltPixel(dst, src, offset, delta, dstColorKey, srcColorKey); + bltPixel(dst, src, offset, delta, dstColorKey, srcColorKey); + return; + } + + for (DWORD i = width; i != 0; --i) + { + bltPixel(dst, src, offset, delta, dstColorKey, srcColorKey); + } + } + + template + __forceinline std::enable_if_t= 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( + reinterpret_cast(dst), + reinterpret_cast(src + (offsetY >> 16) * srcPitch), + dstWidth, offsetX, deltaX, dstColorKey, srcColorKey); + dst += dstPitch; + offsetY += deltaY; + } + } + + template + __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 + 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( + static_cast(dst), dstPitch, dstWidth, dstHeight, + static_cast(src), srcPitch, offsetX, deltaX, offsetY, deltaY, dstColorKey, srcColorKey); + } + + template + auto getVectorizedBltFunc() + { + return &vectorizedBltFunc; + } + + template + auto getVectorizedBltFunc(bool useSrcColorKey) + { + return useSrcColorKey + ? getVectorizedBltFunc() + : getVectorizedBltFunc(); + } + + template + auto getVectorizedBltFunc(bool useDstColorKey, bool useSrcColorKey) + { + return useDstColorKey + ? getVectorizedBltFunc(useSrcColorKey) + : getVectorizedBltFunc(useSrcColorKey); + } + + template + auto getVectorizedBltFunc(bool mirror, bool useDstColorKey, bool useSrcColorKey) + { + return mirror + ? getVectorizedBltFunc(useDstColorKey, useSrcColorKey) + : getVectorizedBltFunc(useDstColorKey, useSrcColorKey); + } + + template + auto getVectorizedBltFunc(bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey) + { + return stretch + ? getVectorizedBltFunc(mirror, useDstColorKey, useSrcColorKey) + : getVectorizedBltFunc(mirror, useDstColorKey, useSrcColorKey); + } + + template + auto getVectorizedBltFunc(DWORD width, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey) + { + if (width >= 16) return getVectorizedBltFunc(stretch, mirror, useDstColorKey, useSrcColorKey); + if (width >= 8) return getVectorizedBltFunc(stretch, mirror, useDstColorKey, useSrcColorKey); + if (width >= 4) return getVectorizedBltFunc(stretch, mirror, useDstColorKey, useSrcColorKey); + if (width >= 2) return getVectorizedBltFunc(stretch, mirror, useDstColorKey, useSrcColorKey); + return getVectorizedBltFunc(stretch, mirror, useDstColorKey, useSrcColorKey); + } + + auto getVectorizedBltFunc(DWORD bytesPerPixel, DWORD width, + bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey) + { + switch (bytesPerPixel) + { + case 4: return getVectorizedBltFunc(width, stretch, mirror, useDstColorKey, useSrcColorKey); + case 3: return getVectorizedBltFunc(width, stretch, mirror, useDstColorKey, useSrcColorKey); + case 2: return getVectorizedBltFunc(width, stretch, mirror, useDstColorKey, useSrcColorKey); + default: return getVectorizedBltFunc(width, stretch, mirror, useDstColorKey, useSrcColorKey); + } + } + + auto getVectorizedBltFuncs() + { + typename MultiDimArray), 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(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(dstWidth * bytesPerPixel), static_cast(dstHeight) }; + RECT srcRect = { 0, 0, static_cast(absSrcWidth * bytesPerPixel), static_cast(absSrcHeight) }; + + srcRect.top = (src - dst) / static_cast(pitch); + srcRect.left = (src - dst) % static_cast(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 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(dstWidth - 1) * deltaX; + deltaX = -deltaX; + } + if (mirrorUpDown) + { + offsetY += static_cast(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(dst), dstPitch, dstWidth, dstHeight, + static_cast(src), srcPitch, srcWidth, srcHeight, + bytesPerPixel, dstColorKey, srcColorKey); + } + } +} diff --git a/DDrawCompat/DDraw/Blitter.h b/DDrawCompat/DDraw/Blitter.h new file mode 100644 index 0000000..09417c8 --- /dev/null +++ b/DDrawCompat/DDraw/Blitter.h @@ -0,0 +1,15 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN + +#include + +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); + } +} diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 4b16a83..d4a664c 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -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); } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index c82b3d7..9748728 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -60,7 +60,7 @@ namespace auto srcSurface(CompatPtr::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); } diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 6735172..33be56e 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -1,6 +1,8 @@ #include #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 dds, std::unique_ptr privateData) @@ -65,8 +83,9 @@ namespace DDraw if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData, privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER))) { - CompatPtr dd; - dds.get().lpVtbl->GetDDInterface(&dds, reinterpret_cast(&dd.getRef())); + CompatPtr ddUnk; + dds.get().lpVtbl->GetDDInterface(&dds, reinterpret_cast(&ddUnk.getRef())); + CompatPtr 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(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 HRESULT Surface::create( CompatRef dd, TSurfaceDesc desc, TSurface*& surface, std::unique_ptr 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::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(dd, desc); + if (privateData->m_lockSurface) + { + attach(*privateData->m_lockSurface, std::make_unique(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()); + 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(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* Surface::getImpl() const { return m_impl7.get(); } + template + CompatPtr Surface::createLockSurface(CompatRef 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 lockSurface; + dd->CreateSurface(&dd, &desc, &lockSurface.getRef(), nullptr); + return LOG_RESULT(lockSurface); + } + template 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 lockSurface) + { + if (lockSurface) + { + auto resource = D3dDdi::Device::getResource(getDriverResourceHandle(*m_surface)); + if (resource) + { + resource->setLockResource(D3dDdi::Device::getResource(getDriverResourceHandle(*lockSurface))); + resource->setRootSurface(m_rootSurface); + } + } + } } diff --git a/DDrawCompat/DDraw/Surfaces/Surface.h b/DDrawCompat/DDraw/Surfaces/Surface.h index 0eace3b..3df117d 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.h +++ b/DDrawCompat/DDraw/Surfaces/Surface.h @@ -20,7 +20,7 @@ namespace DDraw virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); - Surface(); + Surface(Surface* rootSurface = nullptr); virtual ~Surface(); template @@ -33,6 +33,9 @@ namespace DDraw template SurfaceImpl* getImpl() const; + void clearResources(); + void restore(); + protected: static void attach(CompatRef dds, std::unique_ptr privateData); @@ -51,6 +54,16 @@ namespace DDraw template friend class SurfaceImpl2; + template + CompatPtr createLockSurface(CompatRef dd, TSurfaceDesc desc); + + void setResources(CompatWeakPtr lockSurface); + DWORD m_refCount; + Surface* m_rootSurface; + CompatWeakPtr m_surface; + std::vector m_attachedSurfaces; + CompatPtr m_lockSurface; + std::vector> m_attachedLockSurfaces; }; } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index f244dd3..4b34f9f 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -46,11 +46,6 @@ namespace DDraw HRESULT SurfaceImpl::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 HRESULT SurfaceImpl::Restore(TSurface* This) { - return s_origVtable.Restore(This); + HRESULT result = s_origVtable.Restore(This); + if (SUCCEEDED(result)) + { + m_data->restore(); + } + return result; } template diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index c596787..a379819 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -84,6 +84,7 @@ false $(IntDir)%(RelativeDir) ProgramDatabase + stdcpp17 Dll/DDrawCompat.def @@ -102,6 +103,7 @@ MultiThreaded true $(IntDir)%(RelativeDir) + stdcpp17 Dll/DDrawCompat.def @@ -120,6 +122,7 @@ MultiThreaded true $(IntDir)%(RelativeDir) + stdcpp17 Dll/DDrawCompat.def @@ -160,7 +163,6 @@ - @@ -168,6 +170,7 @@ + @@ -237,10 +240,10 @@ - + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 2e958a4..3920133 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -300,9 +300,6 @@ Header Files\DDraw - - Header Files\D3dDdi - Header Files\D3dDdi @@ -351,6 +348,9 @@ Header Files\Common + + Header Files\DDraw + @@ -503,9 +503,6 @@ Source Files\DDraw - - Source Files\D3dDdi - Source Files\D3dDdi @@ -533,6 +530,9 @@ Source Files\D3dDdi + + Source Files\DDraw + diff --git a/DDrawCompat/Gdi/AccessGuard.cpp b/DDrawCompat/Gdi/AccessGuard.cpp index 92654e8..93ef5cc 100644 --- a/DDrawCompat/Gdi/AccessGuard.cpp +++ b/DDrawCompat/Gdi/AccessGuard.cpp @@ -95,13 +95,13 @@ namespace CompatPtr 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; diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index f1acd34..f70c942 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -143,7 +143,7 @@ namespace Gdi CompatPtr dd(ddUnk); CompatPtr surface; - dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr); + dd.get()->lpVtbl->CreateSurface(dd, &desc, &surface.getRef(), nullptr); return surface; }