Compare commits

..

10 Commits

Author SHA1 Message Date
Geoffrey McRae
789ee70674 [host] dxgi: print out the adapter details earlier
Before we try and perhaps fail to init DXGI, we should print out what
the device is so that when there is an error report we can immediately
see if the user has the QXL device attached still.
2021-07-12 19:28:13 +10:00
Geoffrey McRae
3c0616bab7 [host] dxgi: print out the output device name to aid with support 2021-07-12 19:03:02 +10:00
Geoffrey McRae
3ce3b573a3 [host] app: fix infinate loop introduced in the last commit 2021-07-12 17:35:16 +10:00
Geoffrey McRae
ce459c24ce [host] app: wait for space in the frame queue
We must always wait for space in the frame queue so that we do not
overwrite memory that is already queued and may be in use by a client.
2021-07-12 17:30:06 +10:00
Geoffrey McRae
7d0b9711bd [host] nvfbc: remove the frameEvent event and associated code
Now that the host application can run the capture interface in
synchronous mode, and NVFBC uses this mode there is no longer need for
the frameEvent.
2021-07-12 17:01:23 +10:00
Geoffrey McRae
e477663a7e [host] app: allow the capture interface to select async or sync mode
While it's correct for DXGI to use a asyncronous waitFrame model, other
capture interfaces such as NvFBC it is not correct. This change allows
the capture interface to specify which is more correct for it and moves
the waitFrame/post into the main thread if async is not desired.
2021-07-12 16:57:22 +10:00
Quantum
eb01efe0cb [host] nvfbc: do not crash when protected content is playing
We return a timeout, so that when protected content finishes playing, we
can immediately resume capture.
2021-07-11 17:54:23 +10:00
Geoffrey McRae
8db4b65dee [host] app: allocate LGMP memory for KVMFRCursor updates without shapes
This changes the host to use a seperate pool of LGMP memory for cursor
positionl updates without shape information helping to prevent
corruption of the shape entries if they are still pending. While this is
not a perfect solution it resolves the issue without making major
changes to LGMP during the RC phase we are currently in.
2021-07-11 12:52:18 +10:00
Quantum
501b270890 [host] nvfbc: optimize change detection loop
Before, we only break out of the current row when a change is detected,
and all subsequent rows are still scanned. Now we break out of the entire
loop. This should make change detection ever so slightly faster.
2021-07-11 10:15:12 +10:00
Quantum
fd8f8b2b28 [host] dxgi: correctly mention AcquireNextFrame in help text
Also fix some formatting issues.

Co-Authored-By: Tudor Brindus <me@tbrindus.ca>
2021-07-11 10:15:12 +10:00
6 changed files with 225 additions and 182 deletions

View File

