diff --git a/.gitmodules b/.gitmodules index e69de29b..2d2157c2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "LGMP"] + path = LGMP + url = https://github.com/gnif/LGMP.git diff --git a/LGMP b/LGMP new file mode 160000 index 00000000..7e02dfd8 --- /dev/null +++ b/LGMP @@ -0,0 +1 @@ +Subproject commit 7e02dfd8ec53385cab76c819ab33a90911c6a271 diff --git a/VERSION b/VERSION index 54735d0c..7396ee35 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -B1-56-gb8203bec53+1 \ No newline at end of file +B1-57-g8caa220ad5+1 \ No newline at end of file diff --git a/c-host/CMakeLists.txt b/c-host/CMakeLists.txt index 37f78e9d..2b76ad81 100644 --- a/c-host/CMakeLists.txt +++ b/c-host/CMakeLists.txt @@ -52,7 +52,8 @@ set(SOURCES src/app.c ) -add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common") +add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common") +add_subdirectory("${PROJECT_TOP}/LGMP/lgmp" "${CMAKE_BINARY_DIR}/lgmp" ) add_subdirectory(platform) if(WIN32) @@ -63,6 +64,7 @@ endif() target_link_libraries(looking-glass-host lg_common platform + lgmp ) set_target_properties(looking-glass-host PROPERTIES LINK_FLAGS "-Wl,--gc-sections") install(PROGRAMS ${CMAKE_BINARY_DIR}/looking-glass-host DESTINATION bin/ COMPONENT binary) diff --git a/c-host/include/interface/capture.h b/c-host/include/interface/capture.h index daa6040b..9be8a712 100644 --- a/c-host/include/interface/capture.h +++ b/c-host/include/interface/capture.h @@ -71,21 +71,27 @@ typedef struct CapturePointer } CapturePointer; +typedef bool (*CaptureGetPointerBuffer )(void ** data, uint32_t * size); +typedef void (*CapturePostPointerBuffer)(CapturePointer pointer); + typedef struct CaptureInterface { const char * (*getName )(); void (*initOptions )(); - bool (*create )(); - bool (*init )(void * pointerShape, const unsigned int pointerSize); + bool(*create)( + CaptureGetPointerBuffer getPointerBufferFn, + CapturePostPointerBuffer postPointerBufferFn + ); + + bool (*init )(); void (*stop )(); bool (*deinit )(); void (*free )(); unsigned int (*getMaxFrameSize)(); CaptureResult (*capture )(); - CaptureResult (*waitFrame )(CaptureFrame * frame ); - CaptureResult (*getFrame )(FrameBuffer frame ); - CaptureResult (*getPointer)(CapturePointer * pointer); + CaptureResult (*waitFrame )(CaptureFrame * frame); + CaptureResult (*getFrame )(FrameBuffer frame); } CaptureInterface; \ No newline at end of file diff --git a/c-host/platform/Windows/capture/DXGI/src/dxgi.c b/c-host/platform/Windows/capture/DXGI/src/dxgi.c index fc908145..2eca9962 100644 --- a/c-host/platform/Windows/capture/DXGI/src/dxgi.c +++ b/c-host/platform/Windows/capture/DXGI/src/dxgi.c @@ -49,18 +49,6 @@ typedef struct Texture } Texture; -typedef struct Pointer -{ - unsigned int version; - - unsigned int x, y; - unsigned int w, h; - bool visible; - unsigned int pitch; - CaptureFormat format; -} -Pointer; - // locals struct iface { @@ -83,7 +71,9 @@ struct iface int texWIndex; volatile int texReady; bool needsRelease; - LGEvent * pointerEvent; + + CaptureGetPointerBuffer getPointerBufferFn; + CapturePostPointerBuffer postPointerBufferFn; LGEvent * frameEvent; unsigned int width; @@ -92,14 +82,8 @@ struct iface unsigned int stride; CaptureFormat format; - // pointer state - Pointer lastPointer; - Pointer pointer; - - // pointer shape - void * pointerShape; - unsigned int pointerSize; - unsigned int pointerUsed; + int lastPointerX, lastPointerY; + bool lastPointerVisible; }; static bool dpiDone = false; @@ -155,7 +139,7 @@ static void dxgi_initOptions() option_register(options); } -static bool dxgi_create() +static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostPointerBuffer postPointerBufferFn) { assert(!this); this = calloc(sizeof(struct iface), 1); @@ -165,14 +149,6 @@ static bool dxgi_create() return false; } - this->pointerEvent = lgCreateEvent(true, 10); - if (!this->pointerEvent) - { - DEBUG_ERROR("failed to create the pointer event"); - free(this); - return false; - } - this->frameEvent = lgCreateEvent(true, 17); // 60Hz = 16.7ms if (!this->frameEvent) { @@ -185,12 +161,14 @@ static bool dxgi_create() if (this->maxTextures <= 0) this->maxTextures = 1; - this->useAcquireLock = option_get_bool("dxgi", "useAcquireLock"); - this->texture = calloc(sizeof(struct Texture), this->maxTextures); + this->useAcquireLock = option_get_bool("dxgi", "useAcquireLock"); + this->texture = calloc(sizeof(struct Texture), this->maxTextures); + this->getPointerBufferFn = getPointerBufferFn; + this->postPointerBufferFn = postPointerBufferFn; return true; } -static bool dxgi_init(void * pointerShape, const unsigned int pointerSize) +static bool dxgi_init() { assert(this); @@ -213,17 +191,12 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize) HRESULT status; DXGI_OUTPUT_DESC outputDesc; - this->pointerShape = pointerShape; - this->pointerSize = pointerSize; - this->pointerUsed = 0; - this->stop = false; this->texRIndex = 0; this->texWIndex = 0; this->texReady = 0; lgResetEvent(this->frameEvent ); - lgResetEvent(this->pointerEvent); status = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&this->factory); if (FAILED(status)) @@ -549,7 +522,6 @@ fail: static void dxgi_stop() { this->stop = true; - lgSignalEvent(this->pointerEvent); } static bool dxgi_deinit() @@ -627,7 +599,6 @@ static void dxgi_free() if (this->initialized) dxgi_deinit(); - lgFreeEvent(this->pointerEvent); free(this->texture); free(this); @@ -726,32 +697,37 @@ static CaptureResult dxgi_capture() IDXGIResource_Release(res); // if the pointer has moved or changed state - bool signalPointer = false; + bool postPointer = false; + CapturePointer pointer = { 0 }; + void * pointerShape = NULL; + UINT pointerShapeSize = 0; + if (frameInfo.LastMouseUpdateTime.QuadPart) { if ( - frameInfo.PointerPosition.Position.x != this->lastPointer.x || - frameInfo.PointerPosition.Position.y != this->lastPointer.y || - frameInfo.PointerPosition.Visible != this->lastPointer.visible + frameInfo.PointerPosition.Position.x != this->lastPointerX || + frameInfo.PointerPosition.Position.y != this->lastPointerY || + frameInfo.PointerPosition.Visible != this->lastPointerVisible ) { - this->pointer.x = frameInfo.PointerPosition.Position.x; - this->pointer.y = frameInfo.PointerPosition.Position.y; - this->pointer.visible = frameInfo.PointerPosition.Visible; - signalPointer = true; + pointer.x = frameInfo.PointerPosition.Position.x; + pointer.y = frameInfo.PointerPosition.Position.y; + pointer.visible = frameInfo.PointerPosition.Visible; + postPointer = true; } } // if the pointer shape has changed if (frameInfo.PointerShapeBufferSize > 0) { - // update the buffer - if (frameInfo.PointerShapeBufferSize > this->pointerSize) - DEBUG_WARN("The pointer shape is too large to fit in the buffer, ignoring the shape"); + uint32_t bufferSize; + if(!this->getPointerBufferFn(&pointerShape, &bufferSize)) + DEBUG_WARN("Failed to obtain a buffer for the pointer shape"); else { DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; - LOCKED({status = IDXGIOutputDuplication_GetFramePointerShape(this->dup, this->pointerSize, this->pointerShape, &this->pointerUsed, &shapeInfo);}); + + LOCKED({status = IDXGIOutputDuplication_GetFramePointerShape(this->dup, bufferSize, pointerShape, &pointerShapeSize, &shapeInfo);}); if (FAILED(status)) { DEBUG_WINERROR("Failed to get the new pointer shape", status); @@ -760,25 +736,24 @@ static CaptureResult dxgi_capture() switch(shapeInfo.Type) { - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : this->pointer.format = CAPTURE_FMT_COLOR ; break; - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: this->pointer.format = CAPTURE_FMT_MASKED; break; - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : this->pointer.format = CAPTURE_FMT_MONO ; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : pointer.format = CAPTURE_FMT_COLOR ; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: pointer.format = CAPTURE_FMT_MASKED; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : pointer.format = CAPTURE_FMT_MONO ; break; default: DEBUG_ERROR("Unsupported cursor format"); return CAPTURE_RESULT_ERROR; } - this->pointer.w = shapeInfo.Width; - this->pointer.h = shapeInfo.Height; - this->pointer.pitch = shapeInfo.Pitch; - ++this->pointer.version; - signalPointer = true; + pointer.width = shapeInfo.Width; + pointer.height = shapeInfo.Height; + pointer.pitch = shapeInfo.Pitch; + postPointer = true; } } - // signal about the pointer update - if (signalPointer) - lgSignalEvent(this->pointerEvent); + // post back the pointer information + if (postPointer) + this->postPointerBufferFn(pointer); return CAPTURE_RESULT_OK; } @@ -841,34 +816,6 @@ static CaptureResult dxgi_getFrame(FrameBuffer frame) return CAPTURE_RESULT_OK; } -static CaptureResult dxgi_getPointer(CapturePointer * pointer) -{ - assert(this); - assert(this->initialized); - - if (!lgWaitEvent(this->pointerEvent, 1000)) - return CAPTURE_RESULT_TIMEOUT; - - if (this->stop) - return CAPTURE_RESULT_REINIT; - - Pointer p; - memcpy(&p, &this->pointer, sizeof(Pointer)); - - pointer->x = p.x; - pointer->y = p.y; - pointer->width = p.w; - pointer->height = p.h; - pointer->pitch = p.pitch; - pointer->visible = p.visible; - pointer->format = p.format; - pointer->shapeUpdate = p.version > this->lastPointer.version; - - memcpy(&this->lastPointer, &p, sizeof(Pointer)); - - return CAPTURE_RESULT_OK; -} - static CaptureResult dxgi_releaseFrame() { assert(this); @@ -914,6 +861,5 @@ struct CaptureInterface Capture_DXGI = .getMaxFrameSize = dxgi_getMaxFrameSize, .capture = dxgi_capture, .waitFrame = dxgi_waitFrame, - .getFrame = dxgi_getFrame, - .getPointer = dxgi_getPointer + .getFrame = dxgi_getFrame }; \ No newline at end of file diff --git a/c-host/src/app.c b/c-host/src/app.c index a201b085..6df1cf7a 100644 --- a/c-host/src/app.c +++ b/c-host/src/app.c @@ -28,6 +28,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "common/thread.h" #include "common/ivshmem.h" +#include + #include #include #include @@ -36,124 +38,51 @@ Place, Suite 330, Boston, MA 02111-1307 USA #define ALIGN_DN(x) ((uintptr_t)(x) & ~0x7F) #define ALIGN_UP(x) ALIGN_DN(x + 0x7F) -#define MAX_FRAMES 2 + +#define LGMP_Q_POINTER 1 +#define LGMP_Q_POINTER_LEN 10 +#define LGMP_Q_FRAME 2 +#define LGMP_Q_FRAME_LEN 2 + +#define MAX_POINTER_SIZE (sizeof(KVMFRCursor) + (128 * 128 * 4)) struct app { - unsigned int clientInstance; + PLGMPHost lgmp; - KVMFRHeader * shmHeader; - uint8_t * pointerData; - unsigned int pointerDataSize; - unsigned int pointerOffset; + PLGMPHQueue pointerQueue; + PLGMPMemory pointerMemory[LGMP_Q_POINTER_LEN]; + unsigned int pointerIndex; + + size_t maxFrameSize; + PLGMPHQueue frameQueue; + PLGMPMemory frameMemory[LGMP_Q_FRAME_LEN]; + unsigned int frameIndex; CaptureInterface * iface; - uint8_t * frames; - unsigned int frameSize; - FrameBuffer frame[MAX_FRAMES]; - unsigned int frameOffset[MAX_FRAMES]; - bool running; bool reinit; - LGThread * pointerThread; + LGThread * lgmpThread; LGThread * frameThread; }; static struct app app; -static int pointerThread(void * opaque) +static int lgmpThread(void * opaque) { - DEBUG_INFO("Pointer thread started"); - - volatile KVMFRCursor * ci = &(app.shmHeader->cursor); - - uint8_t flags; - bool pointerValid = false; - bool shapeValid = false; - unsigned int clientInstance = 0; - CapturePointer pointer = { 0 }; - + LGMP_STATUS status; while(app.running) { - bool resend = false; - - pointer.shapeUpdate = false; - - switch(app.iface->getPointer(&pointer)) + if ((status = lgmpHostProcess(app.lgmp)) != LGMP_OK) { - case CAPTURE_RESULT_OK: - { - pointerValid = true; - break; - } - - case CAPTURE_RESULT_REINIT: - { - app.reinit = true; - DEBUG_INFO("Pointer thread reinit"); - return 0; - } - - case CAPTURE_RESULT_ERROR: - { - DEBUG_ERROR("Failed to get the pointer"); - return 0; - } - - case CAPTURE_RESULT_TIMEOUT: - { - // if the pointer is valid and the client has restarted, send it - if (pointerValid && clientInstance != app.clientInstance) - { - resend = true; - break; - } - - continue; - } + DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status)); + break; } - - clientInstance = app.clientInstance; - - // wait for the client to finish with the previous update - while((ci->flags & ~KVMFR_CURSOR_FLAG_UPDATE) != 0 && app.running) - usleep(1000); - - flags = KVMFR_CURSOR_FLAG_UPDATE; - ci->x = pointer.x; - ci->y = pointer.y; - flags |= KVMFR_CURSOR_FLAG_POS; - if (pointer.visible) - flags |= KVMFR_CURSOR_FLAG_VISIBLE; - - // if we have shape data - if (pointer.shapeUpdate || (shapeValid && resend)) - { - switch(pointer.format) - { - case CAPTURE_FMT_COLOR : ci->type = CURSOR_TYPE_COLOR ; break; - case CAPTURE_FMT_MONO : ci->type = CURSOR_TYPE_MONOCHROME ; break; - case CAPTURE_FMT_MASKED: ci->type = CURSOR_TYPE_MASKED_COLOR; break; - default: - DEBUG_ERROR("Invalid pointer format: %d", pointer.format); - continue; - } - - ci->width = pointer.width; - ci->height = pointer.height; - ci->pitch = pointer.pitch; - ci->dataPos = app.pointerOffset; - ++ci->version; - shapeValid = true; - flags |= KVMFR_CURSOR_FLAG_SHAPE; - } - - // update the flags for the client - ci->flags = flags; + usleep(1000); } - DEBUG_INFO("Pointer thread stopped"); + app.running = false; return 0; } @@ -161,16 +90,23 @@ static int frameThread(void * opaque) { DEBUG_INFO("Frame thread started"); - volatile KVMFRFrame * fi = &(app.shmHeader->frame); - bool frameValid = false; bool repeatFrame = false; int frameIndex = 0; - unsigned int clientInstance = 0; CaptureFrame frame = { 0 }; + (void)frameIndex; + (void)repeatFrame; + while(app.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)) { case CAPTURE_RESULT_OK: @@ -192,7 +128,7 @@ static int frameThread(void * opaque) case CAPTURE_RESULT_TIMEOUT: { - if (frameValid && clientInstance != app.clientInstance) + if (frameValid && lgmpHostNewSubCount(app.frameQueue) > 0) { // resend the last frame repeatFrame = true; @@ -203,41 +139,40 @@ static int frameThread(void * opaque) } } - clientInstance = app.clientInstance; - - // wait for the client to finish with the previous frame - while(fi->flags & KVMFR_FRAME_FLAG_UPDATE && app.running) - usleep(1000); - if (repeatFrame) - INTERLOCKED_OR8(&fi->flags, KVMFR_FRAME_FLAG_UPDATE); - else { - 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_YUV420: fi->type = FRAME_TYPE_YUV420; break; - default: - DEBUG_ERROR("Unsupported frame format %d, skipping frame", frame.format); - continue; - } - - fi->width = frame.width; - fi->height = frame.height; - fi->stride = frame.stride; - fi->pitch = frame.pitch; - fi->dataPos = app.frameOffset[frameIndex]; - frameValid = true; - - framebuffer_prepare(app.frame[frameIndex]); - INTERLOCKED_OR8(&fi->flags, KVMFR_FRAME_FLAG_UPDATE); - app.iface->getFrame(app.frame[frameIndex]); + lgmpHostPost(app.frameQueue, 0, app.frameMemory[app.frameIndex]); + continue; } - if (++frameIndex == MAX_FRAMES) + // we increment the index first so that if we need to repeat a frame + // the index still points to the latest valid frame + if (frameIndex++ == LGMP_Q_FRAME_LEN) 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_YUV420: fi->type = FRAME_TYPE_YUV420; break; + default: + DEBUG_ERROR("Unsupported frame format %d, skipping frame", frame.format); + continue; + } + + fi->width = frame.width; + fi->height = frame.height; + fi->stride = frame.stride; + fi->pitch = frame.pitch; + frameValid = true; + + FrameBuffer fb = (FrameBuffer)(fi + 1); + framebuffer_prepare(fb); + app.iface->getFrame(fb); + + lgmpHostPost(app.frameQueue, 0, app.frameMemory[app.frameIndex]); } DEBUG_INFO("Frame thread stopped"); return 0; @@ -246,9 +181,9 @@ static int frameThread(void * opaque) bool startThreads() { app.running = true; - if (!lgCreateThread("CursorThread", pointerThread, NULL, &app.pointerThread)) + if (!lgCreateThread("LGMPThread", lgmpThread, NULL, &app.lgmpThread)) { - DEBUG_ERROR("Failed to create the pointer thread"); + DEBUG_ERROR("Failed to create the LGMP thread"); return false; } @@ -275,12 +210,12 @@ bool stopThreads() } app.frameThread = NULL; - if (app.pointerThread && !lgJoinThread(app.pointerThread, NULL)) + if (app.lgmpThread && !lgJoinThread(app.lgmpThread, NULL)) { - DEBUG_WARN("Failed to join the pointer thread"); + DEBUG_WARN("Failed to join the LGMP thread"); ok = false; } - app.pointerThread = NULL; + app.lgmpThread = NULL; return ok; } @@ -290,7 +225,7 @@ static bool captureStart() DEBUG_INFO("Using : %s", app.iface->getName()); const unsigned int maxFrameSize = app.iface->getMaxFrameSize(); - if (maxFrameSize > app.frameSize) + if (maxFrameSize > app.maxFrameSize) { DEBUG_ERROR("Maximum frame size of %d bytes excceds maximum space available", maxFrameSize); return false; @@ -307,7 +242,7 @@ static bool captureRestart() if (!stopThreads()) return false; - if (!app.iface->deinit() || !app.iface->init(app.pointerData, app.pointerDataSize)) + if (!app.iface->deinit() || !app.iface->init()) { DEBUG_ERROR("Failed to reinitialize the capture device"); return false; @@ -319,6 +254,57 @@ static bool captureRestart() return true; } +bool captureGetPointerBuffer(void ** data, uint32_t * size) +{ + if (lgmpHostQueuePending(app.pointerQueue) == LGMP_Q_POINTER_LEN) + return false; + + PLGMPMemory mem = app.pointerMemory[app.pointerIndex]; + *data = ((uint8_t*)lgmpHostMemPtr(mem)) + sizeof(KVMFRCursor); + *size = MAX_POINTER_SIZE - sizeof(KVMFRCursor); + return true; +} + +void capturePostPointerBuffer(CapturePointer pointer) +{ + if (lgmpHostQueuePending(app.pointerQueue) == LGMP_Q_POINTER_LEN) + return; + + PLGMPMemory mem = app.pointerMemory[app.pointerIndex]; + KVMFRCursor *cursor = lgmpHostMemPtr(mem); + + cursor->x = pointer.x; + cursor->y = pointer.y; + cursor->visible = pointer.visible; + + if (pointer.shapeUpdate) + { + cursor->width = pointer.width; + cursor->height = pointer.height; + cursor->pitch = pointer.pitch; + switch(pointer.format) + { + case CAPTURE_FMT_COLOR : cursor->type = CURSOR_TYPE_COLOR ; break; + case CAPTURE_FMT_MONO : cursor->type = CURSOR_TYPE_MONOCHROME ; break; + case CAPTURE_FMT_MASKED: cursor->type = CURSOR_TYPE_MASKED_COLOR; break; + + default: + DEBUG_ERROR("Invalid pointer type"); + return; + } + } + + LGMP_STATUS status; + if ((status = lgmpHostPost(app.pointerQueue, pointer.shapeUpdate ? 1 : 0, mem)) != LGMP_OK) + { + DEBUG_ERROR("lgmpHostPost Failed (Pointer): %s", lgmpStatusString(status)); + return; + } + + if (app.pointerIndex++ == LGMP_Q_POINTER_LEN) + app.pointerIndex = 0; +} + // this is called from the platform specific startup routine int app_main(int argc, char * argv[]) { @@ -366,37 +352,60 @@ int app_main(int argc, char * argv[]) DEBUG_INFO("IVSHMEM Size : %u MiB", shmDev.size / 1048576); DEBUG_INFO("IVSHMEM Address : 0x%" PRIXPTR, (uintptr_t)shmDev.mem); - app.shmHeader = (KVMFRHeader *)shmDev.mem; - app.pointerData = (uint8_t *)ALIGN_UP(shmDev.mem + sizeof(KVMFRHeader)); - app.pointerDataSize = 1048576; // 1MB fixed for pointer size, should be more then enough - app.pointerOffset = app.pointerData - (uint8_t*)shmDev.mem; - app.frames = (uint8_t *)ALIGN_UP(app.pointerData + app.pointerDataSize); - app.frameSize = ALIGN_DN((shmDev.size - (app.frames - (uint8_t*)shmDev.mem)) / MAX_FRAMES); - - DEBUG_INFO("Max Cursor Size : %u MiB", app.pointerDataSize / 1048576); - DEBUG_INFO("Max Frame Size : %u MiB", app.frameSize / 1048576); - DEBUG_INFO("Cursor : 0x%" PRIXPTR " (0x%08x)", (uintptr_t)app.pointerData, app.pointerOffset); - - for (int i = 0; i < MAX_FRAMES; ++i) + LGMP_STATUS status; + if ((status = lgmpHostInit(shmDev.mem, shmDev.size, &app.lgmp)) != LGMP_OK) { - app.frame [i] = (FrameBuffer)(app.frames + i * app.frameSize); - app.frameOffset[i] = (uint8_t *)app.frame[i] - (uint8_t*)shmDev.mem; - DEBUG_INFO("Frame %d : 0x%" PRIXPTR " (0x%08x)", i, (uintptr_t)app.frame[i], app.frameOffset[i]); + DEBUG_ERROR("lgmpHostInit Failed: %s", lgmpStatusString(status)); + goto fail; } + if ((status = lgmpHostAddQueue(app.lgmp, LGMP_Q_POINTER, LGMP_Q_POINTER_LEN, &app.pointerQueue)) != LGMP_OK) + { + DEBUG_ERROR("lgmpHostQueueCreate Failed (Pointer): %s", lgmpStatusString(status)); + goto fail; + } + + for(int i = 0; i < LGMP_Q_POINTER_LEN; ++i) + { + if ((status = lgmpHostMemAlloc(app.lgmp, MAX_POINTER_SIZE, &app.pointerMemory[i])) != LGMP_OK) + { + DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer): %s", lgmpStatusString(status)); + goto fail; + } + } + + if ((status = lgmpHostAddQueue(app.lgmp, LGMP_Q_FRAME, LGMP_Q_FRAME_LEN, &app.frameQueue)) != LGMP_OK) + { + DEBUG_ERROR("lgmpHostQueueCreate Failed (Frame): %s", lgmpStatusString(status)); + goto fail; + } + + app.maxFrameSize = ALIGN_DN(lgmpHostMemAvail(app.lgmp) / LGMP_Q_FRAME_LEN); + for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i) + { + if ((status = lgmpHostMemAlloc(app.lgmp, app.maxFrameSize, &app.frameMemory[i])) != LGMP_OK) + { + DEBUG_ERROR("lgmpHostMemAlloc Failed (Frame): %s", lgmpStatusString(status)); + goto fail; + } + } + + DEBUG_INFO("Max Pointer Size : %u KiB", (unsigned int)MAX_POINTER_SIZE); + DEBUG_INFO("Max Frame Size : %u MiB", (unsigned int)(app.maxFrameSize / 1048576LL)); + CaptureInterface * iface = NULL; for(int i = 0; CaptureInterfaces[i]; ++i) { iface = CaptureInterfaces[i]; DEBUG_INFO("Trying : %s", iface->getName()); - if (!iface->create()) + if (!iface->create(captureGetPointerBuffer, capturePostPointerBuffer)) { iface = NULL; continue; } - if (iface->init(app.pointerData, app.pointerDataSize)) + if (iface->init()) break; iface->free(); @@ -412,31 +421,14 @@ int app_main(int argc, char * argv[]) app.iface = iface; - // initialize the shared memory headers - memcpy(app.shmHeader->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC)); - app.shmHeader->version = KVMFR_HEADER_VERSION; - - // zero and notify the client we are starting - memset(&(app.shmHeader->frame ), 0, sizeof(KVMFRFrame )); - memset(&(app.shmHeader->cursor), 0, sizeof(KVMFRCursor)); - app.shmHeader->flags &= ~KVMFR_HEADER_FLAG_RESTART; - if (!captureStart()) { exitcode = -1; goto exit; } - volatile char * flags = (volatile char *)&(app.shmHeader->flags); - while(app.running) { - if (INTERLOCKED_AND8(flags, ~(KVMFR_HEADER_FLAG_RESTART)) & KVMFR_HEADER_FLAG_RESTART) - { - DEBUG_INFO("Client restarted"); - ++app.clientInstance; - } - if (app.reinit && !captureRestart()) { exitcode = -1; @@ -475,6 +467,13 @@ exit: iface->deinit(); iface->free(); fail: + + for(int i = 0; i < LGMP_Q_POINTER_LEN; ++i) + lgmpHostMemFree(&app.pointerMemory[i]); + for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i) + lgmpHostMemFree(&app.frameMemory[i]); + lgmpHostFree(&app.lgmp); + ivshmemClose(&shmDev); return exitcode; } diff --git a/common/include/common/KVMFR.h b/common/include/common/KVMFR.h index 2449de47..b6b52d81 100644 --- a/common/include/common/KVMFR.h +++ b/common/include/common/KVMFR.h @@ -42,49 +42,23 @@ typedef enum CursorType } CursorType; -#define KVMFR_CURSOR_FLAG_UPDATE 1 // cursor update available -#define KVMFR_CURSOR_FLAG_VISIBLE 2 // cursor is visible -#define KVMFR_CURSOR_FLAG_SHAPE 4 // shape updated -#define KVMFR_CURSOR_FLAG_POS 8 // position updated - typedef struct KVMFRCursor { - volatile uint8_t flags; // KVMFR_CURSOR_FLAGS int16_t x, y; // cursor x & y position - - uint32_t version; // shape version + bool visible; // cursor visible CursorType type; // shape buffer data type uint32_t width; // width of the shape uint32_t height; // height of the shape uint32_t pitch; // row length in bytes of the shape - uint64_t dataPos; // offset to the shape data } KVMFRCursor; -#define KVMFR_FRAME_FLAG_UPDATE 1 // frame update available - typedef struct KVMFRFrame { - volatile uint8_t flags; // KVMFR_FRAME_FLAGS FrameType type; // the frame data type uint32_t width; // the width uint32_t height; // the height uint32_t stride; // the row stride (zero if compressed data) uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size) - uint64_t dataPos; // offset to the frame } -KVMFRFrame; - -#define KVMFR_HEADER_FLAG_RESTART 1 // restart signal from client -#define KVMFR_HEADER_FLAG_READY 2 // ready signal from client -#define KVMFR_HEADER_FLAG_PAUSED 4 // capture has been paused by the host - -typedef struct KVMFRHeader -{ - char magic[sizeof(KVMFR_HEADER_MAGIC)]; - uint32_t version; // version of this structure - volatile uint8_t flags; // KVMFR_HEADER_FLAGS - KVMFRFrame frame; // the frame information - KVMFRCursor cursor; // the cursor information -} -KVMFRHeader; \ No newline at end of file +KVMFRFrame; \ No newline at end of file