From 818164da7f05cd22a3b7b821a43b4177fd50ce4d Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Tue, 12 Dec 2017 07:56:50 +1100 Subject: [PATCH] [host] updated to use new protocol design --- common/KVMFR.h | 67 ++++++++++++++++----- host/Capture/DXGI.cpp | 132 ++++++++++++++++++++--------------------- host/Capture/DXGI.h | 3 - host/Capture/NvFBC.cpp | 4 +- host/ICapture.h | 18 +++++- host/Service.cpp | 80 ++++++++++++++++--------- host/Service.h | 8 +-- host/Util.h | 8 --- 8 files changed, 189 insertions(+), 131 deletions(-) diff --git a/common/KVMFR.h b/common/KVMFR.h index af32b170..ed32b915 100644 --- a/common/KVMFR.h +++ b/common/KVMFR.h @@ -21,7 +21,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #define KVMFR_HEADER_MAGIC "[[KVMFR]]" -#define KVMFR_HEADER_VERSION 1 +#define KVMFR_HEADER_VERSION 2 +#define KVMFR_CURSOR_BUFFER (32*32*4) typedef enum FrameType { @@ -29,20 +30,54 @@ typedef enum FrameType FRAME_TYPE_ARGB , // ABGR interleaved: A,R,G,B 32bpp FRAME_TYPE_RGB , // RGB interleaved : R,G,B 24bpp FRAME_TYPE_MAX , // sentinel value -} FrameType; +} +FrameType; -struct KVMFRHeader +typedef enum CursorType { - char magic[sizeof(KVMFR_HEADER_MAGIC)]; - uint32_t version; // version of this structure - uint16_t hostID; // the host ivshmem client id - uint16_t guestID; // the guest ivshmem client id - FrameType frameType; // the frame type - uint32_t width; // the width - uint32_t height; // the height - uint32_t stride; // the row stride - int32_t mouseX; // the initial mouse X position - int32_t mouseY; // the initial mouse Y position - uint64_t dataLen; // total lengh of the data after this header - uint64_t dataPos; // offset to the frame -}; \ No newline at end of file + CURSOR_TYPE_COLOR , + CURSOR_TYPE_MONOCHROME , + CURSOR_TYPE_MASKED_COLOR +} +CursorType; + +#define KVMFR_CURSOR_FLAG_VISIBLE 1 // cursor is visible +#define KVMFR_CURSOR_FLAG_SHAPE 2 // shape updated +#define KVMFR_CURSOR_FLAG_POS 4 // position updated + +typedef struct KVMFRCursor +{ + uint8_t flags; // KVMFR_CURSOR_FLAGS + int16_t x, y; // cursor x & y position + CursorType type; // shape buffer data type + uint8_t w, h; // shape width and height + uint8_t shape[KVMFR_CURSOR_BUFFER]; +} +KVMFRCursor; + +typedef struct KVMFRFrame +{ + FrameType type; // the frame data type + uint32_t width; // the width + uint32_t height; // the height + uint32_t stride; // the row stride + uint64_t dataPos; // offset to the frame +} +KVMFRFrame; + +#define KVMFR_HEADER_FLAG_FRAME 1 // frame update available +#define KVMFR_HEADER_FLAG_CURSOR 2 // cursor update available + +typedef struct KVMFRHeader +{ + char magic[sizeof(KVMFR_HEADER_MAGIC)]; + uint32_t version; // version of this structure + uint16_t hostID; // the host ivshmem client id + uint16_t guestID; // the guest ivshmem client id + int32_t updateCount; // updated each change + uint8_t flags; // KVMFR_HEADER_FLAGS + + KVMFRFrame frame; // the frame information + KVMFRCursor cursor; // the cursor information +} +KVMFRHeader; diff --git a/host/Capture/DXGI.cpp b/host/Capture/DXGI.cpp index ee41596e..755f17ee 100644 --- a/host/Capture/DXGI.cpp +++ b/host/Capture/DXGI.cpp @@ -20,7 +20,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "DXGI.h" using namespace Capture; -#include "Util.h" #include "common\debug.h" #include "common\memcpySSE.h" @@ -237,9 +236,73 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame) CComPtr res; HRESULT status; + bool cursorUpdate = false; for(int i = 0; i < 2; ++i) { - status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res); + while(true) + { + status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res); + if (!SUCCEEDED(status)) + break; + + // if we have a mouse update + if (frameInfo.LastMouseUpdateTime.QuadPart) + { + cursorUpdate = true; + frame.cursor.hasPos = true; + frame.cursor.visible = frameInfo.PointerPosition.Visible; + frame.cursor.x = frameInfo.PointerPosition.Position.x; + frame.cursor.y = frameInfo.PointerPosition.Position.x; + } + + // if the pointer shape has changed + if (frameInfo.PointerShapeBufferSize > 0) + { + cursorUpdate = true; + if (m_pointerBufSize < frameInfo.PointerShapeBufferSize) + { + if (m_pointer) + delete[] m_pointer; + m_pointer = new BYTE[frameInfo.PointerShapeBufferSize]; + m_pointerBufSize = frameInfo.PointerShapeBufferSize; + } + + DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; + status = m_dup->GetFramePointerShape(m_pointerBufSize, m_pointer, &m_pointerSize, &shapeInfo); + if (!SUCCEEDED(status)) + { + m_dup->ReleaseFrame(); + DEBUG_ERROR("Failed to get the new pointer shape: %08x", status); + return GRAB_STATUS_ERROR; + } + + switch (shapeInfo.Type) + { + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : frame.cursor.type = CURSOR_TYPE_COLOR; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: frame.cursor.type = CURSOR_TYPE_MASKED_COLOR; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : frame.cursor.type = CURSOR_TYPE_MONOCHROME; break; + default: + DEBUG_ERROR("Invalid cursor type"); + return GRAB_STATUS_ERROR; + } + + frame.cursor.hasShape = true; + frame.cursor.shape = m_pointer; + frame.cursor.w = shapeInfo.Width; + frame.cursor.h = shapeInfo.Height; + frame.cursor.dataSize = m_pointerSize; + } + + if (frameInfo.AccumulatedFrames == 1) + break; + + m_dup->ReleaseFrame(); + res.Release(); + + if (cursorUpdate) + return GRAB_STATUS_CURSOR; + } + if (SUCCEEDED(status)) break; @@ -298,26 +361,6 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame) m_deviceContext->CopyResource(m_texture, src); - // if the pointer shape has changed - if (frameInfo.PointerShapeBufferSize > 0) - { - if (m_pointerBufSize < frameInfo.PointerShapeBufferSize) - { - if (m_pointer) - delete[] m_pointer; - m_pointer = new BYTE[frameInfo.PointerShapeBufferSize]; - m_pointerBufSize = frameInfo.PointerShapeBufferSize; - } - - status = m_dup->GetFramePointerShape(m_pointerBufSize, m_pointer, &m_pointerSize, &m_shapeInfo); - if (!SUCCEEDED(status)) - { - m_dup->ReleaseFrame(); - DEBUG_ERROR("Failed to get the new pointer shape: %08x", status); - return GRAB_STATUS_ERROR; - } - } - m_dup->ReleaseFrame(); res.Release(); src.Release(); @@ -344,53 +387,10 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame) frame.width = desc.Width; frame.height = desc.Height; frame.stride = desc.Width; - frame.outSize = min(frame.bufferSize, m_height * pitch); - // if we have a mouse update - if (frameInfo.LastMouseUpdateTime.QuadPart) - { - m_pointerVisible = frameInfo.PointerPosition.Visible; - m_pointerPos = frameInfo.PointerPosition.Position; - - frame.hasMousePos = true; - frame.mouseX = m_pointerPos.x; - frame.mouseY = m_pointerPos.y; - } - - memcpySSE(frame.buffer, rect.pBits, frame.outSize); + memcpySSE(frame.buffer, rect.pBits, min(frame.bufferSize, m_height * pitch)); status = surface->Unmap(); - // if the pointer is to be drawn - if (m_pointerVisible) - { - enum CursorType type; - switch (m_shapeInfo.Type) - { - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : type = CURSOR_TYPE_COLOR ; break; - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: type = CURSOR_TYPE_MASKED_COLOR; break; - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : type = CURSOR_TYPE_MONOCHROME ; break; - default: - DEBUG_ERROR("Invalid cursor type"); - return GRAB_STATUS_ERROR; - } - - POINT cursorPos; - POINT cursorRect; - cursorPos.x = m_pointerPos.x; - cursorPos.y = m_pointerPos.y; - cursorRect.x = m_shapeInfo.Width; - cursorRect.y = m_shapeInfo.Height; - - Util::DrawCursor( - type, - m_pointer, - cursorRect, - m_shapeInfo.Pitch, - cursorPos, - frame - ); - } - if (FAILED(status)) { DEBUG_ERROR("Failed to unmap surface: %08x", status); diff --git a/host/Capture/DXGI.h b/host/Capture/DXGI.h index 1d4cf9a0..7b1939f9 100644 --- a/host/Capture/DXGI.h +++ b/host/Capture/DXGI.h @@ -72,8 +72,5 @@ namespace Capture BYTE * m_pointer; UINT m_pointerBufSize; UINT m_pointerSize; - DXGI_OUTDUPL_POINTER_SHAPE_INFO m_shapeInfo; - BOOL m_pointerVisible; - POINT m_pointerPos; }; }; \ No newline at end of file diff --git a/host/Capture/NvFBC.cpp b/host/Capture/NvFBC.cpp index 8f2693ff..12556b03 100644 --- a/host/Capture/NvFBC.cpp +++ b/host/Capture/NvFBC.cpp @@ -286,9 +286,7 @@ enum GrabStatus NvFBC::GrabFrame(struct FrameInfo & frame) frame.height = realHeight; } - frame.stride = frame.width; - frame.outSize = frame.width * frame.height * 4; - + frame.stride = frame.width; uint8_t *src = (uint8_t *)m_frameBuffer + dataOffset; uint8_t *dst = (uint8_t *)frame.buffer; for(unsigned int y = 0; y < frame.height; ++y, dst += dataWidth, src += m_grabInfo.dwBufferWidth * 4) diff --git a/host/ICapture.h b/host/ICapture.h index c802c489..30753f06 100644 --- a/host/ICapture.h +++ b/host/ICapture.h @@ -22,6 +22,19 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "common/KVMFR.h" #include +struct CursorInfo +{ + bool visible; + bool hasShape; + bool hasPos; + int x, y; + + enum CursorType type; + unsigned int w, h; + void * shape; + unsigned int dataSize; +}; + struct FrameInfo { unsigned int width; @@ -29,16 +42,15 @@ struct FrameInfo unsigned int stride; void * buffer; size_t bufferSize; - size_t outSize; - bool hasMousePos; - int mouseX, mouseY; + struct CursorInfo cursor; }; enum GrabStatus { GRAB_STATUS_OK, GRAB_STATUS_REINIT, + GRAB_STATUS_CURSOR, GRAB_STATUS_ERROR }; diff --git a/host/Service.cpp b/host/Service.cpp index f21cb245..bbed8172 100644 --- a/host/Service.cpp +++ b/host/Service.cpp @@ -87,10 +87,10 @@ bool Service::Initialize(ICapture * captureDevice) ZeroMemory(m_header, sizeof(KVMFRHeader)); memcpy(m_header->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC)); - m_header->version = KVMFR_HEADER_VERSION; - m_header->guestID = m_ivshmem->GetPeerID(); - m_header->hostID = hostID; - m_header->frameType = m_capture->GetFrameType(); + m_header->version = KVMFR_HEADER_VERSION; + m_header->guestID = m_ivshmem->GetPeerID(); + m_header->hostID = hostID; + m_header->updateCount = 0; m_initialized = true; return true; @@ -146,10 +146,10 @@ bool Service::Process() if (!m_initialized) return false; - FrameInfo frame; + struct FrameInfo frame; + ZeroMemory(&frame, sizeof(FrameInfo)); frame.buffer = m_frame[m_frameIndex]; frame.bufferSize = m_frameSize; - frame.hasMousePos = false; // wait for the host to notify that is it is ready to proceed bool eventDone = false; @@ -179,7 +179,8 @@ bool Service::Process() } ResetEvent(m_readyEvent); - bool ok = false; + bool ok = false; + bool cursorOnly = false; for(int i = 0; i < 2; ++i) { // capture a frame of data @@ -189,8 +190,12 @@ bool Service::Process() ok = true; break; + case GRAB_STATUS_CURSOR: + ok = true; + cursorOnly = true; + break; + case GRAB_STATUS_ERROR: - m_header->dataLen = 0; DEBUG_ERROR("Capture failed"); return false; @@ -214,30 +219,49 @@ bool Service::Process() return false; } - // copy the frame details into the header - // setup the header - m_header->width = frame.width; - m_header->height = frame.height; - m_header->stride = frame.stride; - m_header->dataPos = m_dataOffset[m_frameIndex]; - m_header->dataLen = frame.outSize; + m_header->flags = 0; + m_header->cursor.flags = 0; - // tell the host where the cursor is - if (frame.hasMousePos) + if (!cursorOnly) { - m_header->mouseX = frame.mouseX; - m_header->mouseY = frame.mouseY; - } - else - { - POINT cursorPos; - GetPhysicalCursorPos(&cursorPos); - m_header->mouseX = cursorPos.x; - m_header->mouseY = cursorPos.y; + // signal a frame update + m_header->flags |= KVMFR_HEADER_FLAG_FRAME; + m_header->frame.type = m_capture->GetFrameType(); + m_header->frame.width = frame.width; + m_header->frame.height = frame.height; + m_header->frame.stride = frame.stride; + m_header->frame.dataPos = m_dataOffset[m_frameIndex]; + if (++m_frameIndex == 2) + m_frameIndex = 0; } - if (++m_frameIndex == 2) - m_frameIndex = 0; + if (frame.cursor.hasPos) + { + // tell the host where the cursor is + m_header->flags |= KVMFR_HEADER_FLAG_CURSOR; + m_header->cursor.flags |= KVMFR_CURSOR_FLAG_POS; + m_header->cursor.x = frame.cursor.x; + m_header->cursor.y = frame.cursor.y; + } + + if (frame.cursor.hasShape) + { + // give the host the new cursor shape + m_header->flags |= KVMFR_HEADER_FLAG_CURSOR; + m_header->cursor.flags |= KVMFR_CURSOR_FLAG_SHAPE; + m_header->cursor.type = frame.cursor.type; + m_header->cursor.w = frame.cursor.w; + m_header->cursor.h = frame.cursor.h; + if (frame.cursor.dataSize > KVMFR_CURSOR_BUFFER) + { + DEBUG_ERROR("Cursor shape size exceeds buffer size"); + return false; + } + memcpy(m_header->cursor.shape, frame.cursor.shape, frame.cursor.dataSize); + } + + // increment the update count to resume the host + ++m_header->updateCount; return true; } \ No newline at end of file diff --git a/host/Service.h b/host/Service.h index 70678645..8c6844d8 100644 --- a/host/Service.h +++ b/host/Service.h @@ -55,8 +55,8 @@ private: ICapture * m_capture; KVMFRHeader * m_header; - uint8_t * m_frame[2]; - size_t m_frameSize; - uint64_t m_dataOffset[2]; - int m_frameIndex; + uint8_t * m_frame[2]; + size_t m_frameSize; + uint64_t m_dataOffset[2]; + int m_frameIndex; }; \ No newline at end of file diff --git a/host/Util.h b/host/Util.h index f1c12975..b7db3d9e 100644 --- a/host/Util.h +++ b/host/Util.h @@ -25,14 +25,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "common\debug.h" -enum CursorType -{ - CURSOR_TYPE_COLOR, - CURSOR_TYPE_MONOCHROME, - CURSOR_TYPE_MASKED_COLOR, - CURSOR_TYPE_PACKED_MONOCHROME, - CURSOR_TYPE_PACKED_MASKED_COLOR -}; class Util {