@@ -91,9 +91,10 @@ typedef void (*CapturePostPointerBuffer)(CapturePointer pointer);
typedef struct CaptureInterface
{
const char *shortName;
const char * (*getName )();
void (*initOptions )();
const char * shortName;
const bool asyncCapture;
const char * (*getName )();
void (*initOptions )();
bool(*create)(
CaptureGetPointerBuffer getPointerBufferFn,

View File

@@ -236,6 +236,7 @@ static CaptureResult xcb_getFrame(FrameBuffer * frame, const unsigned int height
struct CaptureInterface Capture_XCB =
{
.shortName = "XCB",
.asyncCapture = true,
.getName = xcb_getName,
.create = xcb_create,
.init = xcb_init,

View File

@@ -142,7 +142,7 @@ static void dxgi_initOptions(void)
{
.module = "dxgi",
.name = "useAcquireLock",
.description = "Enable locking around `AcquireFrame` (EXPERIMENTAL, leave enabled if you're not sure!)",
.description = "Enable locking around `AcquireNextFrame` (EXPERIMENTAL, leave enabled if you're not sure!)",
.type = OPTION_TYPE_BOOL,
.value.x_bool = true
},
@@ -230,7 +230,7 @@ static bool dxgi_init(void)
const char * optAdapter = option_get_string("dxgi", "adapter");
const char * optOutput = option_get_string("dxgi", "output" );
for(int i = 0; IDXGIFactory1_EnumAdapters1(this->factory, i, &this->adapter) != DXGI_ERROR_NOT_FOUND; ++i)
for (int i = 0; IDXGIFactory1_EnumAdapters1(this->factory, i, &this->adapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
if (optAdapter)
{
@@ -259,7 +259,7 @@ static bool dxgi_init(void)
DEBUG_INFO("Adapter matched, trying: %ls", adapterDesc.Description);
}
for(int n = 0; IDXGIAdapter1_EnumOutputs(this->adapter, n, &this->output) != DXGI_ERROR_NOT_FOUND; ++n)
for (int n = 0; IDXGIAdapter1_EnumOutputs(this->adapter, n, &this->output) != DXGI_ERROR_NOT_FOUND; ++n)
{
IDXGIOutput_GetDesc(this->output, &outputDesc);
if (optOutput)
@@ -302,6 +302,16 @@ static bool dxgi_init(void)
goto fail;
}
DXGI_ADAPTER_DESC1 adapterDesc;
IDXGIAdapter1_GetDesc1(this->adapter, &adapterDesc);
DEBUG_INFO("Device Name : %ls" , outputDesc.DeviceName);
DEBUG_INFO("Device Descripion: %ls" , adapterDesc.Description);
DEBUG_INFO("Device Vendor ID : 0x%x" , adapterDesc.VendorId);
DEBUG_INFO("Device Device ID : 0x%x" , adapterDesc.DeviceId);
DEBUG_INFO("Device Video Mem : %u MiB" , (unsigned)(adapterDesc.DedicatedVideoMemory / 1048576));
DEBUG_INFO("Device Sys Mem : %u MiB" , (unsigned)(adapterDesc.DedicatedSystemMemory / 1048576));
DEBUG_INFO("Shared Sys Mem : %u MiB" , (unsigned)(adapterDesc.SharedSystemMemory / 1048576));
static const D3D_FEATURE_LEVEL win8[] =
{
D3D_FEATURE_LEVEL_11_1,
@@ -368,9 +378,6 @@ static bool dxgi_init(void)
goto fail;
}
DXGI_ADAPTER_DESC1 adapterDesc;
IDXGIAdapter1_GetDesc1(this->adapter, &adapterDesc);
switch(outputDesc.Rotation)
{
case DXGI_MODE_ROTATION_ROTATE90:
@@ -411,12 +418,6 @@ static bool dxgi_init(void)
this->dpi = monitor_dpi(outputDesc.Monitor);
++this->formatVer;
DEBUG_INFO("Device Descripion: %ls" , adapterDesc.Description);
DEBUG_INFO("Device Vendor ID : 0x%x" , adapterDesc.VendorId);
DEBUG_INFO("Device Device ID : 0x%x" , adapterDesc.DeviceId);
DEBUG_INFO("Device Video Mem : %u MiB" , (unsigned)(adapterDesc.DedicatedVideoMemory / 1048576));
DEBUG_INFO("Device Sys Mem : %u MiB" , (unsigned)(adapterDesc.DedicatedSystemMemory / 1048576));
DEBUG_INFO("Shared Sys Mem : %u MiB" , (unsigned)(adapterDesc.SharedSystemMemory / 1048576));
DEBUG_INFO("Feature Level : 0x%x" , this->featureLevel);
DEBUG_INFO("Capture Size : %u x %u", this->width, this->height);
DEBUG_INFO("AcquireLock : %s" , this->useAcquireLock ? "enabled" : "disabled");
@@ -542,7 +543,7 @@ static bool dxgi_init(void)
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.MiscFlags = 0;
for(int i = 0; i < this->maxTextures; ++i)
for (int i = 0; i < this->maxTextures; ++i)
{
status = ID3D11Device_CreateTexture2D(this->device, &texDesc, NULL, &this->texture[i].tex);
if (FAILED(status))
@@ -583,7 +584,7 @@ static bool dxgi_deinit(void)
{
assert(this);
for(int i = 0; i < this->maxTextures; ++i)
for (int i = 0; i < this->maxTextures; ++i)
{
this->texture[i].state = TEXTURE_STATE_UNUSED;
@@ -764,7 +765,7 @@ static CaptureResult dxgi_capture(void)
uint32_t bufferSize;
if (frameInfo.PointerShapeBufferSize > 0)
{
if(!this->getPointerBufferFn(&pointerShape, &bufferSize))
if (!this->getPointerBufferFn(&pointerShape, &bufferSize))
DEBUG_WARN("Failed to obtain a buffer for the pointer shape");
else
copyPointer = true;
@@ -881,13 +882,13 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
assert(this->initialized);
// NOTE: the event may be signaled when there are no frames available
if(atomic_load_explicit(&this->texReady, memory_order_acquire) == 0)
if (atomic_load_explicit(&this->texReady, memory_order_acquire) == 0)
{
if (!lgWaitEvent(this->frameEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
// the count will still be zero if we are stopping
if(atomic_load_explicit(&this->texReady, memory_order_acquire) == 0)
if (atomic_load_explicit(&this->texReady, memory_order_acquire) == 0)
return CAPTURE_RESULT_TIMEOUT;
}
@@ -996,6 +997,7 @@ static CaptureResult dxgi_releaseFrame(void)
struct CaptureInterface Capture_DXGI =
{
.shortName = "DXGI",
.asyncCapture = true,
.getName = dxgi_getName,
.initOptions = dxgi_initOptions,
.create = dxgi_create,

View File

@@ -57,7 +57,6 @@ struct iface
NvFBCFrameGrabInfo grabInfo;
LGEvent * frameEvent;
LGEvent * cursorEvent;
int mouseX, mouseY, mouseHotX, mouseHotY;
@@ -134,13 +133,6 @@ static bool nvfbc_create(
return false;
this = (struct iface *)calloc(sizeof(struct iface), 1);
this->frameEvent = lgCreateEvent(true, 17);
if (!this->frameEvent)
{
DEBUG_ERROR("failed to create the frame event");
nvfbc_free();
return false;
}
this->seperateCursor = option_get_bool("nvfbc", "decoupleCursor");
this->getPointerBufferFn = getPointerBufferFn;
@@ -165,7 +157,7 @@ static bool nvfbc_init(void)
privDataLen = (bufferLen - 1) / 2;
privData = (uint8_t *)malloc(privDataLen);
char hex[3] = {0};
for(int i = 0; i < privDataLen; ++i)
for (int i = 0; i < privDataLen; ++i)
{
memcpy(hex, &buffer[i*2], 2);
privData[i] = (uint8_t)strtoul(hex, NULL, 16);
@@ -186,7 +178,6 @@ static bool nvfbc_init(void)
free(privData);
getDesktopSize(&this->width, &this->height, &this->dpi);
lgResetEvent(this->frameEvent);
HANDLE event;
if (!NvFBCToSysSetup(
@@ -239,7 +230,6 @@ static void nvfbc_stop(void)
this->stop = true;
lgSignalEvent(this->cursorEvent);
lgSignalEvent(this->frameEvent);
if (this->pointerThread)
{
@@ -262,9 +252,6 @@ static bool nvfbc_deinit(void)
static void nvfbc_free(void)
{
if (this->frameEvent)
lgFreeEvent(this->frameEvent);
if (this->mouseHookCreated)
mouseHook_remove();
@@ -300,28 +287,25 @@ static CaptureResult nvfbc_capture(void)
bool changed = false;
const unsigned int h = (this->height + 127) / 128;
const unsigned int w = (this->width + 127) / 128;
for(unsigned int y = 0; y < h; ++y)
for(unsigned int x = 0; x < w; ++x)
for (unsigned int y = 0; y < h; ++y)
for (unsigned int x = 0; x < w; ++x)
if (this->diffMap[(y*w)+x])
{
changed = true;
break;
goto done;
}
done:
if (!changed)
return CAPTURE_RESULT_TIMEOUT;
memcpy(&this->grabInfo, &grabInfo, sizeof(grabInfo));
lgSignalEvent(this->frameEvent);
return CAPTURE_RESULT_OK;
}
static CaptureResult nvfbc_waitFrame(CaptureFrame * frame,
const size_t maxFrameSize)
{
if (!lgWaitEvent(this->frameEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
if (this->stop)
return CAPTURE_RESULT_REINIT;
@@ -423,6 +407,7 @@ static int pointerThread(void * unused)
struct CaptureInterface Capture_NVFBC =
{
.shortName = "NvFBC",
.asyncCapture = false,
.getName = nvfbc_getName,
.initOptions = nvfbc_initOptions,

View File

@@ -253,6 +253,11 @@ CaptureResult NvFBCToSysCapture(
handle->retry = 0;
break;
case NVFBC_ERROR_PROTECTED_CONTENT:
DEBUG_WARN("Protected content is playing, can't capture");
Sleep(100);
return CAPTURE_RESULT_TIMEOUT;
case NVFBC_ERROR_INVALID_PARAM:
if (handle->retry < 2)
{

View File

@@ -79,17 +79,21 @@ struct app
PLGMPHost lgmp;
PLGMPHostQueue pointerQueue;
PLGMPMemory pointerMemory[POINTER_SHAPE_BUFFERS];
PLGMPMemory pointerMemory[LGMP_Q_POINTER_LEN];
PLGMPMemory pointerShapeMemory[POINTER_SHAPE_BUFFERS];
LG_Lock pointerLock;
CapturePointer pointerInfo;
PLGMPMemory pointerShape;
bool pointerShapeValid;
unsigned int pointerIndex;
unsigned int pointerShapeIndex;
long pageSize;
size_t maxFrameSize;
PLGMPHostQueue frameQueue;
PLGMPMemory frameMemory[LGMP_Q_FRAME_LEN];
unsigned int frameIndex;
bool frameValid;
CaptureInterface * iface;
@@ -138,118 +142,127 @@ static bool lgmpTimer(void * opaque)
return true;
}
static bool sendFrame(void)
{
CaptureFrame frame = { 0 };
bool repeatFrame = false;
//wait until there is room in the queue
while(app.state == APP_STATE_RUNNING &&
lgmpHostQueuePending(app.frameQueue) == LGMP_Q_FRAME_LEN)
{
usleep(1);
continue;
}
if (app.state != APP_STATE_RUNNING)
return false;
switch(app.iface->waitFrame(&frame, app.maxFrameSize))
{
case CAPTURE_RESULT_OK:
break;
case CAPTURE_RESULT_REINIT:
{
app.state = APP_STATE_RESTART;
DEBUG_INFO("Frame thread reinit");
return false;
}
case CAPTURE_RESULT_ERROR:
{
DEBUG_ERROR("Failed to get the frame");
return false;
}
case CAPTURE_RESULT_TIMEOUT:
{
if (app.frameValid && lgmpHostQueueNewSubs(app.frameQueue) > 0)
{
// resend the last frame
repeatFrame = true;
break;
}
return true;
}
}
LGMP_STATUS status;
// if we are repeating a frame just send the last frame again
if (repeatFrame)
{
if ((status = lgmpHostQueuePost(app.frameQueue, 0, app.frameMemory[app.frameIndex])) != LGMP_OK)
DEBUG_ERROR("%s", lgmpStatusString(status));
return true;
}
// we increment the index first so that if we need to repeat a frame
// the index still points to the latest valid frame
if (++app.frameIndex == LGMP_Q_FRAME_LEN)
app.frameIndex = 0;
KVMFRFrame * fi = lgmpHostMemPtr(app.frameMemory[app.frameIndex]);
switch(frame.format)
{
case CAPTURE_FMT_BGRA : fi->type = FRAME_TYPE_BGRA ; break;
case CAPTURE_FMT_RGBA : fi->type = FRAME_TYPE_RGBA ; break;
case CAPTURE_FMT_RGBA10 : fi->type = FRAME_TYPE_RGBA10 ; break;
case CAPTURE_FMT_RGBA16F: fi->type = FRAME_TYPE_RGBA16F; break;
default:
DEBUG_ERROR("Unsupported frame format %d, skipping frame", frame.format);
return true;
}
switch(frame.rotation)
{
case CAPTURE_ROT_0 : fi->rotation = FRAME_ROT_0 ; break;
case CAPTURE_ROT_90 : fi->rotation = FRAME_ROT_90 ; break;
case CAPTURE_ROT_180: fi->rotation = FRAME_ROT_180; break;
case CAPTURE_ROT_270: fi->rotation = FRAME_ROT_270; break;
default:
DEBUG_WARN("Unsupported frame rotation %d", frame.rotation);
fi->rotation = FRAME_ROT_0;
break;
}
fi->formatVer = frame.formatVer;
fi->width = frame.width;
fi->height = frame.height;
fi->realHeight = frame.realHeight;
fi->stride = frame.stride;
fi->pitch = frame.pitch;
fi->offset = app.pageSize - FrameBufferStructSize;
fi->mouseScalePercent = app.iface->getMouseScale();
fi->blockScreensaver = os_blockScreensaver();
app.frameValid = true;
// put the framebuffer on the border of the next page
// this is to allow for aligned DMA transfers by the receiver
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset);
framebuffer_prepare(fb);
/* we post and then get the frame, this is intentional! */
if ((status = lgmpHostQueuePost(app.frameQueue, 0, app.frameMemory[app.frameIndex])) != LGMP_OK)
{
DEBUG_ERROR("%s", lgmpStatusString(status));
return true;
}
app.iface->getFrame(fb, frame.height);
return true;
}
static int frameThread(void * opaque)
{
DEBUG_INFO("Frame thread started");
bool frameValid = false;
bool repeatFrame = false;
CaptureFrame frame = { 0 };
const long pageSize = sysinfo_getPageSize();
while(app.state == APP_STATE_RUNNING)
{
//wait until there is room in the queue
if(lgmpHostQueuePending(app.frameQueue) == LGMP_Q_FRAME_LEN)
{
usleep(1);
continue;
}
switch(app.iface->waitFrame(&frame, app.maxFrameSize))
{
case CAPTURE_RESULT_OK:
repeatFrame = false;
break;
case CAPTURE_RESULT_REINIT:
{
app.state = APP_STATE_RESTART;
DEBUG_INFO("Frame thread reinit");
return 0;
}
case CAPTURE_RESULT_ERROR:
{
DEBUG_ERROR("Failed to get the frame");
return 0;
}
case CAPTURE_RESULT_TIMEOUT:
{
if (frameValid && lgmpHostQueueNewSubs(app.frameQueue) > 0)
{
// resend the last frame
repeatFrame = true;
break;
}
continue;
}
}
LGMP_STATUS status;
// if we are repeating a frame just send the last frame again
if (repeatFrame)
{
if ((status = lgmpHostQueuePost(app.frameQueue, 0, app.frameMemory[app.frameIndex])) != LGMP_OK)
DEBUG_ERROR("%s", lgmpStatusString(status));
continue;
}
// we increment the index first so that if we need to repeat a frame
// the index still points to the latest valid frame
if (++app.frameIndex == LGMP_Q_FRAME_LEN)
app.frameIndex = 0;
KVMFRFrame * fi = lgmpHostMemPtr(app.frameMemory[app.frameIndex]);
switch(frame.format)
{
case CAPTURE_FMT_BGRA : fi->type = FRAME_TYPE_BGRA ; break;
case CAPTURE_FMT_RGBA : fi->type = FRAME_TYPE_RGBA ; break;
case CAPTURE_FMT_RGBA10 : fi->type = FRAME_TYPE_RGBA10 ; break;
case CAPTURE_FMT_RGBA16F: fi->type = FRAME_TYPE_RGBA16F; break;
default:
DEBUG_ERROR("Unsupported frame format %d, skipping frame", frame.format);
continue;
}
switch(frame.rotation)
{
case CAPTURE_ROT_0 : fi->rotation = FRAME_ROT_0 ; break;
case CAPTURE_ROT_90 : fi->rotation = FRAME_ROT_90 ; break;
case CAPTURE_ROT_180: fi->rotation = FRAME_ROT_180; break;
case CAPTURE_ROT_270: fi->rotation = FRAME_ROT_270; break;
default:
DEBUG_WARN("Unsupported frame rotation %d", frame.rotation);
fi->rotation = FRAME_ROT_0;
break;
}
fi->formatVer = frame.formatVer;
fi->width = frame.width;
fi->height = frame.height;
fi->realHeight = frame.realHeight;
fi->stride = frame.stride;
fi->pitch = frame.pitch;
fi->offset = pageSize - FrameBufferStructSize;
fi->mouseScalePercent = app.iface->getMouseScale();
fi->blockScreensaver = os_blockScreensaver();
frameValid = true;
// put the framebuffer on the border of the next page
// this is to allow for aligned DMA transfers by the receiver
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset);
framebuffer_prepare(fb);
/* we post and then get the frame, this is intentional! */
if ((status = lgmpHostQueuePost(app.frameQueue, 0, app.frameMemory[app.frameIndex])) != LGMP_OK)
{
DEBUG_ERROR("%s", lgmpStatusString(status));
continue;
}
app.iface->getFrame(fb, frame.height);
if (!sendFrame())
break;
}
DEBUG_INFO("Frame thread stopped");
return 0;
@@ -258,6 +271,9 @@ static int frameThread(void * opaque)
bool startThreads(void)
{
app.state = APP_STATE_RUNNING;
if (!app.iface->asyncCapture)
return true;
if (!lgCreateThread("FrameThread", frameThread, NULL, &app.frameThread))
{
DEBUG_ERROR("Failed to create the frame thread");
@@ -269,20 +285,25 @@ bool startThreads(void)
bool stopThreads(void)
{
bool ok = true;
app.iface->stop();
if (app.state != APP_STATE_SHUTDOWN)
app.state = APP_STATE_IDLE;
if (app.frameThread && !lgJoinThread(app.frameThread, NULL))
{
DEBUG_WARN("Failed to join the frame thread");
ok = false;
}
app.frameThread = NULL;
if (!app.iface->asyncCapture)
return true;
return ok;
if (app.frameThread)
{
if (!lgJoinThread(app.frameThread, NULL))
{
DEBUG_WARN("Failed to join the frame thread");
app.frameThread = NULL;
return false;
}
app.frameThread = NULL;
}
return true;
}
static bool captureStart(void)
@@ -315,8 +336,8 @@ static bool captureStop(void)
bool captureGetPointerBuffer(void ** data, uint32_t * size)
{
PLGMPMemory mem = app.pointerMemory[app.pointerIndex];
*data = ((uint8_t*)lgmpHostMemPtr(mem)) + sizeof(KVMFRCursor);
PLGMPMemory mem = app.pointerShapeMemory[app.pointerShapeIndex];
*data = (uint8_t*)lgmpHostMemPtr(mem) + sizeof(KVMFRCursor);
*size = MAX_POINTER_SIZE - sizeof(KVMFRCursor);
return true;
}
@@ -342,8 +363,18 @@ static void sendPointer(bool newClient)
// new clients need the last known shape and current position
if (newClient)
{
PLGMPMemory mem;
if (app.pointerShapeValid)
mem = app.pointerShape;
else
{
mem = app.pointerMemory[app.pointerIndex];
if (++app.pointerIndex == LGMP_Q_POINTER_LEN)
app.pointerIndex = 0;
}
// update the saved details with the current cursor position
KVMFRCursor *cursor = lgmpHostMemPtr(app.pointerShape);
KVMFRCursor *cursor = lgmpHostMemPtr(mem);
cursor->x = app.pointerInfo.x;
cursor->y = app.pointerInfo.y;
@@ -351,12 +382,24 @@ static void sendPointer(bool newClient)
(app.pointerShapeValid ? CURSOR_FLAG_SHAPE : 0) |
(app.pointerInfo.visible ? CURSOR_FLAG_VISIBLE : 0);
postPointer(flags, app.pointerShape);
postPointer(flags, mem);
return;
}
uint32_t flags = 0;
PLGMPMemory mem = app.pointerMemory[app.pointerIndex];
PLGMPMemory mem;
if (app.pointerInfo.shapeUpdate)
{
mem = app.pointerShapeMemory[app.pointerShapeIndex];
if (++app.pointerShapeIndex == POINTER_SHAPE_BUFFERS)
app.pointerShapeIndex = 0;
}
else
{
mem = app.pointerMemory[app.pointerIndex];
if (++app.pointerIndex == LGMP_Q_POINTER_LEN)
app.pointerIndex = 0;
}
KVMFRCursor *cursor = lgmpHostMemPtr(mem);
if (app.pointerInfo.positionUpdate || newClient)
@@ -390,16 +433,9 @@ static void sendPointer(bool newClient)
app.pointerShapeValid = true;
flags |= CURSOR_FLAG_SHAPE;
// retain this memory for new clients
app.pointerMemory[app.pointerIndex] = app.pointerShape;
app.pointerShape = mem;
}
// only advance if the pointer shape was not swapped out of the list
if ((flags & CURSOR_FLAG_SHAPE) == 0)
if (++app.pointerIndex == POINTER_SHAPE_BUFFERS)
app.pointerIndex = 0;
postPointer(flags, mem);
}
@@ -525,34 +561,41 @@ int app_main(int argc, char * argv[])
goto fail_lgmp;
}
for(int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
for(int i = 0; i < LGMP_Q_POINTER_LEN; ++i)
{
if ((status = lgmpHostMemAlloc(app.lgmp, MAX_POINTER_SIZE, &app.pointerMemory[i])) != LGMP_OK)
if ((status = lgmpHostMemAlloc(app.lgmp, sizeof(KVMFRCursor), &app.pointerMemory[i])) != LGMP_OK)
{
DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer): %s", lgmpStatusString(status));
exitcode = LG_HOST_EXIT_FATAL;
goto fail_lgmp;
}
memset(lgmpHostMemPtr(app.pointerMemory[i]), 0, MAX_POINTER_SIZE);
memset(lgmpHostMemPtr(app.pointerMemory[i]), 0, sizeof(KVMFRCursor));
}
app.pointerShapeValid = false;
if ((status = lgmpHostMemAlloc(app.lgmp, MAX_POINTER_SIZE, &app.pointerShape)) != LGMP_OK)
for(int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
{
DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer Shape): %s", lgmpStatusString(status));
exitcode = LG_HOST_EXIT_FATAL;
goto fail_lgmp;
if ((status = lgmpHostMemAlloc(app.lgmp, MAX_POINTER_SIZE, &app.pointerShapeMemory[i])) != LGMP_OK)
{
DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer Shapes): %s", lgmpStatusString(status));
exitcode = LG_HOST_EXIT_FATAL;
goto fail_lgmp;
}
memset(lgmpHostMemPtr(app.pointerShapeMemory[i]), 0, MAX_POINTER_SIZE);
}
const long sz = sysinfo_getPageSize();
app.pageSize = sysinfo_getPageSize();
app.frameValid = false;
app.pointerShapeValid = false;
app.maxFrameSize = lgmpHostMemAvail(app.lgmp);
app.maxFrameSize = (app.maxFrameSize - (sz - 1)) & ~(sz - 1);
app.maxFrameSize = (app.maxFrameSize - (app.pageSize - 1)) & ~(app.pageSize - 1);
app.maxFrameSize /= LGMP_Q_FRAME_LEN;
DEBUG_INFO("Max Frame Size : %u MiB", (unsigned int)(app.maxFrameSize / 1048576LL));
for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
{
if ((status = lgmpHostMemAllocAligned(app.lgmp, app.maxFrameSize, sz, &app.frameMemory[i])) != LGMP_OK)
if ((status = lgmpHostMemAllocAligned(app.lgmp, app.maxFrameSize,
app.pageSize, &app.frameMemory[i])) != LGMP_OK)
{
DEBUG_ERROR("lgmpHostMemAlloc Failed (Frame): %s", lgmpStatusString(status));
exitcode = LG_HOST_EXIT_FATAL;
@@ -594,6 +637,8 @@ int app_main(int argc, char * argv[])
}
DEBUG_INFO("Using : %s", iface->getName());
DEBUG_INFO("Capture Method : %s", iface->asyncCapture ?
"Asynchronous" : "Synchronous");
app.state = APP_STATE_RUNNING;
app.iface = iface;
@@ -688,6 +733,9 @@ int app_main(int argc, char * argv[])
exitcode = LG_HOST_EXIT_FAILED;
goto fail_capture;
}
if (!iface->asyncCapture)
sendFrame();
}
if (app.state != APP_STATE_SHUTDOWN)
@@ -728,9 +776,10 @@ fail_timer:
fail_lgmp:
for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
lgmpHostMemFree(&app.frameMemory[i]);
for(int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
for(int i = 0; i < LGMP_Q_POINTER_LEN; ++i)
lgmpHostMemFree(&app.pointerMemory[i]);
lgmpHostMemFree(&app.pointerShape);
for(int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
lgmpHostMemFree(&app.pointerShapeMemory[i]);
lgmpHostFree(&app.lgmp);
fail_ivshmem: