mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Prefer locks and blits in system memory
This commit is contained in:
parent
545b08c55b
commit
c526cc2506
@ -63,7 +63,13 @@ std::ostream& operator<<(std::ostream& os, const WCHAR* wstr)
|
||||
return os << static_cast<const void*>(wstr);
|
||||
}
|
||||
|
||||
return os << std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().to_bytes(wstr);
|
||||
while (*wstr)
|
||||
{
|
||||
os.put(static_cast<char>(*wstr));
|
||||
++wstr;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const DEVMODEA& dm)
|
||||
|
@ -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<DDRAW_CAPS*>(pData->pData)->FxCaps = 0;
|
||||
static_cast<DDRAW_CAPS*>(pData->pData)->FxCaps =
|
||||
DDRAW_FXCAPS_BLTMIRRORLEFTRIGHT | DDRAW_FXCAPS_BLTMIRRORUPDOWN;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -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 <typename Container, typename Predicate>
|
||||
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<std::pair<HANDLE, UINT>, 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;
|
||||
|
@ -1,17 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <d3d.h>
|
||||
#include <d3dnthal.h>
|
||||
#include <d3dumddi.h>
|
||||
|
||||
#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<HANDLE, Resource>& getResources() { return m_resources; }
|
||||
std::unordered_map<HANDLE, Resource>& 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 <typename Arg>
|
||||
HRESULT createResourceImpl(Arg& data);
|
||||
|
||||
void prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex = UINT_MAX);
|
||||
void prepareForRendering(std::map<std::pair<HANDLE, UINT>, Resource&>& resources, bool isReadOnly);
|
||||
|
||||
const D3DDDI_DEVICEFUNCS& m_origVtable;
|
||||
Adapter& m_adapter;
|
||||
HANDLE m_device;
|
||||
std::map<HANDLE, Resource> m_resources;
|
||||
std::map<HANDLE, RenderTargetResource> m_renderTargetResources;
|
||||
std::map<HANDLE, RenderTargetResource&> m_lockedRenderTargetResources;
|
||||
std::unordered_map<HANDLE, Resource> m_resources;
|
||||
std::map<std::pair<HANDLE, UINT>, Resource&> m_dirtyRenderTargets;
|
||||
std::map<std::pair<HANDLE, UINT>, Resource&> m_dirtyTextures;
|
||||
HANDLE m_sharedPrimary;
|
||||
|
||||
static std::map<HANDLE, Device> s_devices;
|
||||
|
@ -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<unsigned char*>(subResource.surfacePtr);
|
||||
if (data.Flags.AreaValid)
|
||||
{
|
||||
surfacePtr += data.Area.top * subResource.pitch + data.Area.left * m_bytesPerPixel;
|
||||
}
|
||||
data.pSurfData = surfacePtr;
|
||||
data.Pitch = subResource.pitch;
|
||||
subResource.isLocked = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const UINT origFlags = data.Flags.Value;
|
||||
data.Flags.Value = 0;
|
||||
const HRESULT result = 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)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d.h>
|
||||
#include <d3dumddi.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
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<SubResource> m_subResources;
|
||||
std::set<UINT> m_lockedSubResources;
|
||||
};
|
||||
}
|
@ -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<D3DDDI_SURFACEINFO> 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<void*>(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<unsigned char*>(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 <typename Arg>
|
||||
Resource Resource::create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*))
|
||||
{
|
||||
Resource resource(device, data);
|
||||
Arg origData = data;
|
||||
auto& baseData = reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(data);
|
||||
fixResourceData(device, baseData);
|
||||
fixResourceData(device, reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(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<void*>(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<BYTE*>(dstGuard.data) +
|
||||
data.DstRect.top * dstGuard.pitch + data.DstRect.left * m_bytesPerPixel;
|
||||
auto srcBuf = static_cast<const BYTE*>(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<const DWORD*>(&data.ColorKey) : nullptr,
|
||||
data.Flags.SrcColorKey ? reinterpret_cast<const DWORD*>(&data.ColorKey) : nullptr);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prepareForRendering(data.DstSubResourceIndex, false);
|
||||
srcResource.prepareForRendering(data.SrcSubResourceIndex, true);
|
||||
return m_device.getOrigVtable().pfnBlt(m_device, &data);
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
#include <d3d.h>
|
||||
#include <d3dumddi.h>
|
||||
#include <ddraw.h>
|
||||
|
||||
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<D3DDDI_SURFACEINFO> 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 <typename Arg>
|
||||
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 <typename Arg>
|
||||
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<LockData> m_lockData;
|
||||
};
|
||||
}
|
||||
|
654
DDrawCompat/DDraw/Blitter.cpp
Normal file
654
DDrawCompat/DDraw/Blitter.cpp
Normal file
@ -0,0 +1,654 @@
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#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<WORD>(value);
|
||||
m_high8 = static_cast<BYTE>((value & 0x00FF0000) >> 16);
|
||||
}
|
||||
|
||||
private:
|
||||
WORD m_low16;
|
||||
BYTE m_high8;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
template <typename Elem, std::size_t... dim>
|
||||
struct MultiDimArray;
|
||||
|
||||
template <typename Elem, std::size_t firstDim, std::size_t... dim>
|
||||
struct MultiDimArray<Elem, firstDim, dim...>
|
||||
{
|
||||
typedef std::array<typename MultiDimArray<Elem, dim...>::type, firstDim> type;
|
||||
};
|
||||
|
||||
template <typename Elem, std::size_t dim>
|
||||
struct MultiDimArray<Elem, dim>
|
||||
{
|
||||
typedef std::array<Elem, dim> 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 <int n> __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 <int n> __m128i _mm_loadu_si(const void* p);
|
||||
template <> __m128i _mm_loadu_si<8>(const void* p) { return _mm_cvtsi32_si128(*static_cast<const uint8_t*>(p)); }
|
||||
template <> __m128i _mm_loadu_si<16>(const void* p) { return _mm_cvtsi32_si128(*static_cast<const uint16_t*>(p)); }
|
||||
template <> __m128i _mm_loadu_si<32>(const void* p) { return _mm_cvtsi32_si128(*static_cast<const uint32_t*>(p)); }
|
||||
template <> __m128i _mm_loadu_si<64>(const void* p) { return _mm_loadl_epi64(static_cast<const __m128i*>(p)); }
|
||||
template <> __m128i _mm_loadu_si<128>(const void* p) { return _mm_loadu_si128(static_cast<const __m128i*>(p)); }
|
||||
|
||||
template <int n> __m128i _mm_set1_epi(DWORD a);
|
||||
template <> __m128i _mm_set1_epi<8>(DWORD a) { return _mm_set1_epi8(static_cast<uint8_t>(a)); }
|
||||
template <> __m128i _mm_set1_epi<16>(DWORD a) { return _mm_set1_epi16(static_cast<uint16_t>(a)); }
|
||||
template <> __m128i _mm_set1_epi<32>(DWORD a) { return _mm_set1_epi32(a); }
|
||||
|
||||
template <int n> void _mm_storeu_si(void* p, __m128i a);
|
||||
template <> void _mm_storeu_si<8>(void* p, __m128i a) { *static_cast<uint8_t*>(p) = static_cast<uint8_t>(_mm_cvtsi128_si32(a)); }
|
||||
template <> void _mm_storeu_si<16>(void* p, __m128i a) { *static_cast<uint16_t*>(p) = static_cast<uint16_t>(_mm_cvtsi128_si32(a)); }
|
||||
template <> void _mm_storeu_si<32>(void* p, __m128i a) { *static_cast<uint32_t*>(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 <typename Pixel, int vectorSize>
|
||||
__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 <int pixelsPerVector, int count>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& vec1, __m128i& vec2,
|
||||
const BYTE*& src, int& offset, int delta, std::integral_constant<int, count>)
|
||||
{
|
||||
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<pixelsPerVector>(vec1, vec2, src, offset, delta, std::integral_constant<int, count - 2>());
|
||||
}
|
||||
|
||||
template <int pixelsPerVector>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& vec1, __m128i& vec2,
|
||||
const BYTE*& src, int& offset, int delta, std::integral_constant<int, 1> /*count*/)
|
||||
{
|
||||
vec1 = _mm_insert_epi16(vec1, *(src + (offset >> 16)), (pixelsPerVector - 1) / 2);
|
||||
offset += delta;
|
||||
}
|
||||
|
||||
template <int pixelsPerVector>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& /*vec1*/, __m128i& /*vec2*/,
|
||||
const BYTE*& /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, 0> /*count*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <int pixelsPerVector>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& /*vec1*/, __m128i& /*vec2*/,
|
||||
const BYTE*& /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, -1> /*count*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <int pixelsPerVector, int count>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& vec,
|
||||
const BYTE* src, int& offset, int delta, std::integral_constant<int, count>)
|
||||
{
|
||||
__m128i vec2 = _mm_loadu_si<8>(src + (offset >> 16));
|
||||
offset += delta;
|
||||
loadSrcVectorRemainder<pixelsPerVector>(vec, vec2, src, offset, delta, std::integral_constant<int, count - 1>());
|
||||
vec2 = _mm_slli_si128(vec2, 1);
|
||||
vec = _mm_or_si128(vec, vec2);
|
||||
}
|
||||
|
||||
template <int pixelsPerVector, int count>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& vec,
|
||||
const WORD* src, int& offset, int delta, std::integral_constant<int, count>)
|
||||
{
|
||||
vec = _mm_insert_epi16(vec, *(src + (offset >> 16)), pixelsPerVector - count);
|
||||
offset += delta;
|
||||
loadSrcVectorRemainder<pixelsPerVector>(vec, src, offset, delta, std::integral_constant<int, count - 1>());
|
||||
}
|
||||
|
||||
template <int pixelsPerVector>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& /*vec*/,
|
||||
const WORD* /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, 0> /*count*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <int pixelsPerVector, int count>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& vec,
|
||||
const DWORD* src, int& offset, int delta, std::integral_constant<int, count>)
|
||||
{
|
||||
__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<pixelsPerVector>(vec, src, offset, delta, std::integral_constant<int, count - 1>());
|
||||
}
|
||||
|
||||
template <int pixelsPerVector>
|
||||
__forceinline void loadSrcVectorRemainder(__m128i& /*vec*/,
|
||||
const DWORD* /*src*/, int& /*offset*/, int /*delta*/, std::integral_constant<int, 0> /*count*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <int vectorSize, bool stretch, bool mirror, typename Pixel>
|
||||
__forceinline __m128i loadSrcVector(const Pixel*& src, int& offset, int delta)
|
||||
{
|
||||
const int pixelsPerVector = vectorSize / sizeof(Pixel);
|
||||
__m128i vec = _mm_loadu_si<sizeof(Pixel) * 8>(stretch ? src + (offset >> 16) : src);
|
||||
if (stretch)
|
||||
{
|
||||
offset += delta;
|
||||
loadSrcVectorRemainder<pixelsPerVector>(vec, src, offset, delta,
|
||||
std::integral_constant<int, pixelsPerVector - 1>());
|
||||
}
|
||||
else
|
||||
{
|
||||
vec = _mm_loadu_si<vectorSize * 8>(src);
|
||||
if (mirror)
|
||||
{
|
||||
vec = reverseVector<Pixel, vectorSize>(vec);
|
||||
src -= pixelsPerVector;
|
||||
}
|
||||
else
|
||||
{
|
||||
src += pixelsPerVector;
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
__forceinline __m128i compareColorKey(__m128i vec, DWORD colorKey)
|
||||
{
|
||||
__m128i colorKeyVec = _mm_set1_epi<sizeof(Pixel) * 8>(colorKey);
|
||||
if (4 == sizeof(Pixel))
|
||||
{
|
||||
__m128i colorKeyMask = _mm_set1_epi<sizeof(Pixel) * 8>(0x00FFFFFF);
|
||||
vec = _mm_and_si128(vec, colorKeyMask);
|
||||
}
|
||||
return _mm_cmpeq_epi<sizeof(Pixel) * 8>(vec, colorKeyVec);
|
||||
}
|
||||
|
||||
template <typename Pixel, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
__forceinline __m128i bltVector(__m128i dst, __m128i src, DWORD dstColorKey, DWORD srcColorKey)
|
||||
{
|
||||
if (useDstColorKey && useSrcColorKey)
|
||||
{
|
||||
__m128i maskDst = compareColorKey<Pixel>(dst, dstColorKey);
|
||||
__m128i maskSrc = compareColorKey<Pixel>(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<Pixel>(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<Pixel>(src, srcColorKey);
|
||||
dst = _mm_and_si128(mask, dst);
|
||||
src = _mm_andnot_si128(mask, src);
|
||||
return _mm_or_si128(dst, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
__forceinline void bltVector(Pixel*& dst, const Pixel*& src, int& offset, int delta,
|
||||
DWORD dstColorKey, DWORD srcColorKey)
|
||||
{
|
||||
__m128i s = loadSrcVector<vectorSize, stretch, mirror>(src, offset, delta);
|
||||
__m128i d = _mm_loadu_si<vectorSize * 8>(dst);
|
||||
d = bltVector<Pixel, mirror, useDstColorKey, useSrcColorKey>(d, s, dstColorKey, srcColorKey);
|
||||
_mm_storeu_si<vectorSize * 8>(dst, d);
|
||||
dst += vectorSize / sizeof(Pixel);
|
||||
}
|
||||
|
||||
template <int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey, typename Pixel>
|
||||
__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<Pixel, 16, stretch, mirror, useDstColorKey, useSrcColorKey>(
|
||||
dst, src, offset, delta, dstColorKey, srcColorKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (sizeof(Pixel) < vectorSize)
|
||||
{
|
||||
const DWORD remainder = width % pixelsPerVector;
|
||||
auto src1 = src;
|
||||
auto offset1 = offset;
|
||||
__m128i s1 = loadSrcVector<vectorSize, stretch, mirror>(src1, offset1, delta);
|
||||
if (stretch)
|
||||
{
|
||||
offset += remainder * delta;
|
||||
}
|
||||
else if (mirror)
|
||||
{
|
||||
src -= remainder;
|
||||
}
|
||||
else
|
||||
{
|
||||
src += remainder;
|
||||
}
|
||||
__m128i s2 = loadSrcVector<vectorSize, stretch, mirror>(src, offset, delta);
|
||||
__m128i d1 = _mm_loadu_si<vectorSize * 8>(dst);
|
||||
__m128i d2 = _mm_loadu_si<vectorSize * 8>(dst + remainder);
|
||||
d1 = bltVector<Pixel, mirror, useDstColorKey, useSrcColorKey>(d1, s1, dstColorKey, srcColorKey);
|
||||
_mm_storeu_si<vectorSize * 8>(dst, d1);
|
||||
d2 = bltVector<Pixel, mirror, useDstColorKey, useSrcColorKey>(d2, s2, dstColorKey, srcColorKey);
|
||||
_mm_storeu_si<vectorSize * 8>(dst + remainder, d2);
|
||||
}
|
||||
else
|
||||
{
|
||||
bltVector<Pixel, vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>(
|
||||
dst, src, offset, delta, dstColorKey, srcColorKey);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
__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<const WORD*>(dst) | (reinterpret_cast<const BYTE*>(dst)[2] << 16);
|
||||
const DWORD s = *reinterpret_cast<const WORD*>(src1) | (reinterpret_cast<const BYTE*>(src1)[2] << 16);
|
||||
const DWORD mask = static_cast<DWORD>(-static_cast<int>(
|
||||
(!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 <int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
__forceinline void bltVectorRow(UInt24* dst, const UInt24* src, DWORD width, int offset, int delta,
|
||||
DWORD dstColorKey, DWORD srcColorKey)
|
||||
{
|
||||
if (!stretch && !mirror && !useDstColorKey && !useSrcColorKey)
|
||||
{
|
||||
bltVectorRow<vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey, BYTE>(
|
||||
reinterpret_cast<BYTE*>(dst), reinterpret_cast<const BYTE*>(src),
|
||||
width * 3, offset, delta, dstColorKey, srcColorKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (2 == vectorSize)
|
||||
{
|
||||
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (4 == vectorSize)
|
||||
{
|
||||
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
|
||||
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
|
||||
return;
|
||||
}
|
||||
|
||||
for (DWORD i = width; i != 0; --i)
|
||||
{
|
||||
bltPixel<stretch, mirror, useDstColorKey, useSrcColorKey>(dst, src, offset, delta, dstColorKey, srcColorKey);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
__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,
|
||||
DWORD dstColorKey, DWORD srcColorKey)
|
||||
{
|
||||
if (3 != sizeof(Pixel) && !stretch && mirror)
|
||||
{
|
||||
src -= vectorSize - sizeof(Pixel);
|
||||
}
|
||||
|
||||
for (DWORD i = dstHeight; i != 0; --i)
|
||||
{
|
||||
bltVectorRow<vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>(
|
||||
reinterpret_cast<Pixel*>(dst),
|
||||
reinterpret_cast<const Pixel*>(src + (offsetY >> 16) * srcPitch),
|
||||
dstWidth, offsetX, deltaX, dstColorKey, srcColorKey);
|
||||
dst += dstPitch;
|
||||
offsetY += deltaY;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
__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 <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
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<Pixel, vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>(
|
||||
static_cast<BYTE*>(dst), dstPitch, dstWidth, dstHeight,
|
||||
static_cast<const BYTE*>(src), srcPitch, offsetX, deltaX, offsetY, deltaY, dstColorKey, srcColorKey);
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey>
|
||||
auto getVectorizedBltFunc()
|
||||
{
|
||||
return &vectorizedBltFunc<Pixel, vectorSize, stretch, mirror, useDstColorKey, useSrcColorKey>;
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch, bool mirror, bool useDstColorKey>
|
||||
auto getVectorizedBltFunc(bool useSrcColorKey)
|
||||
{
|
||||
return useSrcColorKey
|
||||
? getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, useDstColorKey, true>()
|
||||
: getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, useDstColorKey, false>();
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch, bool mirror>
|
||||
auto getVectorizedBltFunc(bool useDstColorKey, bool useSrcColorKey)
|
||||
{
|
||||
return useDstColorKey
|
||||
? getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, true>(useSrcColorKey)
|
||||
: getVectorizedBltFunc<Pixel, vectorSize, stretch, mirror, false>(useSrcColorKey);
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize, bool stretch>
|
||||
auto getVectorizedBltFunc(bool mirror, bool useDstColorKey, bool useSrcColorKey)
|
||||
{
|
||||
return mirror
|
||||
? getVectorizedBltFunc<Pixel, vectorSize, stretch, true>(useDstColorKey, useSrcColorKey)
|
||||
: getVectorizedBltFunc<Pixel, vectorSize, stretch, false>(useDstColorKey, useSrcColorKey);
|
||||
}
|
||||
|
||||
template <typename Pixel, int vectorSize>
|
||||
auto getVectorizedBltFunc(bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey)
|
||||
{
|
||||
return stretch
|
||||
? getVectorizedBltFunc<Pixel, vectorSize, true>(mirror, useDstColorKey, useSrcColorKey)
|
||||
: getVectorizedBltFunc<Pixel, vectorSize, false>(mirror, useDstColorKey, useSrcColorKey);
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
auto getVectorizedBltFunc(DWORD width, bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey)
|
||||
{
|
||||
if (width >= 16) return getVectorizedBltFunc<Pixel, 16>(stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
if (width >= 8) return getVectorizedBltFunc<Pixel, 8>(stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
if (width >= 4) return getVectorizedBltFunc<Pixel, 4>(stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
if (width >= 2) return getVectorizedBltFunc<Pixel, 2>(stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
return getVectorizedBltFunc<Pixel, 1>(stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
}
|
||||
|
||||
auto getVectorizedBltFunc(DWORD bytesPerPixel, DWORD width,
|
||||
bool stretch, bool mirror, bool useDstColorKey, bool useSrcColorKey)
|
||||
{
|
||||
switch (bytesPerPixel)
|
||||
{
|
||||
case 4: return getVectorizedBltFunc<DWORD>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
case 3: return getVectorizedBltFunc<UInt24>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
case 2: return getVectorizedBltFunc<WORD>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
default: return getVectorizedBltFunc<BYTE>(width, stretch, mirror, useDstColorKey, useSrcColorKey);
|
||||
}
|
||||
}
|
||||
|
||||
auto getVectorizedBltFuncs()
|
||||
{
|
||||
typename MultiDimArray<decltype(&vectorizedBltFunc<BYTE, 1, false, false, false, false>), 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<DWORD>(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<LONG>(dstWidth * bytesPerPixel), static_cast<LONG>(dstHeight) };
|
||||
RECT srcRect = { 0, 0, static_cast<LONG>(absSrcWidth * bytesPerPixel), static_cast<LONG>(absSrcHeight) };
|
||||
|
||||
srcRect.top = (src - dst) / static_cast<LONG>(pitch);
|
||||
srcRect.left = (src - dst) % static_cast<LONG>(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<BYTE> 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<int>(dstWidth - 1) * deltaX;
|
||||
deltaX = -deltaX;
|
||||
}
|
||||
if (mirrorUpDown)
|
||||
{
|
||||
offsetY += static_cast<int>(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<BYTE*>(dst), dstPitch, dstWidth, dstHeight,
|
||||
static_cast<const BYTE*>(src), srcPitch, srcWidth, srcHeight,
|
||||
bytesPerPixel, dstColorKey, srcColorKey);
|
||||
}
|
||||
}
|
||||
}
|
15
DDrawCompat/DDraw/Blitter.h
Normal file
15
DDrawCompat/DDraw/Blitter.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ namespace
|
||||
|
||||
auto srcSurface(CompatPtr<IDirectDrawSurface7>::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);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <initguid.h>
|
||||
|
||||
#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<IDirectDrawSurface7> dds, std::unique_ptr<Surface> privateData)
|
||||
@ -65,8 +83,9 @@ namespace DDraw
|
||||
if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData,
|
||||
privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER)))
|
||||
{
|
||||
CompatPtr<IUnknown> dd;
|
||||
dds.get().lpVtbl->GetDDInterface(&dds, reinterpret_cast<void**>(&dd.getRef()));
|
||||
CompatPtr<IUnknown> ddUnk;
|
||||
dds.get().lpVtbl->GetDDInterface(&dds, reinterpret_cast<void**>(&ddUnk.getRef()));
|
||||
CompatPtr<IDirectDraw7> 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<IDirectDraw>(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 <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
|
||||
HRESULT Surface::create(
|
||||
CompatRef<TDirectDraw> dd, TSurfaceDesc desc, TSurface*& surface, std::unique_ptr<Surface> 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<IDirectDrawSurface7>::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<TDirectDraw, TSurface>(dd, desc);
|
||||
if (privateData->m_lockSurface)
|
||||
{
|
||||
attach(*privateData->m_lockSurface, std::make_unique<Surface>(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<Surface>());
|
||||
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<Surface>(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<IDirectDrawSurface7>* Surface::getImpl<IDirectDrawSurface7>() const { return m_impl7.get(); }
|
||||
|
||||
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
|
||||
CompatPtr<IDirectDrawSurface7> Surface::createLockSurface(CompatRef<TDirectDraw> 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<TSurface> lockSurface;
|
||||
dd->CreateSurface(&dd, &desc, &lockSurface.getRef(), nullptr);
|
||||
return LOG_RESULT(lockSurface);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
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<IDirectDrawSurface7> lockSurface)
|
||||
{
|
||||
if (lockSurface)
|
||||
{
|
||||
auto resource = D3dDdi::Device::getResource(getDriverResourceHandle(*m_surface));
|
||||
if (resource)
|
||||
{
|
||||
resource->setLockResource(D3dDdi::Device::getResource(getDriverResourceHandle(*lockSurface)));
|
||||
resource->setRootSurface(m_rootSurface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace DDraw
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
virtual ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
Surface();
|
||||
Surface(Surface* rootSurface = nullptr);
|
||||
virtual ~Surface();
|
||||
|
||||
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
|
||||
@ -33,6 +33,9 @@ namespace DDraw
|
||||
template <typename TSurface>
|
||||
SurfaceImpl<TSurface>* getImpl() const;
|
||||
|
||||
void clearResources();
|
||||
void restore();
|
||||
|
||||
protected:
|
||||
static void attach(CompatRef<IDirectDrawSurface7> dds, std::unique_ptr<Surface> privateData);
|
||||
|
||||
@ -51,6 +54,16 @@ namespace DDraw
|
||||
template <typename TDirectDrawSurface>
|
||||
friend class SurfaceImpl2;
|
||||
|
||||
template <typename TDirectDraw, typename TSurface, typename TSurfaceDesc>
|
||||
CompatPtr<IDirectDrawSurface7> createLockSurface(CompatRef<TDirectDraw> dd, TSurfaceDesc desc);
|
||||
|
||||
void setResources(CompatWeakPtr<IDirectDrawSurface7> lockSurface);
|
||||
|
||||
DWORD m_refCount;
|
||||
Surface* m_rootSurface;
|
||||
CompatWeakPtr<IDirectDrawSurface7> m_surface;
|
||||
std::vector<Surface*> m_attachedSurfaces;
|
||||
CompatPtr<IDirectDrawSurface7> m_lockSurface;
|
||||
std::vector<CompatWeakPtr<IDirectDrawSurface7>> m_attachedLockSurfaces;
|
||||
};
|
||||
}
|
||||
|
@ -46,11 +46,6 @@ namespace DDraw
|
||||
HRESULT SurfaceImpl<TSurface>::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 <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::Restore(TSurface* This)
|
||||
{
|
||||
return s_origVtable.Restore(This);
|
||||
HRESULT result = s_origVtable.Restore(This);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
m_data->restore();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
|
@ -84,6 +84,7 @@
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
|
||||
@ -102,6 +103,7 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
|
||||
@ -120,6 +122,7 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
|
||||
@ -160,7 +163,6 @@
|
||||
<ClInclude Include="D3dDdi\Log\DeviceCallbacksLog.h" />
|
||||
<ClInclude Include="D3dDdi\Log\DeviceFuncsLog.h" />
|
||||
<ClInclude Include="D3dDdi\Log\KernelModeThunksLog.h" />
|
||||
<ClInclude Include="D3dDdi\RenderTargetResource.h" />
|
||||
<ClInclude Include="D3dDdi\Resource.h" />
|
||||
<ClInclude Include="D3dDdi\ScopedCriticalSection.h" />
|
||||
<ClInclude Include="D3dDdi\Visitors\AdapterCallbacksVisitor.h" />
|
||||
@ -168,6 +170,7 @@
|
||||
<ClInclude Include="D3dDdi\Visitors\DeviceCallbacksVisitor.h" />
|
||||
<ClInclude Include="D3dDdi\Visitors\DeviceFuncsVisitor.h" />
|
||||
<ClInclude Include="DDraw\ActivateAppHandler.h" />
|
||||
<ClInclude Include="DDraw\Blitter.h" />
|
||||
<ClInclude Include="DDraw\DirectDraw.h" />
|
||||
<ClInclude Include="DDraw\DirectDrawClipper.h" />
|
||||
<ClInclude Include="DDraw\DirectDrawGammaControl.h" />
|
||||
@ -237,10 +240,10 @@
|
||||
<ClCompile Include="D3dDdi\Log\DeviceCallbacksLog.cpp" />
|
||||
<ClCompile Include="D3dDdi\Log\DeviceFuncsLog.cpp" />
|
||||
<ClCompile Include="D3dDdi\Log\KernelModeThunksLog.cpp" />
|
||||
<ClCompile Include="D3dDdi\RenderTargetResource.cpp" />
|
||||
<ClCompile Include="D3dDdi\Resource.cpp" />
|
||||
<ClCompile Include="D3dDdi\ScopedCriticalSection.cpp" />
|
||||
<ClCompile Include="DDraw\ActivateAppHandler.cpp" />
|
||||
<ClCompile Include="DDraw\Blitter.cpp" />
|
||||
<ClCompile Include="DDraw\DirectDraw.cpp" />
|
||||
<ClCompile Include="DDraw\DirectDrawClipper.cpp" />
|
||||
<ClCompile Include="DDraw\DirectDrawGammaControl.cpp" />
|
||||
|
@ -300,9 +300,6 @@
|
||||
<ClInclude Include="DDraw\DirectDrawGammaControl.h">
|
||||
<Filter>Header Files\DDraw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3dDdi\RenderTargetResource.h">
|
||||
<Filter>Header Files\D3dDdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3dDdi\Device.h">
|
||||
<Filter>Header Files\D3dDdi</Filter>
|
||||
</ClInclude>
|
||||
@ -351,6 +348,9 @@
|
||||
<ClInclude Include="Common\HResultException.h">
|
||||
<Filter>Header Files\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DDraw\Blitter.h">
|
||||
<Filter>Header Files\DDraw</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -503,9 +503,6 @@
|
||||
<ClCompile Include="DDraw\DirectDrawGammaControl.cpp">
|
||||
<Filter>Source Files\DDraw</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3dDdi\RenderTargetResource.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3dDdi\Device.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</ClCompile>
|
||||
@ -533,6 +530,9 @@
|
||||
<ClCompile Include="D3dDdi\Resource.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DDraw\Blitter.cpp">
|
||||
<Filter>Source Files\DDraw</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Dll\DDrawCompat.def">
|
||||
|
@ -95,13 +95,13 @@ namespace
|
||||
CompatPtr<IDirectDrawClipper> 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;
|
||||
|
@ -143,7 +143,7 @@ namespace Gdi
|
||||
CompatPtr<IDirectDraw7> dd(ddUnk);
|
||||
|
||||
CompatPtr<IDirectDrawSurface7> surface;
|
||||
dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
|
||||
dd.get()->lpVtbl->CreateSurface(dd, &desc, &surface.getRef(), nullptr);
|
||||
return surface;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user