Compare commits

...

14 Commits
a5 ... a6

Author SHA1 Message Date
Geoffrey McRae
7c5b2b5c1c [host] dxgi: re-send the last frame if capture times out
This change prevents the guest from stalling on startup if there are no
frames being captured
2017-12-16 10:24:37 +11:00
Geoffrey McRae
758b7af754 [host] use a local copy of the header and then update it all in one go
Writing to shared memory is much faster then reading as the shared
memory is not cached, this change ensures we are using a local copy
of the header performing the final update all in one go.
2017-12-16 10:06:55 +11:00
jmossman
b89a8fee04 [host] simplify dll loading 2017-12-16 07:01:41 +11:00
Geoffrey McRae
2bb8b0227c [client] don't send renderer mouse events until it's configured 2017-12-15 19:14:02 +11:00
Geoffrey McRae
ae4156d041 [client] don't update mouse scaling values until started 2017-12-15 19:14:02 +11:00
Patrick Steinhardt
fe337cf510 [client] ivshmem: fix missing <sys/select.h> include
While the function `ivshmem_wait_irq` makes use of the select(3)
function, it does not include <sys/select.h>. This happens to work on
glibc based systems, which include thet file transitively via other
header files. But on musl libc based systems, this breaks compilation.

Directly include <sys/select.h> to fix the problem.
2017-12-15 18:25:21 +11:00
Geoffrey McRae
7bfed41523 [client] opengl: update mouse draw time when doing decoupled draws 2017-12-15 17:03:51 +11:00
Geoffrey McRae
9bb66b7bd6 [client] opengl: decouple mouse updates from vsync 2017-12-15 16:58:21 +11:00
Geoffrey McRae
f7420317f1 [client] opengl: mouse shape updates bypass the draw timeout 2017-12-15 16:53:26 +11:00
Geoffrey McRae
c1379a45d2 [client] opengl: increase maximum mouse draw frequency 2017-12-15 16:34:29 +11:00
Geoffrey McRae
9c03327701 [client] opengl: added back double buffering and vsync support
This adds back in double buffering and vsync support. This has been
carefully implemented so that the render function blocks until the video
card reports that it has advanced a frame, this ensures that the OpenGL
pipeline never buffers frames.
2017-12-15 16:21:38 +11:00
Geoffrey McRae
0d8b2449cf [client] added back missing vsync disable option 2017-12-15 16:19:47 +11:00
Arti Zirk
d1bd5b3115 Do not minimize fullscreen window on focus loss 2017-12-15 15:59:28 +11:00
Jack Karamanian
e03621a622 [client] Add borderless fullscreen usage 2017-12-15 15:59:09 +11:00
10 changed files with 230 additions and 132 deletions

View File

@@ -30,6 +30,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <sys/mman.h>
@@ -544,4 +545,4 @@ bool ivshmem_kick_irq(uint16_t clientID, uint16_t vector)
DEBUG_ERROR("failed to send kick");
return false;
}
}

View File

@@ -41,6 +41,7 @@ typedef struct LG_RendererParams
TTF_Font * font;
bool showFPS;
bool resample;
bool vsync;
}
LG_RendererParams;
@@ -97,4 +98,4 @@ typedef struct LG_Renderer
LG_RendererOnFrameEvent on_frame_event;
LG_RendererRender render;
}
LG_Renderer;
LG_Renderer;

View File

