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

Fixed presentation of layered windows in scaled fullscreen mode

This commit is contained in:
narzoul 2021-06-20 11:03:55 +02:00
parent ccc23c75b9
commit f7962f6e3b
7 changed files with 87 additions and 122 deletions

View File

@ -16,6 +16,7 @@
#include <Gdi/Cursor.h> #include <Gdi/Cursor.h>
#include <Gdi/Palette.h> #include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
namespace namespace
{ {
@ -537,15 +538,19 @@ namespace D3dDdi
srcResource->copyToVidMem(0); srcResource->copyToVidMem(0);
} }
const auto& si = srcResource->m_fixedData.pSurfList[0];
const bool isPalettized = D3DDDIFMT_P8 == srcResource->m_origData.Format; const bool isPalettized = D3DDDIFMT_P8 == srcResource->m_origData.Format;
const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo(); const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo();
const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor; const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor;
if (isPalettized || isCursorEmulated) const RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
const bool isLayeredPresentNeeded = Gdi::Window::presentLayered(nullptr, monitorRect);
if (isPalettized || isCursorEmulated || isLayeredPresentNeeded)
{ {
auto dst(SurfaceRepository::get(m_device.getAdapter()).getRenderTarget(si.Width, si.Height)); const auto& si = srcResource->m_fixedData.pSurfList[0];
if (!dst) const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getRenderTarget(si.Width, si.Height));
if (!dst.resource)
{ {
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
@ -560,28 +565,32 @@ namespace D3dDdi
pal[i].rgbGreen = entries[i].peGreen; pal[i].rgbGreen = entries[i].peGreen;
pal[i].rgbBlue = entries[i].peBlue; pal[i].rgbBlue = entries[i].peBlue;
} }
m_device.getShaderBlitter().palettizedBlt(*dst, 0, *srcResource, pal); m_device.getShaderBlitter().palettizedBlt(*dst.resource, 0, *srcResource, pal);
} }
else else
{ {
D3DDDIARG_BLT blt = {}; D3DDDIARG_BLT blt = {};
blt.hSrcResource = data.hSrcResource; blt.hSrcResource = data.hSrcResource;
blt.SrcRect = data.SrcRect; blt.SrcRect = data.SrcRect;
blt.hDstResource = *dst; blt.hDstResource = *dst.resource;
blt.DstRect = data.SrcRect; blt.DstRect = data.SrcRect;
blt.Flags.Point = 1; blt.Flags.Point = 1;
m_device.getOrigVtable().pfnBlt(m_device, &blt); m_device.getOrigVtable().pfnBlt(m_device, &blt);
} }
srcResource = dst; srcResource = dst.resource;
data.hSrcResource = *dst; data.hSrcResource = *dst.resource;
}
if (isCursorEmulated) if (isLayeredPresentNeeded)
{ {
RECT monitorRect = DDraw::PrimarySurface::getMonitorRect(); Gdi::Window::presentLayered(dst.surface, monitorRect);
POINT pos = { cursorInfo.ptScreenPos.x - monitorRect.left, cursorInfo.ptScreenPos.y - monitorRect.top }; }
m_device.getShaderBlitter().cursorBlt(*srcResource, 0, cursorInfo.hCursor, pos);
if (isCursorEmulated)
{
POINT pos = { cursorInfo.ptScreenPos.x - monitorRect.left, cursorInfo.ptScreenPos.y - monitorRect.top };
m_device.getShaderBlitter().cursorBlt(*srcResource, 0, cursorInfo.hCursor, pos);
}
} }
data.DstRect = g_presentationRect; data.DstRect = g_presentationRect;

View File

@ -205,13 +205,19 @@ namespace D3dDdi
DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY); DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
} }
Resource* SurfaceRepository::getRenderTarget(DWORD width, DWORD height) const SurfaceRepository::Surface& SurfaceRepository::getRenderTarget(DWORD width, DWORD height)
{ {
return getResource(m_renderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32), return getSurface(m_renderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32),
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY); DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
} }
Resource* SurfaceRepository::getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps) Resource* SurfaceRepository::getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps)
{
return getSurface(surface, width, height, pf, caps).resource;
}
SurfaceRepository::Surface& SurfaceRepository::getSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps)
{ {
if (surface.surface && (surface.width != width || surface.height != height || if (surface.surface && (surface.width != width || surface.height != height ||
0 != memcmp(&surface.pixelFormat, &pf, sizeof(pf)) || isLost(surface))) 0 != memcmp(&surface.pixelFormat, &pf, sizeof(pf)) || isLost(surface)))
@ -232,7 +238,7 @@ namespace D3dDdi
} }
} }
return surface.resource; return surface;
} }
bool SurfaceRepository::isLost(Surface& surface) bool SurfaceRepository::isLost(Surface& surface)

