mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 05:27:20 +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 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);
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -20,14 +20,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <SDL2/SDL_egl.h>
|
||||
|
||||
#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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdatomic.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
||||
#include <SDL2/SDL_egl.h>
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "shader.h"
|
||||
#include "common/framebuffer.h"
|
||||
|
||||
#include <SDL2/SDL_egl.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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" );
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,7 @@ struct AppParams
|
||||
|
||||
unsigned int cursorPollInterval;
|
||||
unsigned int framePollInterval;
|
||||
bool allowDMA;
|
||||
|
||||
bool forceRenderer;
|
||||
unsigned int forceRendererIndex;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user