@@ -50,6 +50,7 @@ struct AppState
SDL_Point srcSize;
LG_RendererRect dstRect;
SDL_Point cursor;
bool cursorVisible;
bool haveCursorPos;
float scaleX, scaleY;
@@ -63,6 +64,7 @@ struct AppState
struct AppParams
{
bool vsync;
bool autoResize;
bool allowResize;
bool keepAspect;
@@ -84,6 +86,7 @@ struct AppParams
struct AppState state;
struct AppParams params =
{
.vsync = true,
.autoResize = false,
.allowResize = true,
.keepAspect = true,
@@ -136,8 +139,11 @@ inline void updatePositionInfo()
state.dstRect.h = h;
}
state.scaleX = (float)state.srcSize.y / (float)state.dstRect.h;
state.scaleY = (float)state.srcSize.x / (float)state.dstRect.w;
if (state.started)
{
state.scaleX = (float)state.srcSize.y / (float)state.dstRect.h;
state.scaleY = (float)state.srcSize.x / (float)state.dstRect.w;
}
if (state.lgr)
state.lgr->on_resize(state.lgrData, w, h, state.dstRect);
@@ -147,6 +153,12 @@ int renderThread(void * unused)
{
bool error = false;
struct KVMFRHeader header;
LG_RendererCursor cursorType = LG_CURSOR_COLOR;
struct KVMFRCursor cursor = {};
size_t cursorDataSize = 0;
uint8_t * cursorData = NULL;
volatile uint32_t * updateCount = &state.shm->updateCount;
memset(&header, 0, sizeof(struct KVMFRHeader));
@@ -254,7 +266,35 @@ int renderThread(void * unused)
state.srcSize.y = header.frame.height;
if (params.autoResize)
SDL_SetWindowSize(state.window, header.frame.width, header.frame.height);
state.started = true;
updatePositionInfo();
// if we have saved shape info, send it now
if (cursorData)
{
if (!state.lgr->on_mouse_shape(state.lgrData, cursorType, cursor.w,
cursor.h, cursor.pitch, cursorData))
{
DEBUG_ERROR("Failed to update mouse shape");
break;
}
free(cursorData);
cursorData = NULL;
cursorDataSize = 0;
}
// if we have a cursor position, send it now
if (state.haveCursorPos)
{
state.lgr->on_mouse_event(
state.lgrData,
state.cursorVisible,
state.cursor.x,
state.cursor.y
);
}
}
const uint8_t * data = (const uint8_t *)state.shm + header.frame.dataPos;
@@ -272,24 +312,29 @@ int renderThread(void * unused)
{
state.cursor.x = header.cursor.x;
state.cursor.y = header.cursor.y;
state.cursorVisible = header.cursor.flags & KVMFR_CURSOR_FLAG_VISIBLE;
state.haveCursorPos = true;
}
if (header.cursor.flags & KVMFR_CURSOR_FLAG_SHAPE)
{
LG_RendererCursor c = LG_CURSOR_COLOR;
switch(header.cursor.type)
{
case CURSOR_TYPE_COLOR : c = LG_CURSOR_COLOR ; break;
case CURSOR_TYPE_MONOCHROME : c = LG_CURSOR_MONOCHROME ; break;
case CURSOR_TYPE_MASKED_COLOR: c = LG_CURSOR_MASKED_COLOR; break;
default:
DEBUG_ERROR("Invalid cursor type");
break;
}
if (state.lgr)
{
bool bad = false;
switch(header.cursor.type)
{
case CURSOR_TYPE_COLOR : cursorType = LG_CURSOR_COLOR ; break;
case CURSOR_TYPE_MONOCHROME : cursorType = LG_CURSOR_MONOCHROME ; break;
case CURSOR_TYPE_MASKED_COLOR: cursorType = LG_CURSOR_MASKED_COLOR; break;
default:
DEBUG_ERROR("Invalid cursor type");
bad = true;
break;
}
if (bad)
break;
// check the data position is sane
const uint64_t dataSize = header.cursor.h * header.cursor.pitch;
if (header.cursor.dataPos + dataSize > state.shmSize)
@@ -299,14 +344,22 @@ int renderThread(void * unused)
}
const uint8_t * data = (const uint8_t *)state.shm + header.cursor.dataPos;
if (!state.lgr->on_mouse_shape(
state.lgrData,
c,
header.cursor.w,
header.cursor.h,
header.cursor.pitch,
data
))
if (!state.started)
{
// save off the cursor data so we can tell the renderer when it's ready
if (cursorDataSize < dataSize)
{
if (cursorData) free(cursorData);
cursorData = (uint8_t *)malloc(dataSize);
cursorDataSize = dataSize;
}
memcpy(&cursor, &header.cursor, sizeof(struct KVMFRCursor));
memcpy(cursorData, data, dataSize);
continue;
}
if (!state.lgr->on_mouse_shape(state.lgrData, cursorType, header.cursor.w,
header.cursor.h, header.cursor.pitch, data))
{
DEBUG_ERROR("Failed to update mouse shape");
break;
@@ -314,21 +367,24 @@ int renderThread(void * unused)
}
}
if (state.lgr)
if (state.lgr && state.started)
{
state.lgr->on_mouse_event(
state.lgrData,
(header.cursor.flags & KVMFR_CURSOR_FLAG_VISIBLE) != 0,
state.cursorVisible,
state.cursor.x,
state.cursor.y
);
}
}
if (state.lgr)
if (state.started && state.lgr)
state.lgr->render(state.lgrData);
}
if (cursorData)
free(cursorData);
return 0;
}
@@ -631,6 +687,7 @@ int run()
lgrParams.font = state.font;
lgrParams.resample = params.useMipmap;
lgrParams.showFPS = params.showFPS;
lgrParams.vsync = params.vsync;
Uint32 sdlFlags;
// probe for a a suitable renderer
@@ -676,6 +733,11 @@ int run()
)
);
if (params.fullscreen)
{
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
}
// set the compositor hint to bypass for low latency
SDL_SysWMinfo wminfo;
SDL_VERSION(&wminfo.version);
@@ -841,13 +903,14 @@ void doHelp(char * app)
" -M Don't hide the host cursor\n"
"\n"
" -m Disable mipmapping\n"
" -v Disable VSync\n"
" -v Disable VSYNC\n"
" -k Enable FPS display\n"
"\n"
" -a Auto resize the window to the guest\n"
" -n Don't allow the window to be manually resized\n"
" -r Don't maintain the aspect ratio\n"
" -d Borderless mode\n"
" -F Borderless fullscreen mode\n"
" -x XPOS Initial window X position [current: %s]\n"
" -y YPOS Initial window Y position [current: %s]\n"
" -w WIDTH Initial window width [current: %u]\n"
@@ -894,7 +957,7 @@ void doLicense()
int main(int argc, char * argv[])
{
int c;
while((c = getopt(argc, argv, "hf:sc:p:jMmkanrdFx:y:w:b:l")) != -1)
while((c = getopt(argc, argv, "hf:sc:p:jMmvkanrdFx:y:w:b:l")) != -1)
switch(c)
{
case '?':
@@ -931,6 +994,10 @@ int main(int argc, char * argv[])
params.useMipmap = false;
break;
case 'v':
params.vsync = false;
break;
case 'k':
params.showFPS = true;
break;

View File

@@ -47,6 +47,7 @@ struct LGR_OpenGL
{
LG_RendererParams params;
bool configured;
SDL_Window * sdlWindow;
SDL_GLContext glContext;
bool doneInfo;
@@ -81,6 +82,7 @@ struct LGR_OpenGL
SDL_Rect fpsRect;
bool mouseUpdate;
bool newShape;
uint64_t lastMouseDraw;
LG_RendererCursor mouseType;
bool mouseVisible;
@@ -131,7 +133,7 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, Uint3
}
*sdlFlags = SDL_WINDOW_OPENGL;
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
return true;
}
@@ -147,6 +149,7 @@ bool lgr_opengl_configure(void * opaque, SDL_Window *window, const LG_RendererFo
return false;
}
this->sdlWindow = window;
this->glContext = SDL_GL_CreateContext(window);
if (!this->glContext)
{
@@ -168,7 +171,7 @@ bool lgr_opengl_configure(void * opaque, SDL_Window *window, const LG_RendererFo
return false;
}
SDL_GL_SetSwapInterval(0);
SDL_GL_SetSwapInterval(this->params.vsync ? 1 : 0);
// check if the GPU supports GL_ARB_buffer_storage first
// there is no advantage to this renderer if it is not present.
@@ -491,6 +494,7 @@ bool lgr_opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, co
}
this->mouseUpdate = true;
this->newShape = true;
return true;
}
@@ -700,15 +704,27 @@ bool lgr_opengl_render(void * opaque)
if (!this->mouseUpdate)
return true;
// don't update the mouse too fast
const uint64_t delta = nanotime() - this->lastMouseDraw;
if (delta < 1e7)
return true;
}
if (!this->newShape)
{
// don't update the mouse too fast
const uint64_t delta = nanotime() - this->lastMouseDraw;
if (delta < 5e6)
return true;
}
this->newShape = false;
// wait for vsync
unsigned int count;
glXWaitVideoSyncSGI(1, 0, &count);
glDrawBuffer(GL_FRONT);
glCallList(this->texList + this->texIndex);
lgr_opengl_draw_mouse(this);
if (this->fpsTexture)
glCallList(this->fpsList);
glDrawBuffer(GL_BACK);
glFlush();
this->mouseUpdate = false;
this->lastMouseDraw = nanotime();
return true;
}
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
@@ -718,7 +734,15 @@ bool lgr_opengl_render(void * opaque)
lgr_opengl_draw_mouse(this);
if (this->fpsTexture)
glCallList(this->fpsList);
glFlush();
unsigned int before, after;
glXGetVideoSyncSGI(&before);
SDL_GL_SwapWindow(this->sdlWindow);
// wait for the swap to happen to ensure we dont buffer frames
glXGetVideoSyncSGI(&after);
if (before == after)
glXWaitVideoSyncSGI(1, 0, &before);
++this->frameCount;
const uint64_t t = nanotime();