View File

@ -24,14 +24,6 @@ namespace D3dDdi
Resource* tempTexture; Resource* tempTexture;
}; };
Cursor getCursor(HCURSOR cursor);
Resource* getLogicalXorTexture();
Resource* getPaletteTexture();
Resource* getRenderTarget(DWORD width, DWORD height);
static SurfaceRepository& get(const Adapter& adapter);
private:
struct Surface struct Surface
{ {
CompatWeakPtr<IDirectDrawSurface7> surface; CompatWeakPtr<IDirectDrawSurface7> surface;
@ -41,6 +33,14 @@ namespace D3dDdi
DDPIXELFORMAT pixelFormat; DDPIXELFORMAT pixelFormat;
}; };
Cursor getCursor(HCURSOR cursor);
Resource* getLogicalXorTexture();
Resource* getPaletteTexture();
const Surface& getRenderTarget(DWORD width, DWORD height);
static SurfaceRepository& get(const Adapter& adapter);
private:
SurfaceRepository(const Adapter& adapter); SurfaceRepository(const Adapter& adapter);
CompatWeakPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps); CompatWeakPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
@ -48,6 +48,7 @@ namespace D3dDdi
Resource* getInitializedResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps, Resource* getInitializedResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps,
std::function<void(const DDSURFACEDESC2&)> initFunc); std::function<void(const DDSURFACEDESC2&)> initFunc);
Resource* getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps); Resource* getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
Surface& getSurface(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
bool isLost(Surface& surface); bool isLost(Surface& surface);
void release(Surface& surface); void release(Surface& surface);

View File

@ -176,16 +176,6 @@ namespace
D3dDdi::KernelModeThunks::setDcPaletteOverride(palette.data()); D3dDdi::KernelModeThunks::setDcPaletteOverride(palette.data());
bltToPrimaryChain(*src); bltToPrimaryChain(*src);
D3dDdi::KernelModeThunks::setDcPaletteOverride(nullptr); D3dDdi::KernelModeThunks::setDcPaletteOverride(nullptr);
if (g_isFullScreen && src == DDraw::PrimarySurface::getGdiSurface())
{
auto backBuffer(getBackBuffer());
if (backBuffer)
{
POINT offset = { -g_monitorRect.left, -g_monitorRect.top };
Gdi::Window::presentLayered(*backBuffer, offset);
}
}
} }
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval) void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval)

View File

