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

Apply ResolutionScale to layered windows

This commit is contained in:
narzoul 2022-01-08 14:17:21 +01:00
parent 26261b5287
commit 7a84efc1da
15 changed files with 383 additions and 172 deletions

View File

@ -0,0 +1,43 @@
#include <Common/Rect.h>
namespace
{
template <typename Rect>
void transform(Rect& rect, const RECT& srcView, const RECT& dstView)
{
const LONG srcWidth = srcView.right - srcView.left;
const LONG srcHeight = srcView.bottom - srcView.top;
const LONG dstWidth = dstView.right - dstView.left;
const LONG dstHeight = dstView.bottom - dstView.top;
rect = {
(rect.left - srcView.left) * dstWidth / srcWidth + dstView.left,
(rect.top - srcView.top) * dstHeight / srcHeight + dstView.top,
(rect.right - srcView.left) * dstWidth / srcWidth + dstView.left,
(rect.bottom - srcView.top) * dstHeight / srcHeight + dstView.top
};
}
}
namespace Rect
{
RectF toRectF(const RECT& rect)
{
return {
static_cast<float>(rect.left),
static_cast<float>(rect.top),
static_cast<float>(rect.right),
static_cast<float>(rect.bottom)
};
}
void transform(RECT& rect, const RECT& srcView, const RECT& dstView)
{
::transform(rect, srcView, dstView);
}
void transform(RectF& rect, const RECT& srcView, const RECT& dstView)
{
::transform(rect, srcView, dstView);
}
}

18
DDrawCompat/Common/Rect.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <Windows.h>
struct RectF
{
float left;
float top;
float right;
float bottom;
};
namespace Rect
{
RectF toRectF(const RECT& rect);
void transform(RECT& rect, const RECT& srcView, const RECT& dstView);
void transform(RectF& rect, const RECT& srcView, const RECT& dstView);
}

View File