View File

@@ -31,6 +31,7 @@ DXGI::DXGI() :
m_deviceContext(),
m_dup(),
m_texture(),
m_surface(),
m_pointer(NULL)
{
}
@@ -190,6 +191,15 @@ void DXGI::DeInitialize()
m_pointerBufSize = 0;
}
if (m_surfaceMapped)
{
m_surface->Unmap();
m_surfaceMapped = false;
}
if (m_surface)
m_surface.Release();
if (m_texture)
m_texture.Release();
@@ -241,7 +251,22 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
{
while(true)
{
status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res);
status = m_dup->AcquireNextFrame(1000, &frameInfo, &res);
if (status == DXGI_ERROR_WAIT_TIMEOUT)
{
if (!m_surfaceMapped)
break;
// send the last frame again if we timeout to prevent the client stalling on restart
frame.width = m_desc.Width;
frame.height = m_desc.Height;
frame.stride = m_rect.Pitch / 4;
unsigned int size = m_height * m_rect.Pitch;
memcpySSE(frame.buffer, m_rect.pBits, size < frame.bufferSize ? size : frame.bufferSize);
return GRAB_STATUS_OK;
}
if (!SUCCEEDED(status))
break;
@@ -371,8 +396,7 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
return GRAB_STATUS_ERROR;
}
D3D11_TEXTURE2D_DESC desc;
src->GetDesc(&desc);
src->GetDesc(&m_desc);
m_deviceContext->CopyResource(m_texture, src);
@@ -380,38 +404,42 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
res.Release();
src.Release();
IDXGISurface1Ptr surface(m_texture);
if (!surface)
if (m_surfaceMapped)
{
status = m_surface->Unmap();
if (FAILED(status))
{
DEBUG_ERROR("Failed to unmap surface: %08x", (int)status);
return GRAB_STATUS_ERROR;
}
m_surfaceMapped = false;
m_surface.Release();
}
m_surface = m_texture;
if (!m_surface)
{
DEBUG_ERROR("Failed to get IDXGISurface1");
return GRAB_STATUS_ERROR;
}
DXGI_MAPPED_RECT rect;
status = surface->Map(&rect, DXGI_MAP_READ);
status = m_surface->Map(&m_rect, DXGI_MAP_READ);
if (FAILED(status))
{
DEBUG_ERROR("Failed to map surface: %08x", (int)status);
return GRAB_STATUS_ERROR;
}
m_surfaceMapped = true;
m_width = desc.Width;
m_height = desc.Height;
m_width = m_desc.Width;
m_height = m_desc.Height;
frame.width = desc.Width;
frame.height = desc.Height;
frame.stride = rect.Pitch / 4;
frame.width = m_desc.Width;
frame.height = m_desc.Height;
frame.stride = m_rect.Pitch / 4;
unsigned int size = m_height * rect.Pitch;
memcpySSE(frame.buffer, rect.pBits, size < frame.bufferSize ? size : frame.bufferSize);
status = surface->Unmap();
if (FAILED(status))
{
DEBUG_ERROR("Failed to unmap surface: %08x", (int)status);
return GRAB_STATUS_ERROR;
}
unsigned int size = m_height * m_rect.Pitch;
memcpySSE(frame.buffer, m_rect.pBits, size < frame.bufferSize ? size : frame.bufferSize);
return GRAB_STATUS_OK;
}

