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

Handle mirroring and color keying via Direct3D

This commit is contained in:
narzoul 2021-12-18 11:42:34 +01:00
parent c1e654de7d
commit 436a8184bb
17 changed files with 334 additions and 238 deletions

View File

@ -190,9 +190,13 @@ namespace D3dDdi
switch (pData->Type)
{
case D3DDDICAPS_DDRAW:
static_cast<DDRAW_CAPS*>(pData->pData)->FxCaps =
DDRAW_FXCAPS_BLTMIRRORLEFTRIGHT | DDRAW_FXCAPS_BLTMIRRORUPDOWN;
{
auto& caps = *static_cast<DDRAW_CAPS*>(pData->pData);
caps.Caps |= DDRAW_CAPS_COLORKEY;
caps.CKeyCaps = DDRAW_CKEYCAPS_SRCBLT;
caps.FxCaps = DDRAW_FXCAPS_BLTMIRRORLEFTRIGHT | DDRAW_FXCAPS_BLTMIRRORUPDOWN;
break;
}
case D3DDDICAPS_GETD3D3CAPS:
{
@ -208,7 +212,7 @@ namespace D3dDdi
return result;
}
void Adapter::setRepository(LUID luid, const DDraw::DirectDraw::Repository& repository)
void Adapter::setRepository(LUID luid, CompatWeakPtr<IDirectDraw7> repository)
{
for (auto& adapter : s_adapters)
{

View File

@ -34,8 +34,7 @@ namespace D3dDdi
LUID getLuid() const { return m_luid; }
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> getMultisampleConfig(D3DDDIFORMAT format) const;
const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; }
CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository.repo; }
bool isSrcColorKeySupported() const { return m_repository.isSrcColorKeySupported; }
CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository; }
HRESULT pfnCloseAdapter();
HRESULT pfnCreateDevice(D3DDDIARG_CREATEDEVICE* pCreateData);
@ -43,7 +42,7 @@ namespace D3dDdi
static void add(const D3DDDIARG_OPENADAPTER& data) { s_adapters.emplace(data.hAdapter, data); }
static Adapter& get(HANDLE adapter) { return s_adapters.find(adapter)->second; }
static void setRepository(LUID luid, const DDraw::DirectDraw::Repository& repository);
static void setRepository(LUID luid, CompatWeakPtr<IDirectDraw7> repository);
private:
template <typename Data>
@ -58,7 +57,7 @@ namespace D3dDdi
UINT m_runtimeVersion;
UINT m_driverVersion;
LUID m_luid;
DDraw::DirectDraw::Repository m_repository;
CompatWeakPtr<IDirectDraw7> m_repository;
static std::map<HANDLE, Adapter> s_adapters;
static std::map<LUID, AdapterInfo> s_adapterInfos;

View File

