Compare commits

..

12 Commits
a1 ... a2

Author SHA1 Message Date
Geoffrey McRae
8c2709a3f4 Revert "[client] disable hacky vsync code now we are single buffering"
This reverts commit d55f0bf841.
2017-12-14 10:40:51 +11:00
Geoffrey McRae
d55f0bf841 [client] disable hacky vsync code now we are single buffering 2017-12-14 10:35:38 +11:00
Geoffrey McRae
dd0930d265 [client] our source is vairable frame rate, we can't double buffer at all 2017-12-14 10:30:55 +11:00
Geoffrey McRae
04f7800df4 [client] remove silly wait logic 2017-12-14 10:12:31 +11:00
Geoffrey McRae
d8a80a1cfc [client] move startup later as DXGI stalls when nothing is going on 2017-12-14 10:08:47 +11:00
Geoffrey McRae
9d29b1195d [client] treat buffers correctly 2017-12-14 10:06:22 +11:00
Geoffrey McRae
2374b1a9fb [client] make methods static inline 2017-12-14 08:23:58 +11:00
Geoffrey McRae
163f612efa [host] treat flags field as volatile 2017-12-14 06:56:33 +11:00
Geoffrey McRae
a7180a5609 [client] another try at better screen sync 2017-12-14 06:54:53 +11:00
Geoffrey McRae
81f4a7fade [client] slow down mouse updates to something reasonable 2017-12-14 04:18:30 +11:00
Geoffrey McRae
7986350cb8 [client] switch to polling mode to fix stutting issues 2017-12-14 02:24:18 +11:00
Geoffrey McRae
e379f70784 [host] switch to fast polling mode, fixes stuttering issues 2017-12-14 02:23:11 +11:00
7 changed files with 189 additions and 178 deletions

View File

@@ -39,6 +39,7 @@ typedef struct LG_RendererParams
SDL_Window * window;
TTF_Font * font;
bool showFPS;
bool resample;
int width;
int height;
}
@@ -78,7 +79,7 @@ typedef bool (* LG_RendererIsCompatible )(void * opaque, const LG_Rende
typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect);
typedef bool (* LG_RendererOnMouseShape )(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data);
typedef bool (* LG_RendererOnMouseEvent )(void * opaque, const bool visible , const int x, const int y);
typedef bool (* LG_RendererOnFrameEvent )(void * opaque, const uint8_t * data, bool resample);
typedef bool (* LG_RendererOnFrameEvent )(void * opaque, const uint8_t * data);
typedef bool (* LG_RendererRender )(void * opaque);
typedef struct LG_Renderer

View File