@ -7,6 +7,7 @@
#include <Common/Log.h> #include <Common/Log.h>
#include <Common/ScopedSrwLock.h> #include <Common/ScopedSrwLock.h>
#include <Dll/Dll.h> #include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/CompatDc.h> #include <Gdi/CompatDc.h>
#include <Gdi/Cursor.h> #include <Gdi/Cursor.h>
#include <Gdi/Dc.h> #include <Gdi/Dc.h>
@ -268,11 +269,9 @@ namespace
{ {
LOG_FUNC("SetLayeredWindowAttributes", hwnd, crKey, bAlpha, dwFlags); LOG_FUNC("SetLayeredWindowAttributes", hwnd, crKey, bAlpha, dwFlags);
BOOL result = CALL_ORIG_FUNC(SetLayeredWindowAttributes)(hwnd, crKey, bAlpha, dwFlags); BOOL result = CALL_ORIG_FUNC(SetLayeredWindowAttributes)(hwnd, crKey, bAlpha, dwFlags);
if (result) if (result && DDraw::RealPrimarySurface::isFullScreen())
{ {
Gdi::Window::updateLayeredWindowInfo(hwnd, DDraw::RealPrimarySurface::scheduleUpdate();
(dwFlags & LWA_COLORKEY) ? crKey : CLR_INVALID,
(dwFlags & LWA_ALPHA) ? bAlpha : 255);
} }
return LOG_RESULT(result); return LOG_RESULT(result);
} }
@ -340,34 +339,6 @@ namespace
} }
} }
BOOL WINAPI updateLayeredWindow(HWND hWnd, HDC hdcDst, POINT* pptDst, SIZE* psize,
HDC hdcSrc, POINT* pptSrc, COLORREF crKey, BLENDFUNCTION* pblend, DWORD dwFlags)
{
LOG_FUNC("UpdateLayeredWindow", hWnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
BOOL result = CALL_ORIG_FUNC(UpdateLayeredWindow)(
hWnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
if (result && hdcSrc)
{
Gdi::Window::updateLayeredWindowInfo(hWnd,
(dwFlags & ULW_COLORKEY) ? crKey : CLR_INVALID,
((dwFlags & LWA_ALPHA) && pblend) ? pblend->SourceConstantAlpha : 255);
}
return LOG_RESULT(result);
}
BOOL WINAPI updateLayeredWindowIndirect(HWND hwnd, const UPDATELAYEREDWINDOWINFO* pULWInfo)
{
LOG_FUNC("UpdateLayeredWindowIndirect", hwnd, pULWInfo);
BOOL result = CALL_ORIG_FUNC(UpdateLayeredWindowIndirect)(hwnd, pULWInfo);
if (result && pULWInfo)
{
Gdi::Window::updateLayeredWindowInfo(hwnd,
(pULWInfo->dwFlags & ULW_COLORKEY) ? pULWInfo->crKey : CLR_INVALID,
((pULWInfo->dwFlags & LWA_ALPHA) && pULWInfo->pblend) ? pULWInfo->pblend->SourceConstantAlpha : 255);
}
return LOG_RESULT(result);
}
void CALLBACK winEventProc( void CALLBACK winEventProc(
HWINEVENTHOOK /*hWinEventHook*/, HWINEVENTHOOK /*hWinEventHook*/,
DWORD event, DWORD event,
@ -393,7 +364,7 @@ namespace
case EVENT_OBJECT_HIDE: case EVENT_OBJECT_HIDE:
if (OBJID_CURSOR == idObject && Gdi::Cursor::isEmulated()) if (OBJID_CURSOR == idObject && Gdi::Cursor::isEmulated())
{ {
Gdi::Cursor::setCursor(GetCursor()); Gdi::Cursor::setCursor(CALL_ORIG_FUNC(GetCursor)());
} }
break; break;
@ -465,8 +436,6 @@ namespace Gdi
HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA); HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA);
HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW); HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW);
HOOK_FUNCTION(user32, SetWindowPos, setWindowPos); HOOK_FUNCTION(user32, SetWindowPos, setWindowPos);
HOOK_FUNCTION(user32, UpdateLayeredWindow, updateLayeredWindow);
HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);

View File