@ -2,49 +2,33 @@
namespace
{
struct ArgbFormatInfo : D3dDdi::FormatInfo
struct RgbFormatInfo : D3dDdi::FormatInfo
{
ArgbFormatInfo(BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount)
: FormatInfo(alphaBitCount, redBitCount, greenBitCount, blueBitCount)
RgbFormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount)
: FormatInfo(unusedBitCount, alphaBitCount, redBitCount, greenBitCount, blueBitCount)
{
redPos = greenBitCount + blueBitCount;
greenPos = blueBitCount;
}
};
struct AbgrFormatInfo : D3dDdi::FormatInfo
struct BgrFormatInfo : D3dDdi::FormatInfo
{
AbgrFormatInfo(BYTE alphaBitCount, BYTE blueBitCount, BYTE greenBitCount, BYTE redBitCount)
: FormatInfo(alphaBitCount, redBitCount, greenBitCount, blueBitCount)
BgrFormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE blueBitCount, BYTE greenBitCount, BYTE redBitCount)
: FormatInfo(unusedBitCount, alphaBitCount, redBitCount, greenBitCount, blueBitCount)
{
bluePos = redBitCount + greenBitCount;
greenPos = redBitCount;
}
};
struct XrgbFormatInfo : ArgbFormatInfo
{
XrgbFormatInfo(BYTE unusedBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount)
: ArgbFormatInfo(0, redBitCount, greenBitCount, blueBitCount)
{
bytesPerPixel = (unusedBitCount + redBitCount + greenBitCount + blueBitCount + 7) / 8;
}
};
struct XbgrFormatInfo : AbgrFormatInfo
{
XbgrFormatInfo(BYTE unusedBitCount, BYTE blueBitCount, BYTE greenBitCount, BYTE redBitCount)
: AbgrFormatInfo(0, redBitCount, greenBitCount, blueBitCount)
{
bytesPerPixel = (unusedBitCount + redBitCount + greenBitCount + blueBitCount + 7) / 8;
bluePos = redBitCount + greenBitCount;
}
};
}
namespace D3dDdi
{
FormatInfo::FormatInfo(BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount)
: bytesPerPixel((alphaBitCount + redBitCount + greenBitCount + blueBitCount + 7) / 8)
FormatInfo::FormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount)
: bitsPerPixel(unusedBitCount + alphaBitCount + redBitCount + greenBitCount + blueBitCount)
, bytesPerPixel((bitsPerPixel + 7) / 8)
, unusedBitCount(unusedBitCount)
, alphaBitCount(alphaBitCount)
, alphaPos(redBitCount + greenBitCount + blueBitCount)
, redBitCount(redBitCount)
@ -83,29 +67,55 @@ namespace D3dDdi
{
switch (format)
{
case D3DDDIFMT_R3G3B2: return ArgbFormatInfo(0, 3, 3, 2);
case D3DDDIFMT_A8: return ArgbFormatInfo(8, 0, 0, 0);
case D3DDDIFMT_P8: return ArgbFormatInfo(0, 0, 0, 8);
case D3DDDIFMT_R8: return ArgbFormatInfo(0, 8, 0, 0);
case D3DDDIFMT_R3G3B2: return RgbFormatInfo(0, 0, 3, 3, 2);
case D3DDDIFMT_A8: return RgbFormatInfo(0, 8, 0, 0, 0);
case D3DDDIFMT_P8: return RgbFormatInfo(0, 0, 0, 0, 8);
case D3DDDIFMT_R8: return RgbFormatInfo(0, 0, 8, 0, 0);
case D3DDDIFMT_R5G6B5: return ArgbFormatInfo(0, 5, 6, 5);
case D3DDDIFMT_X1R5G5B5: return XrgbFormatInfo(1, 5, 5, 5);
case D3DDDIFMT_A1R5G5B5: return ArgbFormatInfo(1, 5, 5, 5);
case D3DDDIFMT_A4R4G4B4: return ArgbFormatInfo(4, 4, 4, 4);
case D3DDDIFMT_A8R3G3B2: return ArgbFormatInfo(8, 3, 3, 2);
case D3DDDIFMT_X4R4G4B4: return XrgbFormatInfo(4, 4, 4, 4);
case D3DDDIFMT_A8P8: return ArgbFormatInfo(8, 0, 0, 8);
case D3DDDIFMT_G8R8: return AbgrFormatInfo(0, 0, 8, 8);
case D3DDDIFMT_R5G6B5: return RgbFormatInfo(0, 0, 5, 6, 5);
case D3DDDIFMT_X1R5G5B5: return RgbFormatInfo(1, 0, 5, 5, 5);
case D3DDDIFMT_A1R5G5B5: return RgbFormatInfo(0, 1, 5, 5, 5);
case D3DDDIFMT_A4R4G4B4: return RgbFormatInfo(0, 4, 4, 4, 4);
case D3DDDIFMT_A8R3G3B2: return RgbFormatInfo(0, 8, 3, 3, 2);
case D3DDDIFMT_X4R4G4B4: return RgbFormatInfo(4, 0, 4, 4, 4);
case D3DDDIFMT_A8P8: return RgbFormatInfo(0, 8, 0, 0, 8);
case D3DDDIFMT_G8R8: return BgrFormatInfo(0, 0, 0, 8, 8);
case D3DDDIFMT_R8G8B8: return ArgbFormatInfo(0, 8, 8, 8);
case D3DDDIFMT_R8G8B8: return RgbFormatInfo(0, 0, 8, 8, 8);
case D3DDDIFMT_A8R8G8B8: return ArgbFormatInfo(8, 8, 8, 8);
case D3DDDIFMT_X8R8G8B8: return XrgbFormatInfo(8, 8, 8, 8);
case D3DDDIFMT_A8B8G8R8: return AbgrFormatInfo(8, 8, 8, 8);
case D3DDDIFMT_X8B8G8R8: return XbgrFormatInfo(8, 8, 8, 8);
case D3DDDIFMT_A8R8G8B8: return RgbFormatInfo(0, 8, 8, 8, 8);
case D3DDDIFMT_X8R8G8B8: return RgbFormatInfo(8, 0, 8, 8, 8);
case D3DDDIFMT_A8B8G8R8: return BgrFormatInfo(0, 8, 8, 8, 8);
case D3DDDIFMT_X8B8G8R8: return BgrFormatInfo(8, 0, 8, 8, 8);
default:
return FormatInfo();
}
}
DDPIXELFORMAT getPixelFormat(D3DDDIFORMAT format)
{
auto info = getFormatInfo(format);
if (0 == info.bytesPerPixel)
{
return {};
}
DDPIXELFORMAT pf = {};
pf.dwSize = sizeof(pf);
pf.dwRGBBitCount = info.bitsPerPixel;
if (0 != pf.dwRGBBitCount)
{
pf.dwFlags = DDPF_RGB;
pf.dwRBitMask = (0xFF >> (8 - info.redBitCount)) << info.redPos;
pf.dwGBitMask = (0xFF >> (8 - info.greenBitCount)) << info.greenPos;
pf.dwBBitMask = (0xFF >> (8 - info.blueBitCount)) << info.bluePos;
}
if (0 != info.alphaBitCount)
{
pf.dwFlags |= (0 == pf.dwFlags) ? DDPF_ALPHA : DDPF_ALPHAPIXELS;
pf.dwRGBAlphaBitMask = (0xFF >> (8 - info.alphaBitCount)) << info.alphaPos;
}
return pf;
}
}

