diff --git a/host/Capture/DXGI.cpp b/host/Capture/DXGI.cpp index 1eb523a7..2f275072 100644 --- a/host/Capture/DXGI.cpp +++ b/host/Capture/DXGI.cpp @@ -211,19 +211,6 @@ void DXGI::DeInitialize() m_initialized = false; } -bool DXGI::ReInitialize() -{ - DeInitialize(); - - /* - DXGI needs some time when mode switches occur, failing to do so causes - failure to start and exceptions internal to DXGI - */ - Sleep(200); - - return Initialize(m_options); -} - FrameType DXGI::GetFrameType() { if (!m_initialized) @@ -240,10 +227,10 @@ size_t DXGI::GetMaxFrameSize() return (m_width * m_height * 4); } -bool DXGI::GrabFrame(FrameInfo & frame) +GrabStatus DXGI::GrabFrame(FrameInfo & frame) { if (!m_initialized) - return false; + return GRAB_STATUS_ERROR; DXGI_OUTDUPL_FRAME_INFO frameInfo; CComPtr res; @@ -258,6 +245,8 @@ bool DXGI::GrabFrame(FrameInfo & frame) switch (status) { case DXGI_ERROR_ACCESS_LOST: // desktop switch, mode change or switch DWM on or off + return GRAB_STATUS_REINIT; + case WAIT_ABANDONED: // this can happen also during desktop switches, not documented by MS though { // see if we can open the desktop, if not the secure desktop @@ -275,7 +264,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) if (!ReInitialize()) { DEBUG_ERROR("Failed to ReInitialize after lost access to desktop"); - return false; + return GRAB_STATUS_ERROR; } continue; } @@ -283,7 +272,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) default: // unknown failure DEBUG_INFO("AcquireNextFrame failed: %08x", status); - return false; + return GRAB_STATUS_ERROR; } } @@ -292,7 +281,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) { m_dup->ReleaseFrame(); DEBUG_ERROR("Failed to acquire next frame"); - return false; + return GRAB_STATUS_ERROR; } CComQIPtr src = res; @@ -300,7 +289,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) { m_dup->ReleaseFrame(); DEBUG_ERROR("Failed to get src ID3D11Texture2D"); - return false; + return GRAB_STATUS_ERROR; } D3D11_TEXTURE2D_DESC desc; @@ -324,7 +313,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) { m_dup->ReleaseFrame(); DEBUG_ERROR("Failed to get the new pointer shape: %08x", status); - return false; + return GRAB_STATUS_ERROR; } } @@ -336,7 +325,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) if (!surface) { DEBUG_ERROR("Failed to get IDXGISurface1"); - return false; + return GRAB_STATUS_ERROR; } DXGI_MAPPED_RECT rect; @@ -344,7 +333,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) if (FAILED(status)) { DEBUG_ERROR("Failed to map surface: %08x", status); - return false; + return GRAB_STATUS_ERROR; } m_width = desc.Width; @@ -381,7 +370,7 @@ bool DXGI::GrabFrame(FrameInfo & frame) case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : type = CURSOR_TYPE_MONOCHROME ; break; default: DEBUG_ERROR("Invalid cursor type"); - return false; + return GRAB_STATUS_ERROR; } POINT cursorPos; @@ -404,8 +393,8 @@ bool DXGI::GrabFrame(FrameInfo & frame) if (FAILED(status)) { DEBUG_ERROR("Failed to unmap surface: %08x", status); - return false; + return GRAB_STATUS_ERROR; } - return true; + return GRAB_STATUS_OK; } \ No newline at end of file diff --git a/host/Capture/DXGI.h b/host/Capture/DXGI.h index 028148d0..a81cea25 100644 --- a/host/Capture/DXGI.h +++ b/host/Capture/DXGI.h @@ -38,16 +38,25 @@ namespace Capture bool Initialize(CaptureOptions * options); void DeInitialize(); + bool ReInitialize() + { + DeInitialize(); + /* + DXGI needs some time when mode switches occur, failing to do so causes + failure to start and exceptions internal to DXGI + */ + Sleep(200); + return Initialize(m_options); + } + enum FrameType GetFrameType(); enum FrameComp GetFrameCompression(); size_t GetMaxFrameSize(); - bool GrabFrame(struct FrameInfo & frame); + enum GrabStatus GrabFrame(struct FrameInfo & frame); private: CaptureOptions * m_options; - bool ReInitialize(); - bool m_initialized; unsigned int m_width; unsigned int m_height; diff --git a/host/Capture/NvFBC.cpp b/host/Capture/NvFBC.cpp index 00139960..1128bf29 100644 --- a/host/Capture/NvFBC.cpp +++ b/host/Capture/NvFBC.cpp @@ -50,7 +50,7 @@ bool NvFBC::Initialize(CaptureOptions * options) if (m_initialized) DeInitialize(); - m_options = options; + m_options = options; m_optNoCrop = false; for (CaptureOptions::const_iterator it = options->cbegin(); it != options->cend(); ++it) { @@ -212,12 +212,14 @@ size_t NvFBC::GetMaxFrameSize() return m_maxCaptureWidth * m_maxCaptureHeight * 4; } -bool NvFBC::GrabFrame(struct FrameInfo & frame) +enum GrabStatus NvFBC::GrabFrame(struct FrameInfo & frame) { if (!m_initialized) - return false; + return GRAB_STATUS_ERROR; const HWND hDesktop = GetDesktopWindow(); + const unsigned int screenWidth = GetSystemMetrics(SM_CXSCREEN); + const unsigned int screenHeight = GetSystemMetrics(SM_CYSCREEN); RECT desktop; GetWindowRect(hDesktop, &desktop); @@ -249,22 +251,22 @@ bool NvFBC::GrabFrame(struct FrameInfo & frame) if (m_optNoCrop) { - dataWidth = m_grabInfo.dwWidth * 4; + dataWidth = m_grabInfo.dwWidth * 4; dataOffset = 0; - frame.width = m_grabInfo.dwWidth; + frame.width = m_grabInfo.dwWidth; frame.height = m_grabInfo.dwHeight; } else { - const unsigned int realHeight = min(m_grabInfo.dwHeight, (unsigned int)(desktop.bottom - desktop.top)); - const unsigned int realWidth = min(m_grabInfo.dwWidth , (unsigned int)(desktop.right - desktop.left)); - dataWidth = realWidth * 4; + const unsigned int realHeight = min(m_grabInfo.dwHeight, screenHeight); + const unsigned int realWidth = min(m_grabInfo.dwWidth, screenWidth); + dataWidth = realWidth * 4; dataOffset = (((m_grabInfo.dwHeight - realHeight) >> 1) * m_grabInfo.dwBufferWidth + - ((m_grabInfo.dwWidth - realWidth ) >> 1)) * 4; + ((m_grabInfo.dwWidth - realWidth) >> 1)) * 4; - frame.width = realWidth; + frame.width = realWidth; frame.height = realHeight; } @@ -276,27 +278,22 @@ bool NvFBC::GrabFrame(struct FrameInfo & frame) for(unsigned int y = 0; y < frame.height; ++y, dst += dataWidth, src += m_grabInfo.dwBufferWidth * 4) memcpySSE(dst, src, dataWidth); - return true; + return GRAB_STATUS_OK; } if (status == NVFBC_ERROR_DYNAMIC_DISABLE) { DEBUG_ERROR("NvFBC was disabled by someone else"); - return false; + return GRAB_STATUS_ERROR; } if (status == NVFBC_ERROR_INVALIDATED_SESSION) { DEBUG_WARN("Session was invalidated, attempting to restart"); - DeInitialize(); - if (!Initialize(m_options)) - { - DEBUG_ERROR("Failed to re-iniaialize"); - return false; - } + return GRAB_STATUS_REINIT; } } DEBUG_ERROR("Failed to grab frame"); - return false; + return GRAB_STATUS_ERROR; } diff --git a/host/Capture/NvFBC.h b/host/Capture/NvFBC.h index 30991534..e3fecc12 100644 --- a/host/Capture/NvFBC.h +++ b/host/Capture/NvFBC.h @@ -37,10 +37,15 @@ namespace Capture bool Initialize(CaptureOptions * options); void DeInitialize(); + bool ReInitialize() + { + DeInitialize(); + return Initialize(m_options); + } enum FrameType GetFrameType(); enum FrameComp GetFrameCompression(); size_t GetMaxFrameSize(); - bool GrabFrame(struct FrameInfo & frame); + enum GrabStatus GrabFrame(struct FrameInfo & frame); private: CaptureOptions * m_options; diff --git a/host/ICapture.h b/host/ICapture.h index c5fbfa58..e05d8cd1 100644 --- a/host/ICapture.h +++ b/host/ICapture.h @@ -34,6 +34,13 @@ struct FrameInfo int mouseX, mouseY; }; +enum GrabStatus +{ + GRAB_STATUS_OK, + GRAB_STATUS_REINIT, + GRAB_STATUS_ERROR +}; + typedef std::vector CaptureOptions; __interface ICapture @@ -43,7 +50,8 @@ public: bool Initialize(CaptureOptions * options); void DeInitialize(); + bool ReInitialize(); enum FrameType GetFrameType(); size_t GetMaxFrameSize(); - bool GrabFrame(struct FrameInfo & frame); + enum GrabStatus GrabFrame(struct FrameInfo & frame); }; \ No newline at end of file diff --git a/host/Service.cpp b/host/Service.cpp index a1f9f2de..3e4172d3 100644 --- a/host/Service.cpp +++ b/host/Service.cpp @@ -28,6 +28,7 @@ Service * Service::m_instance = NULL; Service::Service() : m_initialized(false), + m_memory(NULL), m_readyEvent(INVALID_HANDLE_VALUE), m_capture(NULL), m_header(NULL), @@ -60,14 +61,17 @@ bool Service::Initialize(ICapture * captureDevice) return false; } - uint8_t * memory = static_cast(m_ivshmem->GetMemory()); - if (!memory) + m_memory = static_cast(m_ivshmem->GetMemory()); + if (!m_memory) { DEBUG_ERROR("Failed to get IVSHMEM memory"); DeInitialize(); return false; } + if (!InitPointers()) + return false; + m_readyEvent = m_ivshmem->CreateVectorEvent(0); if (m_readyEvent == INVALID_HANDLE_VALUE) { @@ -76,20 +80,6 @@ bool Service::Initialize(ICapture * captureDevice) return false; } - m_header = reinterpret_cast(memory); - m_frame[0] = (uint8_t *)(((uintptr_t)memory + sizeof(KVMFRHeader *) + 0x7F) & ~0x7F); - m_frameSize = ((m_ivshmem->GetSize() - (m_frame[0] - memory)) & ~0x7F) >> 1; - m_frame[1] = m_frame[0] + m_frameSize; - m_dataOffset[0] = m_frame[0] - memory; - m_dataOffset[1] = m_frame[1] - memory; - - if (m_capture->GetMaxFrameSize() > m_frameSize) - { - DEBUG_ERROR("Frame can exceed buffer size!"); - DeInitialize(); - return false; - } - // we save this as it might actually be valid UINT16 hostID = m_header->hostID; @@ -105,10 +95,32 @@ bool Service::Initialize(ICapture * captureDevice) return true; } +bool Service::InitPointers() +{ + m_header = reinterpret_cast(m_memory); + m_frame[0] = (uint8_t *)(((uintptr_t)m_memory + sizeof(KVMFRHeader *) + 0x7F) & ~0x7F); + m_frameSize = ((m_ivshmem->GetSize() - (m_frame[0] - m_memory)) & ~0x7F) >> 1; + m_frame[1] = m_frame[0] + m_frameSize; + m_dataOffset[0] = m_frame[0] - m_memory; + m_dataOffset[1] = m_frame[1] - m_memory; + + if (m_capture->GetMaxFrameSize() > m_frameSize) + { + DEBUG_ERROR("Frame can exceed buffer size!"); + DeInitialize(); + return false; + } + + return true; +} + void Service::DeInitialize() { if (m_readyEvent != INVALID_HANDLE_VALUE) + { CloseHandle(m_readyEvent); + m_readyEvent = INVALID_HANDLE_VALUE; + } m_header = NULL; m_frame[0] = NULL; @@ -124,6 +136,7 @@ void Service::DeInitialize() m_capture = NULL; } + m_memory = NULL; m_initialized = false; } @@ -165,11 +178,38 @@ bool Service::Process() } ResetEvent(m_readyEvent); - // capture a frame of data - if (!m_capture->GrabFrame(frame)) + bool ok = false; + for(int i = 0; i < 2; ++i) { - m_header->dataLen = 0; - DEBUG_ERROR("Capture failed"); + // capture a frame of data + switch (m_capture->GrabFrame(frame)) + { + case GRAB_STATUS_OK: + ok = true; + break; + + case GRAB_STATUS_ERROR: + m_header->dataLen = 0; + DEBUG_ERROR("Capture failed"); + return false; + + case GRAB_STATUS_REINIT: + DEBUG_INFO("ReInitialize Requested"); + if (!m_capture->ReInitialize() || !InitPointers()) + { + DEBUG_ERROR("ReInitialize Failed"); + return false; + } + continue; + } + + if (ok) + break; + } + + if (!ok) + { + DEBUG_ERROR("Capture retry count exceeded"); return false; } @@ -190,7 +230,7 @@ bool Service::Process() else { POINT cursorPos; - GetCursorPos(&cursorPos); + GetPhysicalCursorPos(&cursorPos); m_header->mouseX = cursorPos.x; m_header->mouseY = cursorPos.y; } diff --git a/host/Service.h b/host/Service.h index e6a73563..e1573056 100644 --- a/host/Service.h +++ b/host/Service.h @@ -40,12 +40,15 @@ public: bool Process(); private: + bool InitPointers(); + static Service * m_instance; Service(); ~Service(); bool m_initialized; + uint8_t * m_memory; IVSHMEM * m_ivshmem; HANDLE m_readyEvent; ICapture * m_capture; diff --git a/host/looking-glass-host.vcxproj b/host/looking-glass-host.vcxproj index f54c2876..58ae5cc4 100644 --- a/host/looking-glass-host.vcxproj +++ b/host/looking-glass-host.vcxproj @@ -100,6 +100,9 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) + + PerMonitorHighDPIAware + @@ -117,6 +120,9 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) + + PerMonitorHighDPIAware + @@ -138,6 +144,9 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) + + PerMonitorHighDPIAware + @@ -159,6 +168,9 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) + + PerMonitorHighDPIAware +