@ -3,6 +3,7 @@
#include <Common/Comparison.h>
#include <Common/HResultException.h>
#include <Common/Log.h>
#include <Common/Rect.h>
#include <Common/Time.h>
#include <Config/Config.h>
#include <D3dDdi/Adapter.h>
@ -15,6 +16,7 @@
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Surfaces/SurfaceImpl.h>
#include <Dll/Dll.h>
#include <Gdi/Cursor.h>
#include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h>
@ -438,6 +440,44 @@ namespace D3dDdi
#endif
}
bool Resource::downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight)
{
LONG newSrcWidth = (srcWidth + 1) / 2;
if (newSrcWidth <= dstWidth)
{
newSrcWidth = srcWidth;
}
LONG newSrcHeight = (srcHeight + 1) / 2;
if (newSrcHeight <= dstHeight)
{
newSrcHeight = srcHeight;
}
if (newSrcWidth == srcWidth && newSrcHeight == srcHeight)
{
return false;
}
auto& repo = SurfaceRepository::get(m_device.getAdapter());
auto newRt = &repo.getTempRenderTarget(newSrcWidth, newSrcHeight, 1);
if (newRt->resource == rt)
{
newRt = &repo.getTempRenderTarget(newSrcWidth, newSrcHeight, 0);
}
if (!newRt->resource)
{
return false;
}
m_device.getShaderBlitter().textureBlt(*newRt->resource, 0, { 0, 0, newSrcWidth, newSrcHeight },
*rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR);
rt = newRt->resource;
srcWidth = newSrcWidth;
srcHeight = newSrcHeight;
return true;
}
void Resource::fixResourceData()
{
if (m_fixedData.Flags.Primary)
@ -768,86 +808,127 @@ namespace D3dDdi
}
srcResource = &srcResource->prepareForGpuRead(0);
data.hSrcResource = *srcResource;
}
const bool isPalettized = D3DDDIFMT_P8 == srcResource->m_origData.Format;
LONG srcWidth = srcResource->m_fixedData.pSurfList[0].Width;
LONG srcHeight = srcResource->m_fixedData.pSurfList[0].Height;
data.SrcRect = { 0, 0, srcWidth, srcHeight };
data.DstRect = g_presentationRect;
auto& repo = SurfaceRepository::get(m_device.getAdapter());
const auto& rtSurface = repo.getTempRenderTarget(srcWidth, srcHeight);
auto rt = rtSurface.resource ? rtSurface.resource : this;
auto rtIndex = rtSurface.resource ? 0 : data.DstSubResourceIndex;
auto rtRect = rtSurface.resource ? data.SrcRect : data.DstRect;
if (D3DDDIFMT_P8 == srcResource->m_origData.Format)
{
auto entries(Gdi::Palette::getHardwarePalette());
RGBQUAD pal[256] = {};
for (UINT i = 0; i < 256; ++i)
{
pal[i].rgbRed = entries[i].peRed;
pal[i].rgbGreen = entries[i].peGreen;
pal[i].rgbBlue = entries[i].peBlue;
}
m_device.getShaderBlitter().palettizedBlt(*rt, rtIndex, rtRect, *srcResource, data.SrcRect, pal);
}
else
{
copySubResourceRegion(*rt, rtIndex, rtRect, *srcResource, 0, data.SrcRect);
}
presentLayeredWindows(*rt, rtIndex, rtRect);
const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo();
const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor;
const RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
const bool isLayeredPresentNeeded = Gdi::Window::presentLayered(nullptr, monitorRect);
const LONG srcWidth = srcResource->m_fixedData.pSurfList[0].Width;
const LONG srcHeight = srcResource->m_fixedData.pSurfList[0].Height;
data.SrcRect = { 0, 0, srcWidth, srcHeight };
UINT presentationFilter = Config::displayFilter.get();
UINT presentationFilterParam = Config::displayFilter.getParam();
if (Config::Settings::DisplayFilter::BILINEAR == presentationFilter &&
(g_presentationRect.right - g_presentationRect.left == srcWidth &&
g_presentationRect.bottom - g_presentationRect.top == srcHeight) ||
(0 == presentationFilterParam &&
0 == (g_presentationRect.right - g_presentationRect.left) % srcWidth &&
0 == (g_presentationRect.bottom - g_presentationRect.top) % srcHeight))
if (isCursorEmulated)
{
presentationFilter = Config::Settings::DisplayFilter::POINT;
m_device.getShaderBlitter().cursorBlt(*rt, rtIndex, rtRect, cursorInfo.hCursor, cursorInfo.ptScreenPos);
}
if (isPalettized || isCursorEmulated || isLayeredPresentNeeded ||
Config::Settings::DisplayFilter::POINT != presentationFilter)
if (!rtSurface.resource)
{
const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getTempRenderTarget(srcWidth, srcHeight));
if (!dst.resource)
{
return E_OUTOFMEMORY;
}
if (isPalettized)
{
auto entries(Gdi::Palette::getHardwarePalette());
RGBQUAD pal[256] = {};
for (UINT i = 0; i < 256; ++i)
{
pal[i].rgbRed = entries[i].peRed;
pal[i].rgbGreen = entries[i].peGreen;
pal[i].rgbBlue = entries[i].peBlue;
}
m_device.getShaderBlitter().palettizedBlt(*dst.resource, 0, *srcResource, pal);
}
else
{
copySubResourceRegion(*dst.resource, 0, data.SrcRect, data.hSrcResource, 0, data.SrcRect);
}
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(*dst.resource, 0, cursorInfo.hCursor, pos);
}
if (Config::Settings::DisplayFilter::BILINEAR == presentationFilter)
{
m_device.getShaderBlitter().genBilinearBlt(*this, data.DstSubResourceIndex, g_presentationRect,
*dst.resource, data.SrcRect, presentationFilterParam);
return S_OK;
}
data.hSrcResource = *dst.resource;
return S_OK;
}
data.DstRect = g_presentationRect;
data.Flags.Linear = 0;
if (Config::Settings::DisplayFilter::BILINEAR == Config::displayFilter.get())
{
const LONG dstWidth = data.DstRect.right - data.DstRect.left;
const LONG dstHeight = data.DstRect.bottom - data.DstRect.top;
while (downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight))
{
}
m_device.getShaderBlitter().genBilinearBlt(*this, data.DstSubResourceIndex, data.DstRect,
*rt, data.SrcRect, Config::displayFilter.getParam());
return S_OK;
}
data.hSrcResource = *rt;
data.SrcSubResourceIndex = 0;
data.Flags.Point = 1;
return m_device.getOrigVtable().pfnBlt(m_device, &data);
}
void Resource::presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect)
{
auto& blitter = m_device.getShaderBlitter();
auto& repo = SurfaceRepository::get(m_device.getAdapter());
RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
auto layeredWindows(Gdi::Window::getVisibleLayeredWindows());
for (auto& layeredWindow : layeredWindows)
{
RECT visibleRect = {};
IntersectRect(&visibleRect, &layeredWindow.rect, &monitorRect);
if (IsRectEmpty(&visibleRect))
{
continue;
}
RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left, visibleRect.bottom - visibleRect.top };
auto& windowSurface = repo.getTempSysMemSurface(srcRect.right, srcRect.bottom);
auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, getPixelFormat(D3DDDIFMT_A8R8G8B8));
if (!windowSurface.resource || !texture.resource)
{
continue;
}
HDC srcDc = GetWindowDC(layeredWindow.hwnd);
HDC dstDc = nullptr;
windowSurface.surface->GetDC(windowSurface.surface, &dstDc);
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right, srcRect.bottom, srcDc,
visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top, SRCCOPY);
windowSurface.surface->ReleaseDC(windowSurface.surface, dstDc);
ReleaseDC(layeredWindow.hwnd, srcDc);
copySubResourceRegion(*texture.resource, 0, srcRect, *windowSurface.resource, 0, srcRect);
texture.resource->notifyLock(0);
COLORREF colorKey = 0;
BYTE alpha = 0;
DWORD flags = 0;
GetLayeredWindowAttributes(layeredWindow.hwnd, &colorKey, &alpha, &flags);
if (flags & ULW_COLORKEY)
{
colorKey = ((colorKey & 0xFF) << 16) | (colorKey & 0xFF00) | ((colorKey & 0xFF0000) >> 16);
}
if (layeredWindow.region)
{
layeredWindow.region &= monitorRect;
layeredWindow.region.offset(-visibleRect.left, -visibleRect.top);
}
Rect::transform(visibleRect, monitorRect, dstRect);
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect, D3DTEXF_POINT,
(flags & ULW_COLORKEY) ? reinterpret_cast<UINT*>(&colorKey) : nullptr,
(flags & ULW_ALPHA) ? &alpha : nullptr,
layeredWindow.region);
}
}
void Resource::scaleRect(RECT& rect)
{
const LONG origWidth = m_fixedData.pSurfList[0].Width;
@ -1151,6 +1232,13 @@ namespace D3dDdi
SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface,
scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig),
DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount);
if (!m_msaaResolvedSurface.resource && m_msaaSurface.resource)
{
m_msaaSurface = {};
SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface,
scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig),
DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount);
}
}
}
}