View File

@ -7,7 +7,9 @@ namespace D3dDdi
{
struct FormatInfo
{
BYTE bitsPerPixel;
BYTE bytesPerPixel;
BYTE unusedBitCount;
BYTE alphaBitCount;
BYTE alphaPos;
BYTE redBitCount;
@ -17,9 +19,11 @@ namespace D3dDdi
BYTE blueBitCount;
BYTE bluePos;
FormatInfo(BYTE alphaBitCount = 0, BYTE redBitCount = 0, BYTE greenBitCount = 0, BYTE blueBitCount = 0);
FormatInfo(BYTE unusedBitCount = 0, BYTE alphaBitCount = 0,
BYTE redBitCount = 0, BYTE greenBitCount = 0, BYTE blueBitCount = 0);
};
D3DCOLOR colorConvert(const FormatInfo& dstFormatInfo, D3DCOLOR srcRgbaColor);
FormatInfo getFormatInfo(D3DDDIFORMAT format);
DDPIXELFORMAT getPixelFormat(D3DDDIFORMAT format);
}

View File

@ -172,6 +172,13 @@ namespace D3dDdi
Gdi::Cursor::setEmulated(false);
Gdi::Cursor::setMonitorClipRect({});
}
if (m_msaaSurface.surface || m_msaaResolvedSurface.surface)
{
auto& repo = SurfaceRepository::get(m_device.getAdapter());
repo.release(m_msaaSurface);
repo.release(m_msaaResolvedSurface);
}
}
HRESULT Resource::blt(D3DDDIARG_BLT data)
@ -319,25 +326,32 @@ namespace D3dDdi
HRESULT Resource::copySubResource(HANDLE dstResource, HANDLE srcResource, UINT subResourceIndex)
{
LOG_FUNC("Resource::copySubResource", dstResource, srcResource, subResourceIndex);
RECT rect = {};
rect.right = m_fixedData.pSurfList[subResourceIndex].Width;
rect.bottom = 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;
return copySubResourceRegion(dstResource, subResourceIndex, rect, srcResource, subResourceIndex, rect);
}
HRESULT result = m_device.getOrigVtable().pfnBlt(m_device, &data);
HRESULT Resource::copySubResourceRegion(HANDLE dst, UINT dstIndex, const RECT& dstRect,
HANDLE src, UINT srcIndex, const RECT& srcRect)
{
LOG_FUNC("Resource::copySubResourceRegion", dst, dstIndex, dstRect, src, srcIndex, srcRect);
D3DDDIARG_BLT data = {};
data.hDstResource = dst;
data.DstSubResourceIndex = dstIndex;
data.DstRect = dstRect;
data.hSrcResource = src;
data.SrcSubResourceIndex = srcIndex;
data.SrcRect = srcRect;
data.Flags.Point = 1;
HRESULT result = LOG_RESULT(m_device.getOrigVtable().pfnBlt(m_device, &data));
if (FAILED(result))
{
LOG_ONCE("ERROR: Resource::copySubResource failed: " << Compat::hex(result));
LOG_ONCE("ERROR: Resource::copySubResourceRegion failed: " << Compat::hex(result));
}
return LOG_RESULT(result);
return result;
}
void Resource::createGdiLockResource()
@ -373,6 +387,7 @@ namespace D3dDdi
flags.Value = g_resourceTypeFlags;
flags.RenderTarget = 0;
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool ||
m_isSurfaceRepoResource ||
0 == m_formatInfo.bytesPerPixel ||
0 != (m_fixedData.Flags.Value & flags.Value))
{
@ -642,15 +657,16 @@ namespace D3dDdi
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
}
void Resource::prepareForBltSrc(const D3DDDIARG_BLT& data)
Resource& Resource::prepareForBltSrc(const D3DDDIARG_BLT& data)
{
if (m_lockResource)
{
loadVidMemResource(data.SrcSubResourceIndex);
}
return *this;
}
void Resource::prepareForBltDst(D3DDDIARG_BLT& data)
Resource& Resource::prepareForBltDst(D3DDDIARG_BLT& data)
{
if (m_lockResource)
{
@ -659,12 +675,14 @@ namespace D3dDdi
data.hDstResource = *m_msaaSurface.resource;
clearUpToDateFlags(data.DstSubResourceIndex);
m_lockData[data.DstSubResourceIndex].isMsaaUpToDate = true;
return *m_msaaSurface.resource;
}
else if (m_lockData[data.DstSubResourceIndex].isMsaaResolvedUpToDate)
{
data.hDstResource = *m_msaaResolvedSurface.resource;
clearUpToDateFlags(data.DstSubResourceIndex);
m_lockData[data.DstSubResourceIndex].isMsaaResolvedUpToDate = true;
return *m_msaaResolvedSurface.resource;
}
else
{
@ -673,6 +691,7 @@ namespace D3dDdi
m_lockData[data.DstSubResourceIndex].isVidMemUpToDate = true;
}
}
return *this;
}
void Resource::prepareForCpuRead(UINT subResourceIndex)
@ -771,7 +790,7 @@ namespace D3dDdi
Config::Settings::DisplayFilter::POINT != presentationFilter)
{
const auto& si = srcResource->m_fixedData.pSurfList[0];
const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getRenderTarget(si.Width, si.Height));
const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getTempRenderTarget(si.Width, si.Height));
if (!dst.resource)
{
return E_OUTOFMEMORY;
@ -791,13 +810,7 @@ namespace D3dDdi
}
else
{
D3DDDIARG_BLT blt = {};
blt.hSrcResource = data.hSrcResource;
blt.SrcRect = data.SrcRect;
blt.hDstResource = *dst.resource;
blt.DstRect = data.SrcRect;
blt.Flags.Point = 1;
m_device.getOrigVtable().pfnBlt(m_device, &blt);
copySubResourceRegion(*dst.resource, 0, data.SrcRect, data.hSrcResource, 0, data.SrcRect);
}
if (isLayeredPresentNeeded)
@ -842,6 +855,97 @@ namespace D3dDdi
}
}
HRESULT Resource::shaderBlt(D3DDDIARG_BLT& data, Resource& srcResource)
{
LOG_FUNC("Resource::shaderBlt", data, srcResource);
auto& repo = SurfaceRepository::get(m_device.getAdapter());
Resource* srcRes = &srcResource.prepareForBltSrc(data);
UINT srcIndex = data.SrcSubResourceIndex;
RECT srcRect = data.SrcRect;
Resource* dstRes = &prepareForBltDst(data);
UINT dstIndex = data.DstSubResourceIndex;
RECT dstRect = data.DstRect;
if (!srcResource.m_fixedData.Flags.Texture)
{
DWORD width = data.SrcRect.right - data.SrcRect.left;
DWORD height = data.SrcRect.bottom - data.SrcRect.top;
auto& texture = repo.getTempTexture(width, height, getPixelFormat(srcResource.m_fixedData.Format));
if (!texture.resource)
{
return LOG_RESULT(E_OUTOFMEMORY);
}
srcRes = texture.resource;
srcIndex = 0;
srcRect = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
HRESULT result = copySubResourceRegion(*srcRes, srcIndex, srcRect,
data.hSrcResource, data.SrcSubResourceIndex, data.SrcRect);
if (FAILED(result))
{
return LOG_RESULT(result);
}
if (D3DDDIPOOL_SYSTEMMEM == srcResource.m_fixedData.Pool)
{
srcResource.notifyLock(data.SrcSubResourceIndex);
}
}
if (!m_fixedData.Flags.RenderTarget)
{
LONG width = data.DstRect.right - data.DstRect.left;
LONG height = data.DstRect.bottom - data.DstRect.top;
auto& rt = repo.getTempRenderTarget(width, height);
if (!rt.resource)
{
return LOG_RESULT(E_OUTOFMEMORY);
}
dstRes = rt.resource;
dstIndex = 0;
dstRect = { 0, 0, width, height };
if (data.Flags.SrcColorKey)
{
HRESULT result = copySubResourceRegion(*dstRes, dstIndex, dstRect,
data.hDstResource, data.DstSubResourceIndex, data.DstRect);
if (FAILED(result))
{
return LOG_RESULT(result);
}
}
}
if (data.Flags.MirrorLeftRight)
{
std::swap(srcRect.left, srcRect.right);
}
if (data.Flags.MirrorUpDown)
{
std::swap(srcRect.top, srcRect.bottom);
}
m_device.getShaderBlitter().textureBlt(*dstRes, dstIndex, dstRect, *srcRes, srcIndex, srcRect,
D3DTEXF_POINT, data.Flags.SrcColorKey ? &data.ColorKey : nullptr);
if (!m_fixedData.Flags.RenderTarget)
{
HRESULT result = copySubResourceRegion(data.hDstResource, data.DstSubResourceIndex, data.DstRect,
*dstRes, dstIndex, dstRect);
if (FAILED(result))
{
return LOG_RESULT(result);
}
}
return LOG_RESULT(S_OK);
}
HRESULT Resource::splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect)
{
LOG_FUNC("Resource::splitBlt", data, subResourceIndex, rect, otherRect);
@ -942,17 +1046,8 @@ namespace D3dDdi
auto now = Time::queryPerformanceCounter();
if (D3DDDIFMT_P8 != m_fixedData.Format)
{
if (data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown ||
(data.Flags.SrcColorKey && !m_device.getAdapter().isSrcColorKeySupported()))
{
dstLockData.qpcLastForcedLock = now;
srcLockData.qpcLastForcedLock = now;
}
else
{
isSysMemBltPreferred = dstLockData.isSysMemUpToDate &&
Time::qpcToMs(now - dstLockData.qpcLastForcedLock) <= Config::evictionTimeout;
}
isSysMemBltPreferred = dstLockData.isSysMemUpToDate &&
Time::qpcToMs(now - dstLockData.qpcLastForcedLock) <= Config::evictionTimeout;
}
if (isSysMemBltPreferred)
@ -983,8 +1078,18 @@ namespace D3dDdi
}
}
srcResource.prepareForBltSrc(data);
prepareForBltDst(data);
if (m_fixedData.Flags.RenderTarget || data.Flags.SrcColorKey || data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown)
{
if (SUCCEEDED(shaderBlt(data, srcResource)))
{
return S_OK;
}
}
else
{
srcResource.prepareForBltSrc(data);
prepareForBltDst(data);
}
HRESULT result = m_device.getOrigVtable().pfnBlt(m_device, &data);
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool)
@ -1060,9 +1165,8 @@ namespace D3dDdi
}
}
auto& surfaceRepo(SurfaceRepository::get(m_device.getAdapter()));
surfaceRepo.release(m_msaaSurface);
surfaceRepo.release(m_msaaResolvedSurface);
m_msaaSurface = {};
m_msaaResolvedSurface = {};
if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig)
{

View File

@ -34,8 +34,8 @@ namespace D3dDdi
HRESULT colorFill(D3DDDIARG_COLORFILL data);
void* getLockPtr(UINT subResourceIndex);
HRESULT lock(D3DDDIARG_LOCK& data);
void prepareForBltSrc(const D3DDDIARG_BLT& data);
void prepareForBltDst(D3DDDIARG_BLT& data);
Resource& prepareForBltSrc(const D3DDDIARG_BLT& data);
Resource& prepareForBltDst(D3DDDIARG_BLT& data);
void prepareForCpuRead(UINT subResourceIndex);
void prepareForCpuWrite(UINT subResourceIndex);
Resource& prepareForGpuRead(UINT subResourceIndex);
@ -74,6 +74,8 @@ namespace D3dDdi
void clearUpToDateFlags(UINT subResourceIndex);
void clipRect(UINT subResourceIndex, RECT& rect);
HRESULT copySubResource(HANDLE dstResource, HANDLE srcResource, UINT subResourceIndex);
HRESULT copySubResourceRegion(HANDLE dst, UINT dstIndex, const RECT& dstRect,
HANDLE src, UINT srcIndex, const RECT& srcRect);
void createGdiLockResource();
void createLockResource();
void createSysMemResource(const std::vector<D3DDDI_SURFACEINFO>& surfaceInfo);
@ -88,6 +90,7 @@ namespace D3dDdi
void loadVidMemResource(UINT subResourceIndex);
void notifyLock(UINT subResourceIndex);
HRESULT presentationBlt(D3DDDIARG_BLT data, Resource* srcResource);
HRESULT shaderBlt(D3DDDIARG_BLT& data, Resource& srcResource);
HRESULT splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect);
template <typename Arg>