View File

@@ -80,6 +80,10 @@ namespace Capture
IDXGIOutput1Ptr m_output;
IDXGIOutputDuplicationPtr m_dup;
ID3D11Texture2DPtr m_texture;
IDXGISurface1Ptr m_surface;
D3D11_TEXTURE2D_DESC m_desc;
DXGI_MAPPED_RECT m_rect;
bool m_surfaceMapped;
BYTE * m_pointer;
UINT m_pointerBufSize;
UINT m_pointerSize;

View File

@@ -61,11 +61,10 @@ bool NvFBC::Initialize(CaptureOptions * options)
if (_strcmpi(*it, "nowait") == 0) { m_optNoWait = true ; continue; }
}
std::string nvfbc = Util::GetSystemRoot() + "\\" + NVFBC_LIBRARY_NAME;
m_hDLL = LoadLibraryA(nvfbc.c_str());
m_hDLL = LoadLibraryA(NVFBC_LIBRARY_NAME);
if (!m_hDLL)
{
DEBUG_ERROR("Failed to load the NvFBC library: %d - %s", GetLastError(), nvfbc.c_str());
DEBUG_ERROR("Failed to load the NvFBC library: %d - %s", GetLastError(), NVFBC_LIBRARY_NAME);
return false;
}
@@ -76,7 +75,7 @@ bool NvFBC::Initialize(CaptureOptions * options)
if (!m_fnCreateEx || !m_fnSetGlobalFlags || !m_fnGetStatusEx || !m_fnEnable)
{
DEBUG_ERROR("Unable to locate required entry points in %s", nvfbc.c_str());
DEBUG_ERROR("Unable to locate required entry points in %s", NVFBC_LIBRARY_NAME);
DeInitialize();
return false;
}

