diff --git a/client/include/interface/renderer.h b/client/include/interface/renderer.h index 4cf7679e..1d576ac9 100644 --- a/client/include/interface/renderer.h +++ b/client/include/interface/renderer.h @@ -51,6 +51,12 @@ typedef struct LG_RendererParams } LG_RendererParams; +typedef enum LG_RendererSupport +{ + LG_SUPPORTS_DMABUF +} +LG_RendererSupport; + typedef struct LG_RendererFormat { FrameType type; // frame type @@ -89,12 +95,13 @@ typedef void (* LG_RendererSetup)(); typedef bool (* LG_RendererCreate )(void ** opaque, const LG_RendererParams params); typedef bool (* LG_RendererInitialize )(void * opaque, Uint32 * sdlFlags); typedef void (* LG_RendererDeInitialize )(void * opaque); +typedef bool (* LG_RendererSupports )(void * opaque, LG_RendererSupport support); typedef void (* LG_RendererOnRestart )(void * opaque); 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_RendererOnFrameFormat)(void * opaque, const LG_RendererFormat format); -typedef bool (* LG_RendererOnFrame )(void * opaque, const FrameBuffer * frame); +typedef bool (* LG_RendererOnFrame )(void * opaque, const FrameBuffer * frame, int dmaFD); typedef void (* LG_RendererOnAlert )(void * opaque, const LG_MsgAlert alert, const char * message, bool ** closeFlag); typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window); typedef void (* LG_RendererUpdateFPS )(void * opaque, const float avgUPS, const float avgFPS); @@ -107,6 +114,7 @@ typedef struct LG_Renderer LG_RendererCreate create; LG_RendererInitialize initialize; LG_RendererDeInitialize deinitialize; + LG_RendererSupports supports; LG_RendererOnRestart on_restart; LG_RendererOnResize on_resize; LG_RendererOnMouseShape on_mouse_shape; diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index b2507236..59e99fe0 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -338,7 +338,7 @@ bool egl_on_frame_format(void * opaque, const LG_RendererFormat format) return egl_desktop_setup(this->desktop, format); } -bool egl_on_frame(void * opaque, const FrameBuffer * frame) +bool egl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd) { struct Inst * this = (struct Inst *)opaque; diff --git a/client/renderers/OpenGL/opengl.c b/client/renderers/OpenGL/opengl.c index 155baa76..8dd5821a 100644 --- a/client/renderers/OpenGL/opengl.c +++ b/client/renderers/OpenGL/opengl.c @@ -386,7 +386,7 @@ bool opengl_on_frame_format(void * opaque, const LG_RendererFormat format) return true; } -bool opengl_on_frame(void * opaque, const FrameBuffer * frame) +bool opengl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd) { struct Inst * this = (struct Inst *)opaque; diff --git a/client/src/main.c b/client/src/main.c index 0fc25b23..41fcca17 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -358,13 +358,29 @@ static int cursorThread(void * unused) static int frameThread(void * unused) { + struct DMAFrameInfo + { + KVMFRFrame * frame; + size_t dataSize; + int fd; + }; + LGMP_STATUS status; PLGMPClientQueue queue; uint32_t formatVer = 0; bool formatValid = false; + size_t dataSize; LG_RendererFormat lgrFormat; + //FIXME: Should use LGMP_Q_FRAME_LEN + struct DMAFrameInfo dmaInfo[2] = {0}; + const bool useDMA = ivshmemHasDMA(&state.shm) && state.lgr->supports && + state.lgr->supports(state.lgrData, LG_SUPPORTS_DMABUF); + + if (useDMA) + DEBUG_INFO("Using DMA buffer support"); + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); lgWaitEvent(e_startup, TIMEOUT_INFINITE); if (state.state != APP_STATE_RUNNING) @@ -409,7 +425,8 @@ static int frameThread(void * unused) break; } - KVMFRFrame * frame = (KVMFRFrame *)msg.mem; + KVMFRFrame * frame = (KVMFRFrame *)msg.mem; + struct DMAFrameInfo *dma = NULL; if (!formatValid || frame->formatVer != formatVer) { @@ -420,8 +437,7 @@ static int frameThread(void * unused) lgrFormat.stride = frame->stride; lgrFormat.pitch = frame->pitch; - size_t dataSize; - bool error = false; + bool error = false; switch(frame->type) { case FRAME_TYPE_RGBA: @@ -471,6 +487,54 @@ static int frameThread(void * unused) } } + if (useDMA) + { + /* find the existing dma buffer if it exists */ + for(int i = 0; i < sizeof(dmaInfo) / sizeof(struct DMAFrameInfo); ++i) + { + if (dmaInfo[i].frame == frame) + { + dma = &dmaInfo[i]; + /* if it's too small close it */ + if (dma->dataSize < dataSize) + { + close(dma->fd); + dma->fd = -1; + } + break; + } + } + + /* otherwise find a free buffer for use */ + if (!dma) + for(int i = 0; i < sizeof(dmaInfo) / sizeof(struct DMAFrameInfo); ++i) + { + if (!dmaInfo[i].frame) + { + dma = &dmaInfo[i]; + dma->frame = frame; + dma->fd = -1; + break; + } + } + + /* open the buffer */ + if (dma->fd == -1) + { + const uintptr_t pos = (uintptr_t)msg.mem - (uintptr_t)state.shm.mem; + const uintptr_t offset = (uintptr_t)frame->offset + FrameBufferStructSize; + + dma->dataSize = dataSize; + dma->fd = ivshmemGetDMABuf(&state.shm, pos + offset, dataSize); + if (dma->fd < 0) + { + DEBUG_ERROR("Failed to get the DMA buffer for the frame"); + state.state = APP_STATE_SHUTDOWN; + break; + } + } + } + if (lgrFormat.width != state.srcSize.x || lgrFormat.height != state.srcSize.y) { state.srcSize.x = lgrFormat.width; @@ -483,7 +547,7 @@ static int frameThread(void * unused) } FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)frame) + frame->offset); - if (!state.lgr->on_frame(state.lgrData, fb)) + if (!state.lgr->on_frame(state.lgrData, fb, useDMA ? dma->fd : -1)) { lgmpClientMessageDone(queue); DEBUG_ERROR("renderer on frame returned failure"); @@ -500,6 +564,14 @@ static int frameThread(void * unused) lgmpClientUnsubscribe(&queue); state.lgr->on_restart(state.lgrData); + if (useDMA) + { + for(int i = 0; i < sizeof(dmaInfo) / sizeof(struct DMAFrameInfo); ++i) + if (dmaInfo[i].fd >= 0) + close(dmaInfo[i].fd); + } + + return 0; }