@@ -166,11 +166,7 @@ int renderThread(void * unused)
// we must take a copy of the header, both to let the guest advance and to
// prevent the contained arguments being abused to overflow buffers
memcpy(&header, state.shm, sizeof(struct KVMFRHeader));
if (!ivshmem_kick_irq(header.guestID, 0))
{
usleep(1000);
continue;
}
__sync_or_and_fetch(&state.shm->flags, KVMFR_HEADER_FLAG_READY);
// check the header's magic and version are valid
if (
@@ -239,11 +235,12 @@ int renderThread(void * unused)
SDL_GetWindowSize(state.window, &width, &height);
LG_RendererParams lgrParams;
lgrParams.window = state.window;
lgrParams.font = state.font;
lgrParams.showFPS = params.showFPS;
lgrParams.width = width;
lgrParams.height = height;
lgrParams.window = state.window;
lgrParams.font = state.font;
lgrParams.resample = params.useMipmap;
lgrParams.showFPS = params.showFPS;
lgrParams.width = width;
lgrParams.height = height;
DEBUG_INFO("Data Format: w=%u, h=%u, s=%u, p=%u, bpp=%u",
lgrFormat.width, lgrFormat.height, lgrFormat.stride, lgrFormat.pitch, lgrFormat.bpp);
@@ -302,7 +299,7 @@ int renderThread(void * unused)
}
const uint8_t * data = (const uint8_t *)state.shm + header.frame.dataPos;
if (!state.lgr->on_frame_event(state.lgrData, data, params.useMipmap))
if (!state.lgr->on_frame_event(state.lgrData, data))
{
DEBUG_ERROR("Failed to render the frame");
break;
@@ -664,6 +661,8 @@ int run()
FcPatternDestroy(pat);
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
state.window = SDL_CreateWindow(
"Looking Glass (Client)",
params.center ? SDL_WINDOWPOS_CENTERED : params.x,
@@ -748,15 +747,6 @@ int run()
state.shmSize = ivshmem_get_map_size();
state.shm->hostID = ivshmem_get_id();
// flag the host that we are starting up this is important so that
// the host wakes up if it is waiting on an interrupt, the host will
// also send us the current mouse shape since we won't know it yet
DEBUG_INFO("Waiting for host to signal it's ready...");
__sync_or_and_fetch(&state.shm->flags, KVMFR_HEADER_FLAG_RESTART);
while(state.running && (state.shm->flags & KVMFR_HEADER_FLAG_RESTART))
usleep(1000);
DEBUG_INFO("Host ready, starting session");
if (params.useSpice)
{
if (!spice_connect(params.spiceHost, params.spicePort, ""))
@@ -786,6 +776,15 @@ int run()
break;
}
// flag the host that we are starting up this is important so that
// the host wakes up if it is waiting on an interrupt, the host will
// also send us the current mouse shape since we won't know it yet
DEBUG_INFO("Waiting for host to signal it's ready...");
__sync_or_and_fetch(&state.shm->flags, KVMFR_HEADER_FLAG_RESTART);
while(state.running && (state.shm->flags & KVMFR_HEADER_FLAG_RESTART))
usleep(1000);
DEBUG_INFO("Host ready, starting session");
while(state.running)
renderThread(NULL);

View File

@@ -14,11 +14,12 @@
#include "memcpySSE.h"
#include "utils.h"
#define VBO_BUFFERS 2
#define BUFFER_COUNT 1
#define FPS_TEXTURE (VBO_BUFFERS )
#define MOUSE_TEXTURE (VBO_BUFFERS+1)
#define TEXTURE_COUNT (VBO_BUFFERS+2)
#define FRAME_TEXTURE 0
#define FPS_TEXTURE 1
#define MOUSE_TEXTURE 2
#define TEXTURE_COUNT 3
static PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI = NULL;
static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI = NULL;
@@ -38,13 +39,14 @@ struct LGR_OpenGL
uint64_t drawStart;
bool hasBuffers;
GLuint vboID[VBO_BUFFERS];
uint8_t * texPixels[VBO_BUFFERS];
GLuint vboID[1];
uint8_t * texPixels[BUFFER_COUNT];
int texIndex;
int texList;
int fpsList;
int mouseList;
LG_RendererRect destRect;
bool mipmap;
bool hasTextures;
GLuint textures[TEXTURE_COUNT];
@@ -56,9 +58,9 @@ struct LGR_OpenGL
uint64_t frameCount;
SDL_Rect fpsRect;
bool mouseUpdate;
uint64_t lastMouseDraw;
LG_RendererCursor mouseType;
bool mouseRepair;
SDL_Rect mouseRepairPos;
bool mouseVisible;
SDL_Rect mousePos;
};
@@ -155,40 +157,44 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
this->texSize = format.height * format.pitch;
// generate lists for drawing
this->texList = glGenLists(2);
this->texList = glGenLists(BUFFER_COUNT);
this->fpsList = glGenLists(1);
this->mouseList = glGenLists(1);
// generate the pixel unpack buffers
glGenBuffers(VBO_BUFFERS, this->vboID);
glGenBuffers(1, this->vboID);
if (lgr_opengl_check_error("glGenBuffers"))
return false;
this->hasBuffers = true;
// persistant bind the buffers
for (int i = 0; i < VBO_BUFFERS; ++i)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[i]);
if (lgr_opengl_check_error("glBindBuffer"))
return false;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[0]);
if (lgr_opengl_check_error("glBindBuffer"))
return false;
glBufferStorage(GL_PIXEL_UNPACK_BUFFER, this->texSize, 0, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
if (lgr_opengl_check_error("glBufferStorage"))
return false;
glBufferStorage(
GL_PIXEL_UNPACK_BUFFER,
this->texSize * BUFFER_COUNT,
NULL,
GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT
);
if (lgr_opengl_check_error("glBufferStorage"))
return false;
this->texPixels[i] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
if (lgr_opengl_check_error("glMapBufferRange"))
return false;
this->texPixels[0] = glMapBufferRange(
GL_PIXEL_UNPACK_BUFFER,
0,
this->texSize * BUFFER_COUNT,
GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT
);
if (!this->texPixels[i])
{
DEBUG_ERROR("Failed to map the buffer range");
return false;
}
if (lgr_opengl_check_error("glMapBufferRange"))
return false;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
for(int i = 1; i < BUFFER_COUNT; ++i)
this->texPixels[i] = this->texPixels[i-1] + this->texSize;
// create the textures
glGenTextures(TEXTURE_COUNT, this->textures);
@@ -196,41 +202,51 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
return false;
this->hasTextures = true;
// bind the textures to the unpack buffers
for (int i = 0; i < VBO_BUFFERS; ++i)
{
glBindTexture(GL_TEXTURE_2D, this->textures[i]);
if (lgr_opengl_check_error("glBindTexture"))
return false;
// create the frame texture
glBindTexture(GL_TEXTURE_2D, this->textures[FRAME_TEXTURE]);
if (lgr_opengl_check_error("glBindTexture"))
return false;
glTexImage2D(
GL_TEXTURE_2D,
0,
this->intFormat,
format.width, format.height,
0,
this->vboFormat,
GL_UNSIGNED_BYTE,
(void*)0
);
glTexImage2D(
GL_TEXTURE_2D,
0,
this->intFormat,
format.width,
format.height * BUFFER_COUNT,
0,
this->vboFormat,
GL_UNSIGNED_BYTE,
(void*)0
);
if (lgr_opengl_check_error("glTexImage2D"))
return false;
// configure the texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
for (int i = 0; i < BUFFER_COUNT; ++i)
{
const float ts = (1.0f / BUFFER_COUNT) * i;
const float te = (1.0f / BUFFER_COUNT) + ts;
// create the display lists
glNewList(this->texList + i, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, this->textures[i]);
glBindTexture(GL_TEXTURE_2D, this->textures[FRAME_TEXTURE]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f); glVertex2i(0 , 0 );
glTexCoord2f(1.0f, 0.0f); glVertex2i(format.width, 0 );
glTexCoord2f(0.0f, 1.0f); glVertex2i(0 , format.height);
glTexCoord2f(1.0f, 1.0f); glVertex2i(format.width, format.height);
glTexCoord2f(0.0f, ts); glVertex2i(0 , 0 );
glTexCoord2f(1.0f, ts); glVertex2i(format.width, 0 );
glTexCoord2f(0.0f, te); glVertex2i(0 , format.height);
glTexCoord2f(1.0f, te); glVertex2i(format.width, format.height);
glEnd();
glEndList();
if (lgr_opengl_check_error("glTexImage2D"))
return false;
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glEnable(GL_TEXTURE_2D);
glEnable(GL_COLOR_MATERIAL);
@@ -255,10 +271,10 @@ void lgr_opengl_deinitialize(void * opaque)
return;
if (this->hasTextures)
glDeleteTextures(VBO_BUFFERS, this->textures);
glDeleteTextures(TEXTURE_COUNT, this->textures);
if (this->hasBuffers)
glDeleteBuffers(VBO_BUFFERS, this->vboID);
glDeleteBuffers(1, this->vboID);
if (this->glContext)
SDL_GL_DeleteContext(this->glContext);
@@ -409,6 +425,7 @@ bool lgr_opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, co
}
}
this->mouseUpdate = true;
return true;
}
@@ -424,19 +441,16 @@ bool lgr_opengl_on_mouse_event(void * opaque, const bool visible, const int x, c
this->mouseVisible = visible;
this->mousePos.x = x;
this->mousePos.y = y;
this->mouseUpdate = true;
return false;
}
bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data, bool resample)
bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data)
{
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized)
return false;
if (++this->texIndex == VBO_BUFFERS)
this->texIndex = 0;
if (this->params.showFPS && this->renderTime > 1e9)
{
char str[128];
@@ -450,7 +464,7 @@ bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data, bool resampl
return false;
}
glBindTexture(GL_TEXTURE_2D , this->textures[VBO_BUFFERS]);
glBindTexture(GL_TEXTURE_2D , this->textures[FPS_TEXTURE]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH, textSurface->w );
glTexImage2D(
@@ -495,7 +509,7 @@ bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data, bool resampl
glEnd();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->textures[VBO_BUFFERS]);
glBindTexture(GL_TEXTURE_2D, this->textures[FPS_TEXTURE]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f , 0.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y );
@@ -507,70 +521,67 @@ bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data, bool resampl
glEndList();
}
// bind the texture and update it
glBindTexture(GL_TEXTURE_2D , this->textures[FRAME_TEXTURE]);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[0] );
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH , this->format.width );
// copy the buffer to the texture
memcpySSE(this->texPixels[this->texIndex], data, this->texSize);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texIndex]);
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize);
// bind the texture and update it
glBindTexture(GL_TEXTURE_2D , this->textures[this->texIndex]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH , this->format.width );
glFlushMappedBufferRange(
GL_PIXEL_UNPACK_BUFFER,
this->texSize * this->texIndex,
this->texSize
);
// update the texture
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0, 0,
0,
this->texIndex * this->format.height,
this->format.width ,
this->format.height,
this->vboFormat,
GL_UNSIGNED_BYTE,
(void*)0
(void*)(this->texIndex * this->texSize)
);
const bool mipmap = resample && (
(this->format.width > this->destRect.w) ||
(this->format.height > this->destRect.h));
lgr_opengl_check_error("glTexSubImage2D");
// unbind the buffer
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// configure the texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
const bool mipmap = this->params.resample && (
(this->format.width > this->destRect.w) ||
(this->format.height > this->destRect.h));
if (this->mipmap != mipmap)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
this->mipmap = mipmap;
}
if (mipmap)
{
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glBindTexture(GL_TEXTURE_2D, 0);
if (++this->texIndex == BUFFER_COUNT)
this->texIndex = 0;
this->frameUpdate = true;
return true;
}
void lgr_opengl_draw_mouse(struct LGR_OpenGL * this)
static inline void lgr_opengl_draw_mouse(struct LGR_OpenGL * this)
{
if (this->mouseRepair)
{
glCallList(this->texList + this->texIndex);
this->mouseRepair = false;
}
if (!this->mouseVisible)
return;
memcpy(&this->mouseRepairPos, &this->mousePos, sizeof(SDL_Rect));
this->mouseRepair = true;
glPushMatrix();
glTranslatef(this->mouseRepairPos.x, this->mouseRepairPos.y, 0.0f);
glTranslatef(this->mousePos.x, this->mousePos.y, 0.0f);
glCallList(this->mouseList);
glPopMatrix();
}
@@ -607,39 +618,42 @@ bool lgr_opengl_render(void * opaque)
);
this->resizeWindow = false;
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
}
if (this->frameUpdate)
if (!this->frameUpdate)
{
glCallList(this->texList + this->texIndex);
this->mouseRepair = false;
if (!this->mouseUpdate)
return true;
// don't update the mouse too fast
const uint64_t delta = nanotime() - this->lastMouseDraw;
if (delta < 1e7)
return true;
}
// wait for vsync
unsigned int count;
glXWaitVideoSyncSGI(1, 0, &count);
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glCallList(this->texList + this->texIndex);
lgr_opengl_draw_mouse(this);
if (this->fpsTexture)
glCallList(this->fpsList);
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glWaitSync(sync, 0, 1000);
glDeleteSync(sync);
unsigned int count;
glXGetVideoSyncSGI(&count);
if (count == this->gpuFrameCount)
glXWaitVideoSyncSGI(1, 0, &count);
SDL_GL_SwapWindow(this->params.window);
glXGetVideoSyncSGI(&this->gpuFrameCount);
glFlush();
++this->frameCount;
const uint64_t t = nanotime();
this->renderTime += t - this->lastFrameTime;
this->lastFrameTime = t;
this->frameUpdate = false;
this->frameUpdate = false;
this->mouseUpdate = false;
this->lastMouseDraw = t;
return true;
}

