From 4f9544d61dccc4a9e8fe87788f2a475b413f8851 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Fri, 30 Oct 2020 02:32:25 +1100 Subject: [PATCH] [client] egl: added DMA texture support for direct upload Note: This only works with the KVMFR kernel module in a VM->VM configuration. If this causes issues it can be disabled with the new option `app:allowDMA` --- client/include/interface/renderer.h | 2 +- client/renderers/EGL/alert.c | 3 +- client/renderers/EGL/cursor.c | 10 +-- client/renderers/EGL/desktop.c | 27 ++++-- client/renderers/EGL/desktop.h | 7 +- client/renderers/EGL/egl.c | 54 ++++++++---- client/renderers/EGL/fps.c | 3 +- client/renderers/EGL/texture.c | 124 +++++++++++++++++++++------- client/renderers/EGL/texture.h | 6 +- client/renderers/OpenGL/opengl.c | 2 +- client/src/config.c | 8 ++ client/src/main.c | 8 +- client/src/main.h | 1 + common/src/framebuffer.c | 6 +- 14 files changed, 190 insertions(+), 71 deletions(-) diff --git a/client/include/interface/renderer.h b/client/include/interface/renderer.h index 1d576ac9..433024cf 100644 --- a/client/include/interface/renderer.h +++ b/client/include/interface/renderer.h @@ -100,7 +100,7 @@ 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_RendererOnFrameFormat)(void * opaque, const LG_RendererFormat format, bool useDMA); 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); diff --git a/client/renderers/EGL/alert.c b/client/renderers/EGL/alert.c index 9b430527..d3afa308 100644 --- a/client/renderers/EGL/alert.c +++ b/client/renderers/EGL/alert.c @@ -72,7 +72,7 @@ bool egl_alert_init(EGL_Alert ** alert, const LG_Font * font, LG_FontObj fontObj (*alert)->fontObj = fontObj; LG_LOCK_INIT((*alert)->lock); - if (!egl_texture_init(&(*alert)->texture)) + if (!egl_texture_init(&(*alert)->texture, NULL)) { DEBUG_ERROR("Failed to initialize the alert texture"); return false; @@ -175,6 +175,7 @@ void egl_alert_render(EGL_Alert * alert, const float scaleX, const float scaleY) alert->bmp->width , alert->bmp->height, alert->bmp->width * alert->bmp->bpp, + false, false ); diff --git a/client/renderers/EGL/cursor.c b/client/renderers/EGL/cursor.c index b0a42265..6215da6a 100644 --- a/client/renderers/EGL/cursor.c +++ b/client/renderers/EGL/cursor.c @@ -76,13 +76,13 @@ bool egl_cursor_init(EGL_Cursor ** cursor) memset(*cursor, 0, sizeof(EGL_Cursor)); LG_LOCK_INIT((*cursor)->lock); - if (!egl_texture_init(&(*cursor)->texture)) + if (!egl_texture_init(&(*cursor)->texture, NULL)) { DEBUG_ERROR("Failed to initialize the cursor texture"); return false; } - if (!egl_texture_init(&(*cursor)->textureMono)) + if (!egl_texture_init(&(*cursor)->textureMono, NULL)) { DEBUG_ERROR("Failed to initialize the cursor mono texture"); return false; @@ -214,7 +214,7 @@ void egl_cursor_render(EGL_Cursor * cursor) case LG_CURSOR_COLOR: { - egl_texture_setup(cursor->texture, EGL_PF_BGRA, cursor->width, cursor->height, cursor->stride, false); + egl_texture_setup(cursor->texture, EGL_PF_BGRA, cursor->width, cursor->height, cursor->stride, false, false); egl_texture_update(cursor->texture, data); egl_model_set_texture(cursor->model, cursor->texture); break; @@ -238,8 +238,8 @@ void egl_cursor_render(EGL_Cursor * cursor) xor[y * cursor->width + x] = xorMask; } - egl_texture_setup (cursor->texture , EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false); - egl_texture_setup (cursor->textureMono, EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false); + egl_texture_setup (cursor->texture , EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false, false); + egl_texture_setup (cursor->textureMono, EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false, false); egl_texture_update(cursor->texture , (uint8_t *)and); egl_texture_update(cursor->textureMono, (uint8_t *)xor); break; diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index a266aba7..7d1e542d 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -47,7 +47,7 @@ struct DesktopShader struct EGL_Desktop { - void * egl; + EGLDisplay * display; EGL_Texture * texture; struct DesktopShader * shader; // the active shader @@ -94,7 +94,7 @@ static bool egl_init_desktop_shader( return true; } -bool egl_desktop_init(void * egl, EGL_Desktop ** desktop) +bool egl_desktop_init(EGL_Desktop ** desktop, EGLDisplay * display) { *desktop = (EGL_Desktop *)malloc(sizeof(EGL_Desktop)); if (!*desktop) @@ -104,8 +104,9 @@ bool egl_desktop_init(void * egl, EGL_Desktop ** desktop) } memset(*desktop, 0, sizeof(EGL_Desktop)); + (*desktop)->display = display; - if (!egl_texture_init(&(*desktop)->texture)) + if (!egl_texture_init(&(*desktop)->texture, display)) { DEBUG_ERROR("Failed to initialize the desktop texture"); return false; @@ -138,7 +139,6 @@ bool egl_desktop_init(void * egl, EGL_Desktop ** desktop) egl_model_set_default((*desktop)->model); egl_model_set_texture((*desktop)->model, (*desktop)->texture); - (*desktop)->egl = egl; (*desktop)->kbNV = app_register_keybind(SDL_SCANCODE_N, egl_desktop_toggle_nv, *desktop); (*desktop)->nvMax = option_get_int("egl", "nvGainMax"); @@ -175,7 +175,7 @@ void egl_desktop_free(EGL_Desktop ** desktop) *desktop = NULL; } -bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format) +bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format, bool useDMA) { enum EGL_PixelFormat pixFmt; switch(format.type) @@ -219,7 +219,8 @@ bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format) format.width, format.height, format.pitch, - true // streaming texture + true, // streaming texture + useDMA )) { DEBUG_ERROR("Failed to setup the desktop texture"); @@ -229,10 +230,18 @@ bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format) return true; } -bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame) +bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd) { - if (!egl_texture_update_from_frame(desktop->texture, frame)) - return false; + if (dmaFd >= 0) + { + if (!egl_texture_update_from_dma(desktop->texture, frame, dmaFd)) + return false; + } + else + { + if (!egl_texture_update_from_frame(desktop->texture, frame)) + return false; + } enum EGL_TexStatus status; if ((status = egl_texture_process(desktop->texture)) != EGL_TEX_STATUS_OK) diff --git a/client/renderers/EGL/desktop.h b/client/renderers/EGL/desktop.h index b7ce3396..fa9b9f5d 100644 --- a/client/renderers/EGL/desktop.h +++ b/client/renderers/EGL/desktop.h @@ -20,14 +20,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA #pragma once #include +#include #include "interface/renderer.h" typedef struct EGL_Desktop EGL_Desktop; -bool egl_desktop_init(void * egl, EGL_Desktop ** desktop); +bool egl_desktop_init(EGL_Desktop ** desktop, EGLDisplay * display); void egl_desktop_free(EGL_Desktop ** desktop); -bool egl_desktop_setup (EGL_Desktop * desktop, const LG_RendererFormat format); -bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame); +bool egl_desktop_setup (EGL_Desktop * desktop, const LG_RendererFormat format, bool useDMA); +bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd); bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest); diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 59e99fe0..c1de30f5 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -52,6 +52,7 @@ struct Options struct Inst { + bool dmaSupport; LG_RendererParams params; struct Options opt; @@ -188,8 +189,8 @@ bool egl_initialize(void * opaque, Uint32 * sdlFlags) DEBUG_INFO("Double buffering is %s", doubleBuffer ? "on" : "off"); *sdlFlags = SDL_WINDOW_OPENGL; - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , doubleBuffer ? 1 : 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , doubleBuffer ? 1 : 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_CORE); if (option_get_bool("egl", "multisample")) { @@ -226,6 +227,20 @@ void egl_deinitialize(void * opaque) free(this); } +bool egl_supports(void * opaque, LG_RendererSupport flag) +{ + struct Inst * this = (struct Inst *)opaque; + + switch(flag) + { + case LG_SUPPORTS_DMABUF: + return this->dmaSupport; + + default: + return false; + } +} + void egl_on_restart(void * opaque) { struct Inst * this = (struct Inst *)opaque; @@ -308,7 +323,7 @@ bool egl_on_mouse_event(void * opaque, const bool visible, const int x, const in return true; } -bool egl_on_frame_format(void * opaque, const LG_RendererFormat format) +bool egl_on_frame_format(void * opaque, const LG_RendererFormat format, bool useDMA) { struct Inst * this = (struct Inst *)opaque; memcpy(&this->format, &format, sizeof(LG_RendererFormat)); @@ -335,14 +350,14 @@ bool egl_on_frame_format(void * opaque, const LG_RendererFormat format) } this->useNearest = this->width < format.width || this->height < format.height; - return egl_desktop_setup(this->desktop, format); + return egl_desktop_setup(this->desktop, format, useDMA); } bool egl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd) { struct Inst * this = (struct Inst *)opaque; - if (!egl_desktop_update(this->desktop, frame)) + if (!egl_desktop_update(this->desktop, frame, dmaFd)) { DEBUG_INFO("Failed to to update the desktop"); return false; @@ -399,12 +414,12 @@ bool egl_render_startup(void * opaque, SDL_Window * window) return false; } - const char *client_exts = eglQueryString(NULL, EGL_EXTENSIONS); - DEBUG_INFO("Supported extensions: %s", client_exts); - bool useNative = false; - if (strstr(client_exts, "EGL_KHR_platform_base") != NULL) - useNative = true; + { + const char *client_exts = eglQueryString(NULL, EGL_EXTENSIONS); + if (strstr(client_exts, "EGL_KHR_platform_base") != NULL) + useNative = true; + } DEBUG_INFO("use native: %s", useNative ? "true" : "false"); @@ -451,7 +466,8 @@ bool egl_render_startup(void * opaque, SDL_Window * window) return false; } - if (!eglInitialize(this->display, NULL, NULL)) + int maj, min; + if (!eglInitialize(this->display, &maj, &min)) { DEBUG_ERROR("Unable to initialize EGL"); return false; @@ -494,14 +510,21 @@ bool egl_render_startup(void * opaque, SDL_Window * window) } eglMakeCurrent(this->display, this->surface, this->surface, this->context); + const char *client_exts = eglQueryString(this->display, EGL_EXTENSIONS); - DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR )); - DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER)); - DEBUG_INFO("Version : %s", glGetString(GL_VERSION )); + DEBUG_INFO("EGL : %d.%d", maj, min); + DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR )); + DEBUG_INFO("Renderer : %s", glGetString(GL_RENDERER)); + DEBUG_INFO("Version : %s", glGetString(GL_VERSION )); + DEBUG_INFO("EGL APIs : %s", eglQueryString(this->display, EGL_CLIENT_APIS)); + DEBUG_INFO("Extensions: %s", client_exts); + + if (strstr(client_exts, "EGL_EXT_image_dma_buf_import") != NULL) + this->dmaSupport = true; eglSwapInterval(this->display, this->opt.vsync ? 1 : 0); - if (!egl_desktop_init(this, &this->desktop)) + if (!egl_desktop_init(&this->desktop, this->display)) { DEBUG_ERROR("Failed to initialize the desktop"); return false; @@ -617,6 +640,7 @@ struct LG_Renderer LGR_EGL = .create = egl_create, .initialize = egl_initialize, .deinitialize = egl_deinitialize, + .supports = egl_supports, .on_restart = egl_on_restart, .on_resize = egl_on_resize, .on_mouse_shape = egl_on_mouse_shape, diff --git a/client/renderers/EGL/fps.c b/client/renderers/EGL/fps.c index 624ad6e9..d3b1f8bc 100644 --- a/client/renderers/EGL/fps.c +++ b/client/renderers/EGL/fps.c @@ -66,7 +66,7 @@ bool egl_fps_init(EGL_FPS ** fps, const LG_Font * font, LG_FontObj fontObj) (*fps)->font = font; (*fps)->fontObj = fontObj; - if (!egl_texture_init(&(*fps)->texture)) + if (!egl_texture_init(&(*fps)->texture, NULL)) { DEBUG_ERROR("Failed to initialize the fps texture"); return false; @@ -158,6 +158,7 @@ void egl_fps_update(EGL_FPS * fps, const float avgFPS, const float renderFPS) bmp->width , bmp->height, bmp->width * bmp->bpp, + false, false ); } diff --git a/client/renderers/EGL/texture.c b/client/renderers/EGL/texture.c index bc2ce9c2..cdea85e2 100644 --- a/client/renderers/EGL/texture.c +++ b/client/renderers/EGL/texture.c @@ -27,6 +27,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include @@ -35,11 +36,11 @@ Place, Suite 330, Boston, MA 02111-1307 USA struct Tex { - GLuint t[3]; - bool hasPBO; - GLuint pbo; - void * map; - GLsync sync; + GLuint t[3]; + bool hasPBO; + GLuint pbo; + void * map; + GLsync sync; }; struct TexState @@ -49,10 +50,13 @@ struct TexState struct EGL_Texture { + EGLDisplay * display; + enum EGL_PixelFormat pixFmt; size_t width, height, stride; size_t bpp; bool streaming; + bool dma; bool ready; int planeCount; @@ -69,7 +73,7 @@ struct EGL_Texture struct Tex tex[TEXTURE_COUNT]; }; -bool egl_texture_init(EGL_Texture ** texture) +bool egl_texture_init(EGL_Texture ** texture, EGLDisplay * display) { *texture = (EGL_Texture *)malloc(sizeof(EGL_Texture)); if (!*texture) @@ -79,6 +83,7 @@ bool egl_texture_init(EGL_Texture ** texture) } memset(*texture, 0, sizeof(EGL_Texture)); + (*texture)->display = display; return true; } @@ -106,8 +111,8 @@ void egl_texture_free(EGL_Texture ** texture) glDeleteSync(t->sync); } - if ((*texture)->planeCount > 0) - glDeleteTextures((*texture)->planeCount, t->t); + if ((*texture)->planeCount > 0) + glDeleteTextures((*texture)->planeCount, t->t); } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); @@ -148,7 +153,7 @@ static void egl_texture_unmap(EGL_Texture * texture, uint8_t i) texture->tex[i].map = NULL; } -bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_t width, size_t height, size_t stride, bool streaming) +bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_t width, size_t height, size_t stride, bool streaming, bool useDMA) { int planeCount; @@ -156,11 +161,14 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_ { for(int i = 0; i < texture->textureCount; ++i) { - egl_texture_unmap(texture, i); - if (texture->tex[i].hasPBO) + if (!useDMA) { - glDeleteBuffers(1, &texture->tex[i].pbo); - texture->tex[i].hasPBO = false; + egl_texture_unmap(texture, i); + if (texture->tex[i].hasPBO) + { + glDeleteBuffers(1, &texture->tex[i].pbo); + texture->tex[i].hasPBO = false; + } } } } @@ -292,7 +300,7 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_ } glBindTexture(GL_TEXTURE_2D, 0); - if (!streaming) + if (!streaming || useDMA) return true; for(int i = 0; i < texture->textureCount; ++i) @@ -394,6 +402,55 @@ bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer * fr return true; } +bool egl_texture_update_from_dma(EGL_Texture * texture, const FrameBuffer * frame, const int dmaFd) +{ + if (!texture->streaming) + return false; + + const uint8_t sw = + atomic_load_explicit(&texture->state.w, memory_order_acquire); + + if (atomic_load_explicit(&texture->state.u, memory_order_acquire) == (uint8_t)(sw + 1)) + { + egl_warn_slow(); + return true; + } + + const uint8_t t = sw % TEXTURE_COUNT; + EGLAttrib const attribs[] = + { + EGL_WIDTH , texture->width, + EGL_HEIGHT , texture->height, + EGL_LINUX_DRM_FOURCC_EXT , DRM_FORMAT_ARGB8888, + EGL_DMA_BUF_PLANE0_FD_EXT , dmaFd, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, + EGL_DMA_BUF_PLANE0_PITCH_EXT , texture->stride, + EGL_NONE , EGL_NONE + }; + + /* create the image backed by the dma buffer */ + EGLImage image = eglCreateImage( + texture->display, + EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, + (EGLClientBuffer)NULL, + attribs + ); + + /* bind the texture and initiate the transfer */ + glBindTexture(GL_TEXTURE_2D, texture->tex[t].t[0]); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + + /* wait for completion */ + framebuffer_wait(frame, texture->height * texture->stride); + + /* destroy the image to prevent future writes corrupting the display image */ + eglDestroyImage(texture->display, image); + + atomic_fetch_add_explicit(&texture->state.w, 1, memory_order_release); + return true; +} + enum EGL_TexStatus egl_texture_process(EGL_Texture * texture) { if (!texture->streaming) @@ -409,24 +466,28 @@ enum EGL_TexStatus egl_texture_process(EGL_Texture * texture) nextu == atomic_load_explicit(&texture->state.d, memory_order_acquire)) return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY; - /* update the texture */ const uint8_t t = su % TEXTURE_COUNT; - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->tex[t].pbo); - for(int p = 0; p < texture->planeCount; ++p) + + /* update the texture */ + if (!texture->dma) { - glBindTexture(GL_TEXTURE_2D, texture->tex[t].t[p]); - glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[p][2]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[p][0], texture->planes[p][1], - texture->format, texture->dataType, (const void *)texture->offsets[p]); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->tex[t].pbo); + for(int p = 0; p < texture->planeCount; ++p) + { + glBindTexture(GL_TEXTURE_2D, texture->tex[t].t[p]); + glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[p][2]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[p][0], texture->planes[p][1], + texture->format, texture->dataType, (const void *)texture->offsets[p]); + } + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + /* create a fence to prevent usage before the update is complete */ + texture->tex[t].sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + + /* we must flush to ensure the sync is in the command buffer */ + glFlush(); } - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - - /* create a fence to prevent usage before the update is complete */ - texture->tex[t].sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - - /* we must flush to ensure the sync is in the command buffer */ - glFlush(); texture->ready = true; atomic_fetch_add_explicit(&texture->state.u, 1, memory_order_release); @@ -445,7 +506,12 @@ enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture) return EGL_TEX_STATUS_NOTREADY; const uint8_t t = ss % TEXTURE_COUNT; - if (texture->tex[t].sync != 0) + if (texture->dma) + { + ss = atomic_fetch_add_explicit(&texture->state.s, 1, + memory_order_release) + 1; + } + else if (texture->tex[t].sync != 0) { switch(glClientWaitSync(texture->tex[t].sync, 0, 20000000)) // 20ms { diff --git a/client/renderers/EGL/texture.h b/client/renderers/EGL/texture.h index 3d0da041..dd5e45bd 100644 --- a/client/renderers/EGL/texture.h +++ b/client/renderers/EGL/texture.h @@ -23,6 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "shader.h" #include "common/framebuffer.h" +#include #include typedef struct EGL_Texture EGL_Texture; @@ -43,12 +44,13 @@ enum EGL_TexStatus EGL_TEX_STATUS_ERROR }; -bool egl_texture_init(EGL_Texture ** tex); +bool egl_texture_init(EGL_Texture ** texture, EGLDisplay * display); void egl_texture_free(EGL_Texture ** tex); -bool egl_texture_setup (EGL_Texture * texture, enum EGL_PixelFormat pixfmt, size_t width, size_t height, size_t stride, bool streaming); +bool egl_texture_setup (EGL_Texture * texture, enum EGL_PixelFormat pixfmt, size_t width, size_t height, size_t stride, bool streaming, bool useDMA); bool egl_texture_update (EGL_Texture * texture, const uint8_t * buffer); bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer * frame); +bool egl_texture_update_from_dma (EGL_Texture * texture, const FrameBuffer * frmame, const int dmaFd); enum EGL_TexStatus egl_texture_process(EGL_Texture * texture); enum EGL_TexStatus egl_texture_bind (EGL_Texture * texture); int egl_texture_count (EGL_Texture * texture); diff --git a/client/renderers/OpenGL/opengl.c b/client/renderers/OpenGL/opengl.c index 8dd5821a..7624a97b 100644 --- a/client/renderers/OpenGL/opengl.c +++ b/client/renderers/OpenGL/opengl.c @@ -375,7 +375,7 @@ bool opengl_on_mouse_event(void * opaque, const bool visible, const int x, const return false; } -bool opengl_on_frame_format(void * opaque, const LG_RendererFormat format) +bool opengl_on_frame_format(void * opaque, const LG_RendererFormat format, bool useDMA) { struct Inst * this = (struct Inst *)opaque; diff --git a/client/src/config.c b/client/src/config.c index 1c8abd0e..0bfc61b0 100644 --- a/client/src/config.c +++ b/client/src/config.c @@ -84,6 +84,13 @@ static struct Option options[] = .type = OPTION_TYPE_INT, .value.x_int = 1000 }, + { + .module = "app", + .name = "allowDMA", + .description = "Allow direct DMA transfers if possible (VM-VM only for now)", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, // window options { @@ -401,6 +408,7 @@ bool config_load(int argc, char * argv[]) // setup the application params for the basic types params.cursorPollInterval = option_get_int ("app", "cursorPollInterval"); params.framePollInterval = option_get_int ("app", "framePollInterval" ); + params.allowDMA = option_get_bool ("app", "allowDMA" ); params.windowTitle = option_get_string("win", "title" ); params.autoResize = option_get_bool ("win", "autoResize" ); diff --git a/client/src/main.c b/client/src/main.c index 41fcca17..fadfaedf 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -375,7 +375,10 @@ static int frameThread(void * unused) //FIXME: Should use LGMP_Q_FRAME_LEN struct DMAFrameInfo dmaInfo[2] = {0}; - const bool useDMA = ivshmemHasDMA(&state.shm) && state.lgr->supports && + const bool useDMA = + params.allowDMA && + ivshmemHasDMA(&state.shm) && + state.lgr->supports && state.lgr->supports(state.lgrData, LG_SUPPORTS_DMABUF); if (useDMA) @@ -479,7 +482,7 @@ static int frameThread(void * unused) frame->width, frame->height, frame->stride, frame->pitch); - if (!state.lgr->on_frame_format(state.lgrData, lgrFormat)) + if (!state.lgr->on_frame_format(state.lgrData, lgrFormat, useDMA)) { DEBUG_ERROR("renderer failed to configure format"); state.state = APP_STATE_SHUTDOWN; @@ -557,7 +560,6 @@ static int frameThread(void * unused) atomic_fetch_add_explicit(&state.frameCount, 1, memory_order_relaxed); lgSignalEvent(e_frame); - lgmpClientMessageDone(queue); } diff --git a/client/src/main.h b/client/src/main.h index 1668420d..201609f1 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -158,6 +158,7 @@ struct AppParams unsigned int cursorPollInterval; unsigned int framePollInterval; + bool allowDMA; bool forceRenderer; unsigned int forceRendererIndex; diff --git a/common/src/framebuffer.c b/common/src/framebuffer.c index 3b4005b6..39b316ab 100644 --- a/common/src/framebuffer.c +++ b/common/src/framebuffer.c @@ -39,7 +39,11 @@ const size_t FrameBufferStructSize = sizeof(FrameBuffer); void framebuffer_wait(const FrameBuffer * frame, size_t size) { - while(atomic_load_explicit(&frame->wp, memory_order_acquire) != size) {} + while(atomic_load_explicit(&frame->wp, memory_order_acquire) < size) { + while(frame->wp < size) + { + } + } } bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,