View File

@ -26,18 +26,18 @@ namespace D3dDdi
}
void ShaderBlitter::blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, HANDLE pixelShader, UINT filter)
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
HANDLE pixelShader, UINT filter, const UINT* srcColorKey)
{
LOG_FUNC("ShaderBlitter::blt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcRect, pixelShader, filter);
static_cast<HANDLE>(srcResource), srcRect, srcSubResourceIndex, pixelShader, filter, srcColorKey);
if (!m_vertexShaderDecl || !pixelShader)
{
return;
}
const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0];
const auto& srcSurface = srcResource.getFixedDesc().pSurfList[srcSubResourceIndex];
auto& state = m_device.getState();
state.setTempRenderState({ D3DDDIRS_SCENECAPTURE, TRUE });
@ -45,7 +45,8 @@ namespace D3dDdi
state.setTempPixelShader(pixelShader);
state.setTempRenderTarget({ 0, dstResource, dstSubResourceIndex });
state.setTempDepthStencil({ nullptr });
state.setTempViewport({ 0, 0, dstSurface.Width, dstSurface.Height });
state.setTempViewport({ static_cast<DWORD>(dstRect.left), static_cast<DWORD>(dstRect.top),
static_cast<DWORD>(dstRect.right - dstRect.left), static_cast<DWORD>(dstRect.bottom - dstRect.top) });
state.setTempZRange({ 0, 1 });
state.setTempRenderState({ D3DDDIRS_ZENABLE, D3DZB_FALSE });
@ -56,7 +57,7 @@ namespace D3dDdi
state.setTempRenderState({ D3DDDIRS_DITHERENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_ALPHABLENDENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_FOGENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_COLORKEYENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_COLORKEYENABLE, nullptr != srcColorKey });
state.setTempRenderState({ D3DDDIRS_STENCILENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_CLIPPING, FALSE });
state.setTempRenderState({ D3DDDIRS_CLIPPLANEENABLE, 0 });
@ -65,6 +66,10 @@ namespace D3dDdi
state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, D3DTEXF_LINEAR == filter });
setTempTextureStage(0, srcResource, filter);
if (srcColorKey)
{
state.setTempTextureStageState({ 0, D3DDDITSS_TEXTURECOLORKEYVAL, *srcColorKey });
}
struct Vertex
{
@ -82,8 +87,8 @@ namespace D3dDdi
Vertex vertices[4] = {
{ dstRect.left - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.top / srcHeight },
{ dstRect.right - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.top / srcHeight },
{ dstRect.right - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.bottom / srcHeight },
{ dstRect.left - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.bottom / srcHeight }
{ dstRect.left - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.bottom / srcHeight },
{ dstRect.right - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.bottom / srcHeight }
};
state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, vertices);
@ -91,7 +96,7 @@ namespace D3dDdi
DeviceState::TempStateLock lock(state);
D3DDDIARG_DRAWPRIMITIVE dp = {};
dp.PrimitiveType = D3DPT_TRIANGLEFAN;
dp.PrimitiveType = D3DPT_TRIANGLESTRIP;
dp.VStart = 0;
dp.PrimitiveCount = 2;
m_device.pfnDrawPrimitive(&dp, nullptr);
@ -169,7 +174,8 @@ namespace D3dDdi
setTempTextureStage(1, *cur.maskTexture, D3DTEXF_POINT);
setTempTextureStage(2, *cur.colorTexture, D3DTEXF_POINT);
setTempTextureStage(3, *xorTexture, D3DTEXF_POINT);
blt(dstResource, dstSubResourceIndex, clippedDstRect, *cur.tempTexture, clippedSrcRect, m_psDrawCursor.get(), D3DTEXF_POINT);
blt(dstResource, dstSubResourceIndex, clippedDstRect, *cur.tempTexture, 0, clippedSrcRect,
m_psDrawCursor.get(), D3DTEXF_POINT);
}
void ShaderBlitter::genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
@ -177,7 +183,8 @@ namespace D3dDdi
{
if (100 == blurPercent)
{
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psTextureSampler.get(), D3DTEXF_LINEAR);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect,
m_psTextureSampler.get(), D3DTEXF_LINEAR);
return;
}
@ -195,7 +202,7 @@ namespace D3dDdi
} };
DeviceState::TempPixelShaderConst tempPsConst(m_device.getState(), { 0, registers.size() }, registers.data());
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR);
}
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
@ -231,7 +238,7 @@ namespace D3dDdi
const RECT srcRect = { 0, 0, static_cast<LONG>(srcSurface.Width), static_cast<LONG>(srcSurface.Height) };
setTempTextureStage(1, *paletteTexture, D3DTEXF_POINT);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT);
}
void ShaderBlitter::setTempTextureStage(UINT stage, HANDLE texture, UINT filter)
@ -246,4 +253,12 @@ namespace D3dDdi
state.setTempTextureStageState({ stage, D3DDDITSS_SRGBTEXTURE, D3DTEXF_LINEAR == filter });
state.setTempRenderState({ static_cast<D3DDDIRENDERSTATETYPE>(D3DDDIRS_WRAP0 + stage), 0 });
}
void ShaderBlitter::textureBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
UINT filter, const UINT* srcColorKey)
{
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect,
m_psTextureSampler.get(), filter, srcColorKey);
}
}