View File

@ -83,6 +83,7 @@ namespace D3dDdi
void createGdiLockResource();
void createLockResource();
void createSysMemResource(const std::vector<D3DDDI_SURFACEINFO>& surfaceInfo);
bool downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight);
void fixResourceData();
D3DDDIFORMAT getFormatConfig();
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> getMultisampleConfig();
@ -95,6 +96,7 @@ namespace D3dDdi
void loadVidMemResource(UINT subResourceIndex);
void notifyLock(UINT subResourceIndex);
HRESULT presentationBlt(D3DDDIARG_BLT data, Resource* srcResource);
void presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect);
HRESULT shaderBlt(D3DDDIARG_BLT& data, Resource& srcResource);
HRESULT sysMemPreferredBlt(D3DDDIARG_BLT& data, Resource& srcResource);

View File

@ -1,9 +1,11 @@
#include <Common/Log.h>
#include <Common/Rect.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ShaderBlitter.h>
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Shaders/DrawCursor.h>
#include <Shaders/GenBilinear.h>
#include <Shaders/PaletteLookup.h>
@ -27,10 +29,11 @@ namespace D3dDdi
void ShaderBlitter::blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
HANDLE pixelShader, UINT filter, const UINT* srcColorKey)
HANDLE pixelShader, UINT filter, const UINT* srcColorKey, const BYTE* alpha, const Gdi::Region& srcRgn)
{
LOG_FUNC("ShaderBlitter::blt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcRect, srcSubResourceIndex, pixelShader, filter, srcColorKey);
static_cast<HANDLE>(srcResource), srcRect, srcSubResourceIndex, pixelShader, filter, srcColorKey,
alpha, static_cast<HRGN>(srcRgn));
if (!m_vertexShaderDecl || !pixelShader)
{
@ -40,6 +43,14 @@ namespace D3dDdi
const auto& srcSurface = srcResource.getFixedDesc().pSurfList[srcSubResourceIndex];
const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
bool srgb = false;
if (D3DTEXF_LINEAR == filter)
{
const auto& formatOps = m_device.getAdapter().getInfo().formatOps;
srgb = (formatOps.at(srcResource.getFixedDesc().Format).Operations & FORMATOP_SRGBREAD) &&
(formatOps.at(dstResource.getFixedDesc().Format).Operations & FORMATOP_SRGBWRITE);
}
auto& state = m_device.getState();
state.setTempRenderState({ D3DDDIRS_SCENECAPTURE, TRUE });
state.setTempVertexShaderDecl(m_vertexShaderDecl.get());
@ -55,7 +66,7 @@ namespace D3dDdi
state.setTempRenderState({ D3DDDIRS_ALPHATESTENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_CULLMODE, D3DCULL_NONE });
state.setTempRenderState({ D3DDDIRS_DITHERENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_ALPHABLENDENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_ALPHABLENDENABLE, nullptr != alpha });
state.setTempRenderState({ D3DDDIRS_FOGENABLE, FALSE });
state.setTempRenderState({ D3DDDIRS_COLORKEYENABLE, nullptr != srcColorKey });
state.setTempRenderState({ D3DDDIRS_STENCILENABLE, FALSE });
@ -63,39 +74,45 @@ namespace D3dDdi
state.setTempRenderState({ D3DDDIRS_CLIPPLANEENABLE, 0 });
state.setTempRenderState({ D3DDDIRS_MULTISAMPLEANTIALIAS, FALSE });
state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0xF });
state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, D3DTEXF_LINEAR == filter });
state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, srgb });
if (alpha)
{
const UINT D3DBLEND_BLENDFACTOR = 14;
const UINT D3DBLEND_INVBLENDFACTOR = 15;
state.setTempRenderState({ D3DDDIRS_SRCBLEND, D3DBLEND_BLENDFACTOR });
state.setTempRenderState({ D3DDDIRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR });
const D3DCOLOR blendFactor = (*alpha << 16) | (*alpha << 8) | *alpha;
state.setTempRenderState({ D3DDDIRS_BLENDFACTOR, blendFactor });
}
setTempTextureStage(0, srcResource, filter, srcColorKey);
struct Vertex
{
float x;
float y;
float z;
float rhw;
float tu;
float tv;
};
state.setTempTextureStageState({ 0, D3DDDITSS_SRGBTEXTURE, srgb });
const float srcWidth = static_cast<float>(srcSurface.Width);
const float srcHeight = static_cast<float>(srcSurface.Height);
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.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 }
};
Vertex vertices[4] = {};
state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, vertices);
DeviceState::TempStateLock lock(state);
D3DDDIARG_DRAWPRIMITIVE dp = {};
dp.PrimitiveType = D3DPT_TRIANGLESTRIP;
dp.VStart = 0;
dp.PrimitiveCount = 2;
m_device.pfnDrawPrimitive(&dp, nullptr);
if (srcRgn)
{
auto srcRects(srcRgn.getRects());
for (const auto& sr : srcRects)
{
RectF dr = Rect::toRectF(sr);
Rect::transform(dr, srcRect, dstRect);
drawRect(vertices, sr, dr, srcWidth, srcHeight);
}
}
else
{
drawRect(vertices, srcRect, Rect::toRectF(dstRect), srcWidth, srcHeight);
}
m_device.flushPrimitives();
}
@ -133,9 +150,10 @@ namespace D3dDdi
return { data.ShaderHandle, ResourceDeleter(m_device, m_device.getOrigVtable().pfnDeleteVertexShaderDecl) };
}
void ShaderBlitter::cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, HCURSOR cursor, POINT pt)
void ShaderBlitter::cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
HCURSOR cursor, POINT pt)
{
LOG_FUNC("ShaderBlitter::cursorBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, cursor, pt);
LOG_FUNC("ShaderBlitter::cursorBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect, cursor, pt);
auto& repo = SurfaceRepository::get(m_device.getAdapter());
auto cur = repo.getCursor(cursor);
@ -143,21 +161,21 @@ namespace D3dDdi
pt.x -= cur.hotspot.x;
pt.y -= cur.hotspot.y;
RECT dstRect = { pt.x, pt.y, pt.x + cur.size.cx, pt.y + cur.size.cy };
RECT srcRect = { pt.x, pt.y, pt.x + cur.size.cx, pt.y + cur.size.cy };
auto& dstDesc = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
RECT clippedDstRect = {};
clippedDstRect.right = dstDesc.Width;
clippedDstRect.bottom = dstDesc.Height;
IntersectRect(&clippedDstRect, &clippedDstRect, &dstRect);
RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
RECT clippedSrcRect = {};
IntersectRect(&clippedSrcRect, &srcRect, &monitorRect);
if (!cur.maskTexture || !cur.colorTexture || !cur.tempTexture || !xorTexture || IsRectEmpty(&clippedDstRect))
if (!cur.maskTexture || !cur.colorTexture || !cur.tempTexture || !xorTexture || IsRectEmpty(&clippedSrcRect))
{
return;
}
RECT clippedSrcRect = clippedDstRect;
OffsetRect(&clippedSrcRect, -dstRect.left, -dstRect.top);
RECT clippedDstRect = clippedSrcRect;
Rect::transform(clippedDstRect, monitorRect, dstRect);
OffsetRect(&clippedSrcRect, -srcRect.left, -srcRect.top);
D3DDDIARG_BLT data = {};
data.hSrcResource = dstResource;
@ -174,6 +192,20 @@ namespace D3dDdi
m_psDrawCursor.get(), D3DTEXF_POINT);
}
void ShaderBlitter::drawRect(Vertex(&vertices)[4], const RECT& srcRect, const RectF& dstRect, float srcWidth, float srcHeight)
{
vertices[0] = { dstRect.left - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.top / srcHeight };
vertices[1] = { dstRect.right - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.top / srcHeight };
vertices[2] = { dstRect.left - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.bottom / srcHeight };
vertices[3] = { dstRect.right - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.bottom / srcHeight };
D3DDDIARG_DRAWPRIMITIVE dp = {};
dp.PrimitiveType = D3DPT_TRIANGLESTRIP;
dp.VStart = 0;
dp.PrimitiveCount = 2;
m_device.pfnDrawPrimitive(&dp, nullptr);
}
void ShaderBlitter::genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, UINT blurPercent)
{
@ -201,11 +233,11 @@ namespace D3dDdi
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR);
}
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256])
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, RGBQUAD palette[256])
{
LOG_FUNC("ShaderBlitter::palettizedBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex,
static_cast<HANDLE>(srcResource), Compat::array(reinterpret_cast<void**>(palette), 256));
LOG_FUNC("ShaderBlitter::palettizedBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcRect, Compat::array(reinterpret_cast<void**>(palette), 256));
auto paletteTexture(SurfaceRepository::get(m_device.getAdapter()).getPaletteTexture());
if (!paletteTexture)
@ -228,11 +260,6 @@ namespace D3dDdi
unlock.hResource = *paletteTexture;
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0];
const RECT dstRect = { 0, 0, static_cast<LONG>(dstSurface.Width), static_cast<LONG>(dstSurface.Height) };
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, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT);
}
@ -246,15 +273,14 @@ namespace D3dDdi
state.setTempTextureStageState({ stage, D3DDDITSS_MAGFILTER, filter });
state.setTempTextureStageState({ stage, D3DDDITSS_MINFILTER, filter });
state.setTempTextureStageState({ stage, D3DDDITSS_MIPFILTER, D3DTEXF_NONE });
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)
UINT filter, const UINT* srcColorKey, const BYTE* alpha, const Gdi::Region& srcRgn)
{
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect,
m_psTextureSampler.get(), filter, srcColorKey);
m_psTextureSampler.get(), filter, srcColorKey, alpha, srcRgn);
}
}

