[host] better sync, helps enormously with 4K!!!

This commit is contained in:
Geoffrey McRae 2018-09-30 03:50:43 +10:00
parent 73a2597c8a
commit 471303a179
4 changed files with 118 additions and 110 deletions

View file

@ -348,12 +348,15 @@ size_t DXGI::GetMaxFrameSize()
return (m_width * m_height * 4); return (m_width * m_height * 4);
} }
GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct CursorInfo & cursor, ID3D11Texture2DPtr & texture, bool & timeout) GrabStatus Capture::DXGI::Capture()
{ {
if (!m_initialized) if (!m_initialized)
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
timeout = false; m_cursor.updated = false;
m_cursor.hasPos = false;
m_cursor.hasShape = false;
DXGI_OUTDUPL_FRAME_INFO frameInfo; DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResourcePtr res; IDXGIResourcePtr res;
@ -368,10 +371,7 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs
status = m_dup->AcquireNextFrame(1000, &frameInfo, &res); status = m_dup->AcquireNextFrame(1000, &frameInfo, &res);
if (status == DXGI_ERROR_WAIT_TIMEOUT) if (status == DXGI_ERROR_WAIT_TIMEOUT)
{ return GRAB_STATUS_TIMEOUT;
timeout = true;
return GRAB_STATUS_OK;
}
if (FAILED(status)) if (FAILED(status))
break; break;
@ -385,27 +385,27 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs
m_lastMousePos.x != frameInfo.PointerPosition.Position.x || m_lastMousePos.x != frameInfo.PointerPosition.Position.x ||
m_lastMousePos.y != frameInfo.PointerPosition.Position.y m_lastMousePos.y != frameInfo.PointerPosition.Position.y
) { ) {
cursor.updated = true; m_cursor.updated = true;
cursor.hasPos = true; m_cursor.hasPos = true;
cursor.x = frameInfo.PointerPosition.Position.x; m_cursor.x = frameInfo.PointerPosition.Position.x;
cursor.y = frameInfo.PointerPosition.Position.y; m_cursor.y = frameInfo.PointerPosition.Position.y;
m_lastMousePos.x = frameInfo.PointerPosition.Position.x; m_lastMousePos.x = frameInfo.PointerPosition.Position.x;
m_lastMousePos.y = frameInfo.PointerPosition.Position.y; m_lastMousePos.y = frameInfo.PointerPosition.Position.y;
} }
if (m_lastMouseVis != frameInfo.PointerPosition.Visible) if (m_lastMouseVis != frameInfo.PointerPosition.Visible)
{ {
cursor.updated = true; m_cursor.updated = true;
m_lastMouseVis = frameInfo.PointerPosition.Visible; m_lastMouseVis = frameInfo.PointerPosition.Visible;
} }
cursor.visible = m_lastMouseVis == TRUE; m_cursor.visible = m_lastMouseVis == TRUE;
} }
// if the pointer shape has changed // if the pointer shape has changed
if (frameInfo.PointerShapeBufferSize > 0) if (frameInfo.PointerShapeBufferSize > 0)
{ {
cursor.updated = true; m_cursor.updated = true;
if (m_pointerBufSize < frameInfo.PointerShapeBufferSize) if (m_pointerBufSize < frameInfo.PointerShapeBufferSize)
{ {
if (m_pointer) if (m_pointer)
@ -424,20 +424,20 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs
switch (shapeInfo.Type) switch (shapeInfo.Type)
{ {
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : cursor.type = CURSOR_TYPE_COLOR; break; case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : m_cursor.type = CURSOR_TYPE_COLOR; break;
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: cursor.type = CURSOR_TYPE_MASKED_COLOR; break; case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: m_cursor.type = CURSOR_TYPE_MASKED_COLOR; break;
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : cursor.type = CURSOR_TYPE_MONOCHROME; break; case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : m_cursor.type = CURSOR_TYPE_MONOCHROME; break;
default: default:
DEBUG_ERROR("Invalid cursor type"); DEBUG_ERROR("Invalid cursor type");
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
} }
cursor.hasShape = true; m_cursor.hasShape = true;
cursor.shape = m_pointer; m_cursor.shape = m_pointer;
cursor.w = shapeInfo.Width; m_cursor.w = shapeInfo.Width;
cursor.h = shapeInfo.Height; m_cursor.h = shapeInfo.Height;
cursor.pitch = shapeInfo.Pitch; m_cursor.pitch = shapeInfo.Pitch;
cursor.dataSize = m_pointerSize; m_cursor.dataSize = m_pointerSize;
} }
// if we also have frame data, break out to process it // if we also have frame data, break out to process it
@ -447,7 +447,7 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs
res = NULL; res = NULL;
// if the cursor has been updated // if the cursor has been updated
if (cursor.updated) if (m_cursor.updated)
return GRAB_STATUS_CURSOR; return GRAB_STATUS_CURSOR;
// otherwise just try again // otherwise just try again
@ -477,9 +477,9 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
} }
res.QueryInterface(IID_PPV_ARGS(&texture)); res.QueryInterface(IID_PPV_ARGS(&m_ftexture));
if (!texture) if (!m_ftexture)
{ {
ReleaseFrame(); ReleaseFrame();
DEBUG_ERROR("Failed to get src ID3D11Texture2D"); DEBUG_ERROR("Failed to get src ID3D11Texture2D");
@ -495,6 +495,8 @@ GrabStatus Capture::DXGI::ReleaseFrame()
return GRAB_STATUS_OK; return GRAB_STATUS_OK;
m_releaseFrame = false; m_releaseFrame = false;
m_ftexture = NULL;
switch (m_dup->ReleaseFrame()) switch (m_dup->ReleaseFrame())
{ {
case S_OK: case S_OK:
@ -512,21 +514,17 @@ GrabStatus Capture::DXGI::ReleaseFrame()
return GRAB_STATUS_OK; return GRAB_STATUS_OK;
} }
GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame, struct CursorInfo & cursor) GrabStatus Capture::DXGI::DiscardFrame()
{
return ReleaseFrame();
}
GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame)
{ {
GrabStatus result; GrabStatus result;
ID3D11Texture2DPtr texture;
bool timeout;
D3D11_MAPPED_SUBRESOURCE mapping; D3D11_MAPPED_SUBRESOURCE mapping;
result = GrabFrameTexture(frame, cursor, texture, timeout); m_deviceContext->CopyResource(m_texture[0], m_ftexture);
if (timeout)
return GRAB_STATUS_TIMEOUT;
if (result != GRAB_STATUS_OK)
return result;
m_deviceContext->CopyResource(m_texture[0], texture);
result = ReleaseFrame(); result = ReleaseFrame();
if (result != GRAB_STATUS_OK) if (result != GRAB_STATUS_OK)
@ -556,21 +554,12 @@ GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame, struct CursorInfo & cu
return GRAB_STATUS_OK; return GRAB_STATUS_OK;
} }
GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame, struct CursorInfo & cursor) GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame)
{ {
GrabStatus result; GrabStatus result;
ID3D11Texture2DPtr texture;
bool timeout;
result = GrabFrameTexture(frame, cursor, texture, timeout);
if (timeout)
return GRAB_STATUS_TIMEOUT;
if (result != GRAB_STATUS_OK)
return result;
TextureList planes; TextureList planes;
if (!m_textureConverter->Convert(texture, planes)) if (!m_textureConverter->Convert(m_ftexture, planes))
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
for(int i = 0; i < 3; ++i) for(int i = 0; i < 3; ++i)
@ -624,7 +613,7 @@ GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame, struct Curso
return GRAB_STATUS_OK; return GRAB_STATUS_OK;
} }
GrabStatus Capture::DXGI::GrabFrameH264(struct FrameInfo & frame, struct CursorInfo & cursor) GrabStatus Capture::DXGI::GrabFrameH264(struct FrameInfo & frame)
{ {
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
#if 0 #if 0
@ -673,16 +662,27 @@ GrabStatus Capture::DXGI::GrabFrameH264(struct FrameInfo & frame, struct CursorI
#endif #endif
} }
GrabStatus DXGI::GrabFrame(struct FrameInfo & frame, struct CursorInfo & cursor) GrabStatus DXGI::GetFrame(struct FrameInfo & frame)
{ {
if (!m_ftexture)
{
DEBUG_ERROR("A frame has not been captured");
return GRAB_STATUS_ERROR;
}
frame.width = m_width; frame.width = m_width;
frame.height = m_height; frame.height = m_height;
switch (m_frameType) switch (m_frameType)
{ {
case FRAME_TYPE_YUV420: return GrabFrameYUV420(frame, cursor); case FRAME_TYPE_YUV420: return GrabFrameYUV420(frame);
case FRAME_TYPE_H264 : return GrabFrameH264 (frame, cursor); case FRAME_TYPE_H264 : return GrabFrameH264 (frame);
} }
return GrabFrameRaw(frame, cursor); return GrabFrameRaw(frame);
}
const CursorInfo & DXGI::GetCursor()
{
return m_cursor;
} }

View file

@ -56,18 +56,23 @@ namespace Capture
enum FrameType GetFrameType(); enum FrameType GetFrameType();
size_t GetMaxFrameSize(); size_t GetMaxFrameSize();
enum GrabStatus GrabFrame(struct FrameInfo & frame, struct CursorInfo & cursor); GrabStatus Capture();
GrabStatus GetFrame (struct FrameInfo & frame );
const CursorInfo & GetCursor();
GrabStatus DiscardFrame();
private: private:
bool InitRawCapture(); bool InitRawCapture();
bool InitYUV420Capture(); bool InitYUV420Capture();
bool InitH264Capture(); bool InitH264Capture();
GrabStatus GrabFrameTexture(struct FrameInfo & frame, struct CursorInfo & cursor, ID3D11Texture2DPtr & texture, bool & timeout); struct CursorInfo m_cursor;
ID3D11Texture2DPtr m_ftexture;
GrabStatus ReleaseFrame(); GrabStatus ReleaseFrame();
GrabStatus GrabFrameRaw (struct FrameInfo & frame, struct CursorInfo & cursor); GrabStatus GrabFrameRaw (struct FrameInfo & frame);
GrabStatus GrabFrameYUV420 (struct FrameInfo & frame, struct CursorInfo & cursor); GrabStatus GrabFrameYUV420 (struct FrameInfo & frame);
GrabStatus GrabFrameH264 (struct FrameInfo & frame, struct CursorInfo & cursor); GrabStatus GrabFrameH264 (struct FrameInfo & frame);
CaptureOptions * m_options; CaptureOptions * m_options;

View file

@ -71,5 +71,8 @@ public:
virtual bool ReInitialize() = 0; virtual bool ReInitialize() = 0;
virtual enum FrameType GetFrameType() = 0; virtual enum FrameType GetFrameType() = 0;
virtual size_t GetMaxFrameSize() = 0; virtual size_t GetMaxFrameSize() = 0;
virtual enum GrabStatus GrabFrame(struct FrameInfo & frame, struct CursorInfo & cursor) = 0; virtual enum GrabStatus Capture() = 0;
virtual enum GrabStatus GetFrame(struct FrameInfo & frame) = 0;
virtual const CursorInfo & GetCursor() = 0;
virtual enum GrabStatus DiscardFrame() = 0;
}; };

