mirror of https://github.com/doitsujin/dxvk
Merge e4e89db23c
into ab715a8876
This commit is contained in:
commit
a3be9f7672
|
@ -183,6 +183,8 @@ namespace dxvk {
|
|||
m_activeRTsWhichAreTextures = 0;
|
||||
m_alphaSwizzleRTs = 0;
|
||||
m_lastHazardsRT = 0;
|
||||
|
||||
m_gamescopeWSI = dxvk::env::getEnvVar("ENABLE_GAMESCOPE_WSI") == "1";
|
||||
}
|
||||
|
||||
|
||||
|
@ -1093,6 +1095,12 @@ namespace dxvk {
|
|||
if (unlikely(iSwapChain != 0))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!IsGamescopeWSIEnabled()) {
|
||||
return D3D9SwapChainEx::GetFrontBufferDataGDI(pDestSurface);
|
||||
}
|
||||
#endif
|
||||
|
||||
D3D9DeviceLock lock = LockDevice();
|
||||
|
||||
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
|
||||
|
|
|
@ -1273,6 +1273,10 @@ namespace dxvk {
|
|||
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
|
||||
}
|
||||
|
||||
bool IsGamescopeWSIEnabled() const {
|
||||
return m_gamescopeWSI;
|
||||
}
|
||||
|
||||
Com<D3D9InterfaceEx> m_parent;
|
||||
D3DDEVTYPE m_deviceType;
|
||||
HWND m_window;
|
||||
|
@ -1439,6 +1443,8 @@ namespace dxvk {
|
|||
|
||||
D3D9SwapChainEx* m_mostRecentlyUsedSwapchain = nullptr;
|
||||
|
||||
bool m_gamescopeWSI;
|
||||
|
||||
#ifdef D3D9_ALLOW_UNMAPPING
|
||||
lru_list<D3D9CommonTexture*> m_mappedTextures;
|
||||
#endif
|
||||
|
|
|
@ -241,9 +241,91 @@ namespace dxvk {
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT D3D9SwapChainEx::GetFrontBufferDataGDI(IDirect3DSurface9* pDestSurface) {
|
||||
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
||||
|
||||
if (unlikely(dst == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
|
||||
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
|
||||
|
||||
if (unlikely(dstTexInfo->Desc()->Format != D3D9Format::A8R8G8B8)) {
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
const POINT ptZero = { 0, 0 };
|
||||
HMONITOR primaryMonitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
|
||||
|
||||
MONITORINFO monitorInfo = {};
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
if (!GetMonitorInfo(primaryMonitor, &monitorInfo)) {
|
||||
Logger::err("D3D9SwapChainEx::GetFrontBufferData: Failed to query window size.");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
VkExtent2D monitorExtent = { uint32_t(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left), uint32_t(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top) };
|
||||
VkExtent2D blitRegionExtent = { std::min(monitorExtent.width, dstTexExtent.width), std::min(monitorExtent.height, dstTexExtent.height) };
|
||||
|
||||
HDC srcDC = GetDC(nullptr);
|
||||
HDC dstDC = CreateCompatibleDC(nullptr);
|
||||
HBITMAP hbitmap = CreateCompatibleBitmap(srcDC, dstTexExtent.width, dstTexExtent.height);
|
||||
|
||||
if (unlikely(hbitmap == nullptr)) {
|
||||
Logger::err("D3D9SwapChainEx::GetFrontBufferData: Failed to create bitmap.");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
HBITMAP oldBitmap = static_cast<HBITMAP>(SelectObject(dstDC, hbitmap));
|
||||
if (unlikely(oldBitmap == nullptr)) {
|
||||
Logger::err("D3D9SwapChainEx::GetFrontBufferData: Failed to select bitmap for DC.");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
// We always want the primary monitor which conveniently always sits at 0,0.
|
||||
if (unlikely(!BitBlt(dstDC, 0, 0, blitRegionExtent.width, blitRegionExtent.height, srcDC, 0, 0, SRCCOPY))) {
|
||||
Logger::err("D3D9SwapChainEx::GetFrontBufferData: Failed to create blit window.");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT lockedRect = {};
|
||||
if (unlikely(pDestSurface->LockRect(&lockedRect, nullptr, D3DLOCK_DISCARD) != D3D_OK)) {
|
||||
Logger::err("D3D9SwapChainEx::GetFrontBufferData: Failed to lock dst surface.");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
BITMAPINFO info = {
|
||||
sizeof(BITMAPINFOHEADER), int32_t(dstTexExtent.width), int32_t(-blitRegionExtent.height), 1, 32, BI_RGB, 0, 0, 0, 0, 0,
|
||||
0,0,0,0
|
||||
};
|
||||
|
||||
// For uncompressed RGB formats, the minimum stride is always the image width in bytes, rounded up to the nearest DWORD
|
||||
// Our pitch is always aligned to 4 and GetFrontBufferData only supports A8R8G8B8. So we can avoid another copy to repack the data.
|
||||
|
||||
uint32_t lines = uint32_t(blitRegionExtent.height);
|
||||
int scanlinesCopied = GetDIBits(dstDC, hbitmap, 0, lines, lockedRect.pBits, &info, DIB_RGB_COLORS);
|
||||
if (unlikely(scanlinesCopied != int32_t(lines))) {
|
||||
Logger::err("D3D9SwapChainEx::GetFrontBufferData: Failed to read hbitmap data.");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
pDestSurface->UnlockRect();
|
||||
|
||||
SelectObject(dstDC, oldBitmap);
|
||||
return D3D_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetFrontBufferData(IDirect3DSurface9* pDestSurface) {
|
||||
#ifdef _WIN32
|
||||
if (!m_parent->IsGamescopeWSIEnabled() && (m_presentParams.Windowed || !HasFrontBuffer())) {
|
||||
return D3D9SwapChainEx::GetFrontBufferDataGDI(pDestSurface);
|
||||
}
|
||||
#endif
|
||||
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
// This function can do absolutely everything!
|
||||
|
|
|
@ -134,6 +134,10 @@ namespace dxvk {
|
|||
|
||||
void UpdateWindowCtx();
|
||||
|
||||
#ifdef _WIN32
|
||||
static HRESULT GetFrontBufferDataGDI(IDirect3DSurface9* pDestSurface);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
|
|
Loading…
Reference in New Issue