View File

@ -5,6 +5,9 @@
#include <Windows.h>
#include <D3dDdi/ResourceDeleter.h>
#include <Gdi/Region.h>
struct RectF;
namespace D3dDdi
{
@ -20,19 +23,32 @@ namespace D3dDdi
ShaderBlitter& operator=(const ShaderBlitter&) = delete;
ShaderBlitter& operator=(ShaderBlitter&&) = delete;
void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, HCURSOR cursor, POINT pt);
void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
HCURSOR cursor, POINT pt);
void genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, UINT blurPercent);
void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256]);
void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, 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);
UINT filter, const UINT* srcColorKey = nullptr, const BYTE* alpha = nullptr,
const Gdi::Region& srcRgn = nullptr);
private:
struct Vertex
{
float x;
float y;
float z;
float rhw;
float tu;
float tv;
};
void blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
HANDLE pixelShader, UINT filter, const UINT* srcColorKey = nullptr);
HANDLE pixelShader, UINT filter, const UINT* srcColorKey = nullptr, const BYTE* alpha = nullptr,
const Gdi::Region& srcRgn = nullptr);
template <int N>
std::unique_ptr<void, ResourceDeleter> createPixelShader(const BYTE(&code)[N])
@ -42,6 +58,7 @@ namespace D3dDdi
std::unique_ptr<void, ResourceDeleter> createPixelShader(const BYTE* code, UINT size);
std::unique_ptr<void, ResourceDeleter> createVertexShaderDecl();
void drawRect(Vertex(&vertices)[4], const RECT& srcRect, const RectF& dstRect, float srcWidth, float srcHeight);
void setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey = nullptr);
Device& m_device;

