mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-05-04 21:51:08 +00:00
[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`
This commit is contained in:
parent
0bf73d862d
commit
4f9544d61d
@ -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 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_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_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 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 void (* LG_RendererOnAlert )(void * opaque, const LG_MsgAlert alert, const char * message, bool ** closeFlag);
|
||||||
typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window);
|
typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window);
|
||||||
|
@ -72,7 +72,7 @@ bool egl_alert_init(EGL_Alert ** alert, const LG_Font * font, LG_FontObj fontObj
|
|||||||
(*alert)->fontObj = fontObj;
|
(*alert)->fontObj = fontObj;
|
||||||
LG_LOCK_INIT((*alert)->lock);
|
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");
|
DEBUG_ERROR("Failed to initialize the alert texture");
|
||||||
return false;
|
return false;
|
||||||
@ -175,6 +175,7 @@ void egl_alert_render(EGL_Alert * alert, const float scaleX, const float scaleY)
|
|||||||
alert->bmp->width ,
|
alert->bmp->width ,
|
||||||
alert->bmp->height,
|
alert->bmp->height,
|
||||||
alert->bmp->width * alert->bmp->bpp,
|
alert->bmp->width * alert->bmp->bpp,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -76,13 +76,13 @@ bool egl_cursor_init(EGL_Cursor ** cursor)
|
|||||||
memset(*cursor, 0, sizeof(EGL_Cursor));
|
memset(*cursor, 0, sizeof(EGL_Cursor));
|
||||||
LG_LOCK_INIT((*cursor)->lock);
|
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");
|
DEBUG_ERROR("Failed to initialize the cursor texture");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!egl_texture_init(&(*cursor)->textureMono))
|
if (!egl_texture_init(&(*cursor)->textureMono, NULL))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the cursor mono texture");
|
DEBUG_ERROR("Failed to initialize the cursor mono texture");
|
||||||
return false;
|
return false;
|
||||||
@ -214,7 +214,7 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
|
|
||||||
case LG_CURSOR_COLOR:
|
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_texture_update(cursor->texture, data);
|
||||||
egl_model_set_texture(cursor->model, cursor->texture);
|
egl_model_set_texture(cursor->model, cursor->texture);
|
||||||
break;
|
break;
|
||||||
@ -238,8 +238,8 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
xor[y * cursor->width + x] = xorMask;
|
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->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);
|
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->texture , (uint8_t *)and);
|
||||||
egl_texture_update(cursor->textureMono, (uint8_t *)xor);
|
egl_texture_update(cursor->textureMono, (uint8_t *)xor);
|
||||||
break;
|
break;
|
||||||
|
@ -47,7 +47,7 @@ struct DesktopShader
|
|||||||
|
|
||||||
struct EGL_Desktop
|
struct EGL_Desktop
|
||||||
{
|
{
|
||||||
void * egl;
|
EGLDisplay * display;
|
||||||
|
|
||||||
EGL_Texture * texture;
|
EGL_Texture * texture;
|
||||||
struct DesktopShader * shader; // the active shader
|
struct DesktopShader * shader; // the active shader
|
||||||
@ -94,7 +94,7 @@ static bool egl_init_desktop_shader(
|
|||||||
return true;
|
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));
|
*desktop = (EGL_Desktop *)malloc(sizeof(EGL_Desktop));
|
||||||
if (!*desktop)
|
if (!*desktop)
|
||||||
@ -104,8 +104,9 @@ bool egl_desktop_init(void * egl, EGL_Desktop ** desktop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(*desktop, 0, sizeof(EGL_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");
|
DEBUG_ERROR("Failed to initialize the desktop texture");
|
||||||
return false;
|
return false;
|
||||||
@ -138,7 +139,6 @@ bool egl_desktop_init(void * egl, EGL_Desktop ** desktop)
|
|||||||
egl_model_set_default((*desktop)->model);
|
egl_model_set_default((*desktop)->model);
|
||||||
egl_model_set_texture((*desktop)->model, (*desktop)->texture);
|
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)->kbNV = app_register_keybind(SDL_SCANCODE_N, egl_desktop_toggle_nv, *desktop);
|
||||||
|
|
||||||
(*desktop)->nvMax = option_get_int("egl", "nvGainMax");
|
(*desktop)->nvMax = option_get_int("egl", "nvGainMax");
|
||||||
@ -175,7 +175,7 @@ void egl_desktop_free(EGL_Desktop ** desktop)
|
|||||||
*desktop = NULL;
|
*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;
|
enum EGL_PixelFormat pixFmt;
|
||||||
switch(format.type)
|
switch(format.type)
|
||||||
@ -219,7 +219,8 @@ bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
|||||||
format.width,
|
format.width,
|
||||||
format.height,
|
format.height,
|
||||||
format.pitch,
|
format.pitch,
|
||||||
true // streaming texture
|
true, // streaming texture
|
||||||
|
useDMA
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to setup the desktop texture");
|
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;
|
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))
|
if (dmaFd >= 0)
|
||||||
return false;
|
{
|
||||||
|
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;
|
enum EGL_TexStatus status;
|
||||||
if ((status = egl_texture_process(desktop->texture)) != EGL_TEX_STATUS_OK)
|
if ((status = egl_texture_process(desktop->texture)) != EGL_TEX_STATUS_OK)
|
||||||
|
@ -20,14 +20,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <SDL2/SDL_egl.h>
|
||||||
|
|
||||||
#include "interface/renderer.h"
|
#include "interface/renderer.h"
|
||||||
|
|
||||||
typedef struct EGL_Desktop EGL_Desktop;
|
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);
|
void egl_desktop_free(EGL_Desktop ** desktop);
|
||||||
|
|
||||||
bool egl_desktop_setup (EGL_Desktop * desktop, const LG_RendererFormat format);
|
bool egl_desktop_setup (EGL_Desktop * desktop, const LG_RendererFormat format, bool useDMA);
|
||||||
bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame);
|
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);
|
bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest);
|
||||||
|
@ -52,6 +52,7 @@ struct Options
|
|||||||
|
|
||||||
struct Inst
|
struct Inst
|
||||||
{
|
{
|
||||||
|
bool dmaSupport;
|
||||||
LG_RendererParams params;
|
LG_RendererParams params;
|
||||||
struct Options opt;
|
struct Options opt;
|
||||||
|
|
||||||
@ -188,8 +189,8 @@ bool egl_initialize(void * opaque, Uint32 * sdlFlags)
|
|||||||
DEBUG_INFO("Double buffering is %s", doubleBuffer ? "on" : "off");
|
DEBUG_INFO("Double buffering is %s", doubleBuffer ? "on" : "off");
|
||||||
|
|
||||||
*sdlFlags = SDL_WINDOW_OPENGL;
|
*sdlFlags = SDL_WINDOW_OPENGL;
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , doubleBuffer ? 1 : 0);
|
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_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
if (option_get_bool("egl", "multisample"))
|
if (option_get_bool("egl", "multisample"))
|
||||||
{
|
{
|
||||||
@ -226,6 +227,20 @@ void egl_deinitialize(void * opaque)
|
|||||||
free(this);
|
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)
|
void egl_on_restart(void * opaque)
|
||||||
{
|
{
|
||||||
struct Inst * this = (struct Inst *)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;
|
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;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
|
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;
|
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)
|
bool egl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd)
|
||||||
{
|
{
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
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");
|
DEBUG_INFO("Failed to to update the desktop");
|
||||||
return false;
|
return false;
|
||||||
@ -399,12 +414,12 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *client_exts = eglQueryString(NULL, EGL_EXTENSIONS);
|
|
||||||
DEBUG_INFO("Supported extensions: %s", client_exts);
|
|
||||||
|
|
||||||
bool useNative = false;
|
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");
|
DEBUG_INFO("use native: %s", useNative ? "true" : "false");
|
||||||
|
|
||||||
@ -451,7 +466,8 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eglInitialize(this->display, NULL, NULL))
|
int maj, min;
|
||||||
|
if (!eglInitialize(this->display, &maj, &min))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Unable to initialize EGL");
|
DEBUG_ERROR("Unable to initialize EGL");
|
||||||
return false;
|
return false;
|
||||||
@ -494,14 +510,21 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
eglMakeCurrent(this->display, this->surface, this->surface, this->context);
|
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("EGL : %d.%d", maj, min);
|
||||||
DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER));
|
DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR ));
|
||||||
DEBUG_INFO("Version : %s", glGetString(GL_VERSION ));
|
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);
|
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");
|
DEBUG_ERROR("Failed to initialize the desktop");
|
||||||
return false;
|
return false;
|
||||||
@ -617,6 +640,7 @@ struct LG_Renderer LGR_EGL =
|
|||||||
.create = egl_create,
|
.create = egl_create,
|
||||||
.initialize = egl_initialize,
|
.initialize = egl_initialize,
|
||||||
.deinitialize = egl_deinitialize,
|
.deinitialize = egl_deinitialize,
|
||||||
|
.supports = egl_supports,
|
||||||
.on_restart = egl_on_restart,
|
.on_restart = egl_on_restart,
|
||||||
.on_resize = egl_on_resize,
|
.on_resize = egl_on_resize,
|
||||||
.on_mouse_shape = egl_on_mouse_shape,
|
.on_mouse_shape = egl_on_mouse_shape,
|
||||||
|
@ -66,7 +66,7 @@ bool egl_fps_init(EGL_FPS ** fps, const LG_Font * font, LG_FontObj fontObj)
|
|||||||
(*fps)->font = font;
|
(*fps)->font = font;
|
||||||
(*fps)->fontObj = fontObj;
|
(*fps)->fontObj = fontObj;
|
||||||
|
|
||||||
if (!egl_texture_init(&(*fps)->texture))
|
if (!egl_texture_init(&(*fps)->texture, NULL))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the fps texture");
|
DEBUG_ERROR("Failed to initialize the fps texture");
|
||||||
return false;
|
return false;
|
||||||
@ -158,6 +158,7 @@ void egl_fps_update(EGL_FPS * fps, const float avgFPS, const float renderFPS)
|
|||||||
bmp->width ,
|
bmp->width ,
|
||||||
bmp->height,
|
bmp->height,
|
||||||
bmp->width * bmp->bpp,
|
bmp->width * bmp->bpp,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
|
||||||
#include <SDL2/SDL_egl.h>
|
#include <SDL2/SDL_egl.h>
|
||||||
|
|
||||||
@ -35,11 +36,11 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
struct Tex
|
struct Tex
|
||||||
{
|
{
|
||||||
GLuint t[3];
|
GLuint t[3];
|
||||||
bool hasPBO;
|
bool hasPBO;
|
||||||
GLuint pbo;
|
GLuint pbo;
|
||||||
void * map;
|
void * map;
|
||||||
GLsync sync;
|
GLsync sync;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TexState
|
struct TexState
|
||||||
@ -49,10 +50,13 @@ struct TexState
|
|||||||
|
|
||||||
struct EGL_Texture
|
struct EGL_Texture
|
||||||
{
|
{
|
||||||
|
EGLDisplay * display;
|
||||||
|
|
||||||
enum EGL_PixelFormat pixFmt;
|
enum EGL_PixelFormat pixFmt;
|
||||||
size_t width, height, stride;
|
size_t width, height, stride;
|
||||||
size_t bpp;
|
size_t bpp;
|
||||||
bool streaming;
|
bool streaming;
|
||||||
|
bool dma;
|
||||||
bool ready;
|
bool ready;
|
||||||
|
|
||||||
int planeCount;
|
int planeCount;
|
||||||
@ -69,7 +73,7 @@ struct EGL_Texture
|
|||||||
struct Tex tex[TEXTURE_COUNT];
|
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));
|
*texture = (EGL_Texture *)malloc(sizeof(EGL_Texture));
|
||||||
if (!*texture)
|
if (!*texture)
|
||||||
@ -79,6 +83,7 @@ bool egl_texture_init(EGL_Texture ** texture)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(*texture, 0, sizeof(EGL_Texture));
|
memset(*texture, 0, sizeof(EGL_Texture));
|
||||||
|
(*texture)->display = display;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +111,8 @@ void egl_texture_free(EGL_Texture ** texture)
|
|||||||
glDeleteSync(t->sync);
|
glDeleteSync(t->sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*texture)->planeCount > 0)
|
if ((*texture)->planeCount > 0)
|
||||||
glDeleteTextures((*texture)->planeCount, t->t);
|
glDeleteTextures((*texture)->planeCount, t->t);
|
||||||
}
|
}
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
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;
|
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;
|
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)
|
for(int i = 0; i < texture->textureCount; ++i)
|
||||||
{
|
{
|
||||||
egl_texture_unmap(texture, i);
|
if (!useDMA)
|
||||||
if (texture->tex[i].hasPBO)
|
|
||||||
{
|
{
|
||||||
glDeleteBuffers(1, &texture->tex[i].pbo);
|
egl_texture_unmap(texture, i);
|
||||||
texture->tex[i].hasPBO = false;
|
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);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
if (!streaming)
|
if (!streaming || useDMA)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for(int i = 0; i < texture->textureCount; ++i)
|
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;
|
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)
|
enum EGL_TexStatus egl_texture_process(EGL_Texture * texture)
|
||||||
{
|
{
|
||||||
if (!texture->streaming)
|
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))
|
nextu == atomic_load_explicit(&texture->state.d, memory_order_acquire))
|
||||||
return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY;
|
return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY;
|
||||||
|
|
||||||
/* update the texture */
|
|
||||||
const uint8_t t = su % TEXTURE_COUNT;
|
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]);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->tex[t].pbo);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[p][2]);
|
for(int p = 0; p < texture->planeCount; ++p)
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[p][0], texture->planes[p][1],
|
{
|
||||||
texture->format, texture->dataType, (const void *)texture->offsets[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;
|
texture->ready = true;
|
||||||
atomic_fetch_add_explicit(&texture->state.u, 1, memory_order_release);
|
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;
|
return EGL_TEX_STATUS_NOTREADY;
|
||||||
|
|
||||||
const uint8_t t = ss % TEXTURE_COUNT;
|
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
|
switch(glClientWaitSync(texture->tex[t].sync, 0, 20000000)) // 20ms
|
||||||
{
|
{
|
||||||
|
@ -23,6 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "common/framebuffer.h"
|
#include "common/framebuffer.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_egl.h>
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
|
||||||
typedef struct EGL_Texture EGL_Texture;
|
typedef struct EGL_Texture EGL_Texture;
|
||||||
@ -43,12 +44,13 @@ enum EGL_TexStatus
|
|||||||
EGL_TEX_STATUS_ERROR
|
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);
|
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 (EGL_Texture * texture, const uint8_t * buffer);
|
||||||
bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer * frame);
|
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_process(EGL_Texture * texture);
|
||||||
enum EGL_TexStatus egl_texture_bind (EGL_Texture * texture);
|
enum EGL_TexStatus egl_texture_bind (EGL_Texture * texture);
|
||||||
int egl_texture_count (EGL_Texture * texture);
|
int egl_texture_count (EGL_Texture * texture);
|
||||||
|
@ -375,7 +375,7 @@ bool opengl_on_mouse_event(void * opaque, const bool visible, const int x, const
|
|||||||
return false;
|
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;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
|
|
||||||
|
@ -84,6 +84,13 @@ static struct Option options[] =
|
|||||||
.type = OPTION_TYPE_INT,
|
.type = OPTION_TYPE_INT,
|
||||||
.value.x_int = 1000
|
.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
|
// window options
|
||||||
{
|
{
|
||||||
@ -401,6 +408,7 @@ bool config_load(int argc, char * argv[])
|
|||||||
// setup the application params for the basic types
|
// setup the application params for the basic types
|
||||||
params.cursorPollInterval = option_get_int ("app", "cursorPollInterval");
|
params.cursorPollInterval = option_get_int ("app", "cursorPollInterval");
|
||||||
params.framePollInterval = option_get_int ("app", "framePollInterval" );
|
params.framePollInterval = option_get_int ("app", "framePollInterval" );
|
||||||
|
params.allowDMA = option_get_bool ("app", "allowDMA" );
|
||||||
|
|
||||||
params.windowTitle = option_get_string("win", "title" );
|
params.windowTitle = option_get_string("win", "title" );
|
||||||
params.autoResize = option_get_bool ("win", "autoResize" );
|
params.autoResize = option_get_bool ("win", "autoResize" );
|
||||||
|
@ -375,7 +375,10 @@ static int frameThread(void * unused)
|
|||||||
|
|
||||||
//FIXME: Should use LGMP_Q_FRAME_LEN
|
//FIXME: Should use LGMP_Q_FRAME_LEN
|
||||||
struct DMAFrameInfo dmaInfo[2] = {0};
|
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);
|
state.lgr->supports(state.lgrData, LG_SUPPORTS_DMABUF);
|
||||||
|
|
||||||
if (useDMA)
|
if (useDMA)
|
||||||
@ -479,7 +482,7 @@ static int frameThread(void * unused)
|
|||||||
frame->width, frame->height,
|
frame->width, frame->height,
|
||||||
frame->stride, frame->pitch);
|
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");
|
DEBUG_ERROR("renderer failed to configure format");
|
||||||
state.state = APP_STATE_SHUTDOWN;
|
state.state = APP_STATE_SHUTDOWN;
|
||||||
@ -557,7 +560,6 @@ static int frameThread(void * unused)
|
|||||||
|
|
||||||
atomic_fetch_add_explicit(&state.frameCount, 1, memory_order_relaxed);
|
atomic_fetch_add_explicit(&state.frameCount, 1, memory_order_relaxed);
|
||||||
lgSignalEvent(e_frame);
|
lgSignalEvent(e_frame);
|
||||||
|
|
||||||
lgmpClientMessageDone(queue);
|
lgmpClientMessageDone(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +158,7 @@ struct AppParams
|
|||||||
|
|
||||||
unsigned int cursorPollInterval;
|
unsigned int cursorPollInterval;
|
||||||
unsigned int framePollInterval;
|
unsigned int framePollInterval;
|
||||||
|
bool allowDMA;
|
||||||
|
|
||||||
bool forceRenderer;
|
bool forceRenderer;
|
||||||
unsigned int forceRendererIndex;
|
unsigned int forceRendererIndex;
|
||||||
|
@ -39,7 +39,11 @@ const size_t FrameBufferStructSize = sizeof(FrameBuffer);
|
|||||||
|
|
||||||
void framebuffer_wait(const FrameBuffer * frame, size_t size)
|
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,
|
bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user