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

View File

@ -205,13 +205,19 @@ namespace D3dDdi
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);
}
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 ||
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)

View File

@ -24,14 +24,6 @@ namespace D3dDdi
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
{
CompatWeakPtr<IDirectDrawSurface7> surface;
@ -41,6 +33,14 @@ namespace D3dDdi
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);
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,
std::function<void(const DDSURFACEDESC2&)> initFunc);
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);
void release(Surface& surface);

View File

@ -176,16 +176,6 @@ namespace
D3dDdi::KernelModeThunks::setDcPaletteOverride(palette.data());
bltToPrimaryChain(*src);
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)

View File

@ -7,6 +7,7 @@
#include <Common/Log.h>
#include <Common/ScopedSrwLock.h>
#include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Cursor.h>
#include <Gdi/Dc.h>
@ -268,11 +269,9 @@ namespace
{
LOG_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,
(dwFlags & LWA_COLORKEY) ? crKey : CLR_INVALID,
(dwFlags & LWA_ALPHA) ? bAlpha : 255);
DDraw::RealPrimarySurface::scheduleUpdate();
}
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(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD event,
@ -393,7 +364,7 @@ namespace
case EVENT_OBJECT_HIDE:
if (OBJID_CURSOR == idObject && Gdi::Cursor::isEmulated())
{
Gdi::Cursor::setCursor(GetCursor());
Gdi::Cursor::setCursor(CALL_ORIG_FUNC(GetCursor)());
}
break;
@ -465,8 +436,6 @@ namespace Gdi
HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA);
HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW);
HOOK_FUNCTION(user32, SetWindowPos, setWindowPos);
HOOK_FUNCTION(user32, UpdateLayeredWindow, updateLayeredWindow);
HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);

View File

@ -31,8 +31,6 @@ namespace
Gdi::Region windowRegion;
Gdi::Region visibleRegion;
Gdi::Region invalidatedRegion;
COLORREF colorKey;
BYTE alpha;
bool isLayered;
bool isVisibleRegionChanged;
@ -42,8 +40,6 @@ namespace
, windowRect{}
, clientRect{}
, windowRegion(nullptr)
, colorKey(CLR_INVALID)
, alpha(255)
, isLayered(true)
, 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;
bool result = false;
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{
auto& window = **it;
if (!window.isLayered)
if (!window.isLayered || window.visibleRegion.isEmpty())
{
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)
{
const UINT D3DDDIFMT_UNKNOWN = 0;
const UINT D3DDDIFMT_X8R8G8B8 = 22;
D3dDdi::KernelModeThunks::setDcFormatOverride(D3DDDIFMT_X8R8G8B8);
dst->GetDC(&dst, &dstDc);
D3dDdi::KernelModeThunks::setDcFormatOverride(D3DDDIFMT_UNKNOWN);
dst->GetDC(dst, &dstDc);
if (!dstDc)
{
return;
return false;
}
}
result = true;
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);
auto colorKey = window.colorKey;
if (CLR_INVALID != colorKey)
COLORREF colorKey = 0;
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,
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey);
}
else
{
BLENDFUNCTION blend = {};
blend.SourceConstantAlpha = window.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);
if (flags & LWA_COLORKEY)
{
CALL_ORIG_FUNC(TransparentBlt)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey);
}
else
{
BLENDFUNCTION 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);
@ -505,8 +509,9 @@ namespace Gdi
if (dstDc)
{
SelectClipRgn(dstDc, nullptr);
dst->ReleaseDC(&dst, dstDc);
dst->ReleaseDC(dst, dstDc);
}
return result;
}
void updateAll()
@ -558,20 +563,5 @@ namespace Gdi
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 <Common/CompatWeakPtr.h>
#include <Common/CompatRef.h>
#include <Gdi/Region.h>
@ -14,8 +15,7 @@ namespace Gdi
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion);
void presentLayered(CompatRef<IDirectDrawSurface7> dst, POINT offset);
bool presentLayered(CompatWeakPtr<IDirectDrawSurface7> dst, const RECT& monitorRect);
void updateAll();
void updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha);
}
}