View File

@@ -40,7 +40,7 @@ Service::Service() :
m_memory(NULL),
m_timer(NULL),
m_capture(NULL),
m_header(NULL),
m_shmHeader(NULL),
m_frameIndex(0),
m_cursorDataSize(0),
m_cursorData(NULL),
@@ -92,15 +92,15 @@ bool Service::Initialize(ICapture * captureDevice)
}
// update everything except for the hostID
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->updateCount = 0;
memcpy(m_shmHeader->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC));
m_shmHeader->version = KVMFR_HEADER_VERSION;
m_shmHeader->guestID = m_ivshmem->GetPeerID();
m_shmHeader->updateCount = 0;
// clear but retain the restart flag if it was set by the client
INTERLOCKED_AND8((char *)&m_header->flags, KVMFR_HEADER_FLAG_RESTART);
ZeroMemory(&m_header->frame , sizeof(KVMFRFrame ));
ZeroMemory(&m_header->cursor, sizeof(KVMFRCursor));
INTERLOCKED_AND8((char *)&m_shmHeader->flags, KVMFR_HEADER_FLAG_RESTART);
ZeroMemory(&m_shmHeader->frame , sizeof(KVMFRFrame ));
ZeroMemory(&m_shmHeader->cursor, sizeof(KVMFRCursor));
m_initialized = true;
return true;
@@ -108,7 +108,7 @@ bool Service::Initialize(ICapture * captureDevice)
bool Service::InitPointers()
{
m_header = reinterpret_cast<KVMFRHeader *>(m_memory);
m_shmHeader = reinterpret_cast<KVMFRHeader *>(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;
@@ -142,7 +142,7 @@ void Service::DeInitialize()
m_cursorData = NULL;
}
m_header = NULL;
m_shmHeader = NULL;
m_frame[0] = NULL;
m_frame[1] = NULL;
m_dataOffset[0] = 0;
@@ -171,7 +171,7 @@ bool Service::Process()
frame.buffer = m_frame[m_frameIndex];
frame.bufferSize = m_frameSize;
volatile uint8_t *flags = &m_header->flags;
volatile uint8_t *flags = &m_shmHeader->flags;
// wait for the host to notify that is it is ready to proceed
while (true)
@@ -181,7 +181,7 @@ bool Service::Process()
// check if the client has flagged a restart
if (f & KVMFR_HEADER_FLAG_RESTART)
{
m_header->updateCount = 0;
m_shmHeader->updateCount = 0;
INTERLOCKED_AND8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART));
restart = true;
break;
@@ -252,17 +252,17 @@ bool Service::Process()
}
uint8_t updateFlags = 0;
m_header->cursor.flags = 0;
m_header.cursor.flags = 0;
if (!cursorOnly)
{
// signal a frame update
updateFlags |= 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];
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;
}
@@ -280,11 +280,11 @@ bool Service::Process()
// tell the host where the cursor is
updateFlags |= KVMFR_HEADER_FLAG_CURSOR;
m_header->cursor.flags |= KVMFR_CURSOR_FLAG_POS;
m_header.cursor.flags |= KVMFR_CURSOR_FLAG_POS;
if (m_cursor.visible)
m_header->cursor.flags |= KVMFR_CURSOR_FLAG_VISIBLE;
m_header->cursor.x = m_cursor.x;
m_header->cursor.y = m_cursor.y;
m_header.cursor.flags |= KVMFR_CURSOR_FLAG_VISIBLE;
m_header.cursor.x = m_cursor.x;
m_header.cursor.y = m_cursor.y;
}
if (frame.cursor.hasShape || m_shapePending || (m_cursor.hasShape && restart))
@@ -323,15 +323,15 @@ bool Service::Process()
{
// give the host the new cursor shape
updateFlags |= KVMFR_HEADER_FLAG_CURSOR;
m_header->cursor.flags |= KVMFR_CURSOR_FLAG_SHAPE;
m_header.cursor.flags |= KVMFR_CURSOR_FLAG_SHAPE;
if (m_cursor.visible)
m_header->cursor.flags |= KVMFR_CURSOR_FLAG_VISIBLE;
m_header.cursor.flags |= KVMFR_CURSOR_FLAG_VISIBLE;
m_header->cursor.type = m_cursor.type;
m_header->cursor.w = m_cursor.w;
m_header->cursor.h = m_cursor.h;
m_header->cursor.pitch = m_cursor.pitch;
m_header->cursor.dataPos = m_dataOffset[m_frameIndex];
m_header.cursor.type = m_cursor.type;
m_header.cursor.w = m_cursor.w;
m_header.cursor.h = m_cursor.h;
m_header.cursor.pitch = m_cursor.pitch;
m_header.cursor.dataPos = m_dataOffset[m_frameIndex];
memcpy(m_frame[m_frameIndex], m_cursorData, m_cursor.dataSize);
m_shapePending = false;
@@ -344,8 +344,16 @@ bool Service::Process()
INTERLOCKED_AND8((volatile char *)flags, KVMFR_HEADER_FLAG_RESTART);
INTERLOCKED_OR8 ((volatile char *)flags, updateFlags);
// increment the update count to resume the host
++m_header->updateCount;
// update the shared header but don't touch the setup fields
const size_t offset = (uintptr_t)&m_header.frame - (uintptr_t)&m_header;
memcpy(
(uint8_t *)m_shmHeader + offset,
(uint8_t *)&m_header + offset,
sizeof(KVMFRHeader) - offset
);
// increment the update count so the guest stops waiting
++m_shmHeader->updateCount;
return true;
}