View File

@ -239,9 +239,13 @@ namespace D3dDdi
return surface;
}
const SurfaceRepository::Surface& SurfaceRepository::getTempRenderTarget(DWORD width, DWORD height)
const SurfaceRepository::Surface& SurfaceRepository::getTempRenderTarget(DWORD width, DWORD height, UINT index)
{
return getTempSurface(m_renderTarget, width, height, getPixelFormat(D3DDDIFMT_A8R8G8B8),
if (index >= m_renderTargets.size())
{
m_renderTargets.resize(index + 1);
}
return getTempSurface(m_renderTargets[index], width, height, getPixelFormat(D3DDDIFMT_A8R8G8B8),
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
}
@ -251,6 +255,12 @@ namespace D3dDdi
return getSurface(surface, max(width, surface.width), max(height, surface.height), pf, caps, surfaceCount);
}
SurfaceRepository::Surface& SurfaceRepository::getTempSysMemSurface(DWORD width, DWORD height)
{
return getTempSurface(m_sysMemSurface, width, height, getPixelFormat(D3DDDIFMT_A8R8G8B8),
DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY);
}
const SurfaceRepository::Surface& SurfaceRepository::getTempTexture(DWORD width, DWORD height, const DDPIXELFORMAT& pf)
{
return getTempSurface(m_textures[pf], width, height, pf, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);

View File

@ -40,7 +40,8 @@ namespace D3dDdi
Resource* getPaletteTexture();
Surface& getSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount = 1);
const Surface& getTempRenderTarget(DWORD width, DWORD height);
const Surface& getTempRenderTarget(DWORD width, DWORD height, UINT index = 0);
Surface& getTempSysMemSurface(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);
@ -68,9 +69,10 @@ namespace D3dDdi
Surface m_cursorTempTexture;
Surface m_logicalXorTexture;
Surface m_paletteTexture;
Surface m_renderTarget;
std::vector<Surface> m_renderTargets;
std::map<DDPIXELFORMAT, Surface> m_textures;
std::vector<Surface> m_releasedSurfaces;
Surface m_sysMemSurface;
static bool s_inCreateSurface;
};