View File

@@ -22,14 +22,14 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <time.h>
#include <stdint.h>
inline uint64_t microtime()
static inline uint64_t microtime()
{
struct timespec time;
clock_gettime(CLOCK_MONOTONIC_RAW, &time);
return ((uint64_t)time.tv_sec * 1000000) + (time.tv_nsec / 1000);
}
inline uint64_t nanotime()
static inline uint64_t nanotime()
{
struct timespec time;
clock_gettime(CLOCK_MONOTONIC_RAW, &time);

View File

@@ -69,6 +69,7 @@ KVMFRFrame;
#define KVMFR_HEADER_FLAG_FRAME 1 // frame update available
#define KVMFR_HEADER_FLAG_CURSOR 2 // cursor update available
#define KVMFR_HEADER_FLAG_RESTART 4 // restart signal from client
#define KVMFR_HEADER_FLAG_READY 8 // ready signal from client
typedef struct KVMFRHeader
{

View File

@@ -30,7 +30,7 @@ Service * Service::m_instance = NULL;
Service::Service() :
m_initialized(false),
m_memory(NULL),
m_readyEvent(INVALID_HANDLE_VALUE),
m_timer(NULL),
m_capture(NULL),
m_header(NULL),
m_frameIndex(0)
@@ -73,11 +73,10 @@ bool Service::Initialize(ICapture * captureDevice)
if (!InitPointers())
return false;
m_readyEvent = m_ivshmem->CreateVectorEvent(0);
if (m_readyEvent == INVALID_HANDLE_VALUE)
m_timer = CreateWaitableTimer(NULL, TRUE, NULL);
if (!m_timer)
{
DEBUG_ERROR("Failed to get event for vector 0");
DeInitialize();
DEBUG_ERROR("Failed to create waitable timer");
return false;
}
@@ -117,10 +116,10 @@ bool Service::InitPointers()
void Service::DeInitialize()
{
if (m_readyEvent != INVALID_HANDLE_VALUE)
if (m_timer)
{
CloseHandle(m_readyEvent);
m_readyEvent = INVALID_HANDLE_VALUE;
CloseHandle(m_timer);
m_timer = NULL;
}
m_header = NULL;
@@ -152,41 +151,38 @@ bool Service::Process()
frame.buffer = m_frame[m_frameIndex];
frame.bufferSize = m_frameSize;
volatile uint8_t *flags = &m_header->flags;
// wait for the host to notify that is it is ready to proceed
bool eventDone = false;
while (!eventDone)
while (true)
{
const uint8_t f = *flags;
// check if the client has flagged a restart
if (m_header->flags & KVMFR_HEADER_FLAG_RESTART)
if (f & KVMFR_HEADER_FLAG_RESTART)
{
InterlockedAnd8((char *)&m_header->flags, ~(KVMFR_HEADER_FLAG_RESTART));
InterlockedAnd8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART));
restart = true;
break;
}
switch (WaitForSingleObject(m_readyEvent, 200))
// check if the client has flagged it's ready
if (f & KVMFR_HEADER_FLAG_READY)
{
case WAIT_ABANDONED:
DEBUG_ERROR("Wait abandoned");
return false;
case WAIT_OBJECT_0:
eventDone = true;
InterlockedAnd8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_READY));
break;
}
case WAIT_TIMEOUT:
continue;
case WAIT_FAILED:
DEBUG_ERROR("Wait failed");
return false;
default:
DEBUG_ERROR("Unknown error");
// wait for 100ns before polling again
LARGE_INTEGER timeout;
timeout.QuadPart = -100;
if (!SetWaitableTimer(m_timer, &timeout, 0, NULL, NULL, FALSE))
{
DEBUG_ERROR("Failed to set waitable timer");
return false;
}
WaitForSingleObject(m_timer, INFINITE);
}
ResetEvent(m_readyEvent);
bool ok = false;
bool cursorOnly = false;
@@ -228,13 +224,13 @@ bool Service::Process()
return false;
}
uint8_t flags = 0;
uint8_t updateFlags = 0;
m_header->cursor.flags = 0;
if (!cursorOnly)
{
// signal a frame update
flags |= KVMFR_HEADER_FLAG_FRAME;
updateFlags |= KVMFR_HEADER_FLAG_FRAME;
m_header->frame.type = m_capture->GetFrameType();
m_header->frame.width = frame.width;
m_header->frame.height = frame.height;
@@ -247,7 +243,7 @@ bool Service::Process()
if (frame.cursor.hasPos)
{
// tell the host where the cursor is
flags |= KVMFR_HEADER_FLAG_CURSOR;
updateFlags |= KVMFR_HEADER_FLAG_CURSOR;
m_header->cursor.flags |= KVMFR_CURSOR_FLAG_POS;
if (frame.cursor.visible)
m_header->cursor.flags |= KVMFR_CURSOR_FLAG_VISIBLE;
@@ -263,7 +259,7 @@ bool Service::Process()
if (frame.cursor.hasShape)
{
// give the host the new cursor shape
flags |= KVMFR_HEADER_FLAG_CURSOR;
updateFlags |= 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;
@@ -287,15 +283,15 @@ bool Service::Process()
// if we already have a shape and the client restarted send it to them
if (restart && m_haveShape)
{
flags |= KVMFR_HEADER_FLAG_CURSOR;
updateFlags |= KVMFR_HEADER_FLAG_CURSOR;
m_cursor.flags |= KVMFR_CURSOR_FLAG_SHAPE;
memcpy(&m_header->cursor, &m_cursor, sizeof(KVMFRCursor));
}
}
// update the flags
InterlockedAnd8((char *)&m_header->flags, KVMFR_HEADER_FLAG_RESTART);
InterlockedOr8 ((char *)&m_header->flags, flags);
InterlockedAnd8((volatile char *)flags, KVMFR_HEADER_FLAG_RESTART);
InterlockedOr8 ((volatile char *)flags, updateFlags);
// increment the update count to resume the host
++m_header->updateCount;

View File

@@ -51,7 +51,7 @@ private:
bool m_initialized;
uint8_t * m_memory;
IVSHMEM * m_ivshmem;
HANDLE m_readyEvent;
HANDLE m_timer;
ICapture * m_capture;
KVMFRHeader * m_header;