View File

@@ -54,7 +54,8 @@ private:
HANDLE m_timer;
ICapture * m_capture;
KVMFRHeader * m_header;
KVMFRHeader m_header;
KVMFRHeader * m_shmHeader;
uint8_t * m_frame[2];
size_t m_frameSize;
uint64_t m_dataOffset[2];

View File

@@ -23,45 +23,10 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <inttypes.h>
#include <tmmintrin.h>
#include "common\debug.h"
class Util
{
public:
static std::string GetSystemRoot()
{
std::string defaultPath;
size_t pathSize;
char *libPath;
if (_dupenv_s(&libPath, &pathSize, "SystemRoot") != 0)
{
DEBUG_ERROR("Unable to get the SystemRoot environment variable");
return defaultPath;
}
if (!pathSize)
{
DEBUG_ERROR("The SystemRoot environment variable is not set");
return defaultPath;
}
#ifdef _WIN64
defaultPath = std::string(libPath) + "\\System32";
#else
if (IsWow64())
{
defaultPath = std::string(libPath) + "\\Syswow64";
}
else
{
defaultPath = std::string(libPath) + "\\System32";
}
#endif
return defaultPath;
}
static inline void BGRAtoRGB(uint8_t * orig, size_t imagesize, uint8_t * dest)
{
assert((uintptr_t)orig % 16 == 0);