[host] updated to use new protocol design

This commit is contained in:
Geoffrey McRae 2017-12-12 07:56:50 +11:00
parent 0c90032db1
commit 818164da7f
8 changed files with 189 additions and 131 deletions

View File

@ -21,7 +21,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdint.h> #include <stdint.h>
#define KVMFR_HEADER_MAGIC "[[KVMFR]]" #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 typedef enum FrameType
{ {
@ -29,20 +30,54 @@ typedef enum FrameType
FRAME_TYPE_ARGB , // ABGR interleaved: A,R,G,B 32bpp FRAME_TYPE_ARGB , // ABGR interleaved: A,R,G,B 32bpp
FRAME_TYPE_RGB , // RGB interleaved : R,G,B 24bpp FRAME_TYPE_RGB , // RGB interleaved : R,G,B 24bpp
FRAME_TYPE_MAX , // sentinel value FRAME_TYPE_MAX , // sentinel value
} FrameType; }
FrameType;
struct KVMFRHeader typedef enum CursorType
{ {
char magic[sizeof(KVMFR_HEADER_MAGIC)]; CURSOR_TYPE_COLOR ,
uint32_t version; // version of this structure CURSOR_TYPE_MONOCHROME ,
uint16_t hostID; // the host ivshmem client id CURSOR_TYPE_MASKED_COLOR
uint16_t guestID; // the guest ivshmem client id }
FrameType frameType; // the frame type CursorType;
uint32_t width; // the width
uint32_t height; // the height #define KVMFR_CURSOR_FLAG_VISIBLE 1 // cursor is visible
uint32_t stride; // the row stride #define KVMFR_CURSOR_FLAG_SHAPE 2 // shape updated
int32_t mouseX; // the initial mouse X position #define KVMFR_CURSOR_FLAG_POS 4 // position updated
int32_t mouseY; // the initial mouse Y position
uint64_t dataLen; // total lengh of the data after this header typedef struct KVMFRCursor
uint64_t dataPos; // offset to the frame {
}; 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;

View File

@ -20,7 +20,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "DXGI.h" #include "DXGI.h"
using namespace Capture; using namespace Capture;
#include "Util.h"
#include "common\debug.h" #include "common\debug.h"
#include "common\memcpySSE.h" #include "common\memcpySSE.h"
@ -237,9 +236,73 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
CComPtr<IDXGIResource> res; CComPtr<IDXGIResource> res;
HRESULT status; HRESULT status;
bool cursorUpdate = false;
for(int i = 0; i < 2; ++i) 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)) if (SUCCEEDED(status))
break; break;
@ -298,26 +361,6 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
m_deviceContext->CopyResource(m_texture, src); 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(); m_dup->ReleaseFrame();
res.Release(); res.Release();
src.Release(); src.Release();
@ -344,53 +387,10 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
frame.width = desc.Width; frame.width = desc.Width;
frame.height = desc.Height; frame.height = desc.Height;
frame.stride = desc.Width; frame.stride = desc.Width;
frame.outSize = min(frame.bufferSize, m_height * pitch);
// if we have a mouse update memcpySSE(frame.buffer, rect.pBits, min(frame.bufferSize, m_height * pitch));
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);
status = surface->Unmap(); 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)) if (FAILED(status))
{ {
DEBUG_ERROR("Failed to unmap surface: %08x", status); DEBUG_ERROR("Failed to unmap surface: %08x", status);

View File

@ -72,8 +72,5 @@ namespace Capture
BYTE * m_pointer; BYTE * m_pointer;
UINT m_pointerBufSize; UINT m_pointerBufSize;
UINT m_pointerSize; UINT m_pointerSize;
DXGI_OUTDUPL_POINTER_SHAPE_INFO m_shapeInfo;
BOOL m_pointerVisible;
POINT m_pointerPos;
}; };
}; };

View File

@ -286,9 +286,7 @@ enum GrabStatus NvFBC::GrabFrame(struct FrameInfo & frame)
frame.height = realHeight; frame.height = realHeight;
} }
frame.stride = frame.width; frame.stride = frame.width;
frame.outSize = frame.width * frame.height * 4;
uint8_t *src = (uint8_t *)m_frameBuffer + dataOffset; uint8_t *src = (uint8_t *)m_frameBuffer + dataOffset;
uint8_t *dst = (uint8_t *)frame.buffer; uint8_t *dst = (uint8_t *)frame.buffer;
for(unsigned int y = 0; y < frame.height; ++y, dst += dataWidth, src += m_grabInfo.dwBufferWidth * 4) for(unsigned int y = 0; y < frame.height; ++y, dst += dataWidth, src += m_grabInfo.dwBufferWidth * 4)