View File

@ -25,10 +25,14 @@ namespace D3dDdi
const Resource& srcResource, const RECT& srcRect, UINT blurPercent);
void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256]);
void textureBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
UINT filter, const UINT* srcColorKey = nullptr);
private:
void blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, HANDLE pixelShader, UINT filter);
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
HANDLE pixelShader, UINT filter, const UINT* srcColorKey = nullptr);
template <int N>
std::unique_ptr<void, ResourceDeleter> createPixelShader(const BYTE(&code)[N])

View File

@ -28,7 +28,7 @@ namespace D3dDdi
{
}
CompatWeakPtr<IDirectDrawSurface7> SurfaceRepository::createSurface(
CompatPtr<IDirectDrawSurface7> SurfaceRepository::createSurface(
DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount)
{
auto dd(m_adapter.getRepository());
@ -38,6 +38,7 @@ namespace D3dDdi
return nullptr;
}
m_releasedSurfaces.clear();
CompatPtr<IDirectDrawSurface7> surface;
DDSURFACEDESC2 desc = {};
@ -62,7 +63,7 @@ namespace D3dDdi
LOG_ONCE("ERROR: Failed to create repository surface: " << Compat::hex(result) << " " << desc);
return nullptr;
}
return surface.detach();
return surface;
}
SurfaceRepository& SurfaceRepository::get(const Adapter& adapter)
@ -108,8 +109,8 @@ namespace D3dDdi
if (isLost(m_cursorMaskTexture) || isLost(m_cursorColorTexture))
{
m_cursor = nullptr;
release(m_cursorMaskTexture);
release(m_cursorColorTexture);
m_cursorMaskTexture = {};
m_cursorColorTexture = {};
}
if (cursor != m_cursor)
@ -213,19 +214,13 @@ namespace D3dDdi
DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource;
}
const SurfaceRepository::Surface& SurfaceRepository::getRenderTarget(DWORD width, DWORD height)
{
return getSurface(m_renderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32),
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
}
SurfaceRepository::Surface& SurfaceRepository::getSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount)
{
if (surface.surface && (surface.width != width || surface.height != height ||
0 != memcmp(&surface.pixelFormat, &pf, sizeof(pf)) || isLost(surface)))
{
release(surface);
surface = {};
}
if (!surface.surface)
@ -244,6 +239,23 @@ namespace D3dDdi
return surface;
}
const SurfaceRepository::Surface& SurfaceRepository::getTempRenderTarget(DWORD width, DWORD height)
{
return getTempSurface(m_renderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32),
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
}
SurfaceRepository::Surface& SurfaceRepository::getTempSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount)
{
return getSurface(surface, max(width, surface.width), max(height, surface.height), pf, caps, surfaceCount);
}
const SurfaceRepository::Surface& SurfaceRepository::getTempTexture(DWORD width, DWORD height, const DDPIXELFORMAT& pf)
{
return getTempSurface(m_textures[pf], width, height, pf, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
}
bool SurfaceRepository::isLost(Surface& surface)
{
return !surface.surface || FAILED(surface.surface->IsLost(surface.surface));
@ -253,7 +265,7 @@ namespace D3dDdi
{
if (surface.surface)
{
surface.surface->Release(surface.surface);
m_releasedSurfaces.push_back(surface);
surface = {};
}
}

View File

@ -1,10 +1,12 @@
#pragma once
#include <functional>
#include <map>
#include <ddraw.h>
#include <Common/CompatWeakPtr.h>
#include <Common/CompatPtr.h>
#include <DDraw/Comparison.h>
namespace D3dDdi
{
@ -16,29 +18,32 @@ namespace D3dDdi
public:
struct Cursor
{
HCURSOR cursor;
SIZE size;
POINT hotspot;
Resource* maskTexture;
Resource* colorTexture;
Resource* tempTexture;
HCURSOR cursor = nullptr;
SIZE size = {};
POINT hotspot = {};
Resource* maskTexture = nullptr;
Resource* colorTexture = nullptr;
Resource* tempTexture = nullptr;
};
struct Surface
{
CompatWeakPtr<IDirectDrawSurface7> surface;
Resource* resource;
DWORD width;
DWORD height;
DDPIXELFORMAT pixelFormat;
CompatPtr<IDirectDrawSurface7> surface;
Resource* resource = nullptr;
DWORD width = 0;
DWORD height = 0;
DDPIXELFORMAT pixelFormat = {};
};
Cursor getCursor(HCURSOR cursor);
Resource* getLogicalXorTexture();
Resource* getPaletteTexture();
const Surface& getRenderTarget(DWORD width, DWORD height);
Surface& getSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount = 1);
const Surface& getTempRenderTarget(DWORD width, DWORD height);
Surface& getTempSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount = 1);
const Surface& getTempTexture(DWORD width, DWORD height, const DDPIXELFORMAT& pf);
void release(Surface& surface);
static SurfaceRepository& get(const Adapter& adapter);
@ -47,7 +52,7 @@ namespace D3dDdi
private:
SurfaceRepository(const Adapter& adapter);
CompatWeakPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height,
CompatPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount);
Resource* getBitmapResource(Surface& surface, HBITMAP bitmap, const RECT& rect, const DDPIXELFORMAT& pf, DWORD caps);
Resource* getInitializedResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps,
@ -64,6 +69,8 @@ namespace D3dDdi
Surface m_logicalXorTexture;
Surface m_paletteTexture;
Surface m_renderTarget;
std::map<DDPIXELFORMAT, Surface> m_textures;
std::vector<Surface> m_releasedSurfaces;
static bool s_inCreateSurface;
};