View File

@ -136,14 +136,10 @@ namespace
g_frontBuffer->GetSurfaceDesc(g_frontBuffer, &desc);
g_clipper.release();
CALL_ORIG_PROC(DirectDrawCreateClipper)(0, &g_clipper.getRef(), nullptr);
g_frontBuffer->SetClipper(g_frontBuffer, g_clipper);
const bool isFlippable = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP);
if (!isFlippable)
{
CALL_ORIG_PROC(DirectDrawCreateClipper)(0, &g_clipper.getRef(), nullptr);
g_frontBuffer->SetClipper(g_frontBuffer, g_clipper);
}
g_surfaceDesc = desc;
g_isFullscreen = isFlippable;
g_isUpdatePending = true;

View File

@ -201,6 +201,7 @@
<ClInclude Include="Common\HResultException.h" />
<ClInclude Include="Common\Log.h" />
<ClInclude Include="Common\Path.h" />
<ClInclude Include="Common\Rect.h" />
<ClInclude Include="Common\ScopedSrwLock.h" />
<ClInclude Include="Common\VtableHookVisitor.h" />
<ClInclude Include="Common\VtableSizeVisitor.h" />
@ -331,6 +332,7 @@
<ClCompile Include="Common\Log.cpp" />
<ClCompile Include="Common\Hook.cpp" />
<ClCompile Include="Common\Path.cpp" />
<ClCompile Include="Common\Rect.cpp" />
<ClCompile Include="Common\Time.cpp" />
<ClCompile Include="Config\Config.cpp" />
<ClCompile Include="Config\EnumSetting.cpp" />

