diff --git a/DDrawCompat/Common/Rect.cpp b/DDrawCompat/Common/Rect.cpp new file mode 100644 index 0000000..e4bbe49 --- /dev/null +++ b/DDrawCompat/Common/Rect.cpp @@ -0,0 +1,43 @@ +#include + +namespace +{ + template + 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(rect.left), + static_cast(rect.top), + static_cast(rect.right), + static_cast(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); + } +} diff --git a/DDrawCompat/Common/Rect.h b/DDrawCompat/Common/Rect.h new file mode 100644 index 0000000..24ff8a9 --- /dev/null +++ b/DDrawCompat/Common/Rect.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +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); +} diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 19e5749..fa4e517 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -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(&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); + } } } } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index a684016..91e3d6b 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -83,6 +83,7 @@ namespace D3dDdi void createGdiLockResource(); void createLockResource(); void createSysMemResource(const std::vector& surfaceInfo); + bool downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight); void fixResourceData(); D3DDDIFORMAT getFormatConfig(); std::pair 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); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 56a0b6a..0127314 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -1,9 +1,11 @@ #include +#include #include #include #include #include #include +#include #include #include #include @@ -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(dstResource), dstSubResourceIndex, dstRect, - static_cast(srcResource), srcRect, srcSubResourceIndex, pixelShader, filter, srcColorKey); + static_cast(srcResource), srcRect, srcSubResourceIndex, pixelShader, filter, srcColorKey, + alpha, static_cast(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(srcSurface.Width); const float srcHeight = static_cast(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(dstResource), dstSubResourceIndex, cursor, pt); + LOG_FUNC("ShaderBlitter::cursorBlt", static_cast(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(dstResource), dstSubResourceIndex, - static_cast(srcResource), Compat::array(reinterpret_cast(palette), 256)); + LOG_FUNC("ShaderBlitter::palettizedBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcRect, Compat::array(reinterpret_cast(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(dstSurface.Width), static_cast(dstSurface.Height) }; - const RECT srcRect = { 0, 0, static_cast(srcSurface.Width), static_cast(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(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); } } diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index be7a103..971b514 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -5,6 +5,9 @@ #include #include +#include + +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 std::unique_ptr createPixelShader(const BYTE(&code)[N]) @@ -42,6 +58,7 @@ namespace D3dDdi std::unique_ptr createPixelShader(const BYTE* code, UINT size); std::unique_ptr 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; diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 49562ea..03586ff 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -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); diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index e7252c1..186c630 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -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 m_renderTargets; std::map m_textures; std::vector m_releasedSurfaces; + Surface m_sysMemSurface; static bool s_inCreateSurface; }; diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index ab5389d..3fa48e3 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -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; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index ebd394b..c44216c 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -201,6 +201,7 @@ + @@ -331,6 +332,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 64e6d06..35f0bda 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -510,6 +510,9 @@ Header Files\Config\Settings + + Header Files\Common + @@ -803,6 +806,9 @@ Source Files\Config\Settings + + Source Files\Common + diff --git a/DDrawCompat/Gdi/Region.cpp b/DDrawCompat/Gdi/Region.cpp index 71cd291..e81b770 100644 --- a/DDrawCompat/Gdi/Region.cpp +++ b/DDrawCompat/Gdi/Region.cpp @@ -73,6 +73,17 @@ namespace Gdi SetRectRgn(m_region, 0, 0, 0, 0); } + std::vector Region::getRects() const + { + DWORD rgnSize = GetRegionData(m_region, 0, nullptr); + std::vector rgnDataBuf(rgnSize); + auto rgnData = reinterpret_cast(rgnDataBuf.data()); + + GetRegionData(m_region, rgnSize, rgnData); + auto rects = reinterpret_cast(rgnData->Buffer); + return { rects, rects + rgnData->rdh.nCount }; + } + bool Region::isEmpty() const { return sizeof(RGNDATAHEADER) == GetRegionData(m_region, 0, nullptr); diff --git a/DDrawCompat/Gdi/Region.h b/DDrawCompat/Gdi/Region.h index 7addbc4..b78febe 100644 --- a/DDrawCompat/Gdi/Region.h +++ b/DDrawCompat/Gdi/Region.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -19,6 +20,7 @@ namespace Gdi Region& operator=(Region other); void clear(); + std::vector getRects() const; bool isEmpty() const; void offset(int x, int y); HRGN release(); diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 29ccfb3..32bf343 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -508,59 +508,40 @@ namespace Gdi } } - bool presentLayered(CompatWeakPtr dst, const RECT& monitorRect) + std::vector getVisibleLayeredWindows() { - HDC dstDc = nullptr; - - try + std::vector 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() diff --git a/DDrawCompat/Gdi/Window.h b/DDrawCompat/Gdi/Window.h index 2a4cfe2..b18f163 100644 --- a/DDrawCompat/Gdi/Window.h +++ b/DDrawCompat/Gdi/Window.h @@ -10,12 +10,19 @@ namespace Gdi { namespace Window { + struct LayeredWindow + { + HWND hwnd; + RECT rect; + Gdi::Region region; + }; + + std::vector getVisibleLayeredWindows(); void onStyleChanged(HWND hwnd, WPARAM wParam); void onSyncPaint(HWND hwnd); void present(CompatRef dst, CompatRef src, CompatRef clipper); void present(Gdi::Region excludeRegion); - bool presentLayered(CompatWeakPtr dst, const RECT& monitorRect); void updateAll(); } }