View File

@ -0,0 +1,11 @@
#pragma once
#include <Common/Comparison.h>
#include <ddraw.h>
inline auto toTuple(const DDPIXELFORMAT& pf)
{
return std::make_tuple(pf.dwFlags, pf.dwFourCC, pf.dwRGBBitCount,
pf.dwRBitMask, pf.dwGBitMask, pf.dwBBitMask, pf.dwRGBAlphaBitMask);
}

View File

@ -14,105 +14,6 @@
namespace
{
void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode);
bool checkSrcColorKeySupport(CompatRef<IDirectDraw7> dd)
{
DDCAPS caps = {};
caps.dwSize = sizeof(caps);
dd->GetCaps(&dd, &caps, nullptr);
if (!(caps.dwCaps & DDCAPS_COLORKEY) || !(caps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
{
logSrcColorKeySupportFailure("driver indicates no support", 0);
return false;
}
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.dwWidth = 2;
desc.dwHeight = 1;
desc.ddpfPixelFormat = DDraw::DirectDraw::getRgbPixelFormat(16);
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
CompatPtr<IDirectDrawSurface7> src;
HRESULT result = dd->CreateSurface(&dd, &desc, &src.getRef(), nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error creating source surface", result);
return false;
}
CompatPtr<IDirectDrawSurface7> dst;
result = dd->CreateSurface(&dd, &desc, &dst.getRef(), nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error creating destination surface", result);
return false;
}
result = src->Lock(src, nullptr, &desc, DDLOCK_WAIT, nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking source surface", result);
return false;
}
const UINT16 colorKey = 0xFA9F;
*static_cast<UINT32*>(desc.lpSurface) = colorKey;
src->Unlock(src, nullptr);
result = dst->Lock(dst, nullptr, &desc, DDLOCK_WAIT, nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking destination surface", result);
return false;
}
*static_cast<UINT32*>(desc.lpSurface) = 0xFFFFFFFF;
dst->Unlock(dst, nullptr);
DDBLTFX fx = {};
fx.dwSize = sizeof(fx);
fx.ddckSrcColorkey.dwColorSpaceLowValue = colorKey;
fx.ddckSrcColorkey.dwColorSpaceHighValue = colorKey;
result = dst->Blt(dst, nullptr, src, nullptr, DDBLT_KEYSRCOVERRIDE | DDBLT_WAIT, &fx);
if (FAILED(result))
{
logSrcColorKeySupportFailure("blt error", result);
return false;
}
result = dst->Lock(dst, nullptr, &desc, DDLOCK_WAIT, nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking destination resource after blt", result);
return false;
}
const UINT32 dstPixels = *static_cast<UINT32*>(desc.lpSurface);
dst->Unlock(dst, nullptr);
if (dstPixels != 0xFFFF)
{
logSrcColorKeySupportFailure("test result pattern is incorrect", dstPixels);
return false;
}
Compat::Log() << "Source color key support: yes";
return true;
}
void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode)
{
Compat::Log log;
log << "Source color key support: no (" << reason;
if (resultCode)
{
log << ": " << Compat::hex(resultCode);
}
log << ')';
}
template <typename TDirectDraw, typename TSurfaceDesc, typename TSurface>
HRESULT STDMETHODCALLTYPE CreateSurface(
@ -242,7 +143,7 @@ namespace DDraw
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd)
{
static std::map<LUID, Repository> repositories;
static std::map<LUID, CompatWeakPtr<IDirectDraw7>> repositories;
auto adapterInfo = D3dDdi::KernelModeThunks::getAdapterInfo(dd);
auto it = repositories.find(adapterInfo.luid);
if (it == repositories.end())
@ -254,7 +155,7 @@ namespace DDraw
return;
}
repo->SetCooperativeLevel(repo, nullptr, DDSCL_NORMAL);
it = repositories.insert({ adapterInfo.luid, { repo, checkSrcColorKeySupport(*repo) } }).first;
it = repositories.insert({ adapterInfo.luid, repo }).first;
repo.detach();
}
D3dDdi::Adapter::setRepository(adapterInfo.luid, it->second);