View File

@ -510,6 +510,9 @@
<ClInclude Include="Config\Settings\ResolutionScale.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="Common\Rect.h">
<Filter>Header Files\Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -803,6 +806,9 @@
<ClCompile Include="Config\Settings\ResolutionScale.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
<ClCompile Include="Common\Rect.cpp">
<Filter>Source Files\Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">

View File

@ -73,6 +73,17 @@ namespace Gdi
SetRectRgn(m_region, 0, 0, 0, 0);
}
std::vector<RECT> Region::getRects() const
{
DWORD rgnSize = GetRegionData(m_region, 0, nullptr);
std::vector<unsigned char> rgnDataBuf(rgnSize);
auto rgnData = reinterpret_cast<RGNDATA*>(rgnDataBuf.data());
GetRegionData(m_region, rgnSize, rgnData);
auto rects = reinterpret_cast<RECT*>(rgnData->Buffer);
return { rects, rects + rgnData->rdh.nCount };
}
bool Region::isEmpty() const
{
return sizeof(RGNDATAHEADER) == GetRegionData(m_region, 0, nullptr);

View File

@ -1,6 +1,7 @@
#pragma once
#include <cstddef>
#include <vector>
#include <Windows.h>
@ -19,6 +20,7 @@ namespace Gdi
Region& operator=(Region other);
void clear();
std::vector<RECT> getRects() const;
bool isEmpty() const;
void offset(int x, int y);
HRGN release();

View File

@ -508,59 +508,40 @@ namespace Gdi
}
}
bool presentLayered(CompatWeakPtr<IDirectDrawSurface7> dst, const RECT& monitorRect)
std::vector<LayeredWindow> getVisibleLayeredWindows()
{
HDC dstDc = nullptr;
try
std::vector<LayeredWindow> layeredWindows;
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;
if (window.isLayered && !window.visibleRegion.isEmpty())
{
auto& window = **it;
if (!window.isLayered || window.visibleRegion.isEmpty())
{
continue;
}
Gdi::Region rgn(window.visibleRegion);
rgn &= monitorRect;
if (rgn.isEmpty())
{
continue;
}
presentLayeredWindow(dst, window.hwnd, window.windowRect, monitorRect, dstDc, &rgn, window.isMenu);
}
auto configWindow = PresentationWindow::getConfigWindow();
if (configWindow && configWindow->isVisible())
{
presentOverlayWindow(dst, configWindow->getWindow(), monitorRect, dstDc);
auto capture = Input::getCapture();
if (capture && capture != configWindow)
{
presentOverlayWindow(dst, capture->getWindow(), monitorRect, dstDc);
}
}
HWND cursorWindow = Input::getCursorWindow();
if (cursorWindow)
{
presentOverlayWindow(dst, cursorWindow, monitorRect, dstDc);
layeredWindows.push_back({ window.hwnd, window.windowRect, window.visibleRegion });
}
}
catch (bool result)
RECT wr = {};
auto configWindow = PresentationWindow::getConfigWindow();
if (configWindow && configWindow->isVisible())
{
return result;
GetWindowRect(configWindow->getWindow(), &wr);
layeredWindows.push_back({ configWindow->getWindow(), wr, nullptr });
auto capture = Input::getCapture();
if (capture && capture != configWindow)
{
GetWindowRect(capture->getWindow(), &wr);
layeredWindows.push_back({ capture->getWindow(), wr, nullptr });
}
}
if (dstDc)
HWND cursorWindow = Input::getCursorWindow();
if (cursorWindow)
{
SelectClipRgn(dstDc, nullptr);
dst->ReleaseDC(dst, dstDc);
GetWindowRect(cursorWindow, &wr);
layeredWindows.push_back({ cursorWindow, wr, nullptr });
}
return false;
return layeredWindows;
}
void updateAll()

View File

@ -10,12 +10,19 @@ namespace Gdi
{
namespace Window
{
struct LayeredWindow
{
HWND hwnd;
RECT rect;
Gdi::Region region;
};
std::vector<LayeredWindow> getVisibleLayeredWindows();
void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion);
bool presentLayered(CompatWeakPtr<IDirectDrawSurface7> dst, const RECT& monitorRect);
void updateAll();
}
}