@ -31,8 +31,6 @@ namespace
Gdi::Region windowRegion; Gdi::Region windowRegion;
Gdi::Region visibleRegion; Gdi::Region visibleRegion;
Gdi::Region invalidatedRegion; Gdi::Region invalidatedRegion;
COLORREF colorKey;
BYTE alpha;
bool isLayered; bool isLayered;
bool isVisibleRegionChanged; bool isVisibleRegionChanged;
@ -42,8 +40,6 @@ namespace
, windowRect{} , windowRect{}
, clientRect{} , clientRect{}
, windowRegion(nullptr) , windowRegion(nullptr)
, colorKey(CLR_INVALID)
, alpha(255)
, isLayered(true) , isLayered(true)
, isVisibleRegionChanged(false) , isVisibleRegionChanged(false)
{ {
@ -447,56 +443,64 @@ namespace Gdi
} }
} }
void presentLayered(CompatRef<IDirectDrawSurface7> dst, POINT offset) bool presentLayered(CompatWeakPtr<IDirectDrawSurface7> dst, const RECT& monitorRect)
{ {
D3dDdi::ScopedCriticalSection lock;
HDC dstDc = nullptr; HDC dstDc = nullptr;
bool result = false;
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it) for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{ {
auto& window = **it; auto& window = **it;
if (!window.isLayered) if (!window.isLayered || window.visibleRegion.isEmpty())
{ {
continue; continue;
} }
Gdi::Region rgn(window.visibleRegion);
rgn &= monitorRect;
if (rgn.isEmpty())
{
continue;
}
RECT wr = window.windowRect;
OffsetRect(&wr, -monitorRect.left, -monitorRect.top);
rgn.offset(-monitorRect.left, -monitorRect.top);
if (!dst)
{
return true;
}
if (!dstDc) if (!dstDc)
{ {
const UINT D3DDDIFMT_UNKNOWN = 0; dst->GetDC(dst, &dstDc);
const UINT D3DDDIFMT_X8R8G8B8 = 22;
D3dDdi::KernelModeThunks::setDcFormatOverride(D3DDDIFMT_X8R8G8B8);
dst->GetDC(&dst, &dstDc);
D3dDdi::KernelModeThunks::setDcFormatOverride(D3DDDIFMT_UNKNOWN);
if (!dstDc) if (!dstDc)
{ {
return; return false;
} }
} }
result = true;
HDC windowDc = GetWindowDC(window.hwnd); HDC windowDc = GetWindowDC(window.hwnd);
Gdi::Region rgn(window.visibleRegion);
RECT wr = window.windowRect;
if (0 != offset.x || 0 != offset.y)
{
OffsetRect(&wr, offset.x, offset.y);
rgn.offset(offset.x, offset.y);
}
SelectClipRgn(dstDc, rgn); SelectClipRgn(dstDc, rgn);
auto colorKey = window.colorKey; COLORREF colorKey = 0;
if (CLR_INVALID != colorKey) BYTE alpha = 0;
DWORD flags = 0;
if (CALL_ORIG_FUNC(GetLayeredWindowAttributes)(window.hwnd, &colorKey, &alpha, &flags))
{ {
CALL_ORIG_FUNC(TransparentBlt)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top, if (flags & LWA_COLORKEY)
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey); {
} CALL_ORIG_FUNC(TransparentBlt)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
else windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey);
{ }
BLENDFUNCTION blend = {}; else
blend.SourceConstantAlpha = window.alpha; {
CALL_ORIG_FUNC(AlphaBlend)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top, BLENDFUNCTION blend = {};
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, blend); blend.SourceConstantAlpha = alpha;
CALL_ORIG_FUNC(AlphaBlend)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, blend);
}
} }
CALL_ORIG_FUNC(ReleaseDC)(window.hwnd, windowDc); CALL_ORIG_FUNC(ReleaseDC)(window.hwnd, windowDc);
@ -505,8 +509,9 @@ namespace Gdi
if (dstDc) if (dstDc)
{ {
SelectClipRgn(dstDc, nullptr); SelectClipRgn(dstDc, nullptr);
dst->ReleaseDC(&dst, dstDc); dst->ReleaseDC(dst, dstDc);
} }
return result;
} }
void updateAll() void updateAll()
@ -558,20 +563,5 @@ namespace Gdi
SendNotifyMessage(hwnd, WM_SYNCPAINT, 0, 0); SendNotifyMessage(hwnd, WM_SYNCPAINT, 0, 0);
} }
} }
void updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha)
{
D3dDdi::ScopedCriticalSection lock;
auto it = g_windows.find(hwnd);
if (it != g_windows.end())
{
it->second.colorKey = colorKey;
it->second.alpha = alpha;
if (!it->second.visibleRegion.isEmpty())
{
DDraw::RealPrimarySurface::scheduleUpdate();
}
}
}
} }
} }

View File

@ -2,6 +2,7 @@
#include <ddraw.h> #include <ddraw.h>
#include <Common/CompatWeakPtr.h>
#include <Common/CompatRef.h> #include <Common/CompatRef.h>
#include <Gdi/Region.h> #include <Gdi/Region.h>
@ -14,8 +15,7 @@ namespace Gdi
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src, void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper); CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion); void present(Gdi::Region excludeRegion);
void presentLayered(CompatRef<IDirectDrawSurface7> dst, POINT offset); bool presentLayered(CompatWeakPtr<IDirectDrawSurface7> dst, const RECT& monitorRect);
void updateAll(); void updateAll();
void updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha);
} }
} }