View file

@ -98,8 +98,8 @@ bool Service::Initialize(ICapture * captureDevice)
m_shmHeader->version = KVMFR_HEADER_VERSION; m_shmHeader->version = KVMFR_HEADER_VERSION;
// zero and tell the client we have restarted // zero and tell the client we have restarted
ZeroMemory(&m_shmHeader->frame , sizeof(KVMFRFrame )); ZeroMemory(&(m_shmHeader->frame ), sizeof(KVMFRFrame ));
ZeroMemory(&m_shmHeader->cursor, sizeof(KVMFRCursor)); ZeroMemory(&(m_shmHeader->cursor), sizeof(KVMFRCursor));
m_shmHeader->flags &= ~KVMFR_HEADER_FLAG_RESTART; m_shmHeader->flags &= ~KVMFR_HEADER_FLAG_RESTART;
m_haveFrame = false; m_haveFrame = false;
@ -171,54 +171,28 @@ bool Service::Process()
if (!m_initialized) if (!m_initialized)
return false; return false;
volatile uint8_t *flags = &m_shmHeader->flags; volatile uint8_t *flags = &(m_shmHeader->flags);
int tryCount = 0;
// wait for the host to notify that is it is ready to proceed // check if the client has flagged a restart
while (true) if (*flags & KVMFR_HEADER_FLAG_RESTART)
{ {
// check if the client has flagged a restart DEBUG_INFO("Restart Requested");
if (*flags & KVMFR_HEADER_FLAG_RESTART) if (!m_capture->ReInitialize())
{ {
DEBUG_INFO("Restart Requested"); DEBUG_ERROR("ReInitialize Failed");
if (!m_capture->ReInitialize()) return false;
{
DEBUG_ERROR("ReInitialize Failed");
return false;
}
if (m_capture->GetMaxFrameSize() > m_frameSize)
{
DEBUG_ERROR("Maximum frame size of %zd bytes exceeds maximum space available", m_capture->GetMaxFrameSize());
return false;
}
INTERLOCKED_AND8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART));
break;
} }
// check if the client has flagged it's ready for a frame if (m_capture->GetMaxFrameSize() > m_frameSize)
if (!(m_shmHeader->frame.flags & KVMFR_FRAME_FLAG_UPDATE))
break;
// save CPU if the client has stopped polling for updates
if (++tryCount > m_tryTarget * 400)
{ {
m_tryTarget = 250; DEBUG_ERROR("Maximum frame size of %zd bytes exceeds maximum space available", m_capture->GetMaxFrameSize());
Sleep(100); return false;
} }
INTERLOCKED_AND8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART));
} }
int diff = (tryCount - m_lastTryCount) / 200; GrabStatus result;
m_lastTryCount = tryCount;
m_tryTarget += diff;
if (m_tryTarget < 250)
m_tryTarget = 250;
struct FrameInfo frame = {0};
struct CursorInfo cursor = {0};
frame.buffer = m_frame[m_frameIndex];
frame.bufferSize = m_frameSize;
bool ok = false; bool ok = false;
bool cursorOnly = false; bool cursorOnly = false;
@ -226,7 +200,7 @@ bool Service::Process()
for(int i = 0; i < 2; ++i) for(int i = 0; i < 2; ++i)
{ {
// capture a frame of data // capture a frame of data
switch (m_capture->GrabFrame(frame, cursor)) switch (m_capture->Capture())
{ {
case GRAB_STATUS_OK: case GRAB_STATUS_OK:
ok = true; ok = true;
@ -298,6 +272,8 @@ bool Service::Process()
return false; return false;
} }
const CursorInfo & cursor = m_capture->GetCursor();
if (cursor.updated) if (cursor.updated)
{ {
EnterCriticalSection(&m_cursorCS); EnterCriticalSection(&m_cursorCS);
@ -326,24 +302,48 @@ bool Service::Process()
if (!cursorOnly) if (!cursorOnly)
{ {
KVMFRFrame * fi = &m_shmHeader->frame; volatile KVMFRFrame * fi = &(m_shmHeader->frame);
// only update the header if the frame is new // only update the header if the frame is new
if (!repeat) if (!repeat)
{ {
FrameInfo frame = { 0 };
frame.buffer = m_frame[m_frameIndex];
frame.bufferSize = m_frameSize;
result = m_capture->GetFrame(frame);
if (result != GRAB_STATUS_OK)
return result;
/* don't touch the frame inforamtion until the client is done with it */
while (fi->flags & KVMFR_FRAME_FLAG_UPDATE)
{
if (*flags & KVMFR_HEADER_FLAG_RESTART)
break;
}
fi->type = m_capture->GetFrameType(); fi->type = m_capture->GetFrameType();
fi->width = frame.width; fi->width = frame.width;
fi->height = frame.height; fi->height = frame.height;
fi->stride = frame.stride; fi->stride = frame.stride;
fi->pitch = frame.pitch; fi->pitch = frame.pitch;
fi->dataPos = m_dataOffset[m_frameIndex]; fi->dataPos = m_dataOffset[m_frameIndex];
if (++m_frameIndex == MAX_FRAMES)
m_frameIndex = 0;
// remember that we have a valid frame
m_haveFrame = true;
}
else
{
/* don't touch the frame inforamtion until the client is done with it */
while (fi->flags & KVMFR_FRAME_FLAG_UPDATE)
{
if (*flags & KVMFR_HEADER_FLAG_RESTART)
break;
}
} }
if (++m_frameIndex == MAX_FRAMES)
m_frameIndex = 0;
// remember that we have a valid frame
m_haveFrame = true;
// signal a frame update // signal a frame update
fi->flags |= KVMFR_FRAME_FLAG_UPDATE; fi->flags |= KVMFR_FRAME_FLAG_UPDATE;
@ -361,7 +361,7 @@ DWORD Service::CursorThread()
if (WaitForSingleObject(m_cursorEvent, 1000) != WAIT_OBJECT_0) if (WaitForSingleObject(m_cursorEvent, 1000) != WAIT_OBJECT_0)
continue; continue;
KVMFRCursor * cursor = &m_shmHeader->cursor; volatile KVMFRCursor * cursor = &(m_shmHeader->cursor);
// wait until the client is ready // wait until the client is ready
while (cursor->flags != 0) while (cursor->flags != 0)
{ {