View File

@ -9,12 +9,6 @@ namespace DDraw
{
namespace DirectDraw
{
struct Repository
{
CompatWeakPtr<IDirectDraw7> repo;
bool isSrcColorKeySupported;
};
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);

View File

@ -3,6 +3,28 @@
#include <Common/Log.h>
#include <DDraw/Log.h>
std::ostream& operator<<(std::ostream& os, const DDBLTFX& fx)
{
return Compat::LogStruct(os)
<< Compat::hex(fx.dwDDFX)
<< Compat::hex(fx.dwROP)
<< Compat::hex(fx.dwDDROP)
<< fx.dwRotationAngle
<< Compat::hex(fx.dwFillColor)
<< fx.dwFillDepth
<< Compat::hex(fx.dwFillPixel)
<< fx.lpDDSPattern
<< fx.ddckDestColorkey
<< fx.ddckSrcColorkey;
}
std::ostream& operator<<(std::ostream& os, const DDCOLORKEY& ck)
{
return Compat::LogStruct(os)
<< Compat::hex(ck.dwColorSpaceLowValue)
<< Compat::hex(ck.dwColorSpaceHighValue);
}
std::ostream& operator<<(std::ostream& os, const DDSCAPS& caps)
{
return Compat::LogStruct(os)

View File

@ -4,6 +4,8 @@
#include <ddraw.h>
std::ostream& operator<<(std::ostream& os, const DDBLTFX& fx);
std::ostream& operator<<(std::ostream& os, const DDCOLORKEY& ck);
std::ostream& operator<<(std::ostream& os, const DDSCAPS& caps);
std::ostream& operator<<(std::ostream& os, const DDSCAPS2& caps);
std::ostream& operator<<(std::ostream& os, const DDPIXELFORMAT& pf);

View File

@ -252,6 +252,7 @@
<ClInclude Include="D3dDdi\Visitors\DeviceCallbacksVisitor.h" />
<ClInclude Include="D3dDdi\Visitors\DeviceFuncsVisitor.h" />
<ClInclude Include="DDraw\Blitter.h" />
<ClInclude Include="DDraw\Comparison.h" />
<ClInclude Include="DDraw\DirectDraw.h" />
<ClInclude Include="DDraw\DirectDrawClipper.h" />
<ClInclude Include="DDraw\DirectDrawGammaControl.h" />

View File

@ -504,6 +504,9 @@
<ClInclude Include="Config\Settings\RenderColorDepth.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="DDraw\Comparison.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">