View File

@ -22,6 +22,19 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/KVMFR.h" #include "common/KVMFR.h"
#include <vector> #include <vector>
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 struct FrameInfo
{ {
unsigned int width; unsigned int width;
@ -29,16 +42,15 @@ struct FrameInfo
unsigned int stride; unsigned int stride;
void * buffer; void * buffer;
size_t bufferSize; size_t bufferSize;
size_t outSize;
bool hasMousePos; struct CursorInfo cursor;
int mouseX, mouseY;
}; };
enum GrabStatus enum GrabStatus
{ {
GRAB_STATUS_OK, GRAB_STATUS_OK,
GRAB_STATUS_REINIT, GRAB_STATUS_REINIT,
GRAB_STATUS_CURSOR,
GRAB_STATUS_ERROR GRAB_STATUS_ERROR
}; };

View File

@ -87,10 +87,10 @@ bool Service::Initialize(ICapture * captureDevice)
ZeroMemory(m_header, sizeof(KVMFRHeader)); ZeroMemory(m_header, sizeof(KVMFRHeader));
memcpy(m_header->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC)); memcpy(m_header->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC));
m_header->version = KVMFR_HEADER_VERSION; m_header->version = KVMFR_HEADER_VERSION;
m_header->guestID = m_ivshmem->GetPeerID(); m_header->guestID = m_ivshmem->GetPeerID();
m_header->hostID = hostID; m_header->hostID = hostID;
m_header->frameType = m_capture->GetFrameType(); m_header->updateCount = 0;
m_initialized = true; m_initialized = true;
return true; return true;
@ -146,10 +146,10 @@ bool Service::Process()
if (!m_initialized) if (!m_initialized)
return false; return false;
FrameInfo frame; struct FrameInfo frame;
ZeroMemory(&frame, sizeof(FrameInfo));
frame.buffer = m_frame[m_frameIndex]; frame.buffer = m_frame[m_frameIndex];
frame.bufferSize = m_frameSize; frame.bufferSize = m_frameSize;
frame.hasMousePos = false;
// wait for the host to notify that is it is ready to proceed // wait for the host to notify that is it is ready to proceed
bool eventDone = false; bool eventDone = false;
@ -179,7 +179,8 @@ bool Service::Process()
} }
ResetEvent(m_readyEvent); ResetEvent(m_readyEvent);
bool ok = false; bool ok = false;
bool cursorOnly = false;
for(int i = 0; i < 2; ++i) for(int i = 0; i < 2; ++i)
{ {
// capture a frame of data // capture a frame of data
@ -189,8 +190,12 @@ bool Service::Process()
ok = true; ok = true;
break; break;
case GRAB_STATUS_CURSOR:
ok = true;
cursorOnly = true;
break;
case GRAB_STATUS_ERROR: case GRAB_STATUS_ERROR:
m_header->dataLen = 0;
DEBUG_ERROR("Capture failed"); DEBUG_ERROR("Capture failed");
return false; return false;
@ -214,30 +219,49 @@ bool Service::Process()
return false; return false;
} }
// copy the frame details into the header m_header->flags = 0;
// setup the header m_header->cursor.flags = 0;
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;
// tell the host where the cursor is if (!cursorOnly)
if (frame.hasMousePos)
{ {
m_header->mouseX = frame.mouseX; // signal a frame update
m_header->mouseY = frame.mouseY; m_header->flags |= KVMFR_HEADER_FLAG_FRAME;
} m_header->frame.type = m_capture->GetFrameType();
else m_header->frame.width = frame.width;
{ m_header->frame.height = frame.height;
POINT cursorPos; m_header->frame.stride = frame.stride;
GetPhysicalCursorPos(&cursorPos); m_header->frame.dataPos = m_dataOffset[m_frameIndex];
m_header->mouseX = cursorPos.x; if (++m_frameIndex == 2)
m_header->mouseY = cursorPos.y; m_frameIndex = 0;
} }
if (++m_frameIndex == 2) if (frame.cursor.hasPos)
m_frameIndex = 0; {
// 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; return true;
} }

View File

@ -55,8 +55,8 @@ private:
ICapture * m_capture; ICapture * m_capture;
KVMFRHeader * m_header; KVMFRHeader * m_header;
uint8_t * m_frame[2]; uint8_t * m_frame[2];
size_t m_frameSize; size_t m_frameSize;
uint64_t m_dataOffset[2]; uint64_t m_dataOffset[2];
int m_frameIndex; int m_frameIndex;
}; };

View File

@ -25,14 +25,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common\debug.h" #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 class Util
{ {