mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-04-25 08:06:30 +00:00
[kvmfr] decouple cursor flags from frame flags and fix timings
This commit is contained in:
parent
7a5bbb1e59
commit
df7183a572
122
client/main.c
122
client/main.c
@ -186,11 +186,17 @@ int renderThread(void * unused)
|
|||||||
{
|
{
|
||||||
if (state.started)
|
if (state.started)
|
||||||
{
|
{
|
||||||
|
uint64_t start = microtime();
|
||||||
|
|
||||||
if (!state.lgr->render(state.lgrData, state.window))
|
if (!state.lgr->render(state.lgrData, state.window))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// put some breaks on (400fps) if we are rendering too fast
|
||||||
|
if (microtime() - start < (1000000/400))
|
||||||
|
usleep((1000000/400) - (microtime() - start));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
usleep(1000);
|
usleep(1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -198,36 +204,37 @@ int renderThread(void * unused)
|
|||||||
|
|
||||||
int cursorThread(void * unused)
|
int cursorThread(void * unused)
|
||||||
{
|
{
|
||||||
struct KVMFRHeader header;
|
KVMFRCursor header;
|
||||||
LG_RendererCursor cursorType = LG_CURSOR_COLOR;
|
LG_RendererCursor cursorType = LG_CURSOR_COLOR;
|
||||||
uint32_t version = 0;
|
uint32_t version = 0;
|
||||||
|
|
||||||
memset(&header, 0, sizeof(struct KVMFRHeader));
|
memset(&header, 0, sizeof(KVMFRCursor));
|
||||||
|
|
||||||
while(state.running)
|
while(state.running)
|
||||||
{
|
{
|
||||||
// poll until we have cursor data
|
// poll until we have cursor data
|
||||||
if(!(state.shm->flags & KVMFR_HEADER_FLAG_CURSOR))
|
if(!(state.shm->cursor.flags & KVMFR_CURSOR_FLAG_UPDATE))
|
||||||
{
|
{
|
||||||
if (!state.running)
|
if (!state.running)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
nsleep(100);
|
// cursor shape updates are not so critical
|
||||||
|
// only check for udpates once every 15ms
|
||||||
|
usleep(150000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we must take a copy of the header, both to let the guest advance and to
|
// we must take a copy of the header to prevent the contained arguments
|
||||||
// prevent the contained arguments being abused to overflow buffers
|
// from being abused to overflow buffers.
|
||||||
memcpy(&header, (KVMFRHeader *)state.shm, sizeof(struct KVMFRHeader));
|
memcpy(&header, &state.shm->cursor, sizeof(struct KVMFRCursor));
|
||||||
__sync_and_and_fetch(&state.shm->flags, ~KVMFR_HEADER_FLAG_CURSOR);
|
|
||||||
|
|
||||||
if (header.detail.cursor.flags & KVMFR_CURSOR_FLAG_SHAPE &&
|
if (header.flags & KVMFR_CURSOR_FLAG_SHAPE &&
|
||||||
header.detail.cursor.version != version)
|
header.version != version)
|
||||||
{
|
{
|
||||||
version = header.detail.cursor.version;
|
version = header.version;
|
||||||
|
|
||||||
bool bad = false;
|
bool bad = false;
|
||||||
switch(header.detail.cursor.type)
|
switch(header.type)
|
||||||
{
|
{
|
||||||
case CURSOR_TYPE_COLOR : cursorType = LG_CURSOR_COLOR ; break;
|
case CURSOR_TYPE_COLOR : cursorType = LG_CURSOR_COLOR ; break;
|
||||||
case CURSOR_TYPE_MONOCHROME : cursorType = LG_CURSOR_MONOCHROME ; break;
|
case CURSOR_TYPE_MONOCHROME : cursorType = LG_CURSOR_MONOCHROME ; break;
|
||||||
@ -242,20 +249,20 @@ int cursorThread(void * unused)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// check the data position is sane
|
// check the data position is sane
|
||||||
const uint64_t dataSize = header.detail.cursor.height * header.detail.cursor.pitch;
|
const uint64_t dataSize = header.height * header.pitch;
|
||||||
if (header.detail.cursor.dataPos + dataSize > state.shmSize)
|
if (header.dataPos + dataSize > state.shmSize)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("The guest sent an invalid mouse dataPos");
|
DEBUG_ERROR("The guest sent an invalid mouse dataPos");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t * data = (const uint8_t *)state.shm + header.detail.cursor.dataPos;
|
const uint8_t * data = (const uint8_t *)state.shm + header.dataPos;
|
||||||
if (!state.lgr->on_mouse_shape(
|
if (!state.lgr->on_mouse_shape(
|
||||||
state.lgrData,
|
state.lgrData,
|
||||||
cursorType,
|
cursorType,
|
||||||
header.detail.cursor.width,
|
header.width,
|
||||||
header.detail.cursor.height,
|
header.height,
|
||||||
header.detail.cursor.pitch,
|
header.pitch,
|
||||||
data)
|
data)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -264,11 +271,14 @@ int cursorThread(void * unused)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.detail.cursor.flags & KVMFR_CURSOR_FLAG_POS)
|
// now we have taken the mouse data, we can flag to the host we are ready
|
||||||
|
__sync_and_and_fetch(&state.shm->cursor.flags, ~KVMFR_CURSOR_FLAG_UPDATE);
|
||||||
|
|
||||||
|
if (header.flags & KVMFR_CURSOR_FLAG_POS)
|
||||||
{
|
{
|
||||||
state.cursor.x = header.detail.cursor.x;
|
state.cursor.x = header.x;
|
||||||
state.cursor.y = header.detail.cursor.y;
|
state.cursor.y = header.y;
|
||||||
state.cursorVisible = header.detail.cursor.flags & KVMFR_CURSOR_FLAG_VISIBLE;
|
state.cursorVisible = header.flags & KVMFR_CURSOR_FLAG_VISIBLE;
|
||||||
state.haveCursorPos = true;
|
state.haveCursorPos = true;
|
||||||
|
|
||||||
state.lgr->on_mouse_event
|
state.lgr->on_mouse_event
|
||||||
@ -279,13 +289,6 @@ int cursorThread(void * unused)
|
|||||||
state.cursor.y
|
state.cursor.y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// poll until we have cursor data
|
|
||||||
while(((state.shm->flags & KVMFR_HEADER_FLAG_CURSOR) == 0) && state.running)
|
|
||||||
{
|
|
||||||
usleep(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -293,37 +296,42 @@ int cursorThread(void * unused)
|
|||||||
|
|
||||||
int frameThread(void * unused)
|
int frameThread(void * unused)
|
||||||
{
|
{
|
||||||
bool error = false;
|
bool error = false;
|
||||||
struct KVMFRHeader header;
|
KVMFRFrame header;
|
||||||
|
|
||||||
memset(&header, 0, sizeof(struct KVMFRHeader));
|
memset(&header, 0, sizeof(struct KVMFRFrame));
|
||||||
|
|
||||||
while(state.running)
|
while(state.running)
|
||||||
{
|
{
|
||||||
// poll until we have a new frame
|
// poll until we have a new frame
|
||||||
if(!(state.shm->flags & KVMFR_HEADER_FLAG_FRAME))
|
if(!(state.shm->frame.flags & KVMFR_FRAME_FLAG_UPDATE))
|
||||||
{
|
{
|
||||||
if (!state.running)
|
if (!state.running)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
nsleep(100);
|
// allow for a maximum refresh of 200fps (1000/200 = 5ms), this should
|
||||||
|
// befreqent enough without chewing up too much CPU time
|
||||||
|
usleep(5000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we must take a copy of the header, both to let the guest advance and to
|
// we must take a copy of the header to prevent the contained
|
||||||
// prevent the contained arguments being abused to overflow buffers
|
// arguments from being abused to overflow buffers.
|
||||||
memcpy(&header, (KVMFRHeader *)state.shm, sizeof(struct KVMFRHeader));
|
memcpy(&header, &state.shm->frame, sizeof(struct KVMFRFrame));
|
||||||
__sync_and_and_fetch(&state.shm->flags, ~KVMFR_HEADER_FLAG_FRAME);
|
|
||||||
|
// tell the host to continue as the host buffers up to one frame
|
||||||
|
// we can be sure the data for this frame wont be touched
|
||||||
|
__sync_and_and_fetch(&state.shm->frame.flags, ~KVMFR_FRAME_FLAG_UPDATE);
|
||||||
|
|
||||||
// sainty check of the frame format
|
// sainty check of the frame format
|
||||||
if (
|
if (
|
||||||
header.detail.frame.type >= FRAME_TYPE_MAX ||
|
header.type >= FRAME_TYPE_MAX ||
|
||||||
header.detail.frame.width == 0 ||
|
header.width == 0 ||
|
||||||
header.detail.frame.height == 0 ||
|
header.height == 0 ||
|
||||||
header.detail.frame.pitch == 0 ||
|
header.pitch == 0 ||
|
||||||
header.detail.frame.dataPos == 0 ||
|
header.dataPos == 0 ||
|
||||||
header.detail.frame.dataPos > state.shmSize ||
|
header.dataPos > state.shmSize ||
|
||||||
header.detail.frame.pitch < header.detail.frame.width
|
header.pitch < header.width
|
||||||
){
|
){
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
continue;
|
continue;
|
||||||
@ -331,13 +339,13 @@ int frameThread(void * unused)
|
|||||||
|
|
||||||
// setup the renderer format with the frame format details
|
// setup the renderer format with the frame format details
|
||||||
LG_RendererFormat lgrFormat;
|
LG_RendererFormat lgrFormat;
|
||||||
lgrFormat.width = header.detail.frame.width;
|
lgrFormat.width = header.width;
|
||||||
lgrFormat.height = header.detail.frame.height;
|
lgrFormat.height = header.height;
|
||||||
lgrFormat.stride = header.detail.frame.stride;
|
lgrFormat.stride = header.stride;
|
||||||
lgrFormat.pitch = header.detail.frame.pitch;
|
lgrFormat.pitch = header.pitch;
|
||||||
|
|
||||||
size_t dataSize;
|
size_t dataSize;
|
||||||
switch(header.detail.frame.type)
|
switch(header.type)
|
||||||
{
|
{
|
||||||
case FRAME_TYPE_ARGB:
|
case FRAME_TYPE_ARGB:
|
||||||
dataSize = lgrFormat.height * lgrFormat.pitch;
|
dataSize = lgrFormat.height * lgrFormat.pitch;
|
||||||
@ -361,22 +369,22 @@ int frameThread(void * unused)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// check the header's dataPos is sane
|
// check the header's dataPos is sane
|
||||||
if (header.detail.frame.dataPos + dataSize > state.shmSize)
|
if (header.dataPos + dataSize > state.shmSize)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("The guest sent an invalid dataPos");
|
DEBUG_ERROR("The guest sent an invalid dataPos");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.detail.frame.width != state.srcSize.x || header.detail.frame.height != state.srcSize.y)
|
if (header.width != state.srcSize.x || header.height != state.srcSize.y)
|
||||||
{
|
{
|
||||||
state.srcSize.x = header.detail.frame.width;
|
state.srcSize.x = header.width;
|
||||||
state.srcSize.y = header.detail.frame.height;
|
state.srcSize.y = header.height;
|
||||||
if (params.autoResize)
|
if (params.autoResize)
|
||||||
SDL_SetWindowSize(state.window, header.detail.frame.width, header.detail.frame.height);
|
SDL_SetWindowSize(state.window, header.width, header.height);
|
||||||
updatePositionInfo();
|
updatePositionInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t * data = (const uint8_t *)state.shm + header.detail.frame.dataPos;
|
const uint8_t * data = (const uint8_t *)state.shm + header.dataPos;
|
||||||
if (!state.lgr->on_frame_event(state.lgrData, lgrFormat, data))
|
if (!state.lgr->on_frame_event(state.lgrData, lgrFormat, data))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("renderer on frame event returned failure");
|
DEBUG_ERROR("renderer on frame event returned failure");
|
||||||
|
@ -21,7 +21,7 @@ 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 5
|
#define KVMFR_HEADER_VERSION 6
|
||||||
|
|
||||||
typedef enum FrameType
|
typedef enum FrameType
|
||||||
{
|
{
|
||||||
@ -40,9 +40,10 @@ typedef enum CursorType
|
|||||||
}
|
}
|
||||||
CursorType;
|
CursorType;
|
||||||
|
|
||||||
#define KVMFR_CURSOR_FLAG_VISIBLE 1 // cursor is visible
|
#define KVMFR_CURSOR_FLAG_UPDATE 1 // cursor update available
|
||||||
#define KVMFR_CURSOR_FLAG_SHAPE 2 // shape updated
|
#define KVMFR_CURSOR_FLAG_VISIBLE 2 // cursor is visible
|
||||||
#define KVMFR_CURSOR_FLAG_POS 4 // position updated
|
#define KVMFR_CURSOR_FLAG_SHAPE 4 // shape updated
|
||||||
|
#define KVMFR_CURSOR_FLAG_POS 8 // position updated
|
||||||
|
|
||||||
typedef struct KVMFRCursor
|
typedef struct KVMFRCursor
|
||||||
{
|
{
|
||||||
@ -58,8 +59,11 @@ typedef struct KVMFRCursor
|
|||||||
}
|
}
|
||||||
KVMFRCursor;
|
KVMFRCursor;
|
||||||
|
|
||||||
|
#define KVMFR_FRAME_FLAG_UPDATE 1 // frame update available
|
||||||
|
|
||||||
typedef struct KVMFRFrame
|
typedef struct KVMFRFrame
|
||||||
{
|
{
|
||||||
|
uint8_t flags; // KVMFR_FRAME_FLAGS
|
||||||
FrameType type; // the frame data type
|
FrameType type; // the frame data type
|
||||||
uint32_t width; // the width
|
uint32_t width; // the width
|
||||||
uint32_t height; // the height
|
uint32_t height; // the height
|
||||||
@ -69,23 +73,16 @@ typedef struct KVMFRFrame
|
|||||||
}
|
}
|
||||||
KVMFRFrame;
|
KVMFRFrame;
|
||||||
|
|
||||||
#define KVMFR_HEADER_FLAG_FRAME 1 // frame update available
|
#define KVMFR_HEADER_FLAG_RESTART 1 // restart signal from client
|
||||||
#define KVMFR_HEADER_FLAG_CURSOR 2 // cursor update available
|
#define KVMFR_HEADER_FLAG_READY 2 // ready signal from client
|
||||||
#define KVMFR_HEADER_FLAG_RESTART 4 // restart signal from client
|
#define KVMFR_HEADER_FLAG_PAUSED 4 // capture has been paused by the host
|
||||||
#define KVMFR_HEADER_FLAG_READY 8 // ready signal from client
|
|
||||||
|
|
||||||
typedef struct KVMFRDetail
|
|
||||||
{
|
|
||||||
KVMFRFrame frame; // the frame information
|
|
||||||
KVMFRCursor cursor; // the cursor information
|
|
||||||
}
|
|
||||||
KVMFRDetail;
|
|
||||||
|
|
||||||
typedef struct KVMFRHeader
|
typedef struct KVMFRHeader
|
||||||
{
|
{
|
||||||
char magic[sizeof(KVMFR_HEADER_MAGIC)];
|
char magic[sizeof(KVMFR_HEADER_MAGIC)];
|
||||||
uint32_t version; // version of this structure
|
uint32_t version; // version of this structure
|
||||||
uint8_t flags; // KVMFR_HEADER_FLAGS
|
uint8_t flags; // KVMFR_HEADER_FLAGS
|
||||||
KVMFRDetail detail; // details
|
KVMFRFrame frame; // the frame information
|
||||||
|
KVMFRCursor cursor; // the cursor information
|
||||||
}
|
}
|
||||||
KVMFRHeader;
|
KVMFRHeader;
|
Loading…
x
Reference in New Issue
Block a user