Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

vaapi: add support for EGL and texture-from-pixmap.

This initial approach relies on VA/X11 and vaPutSurface() to a Pixmap.
Then, an EGLImage is created from that pixmap and bound to a texture
with glEGLImageTargetTexture2DOES().

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
  • Loading branch information...
commit c734a0bcbeef9ab61da27f2d26ea5e074befe707 1 parent 72571bb
@gbeauchesne authored
View
10 configure.in
@@ -1545,6 +1545,13 @@ if test "x$use_vaapi" != "xno"; then
INCLUDES="$INCLUDES $LIBVA_CFLAGS"
LIBS="$LIBS $LIBVA_LIBS"], [use_vaapi="no"])
if test "x$use_vaapi" != "xno"; then
+ if test "$use_gles" = "yes"; then
+ dnl XXX: necessary for texture-from-pixmap
+ PKG_CHECK_MODULES([LIBVA_X11], [libva-x11], [
+ INCLUDES="$INCLUDES $LIBVA_X11_CFLAGS"
+ LIBS="$LIBS $LIBVA_X11_LIBS"
+ has_va_x11="yes"], [use_vaapi="no"])
+ fi
if test "$use_gl" = "yes"; then
PKG_CHECK_MODULES([LIBVA_GLX], [libva-glx], [
INCLUDES="$INCLUDES $LIBVA_GLX_CFLAGS"
@@ -1562,6 +1569,9 @@ if test "x$use_vaapi" != "xno"; then
USE_VAAPI=0
else
AC_DEFINE([HAVE_LIBVA], [1], [Define to 1 if you have the 'vaapi' libraries])
+ if test "$has_va_x11" = "yes"; then
+ AC_DEFINE([HAVE_VA_X11], [1], [Defined to 1 if VA/X11 API is available])
+ fi
if test "$has_va_glx" = "yes"; then
AC_DEFINE([HAVE_VA_GLX], [1], [Defined to 1 if VA/GLX API is available])
fi
View
346 xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
@@ -59,10 +59,72 @@
#ifdef TARGET_DARWIN_IOS
#include "osx/DarwinUtils.h"
#endif
+#ifdef HAVE_LIBVA
+#include <va/va.h>
+#include "cores/dvdplayer/DVDCodecs/Video/VAAPI.h"
+#endif
using namespace Shaders;
+class CGLESVTable
+{
+ bool m_gotSymbols;
+
+ bool GetSymbol(void *fnptr, const char *name);
+ bool GetSymbols();
+
+public:
+ CGLESVTable();
+
+ static const CGLESVTable * Get();
+
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture2d_oes;
+};
+
+CGLESVTable::CGLESVTable()
+ : m_gotSymbols(false)
+{
+}
+
+bool CGLESVTable::GetSymbol(void *arg, const char *name)
+{
+ typedef void (*GenericFunc)(void);
+ GenericFunc func, *func_ptr = (GenericFunc *)arg;
+
+ func = static_cast<GenericFunc>(eglGetProcAddress(name));
+ if (!func)
+ {
+ CLog::Log(LOGERROR, "GLES: Failed to load symbol %s", name);
+ return false;
+ }
+
+ *func_ptr = func;
+ return true;
+}
+
+bool CGLESVTable::GetSymbols()
+{
+ if (m_gotSymbols)
+ return true;
+ if (!GetSymbol(&gl_egl_image_target_texture2d_oes, "glEGLImageTargetTexture2DOES"))
+ return false;
+ m_gotSymbols = true;
+ return true;
+}
+
+const CGLESVTable *CGLESVTable::Get()
+{
+ static CGLESVTable g_vtable;
+
+ if (!g_vtable.GetSymbols())
+ return NULL;
+ return &g_vtable;
+}
+
CLinuxRendererGLES::YUVBUFFER::YUVBUFFER()
+#ifdef HAVE_LIBVA
+ : vaapi(*(new VAAPI::CHolder()))
+#endif
{
memset(&fields, 0, sizeof(fields));
memset(&image , 0, sizeof(image));
@@ -71,6 +133,9 @@ CLinuxRendererGLES::YUVBUFFER::YUVBUFFER()
CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER()
{
+#ifdef HAVE_LIBVA
+ delete &vaapi;
+#endif
}
CLinuxRendererGLES::CLinuxRendererGLES()
@@ -627,6 +692,12 @@ void CLinuxRendererGLES::LoadShaders(int field)
m_renderMethod = RENDER_CVREF;
break;
}
+ else if (m_format == RENDER_FMT_VAAPI)
+ {
+ CLog::Log(LOGNOTICE, "GL: Using VAAPI render method");
+ m_renderMethod = RENDER_VAAPI;
+ break;
+ }
#if defined(TARGET_DARWIN_IOS)
else if (ios_version < 5.0 && m_format == RENDER_FMT_YUV420P)
{
@@ -677,7 +748,13 @@ void CLinuxRendererGLES::LoadShaders(int field)
CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
// Now that we now the render method, setup texture function handlers
- if (m_format == RENDER_FMT_CVBREF)
+ if (m_format == RENDER_FMT_VAAPI)
+ {
+ m_textureUpload = &CLinuxRendererGLES::UploadVAAPITexture;
+ m_textureCreate = &CLinuxRendererGLES::CreateVAAPITexture;
+ m_textureDelete = &CLinuxRendererGLES::DeleteVAAPITexture;
+ }
+ else if (m_format == RENDER_FMT_CVBREF)
{
m_textureUpload = &CLinuxRendererGLES::UploadCVRefTexture;
m_textureCreate = &CLinuxRendererGLES::CreateCVRefTexture;
@@ -793,6 +870,11 @@ void CLinuxRendererGLES::Render(DWORD flags, int index)
break;
}
}
+ else if (m_renderMethod & RENDER_VAAPI)
+ {
+ RenderVAAPI(index, m_currentField);
+ VerifyGLState();
+ }
else if (m_renderMethod & RENDER_OMXEGL)
{
RenderOpenMax(index, m_currentField);
@@ -1168,6 +1250,93 @@ void CLinuxRendererGLES::RenderSoftware(int index, int field)
VerifyGLState();
}
+void CLinuxRendererGLES::RenderRGB(const YUVPLANE& plane)
+{
+ glDisable(GL_DEPTH_TEST);
+
+ glEnable(m_textureTarget);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(m_textureTarget, plane.id);
+
+ g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
+
+ GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
+ GLfloat ver[4][4];
+ GLfloat tex[4][2];
+ float col[4][3];
+
+ for (int index = 0;index < 4;++index)
+ col[index][0] = col[index][1] = col[index][2] = 1.0;
+
+ GLint posLoc = g_Windowing.GUIShaderGetPos();
+ GLint texLoc = g_Windowing.GUIShaderGetCoord0();
+ GLint colLoc = g_Windowing.GUIShaderGetCol();
+
+ glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
+ glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
+ glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
@theuni
theuni added a note

don't need a float here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ glEnableVertexAttribArray(posLoc);
+ glEnableVertexAttribArray(texLoc);
+ glEnableVertexAttribArray(colLoc);
+
+ // Set vertex coordinates
+ for(int i = 0; i < 4; i++)
+ {
+ ver[i][0] = m_rotatedDestCoords[i].x;
+ ver[i][1] = m_rotatedDestCoords[i].y;
+ ver[i][2] = 0.0f;// set z to 0
+ ver[i][3] = 1.0f;
+ }
+
+ // Set texture coordinates
+ // FIXME: populate plane.rect correctly
+ tex[0][0] = tex[3][0] = 0;
+ tex[0][1] = tex[1][1] = 0;
+ tex[1][0] = tex[2][0] = 1;
+ tex[2][1] = tex[3][1] = 1;
+
+ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
+
+ glDisableVertexAttribArray(posLoc);
+ glDisableVertexAttribArray(texLoc);
+ glDisableVertexAttribArray(colLoc);
+
+ g_Windowing.DisableGUIShader();
+
+ VerifyGLState();
+
+ glDisable(m_textureTarget);
+ VerifyGLState();
+}
+
+void CLinuxRendererGLES::RenderVAAPI(int index, int field)
+{
+#if defined(HAVE_LIBVA)
+ VAAPI::CHolder &va = m_buffers[index].vaapi;
+ YUVPLANES &planes = m_buffers[index].fields[0];
+
+ if (!va.surface)
+ {
+ CLog::Log(LOGINFO, "GLES: VAAPI - No VA surface");
+ return;
+ }
+
+ if (!va.surfegl)
+ {
+ CLog::Log(LOGINFO, "GLES: VAAPI - No VA/EGL surface");
+ return;
+ }
+
+ switch (va.surfegl->m_format)
+ {
+ case EGL_TEXTURE_RGBA:
@theuni
theuni added a note

Is there no extension for a quick buffer->fb swap/blit? Granted it'd only be of use when we have no GUI up and no postprocessing but it'd still be worth having if available imo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ RenderRGB(planes[0]);
+ break;
+ }
+#endif
+}
+
void CLinuxRendererGLES::RenderOpenMax(int index, int field)
{
#if defined(HAVE_LIBOPENMAX)
@@ -1639,6 +1808,173 @@ bool CLinuxRendererGLES::CreateYV12Texture(int index)
}
//********************************************************************************************************
+// VAAPI Texture creation, deletion, copying + clearing
+//********************************************************************************************************
+void CLinuxRendererGLES::UploadVAAPITexture(int index)
+{
+#ifdef HAVE_LIBVA
+ VAAPI::CHolder &va = m_buffers[index].vaapi;
+ YV12Image &im = m_buffers[index].image;
+ YUVPLANES &planes = m_buffers[index].fields[0];
+
+ if (!va.surface)
+ return;
+
+ if (va.display && va.surface->m_display != va.display)
+ {
+ CLog::Log(LOGDEBUG, "GLES: VAAPI - Context changed");
+ va.surfegl.reset();
+ }
+ va.display = va.surface->m_display;
+
+ CSingleLock lock(*va.display);
+
+ if (va.display->lost())
+ return;
+
+ if (!va.surfegl)
+ {
+ VAAPI::CSurfaceEGL *surface = NULL;
+#ifdef HAVE_VA_X11
+ if (!surface)
+ surface = VAAPI::CSurfaceEGLPixmap::Create(va.display, im.width, im.height);
+#endif
+ if (!surface)
+ {
+ CLog::Log(LOGERROR, "GLES: VAAPI - Failed to create VA/EGL surface");
+ return;
+ }
+ va.surfegl.reset(surface);
+ }
+ else if (!va.surfegl->EnsureSize(im.width, im.height))
+ {
+ CLog::Log(LOGERROR, "GLES: VAAPI - Failed to resize VA/EGL surface");
+ return;
+ }
+
+ unsigned int flags = 0;
+ if (CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_BT709)
+ flags |= VA_SRC_BT709;
+ else
+ flags |= VA_SRC_BT601;
+
+ if (m_currentField == FIELD_TOP)
+ flags |= VA_TOP_FIELD;
+ else if (m_currentField == FIELD_BOT)
+ flags |= VA_BOTTOM_FIELD;
+ else
+ flags |= VA_FRAME_PICTURE;
+
+ if (!va.surfegl->Upload(va.surface, flags))
+ {
+ CLog::Log(LOGERROR, "GLES: VAAPI - Failed to update VA/EGL surface");
+ return;
+ }
+
+ unsigned int i, numPlanes;
+ switch (va.surfegl->m_format) {
+ case EGL_TEXTURE_RGBA:
+ numPlanes = 1;
+ break;
+ default:
+ CLog::Log(LOGERROR, "GLES: VAAPI - Unsupported VA/EGL surface format");
+ return;
+ }
+ ASSERT(numPlanes == va.surfegl->m_numPlanes);
+
+ const CGLESVTable * const gles_vtable = CGLESVTable::Get();
+ for (i = 0; i < numPlanes; i++)
+ {
+ glBindTexture(m_textureTarget, planes[i].id);
+ gles_vtable->gl_egl_image_target_texture2d_oes(m_textureTarget, va.surfegl->m_images[i]);
+ glBindTexture(m_textureTarget, 0);
+ }
+
+ CLog::Log(LOGNOTICE, "GLES: VAAPI - Texture uploaded");
+
+ m_eventTexturesDone[index]->Set();
+#endif
+}
+
+void CLinuxRendererGLES::DeleteVAAPITexture(int index)
+{
+#ifdef HAVE_LIBVA
+ VAAPI::CHolder &va = m_buffers[index].vaapi;
+ YUVPLANES &planes = m_buffers[index].fields[0];
+ unsigned int i;
+
+ va.display.reset();
+ va.surface.reset();
+ va.surfegl.reset();
+
+ for (i = 0; i < MAX_PLANES; i++)
+ {
+ if (planes[i].id && glIsTexture(planes[i].id))
+ glDeleteTextures(1, &planes[i].id);
+ planes[i].id = 0;
+ }
+
+ CLog::Log(LOGNOTICE, "GLES: VAAPI - Texture destroyed");
+#endif
+}
+
+bool CLinuxRendererGLES::CreateVAAPITexture(int index)
+{
+#ifdef HAVE_LIBVA
+ VAAPI::CHolder &va = m_buffers[index].vaapi;
+ YV12Image &im = m_buffers[index].image;
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANES &planes = fields[0];
+ VAAPI::CSurfaceEGL* surface = NULL;
+ unsigned int i;
+
+ DeleteVAAPITexture(index);
+
+ memset(&im , 0, sizeof(im));
+ memset(&fields, 0, sizeof(fields));
+
+ im.height = m_sourceHeight;
+ im.width = m_sourceWidth;
+
+ CLog::Log(LOGNOTICE, "GLES: VAAPI - Image size %dx%d", im.width, im.height);
+
+#ifdef HAVE_VA_X11
+ if (!surface)
+ surface = VAAPI::CSurfaceEGLPixmap::Create(va.display, im.width, im.height);
+#endif
+ if (!surface)
+ {
+ CLog::Log(LOGERROR, "GLES: VAAPI - Failed to create VA/EGL surface");
+ return false;
+ }
+ va.surfegl.reset(surface);
+
+ glEnable(m_textureTarget);
+ for (i = 0; i < surface->m_numPlanes; i++)
+ {
+ glGenTextures(1, &planes[i].id);
+ VerifyGLState();
+ glBindTexture(m_textureTarget, planes[i].id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glBindTexture(m_textureTarget, 0);
+ }
+ glDisable(m_textureTarget);
+ m_eventTexturesDone[index]->Set();
+
+ // Ensure we have the necessary GLES extensions
+ if (!CGLESVTable::Get())
@theuni
theuni added a note

Makes more sense in the begging, no?

@theuni
theuni added a note

*beginning

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ return false;
+
+ CLog::Log(LOGNOTICE, "GLES: VAAPI - Texture created");
+#endif
+ return true;
+}
+
+//********************************************************************************************************
// CoreVideoRef Texture creation, deletion, copying + clearing
//********************************************************************************************************
void CLinuxRendererGLES::UploadCVRefTexture(int index)
@@ -1913,6 +2249,14 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
#endif
}
+#ifdef HAVE_LIBVA
+void CLinuxRendererGLES::AddProcessor(VAAPI::CHolder& holder)
+{
+ YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+ buf.vaapi.surface = holder.surface;
+}
+#endif
+
#ifdef HAVE_LIBOPENMAX
void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture)
{
View
16 xbmc/cores/VideoRenderers/LinuxRendererGLES.h
@@ -86,7 +86,8 @@ enum RenderMethod
RENDER_POT = 0x010,
RENDER_OMXEGL = 0x040,
RENDER_CVREF = 0x080,
- RENDER_BYPASS = 0x100
+ RENDER_BYPASS = 0x100,
+ RENDER_VAAPI = 0x200
};
enum RenderQuality
@@ -152,6 +153,9 @@ class CLinuxRendererGLES : public CBaseRenderer
virtual std::vector<ERenderFormat> SupportedFormats() { return m_formats; }
+#ifdef HAVE_LIBVA
+ virtual void AddProcessor(VAAPI::CHolder& holder);
+#endif
#ifdef HAVE_LIBOPENMAX
virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture);
#endif
@@ -178,6 +182,10 @@ class CLinuxRendererGLES : public CBaseRenderer
void DeleteYV12Texture(int index);
bool CreateYV12Texture(int index);
+ void UploadVAAPITexture(int index);
+ void DeleteVAAPITexture(int index);
+ bool CreateVAAPITexture(int index);
+
void UploadCVRefTexture(int index);
void DeleteCVRefTexture(int index);
bool CreateCVRefTexture(int index);
@@ -192,6 +200,7 @@ class CLinuxRendererGLES : public CBaseRenderer
void RenderMultiPass(int index, int field); // multi pass glsl renderer
void RenderSinglePass(int index, int field); // single pass glsl renderer
void RenderSoftware(int index, int field); // single pass s/w yuv2rgb renderer
+ void RenderVAAPI(int index, int field); // VA-API surface
void RenderOpenMax(int index, int field); // OpenMAX rgb texture
void RenderCoreVideoRef(int index, int field); // CoreVideo reference
@@ -235,6 +244,8 @@ class CLinuxRendererGLES : public CBaseRenderer
typedef YUVPLANE YUVPLANES[MAX_PLANES];
typedef YUVPLANES YUVFIELDS[MAX_FIELDS];
+ void RenderRGB(const YUVPLANE& plane);
+
struct YUVBUFFER
{
YUVBUFFER();
@@ -244,6 +255,9 @@ class CLinuxRendererGLES : public CBaseRenderer
YV12Image image;
unsigned flipindex; /* used to decide if this has been uploaded */
+#ifdef HAVE_LIBVA
+ VAAPI::CHolder& vaapi;
+#endif
#ifdef HAVE_LIBOPENMAX
OpenMaxVideoBuffer *openMaxBuffer;
#endif
View
246 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
@@ -26,6 +26,7 @@
#include "DVDVideoCodec.h"
#include <boost/scoped_array.hpp>
#include <boost/weak_ptr.hpp>
+#include "utils/MathUtils.h"
#define CHECK(a) \
do { \
@@ -92,6 +93,9 @@ static CDisplayPtr GetGlobalDisplay()
#ifdef HAVE_VA_GLX
disp = vaGetDisplayGLX(g_Windowing.GetDisplay());
#endif
+#ifdef HAVE_VA_X11
+ disp = vaGetDisplay(g_Windowing.GetDisplay());
+#endif
int major_version, minor_version;
VAStatus res = vaInitialize(disp, &major_version, &minor_version);
@@ -419,7 +423,12 @@ bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count)
, 0))
for(unsigned i = old_surfaces_count; i < m_surfaces_count; i++)
- m_surfaces_free.push_back(CSurfacePtr(new CSurface(m_surfaces[i], m_display)));
+ {
+ CSurfacePtr surface(new CSurface(m_surfaces[i], m_display));
+ surface->m_width = avctx->width;
+ surface->m_height = avctx->height;
+ m_surfaces_free.push_back(surface);
+ }
//shared_ptr<VASurfaceID const> test = VASurfaceIDPtr(m_surfaces[0], m_display);
@@ -519,4 +528,239 @@ int CDecoder::Check(AVCodecContext* avctx)
return 0;
}
+static void GetPixmapSize(int width, int height, int& outWidth, int& outHeight)
+{
+ // Pick the smallest dimensions so that to save GPU memory bandwidth
+ // XXX: code derived from VDPAU.cpp:MakePixmap()
+ if (g_graphicsContext.GetWidth() < width ||
+ g_graphicsContext.GetHeight() < height)
+ {
+ if ((double)height * g_graphicsContext.GetWidth() / width <= (double)
+ g_graphicsContext.GetHeight())
+ {
+ // Scale width to the desktop size if the aspect ratio is the
+ // same or bigger than the desktop
+ outWidth = g_graphicsContext.GetWidth();
+ outHeight = MathUtils::round_int(
+ (double)height * g_graphicsContext.GetWidth() / width);
+ }
+ else
+ {
+ // Scale height to the desktop size if the aspect ratio is
+ // smaller than the desktop
+ outHeight = g_graphicsContext.GetHeight();
+ outWidth = MathUtils::round_int(
+ (double)width * g_graphicsContext.GetHeight() / height);
+ }
+ }
+ else
+ {
+ // Let OpenGL scale
+ outWidth = width;
+ outHeight = height;
+ }
+}
+
+#ifdef HAS_EGL
+class CEGLVTable
+{
+ bool m_gotSymbols;
+
+ bool GetSymbol(void *fnptr, const char *name);
+ bool GetSymbols();
+
+public:
+ CEGLVTable();
+ static const CEGLVTable * Get();
+
+ PFNEGLCREATEIMAGEKHRPROC create_image;
+ PFNEGLDESTROYIMAGEKHRPROC destroy_image;
+};
+
+CEGLVTable::CEGLVTable()
+ : m_gotSymbols(false)
+{
+}
+
+bool CEGLVTable::GetSymbol(void *arg, const char *name)
+{
+ typedef void (*GenericFunc)(void);
+ GenericFunc func, *func_ptr = (GenericFunc *)arg;
+
+ func = static_cast<GenericFunc>(eglGetProcAddress(name));
+ if (!func)
+ {
+ CLog::Log(LOGERROR, "VAAPI - EGL: failed to load symbol %s", name);
+ return false;
+ }
+
+ *func_ptr = func;
+ return true;
+}
+
+bool CEGLVTable::GetSymbols()
+{
+ if (m_gotSymbols)
+ return true;
+ if (!GetSymbol(&create_image, "eglCreateImageKHR"))
+ return false;
+ if (!GetSymbol(&destroy_image, "eglDestroyImageKHR"))
+ return false;
+ m_gotSymbols = true;
+ return true;
+}
+
+const CEGLVTable *CEGLVTable::Get()
+{
+ static CEGLVTable g_vtable;
+
+ if (!g_vtable.GetSymbols())
+ return NULL;
+ return &g_vtable;
+}
+
+CSurfaceEGL::CSurfaceEGL(CDisplayPtr& display)
+ : CSurfaceGL(display)
+ , m_eglDisplay(g_Windowing.GetEGLDisplay())
+ , m_format(0)
+ , m_numPlanes(0)
+{
+ for (unsigned int i = 0; i < kMaxPlanes; i++)
+ m_images[i] = EGL_NO_IMAGE_KHR;
+}
+
+CSurfaceEGL::~CSurfaceEGL()
+{
+ DestroyImages();
+}
+
+void CSurfaceEGL::DestroyImage(unsigned int index)
+{
+ const CEGLVTable * const egl_vtable = CEGLVTable::Get();
+
+ if (m_images[index] != EGL_NO_IMAGE_KHR)
+ {
+ if (egl_vtable)
+ egl_vtable->destroy_image(m_eglDisplay, m_images[index]);
+ m_images[index] = EGL_NO_IMAGE_KHR;
+ }
+}
+
+void CSurfaceEGL::DestroyImages()
+{
+ for (unsigned int i = 0; i < m_numPlanes; i++)
+ DestroyImage(i);
+ m_numPlanes = 0;
+}
+
+bool CSurfaceEGL::Upload(CSurfacePtr surface, unsigned int flags)
+{
+ return false;
+}
+
+bool CSurfaceEGL::EnsureSize(int width, int height)
+{
+ return false;
+}
+
+#ifdef HAVE_VA_X11
+CSurfaceEGLPixmap::CSurfaceEGLPixmap(CDisplayPtr& display)
+ : CSurfaceEGL(display)
+ , m_display(g_Windowing.GetDisplay())
+ , m_pixmap(None)
+ , m_pixmapWidth(0)
+ , m_pixmapHeight(0)
+{
+ m_format = EGL_TEXTURE_RGBA;
+ m_numPlanes = 1;
+}
+
+CSurfaceEGLPixmap::~CSurfaceEGLPixmap()
+{
+ if (m_pixmap)
+ {
+ XFreePixmap(m_display, m_pixmap);
+ m_pixmap = None;
+ }
+}
+
+bool CSurfaceEGLPixmap::Upload(CSurfacePtr surface, unsigned int flags)
+{
+ if (!m_pixmap)
+ return false;
+
+ DestroyImages();
+
+ CHECK(vaPutSurface(surface->m_display->get(), surface->m_id, m_pixmap,
+ 0, 0, surface->m_width, surface->m_height,
+ 0, 0, m_pixmapWidth, m_pixmapHeight,
+ NULL, 0, flags));
+
+ const CEGLVTable * const egl_vtable = CEGLVTable::Get();
+ if (!egl_vtable)
+ return false;
+
+ static const EGLint attribs[] =
+ {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
@theuni
theuni added a note

Needed? Wouldn't it be a simple flip and less delete logic without it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ EGL_NONE
+ };
+
+ m_images[0] = egl_vtable->create_image(m_eglDisplay, EGL_NO_CONTEXT,
+ EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)m_pixmap, attribs);
+ if (!m_images[0])
+ {
+ CLog::Log(LOGERROR, "VAAPI - EGL: failed to create EGLImage from pixmap");
+ return false;
+ }
+ m_numPlanes = 1;
+ return true;
+}
+
+bool CSurfaceEGLPixmap::EnsureSize(int width, int height)
+{
+ int pixmapWidth, pixmapHeight;
+
+ GetPixmapSize(width, height, pixmapWidth, pixmapHeight);
+ if (m_pixmapWidth == pixmapWidth && m_pixmapHeight == pixmapHeight)
+ return true;
+
+ XWindowAttributes win_attrs;
+ XGetWindowAttributes(m_display, g_Windowing.GetWindow(), &win_attrs);
+
+ if (m_pixmap)
+ {
+ XFreePixmap(m_display, m_pixmap);
+ m_pixmap = None;
+ }
+
+ m_pixmap = XCreatePixmap(m_display, DefaultRootWindow(m_display),
+ pixmapWidth, pixmapHeight, win_attrs.depth);
+ if (!m_pixmap)
+ {
+ CLog::Log(LOGERROR, "VAAPI - EGL: failed to create Pixmap");
+ return false;
+ }
+
+ CLog::Log(LOGNOTICE, "VAAPI - EGL: created %dx%d pixmap 0x%08lx",
+ pixmapWidth, pixmapHeight, m_pixmap);
+
+ m_pixmapWidth = pixmapWidth;
+ m_pixmapHeight = pixmapHeight;
+ return true;
+}
+
+CSurfaceEGL *CSurfaceEGLPixmap::Create(CDisplayPtr& display, int width, int height)
+{
+ CSurfaceEGL *surface;
+
+ surface = new CSurfaceEGLPixmap(display);
+ if (surface->EnsureSize(width, height))
+ return surface;
+ delete surface;
+ return NULL;
+}
+#endif /* HAVE_VA_X11 */
+#endif /* HAS_EGL */
+
#endif
View
54 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
@@ -29,9 +29,16 @@
#include <list>
#include <boost/shared_ptr.hpp>
+#ifdef HAVE_VA_X11
+# include <va/va_x11.h>
+#endif
#ifdef HAVE_VA_GLX
# include <va/va_glx.h>
#endif
+#ifdef HAS_EGL
+# include <EGL/egl.h>
+# include <EGL/eglext.h>
+#endif
namespace VAAPI {
@@ -69,6 +76,8 @@ struct CSurface
~CSurface();
VASurfaceID m_id;
+ int m_width;
+ int m_height;
CDisplayPtr m_display;
};
@@ -99,6 +108,48 @@ struct CSurfaceGLX : public CSurfaceGL
typedef boost::shared_ptr<CSurfaceGLX> CSurfaceGLXPtr;
#endif
+#ifdef HAS_EGL
+struct CSurfaceEGL : public CSurfaceGL
+{
+ CSurfaceEGL(CDisplayPtr& display);
+ virtual ~CSurfaceEGL() = 0;
+
+ static const unsigned int kMaxPlanes = 3;
+
+ virtual bool Upload(CSurfacePtr surface, unsigned int flags) = 0;
+ virtual bool EnsureSize(int width, int height) = 0;
+
+ EGLDisplay m_eglDisplay;
+ GLenum m_format;
+ unsigned int m_numPlanes;
+ EGLImageKHR m_images[kMaxPlanes];
+
+protected:
+ void DestroyImage(unsigned int index);
+ void DestroyImages();
+};
+
+typedef boost::shared_ptr<CSurfaceEGL> CSurfaceEGLPtr;
+
+#ifdef HAVE_VA_X11
+struct CSurfaceEGLPixmap : public CSurfaceEGL
+{
+ CSurfaceEGLPixmap(CDisplayPtr& display);
+ virtual ~CSurfaceEGLPixmap();
+
+ virtual bool Upload(CSurfacePtr surface, unsigned int flags);
+ virtual bool EnsureSize(int width, int height);
+
+ static CSurfaceEGL *Create(CDisplayPtr& display, int width, int height);
+
+ Display* m_display;
+ Pixmap m_pixmap;
+ int m_pixmapWidth;
+ int m_pixmapHeight;
+};
+#endif
+#endif
+
// silly type to avoid includes
struct CHolder
{
@@ -107,6 +158,9 @@ struct CHolder
#ifdef HAVE_VA_GLX
CSurfaceGLXPtr surfglx;
#endif
+#ifdef HAS_EGL
+ CSurfaceEGLPtr surfegl;
+#endif
CHolder()
{}
View
4 xbmc/windowing/X11/WinSystemX11GLES.h
@@ -56,6 +56,10 @@ class CWinSystemX11GLES : public CWinSystemBase, public CRenderSystemGLES
virtual bool makeOMXCurrent();
+ // Local to WinSystemX11 only
+ Display* GetDisplay() const { return m_dpy; }
+ Window GetWindow() const { return m_eglWindow; }
+
EGLContext GetEGLContext() const;
EGLDisplay GetEGLDisplay() const;
protected:

3 comments on commit c734a0b

@theuni

Is there no extension for a quick buffer->fb swap/blit? Granted it'd only be of use when we have no GUI up and no postprocessing but it'd still be worth having if available imo.

@theuni

Makes more sense in the begging, no?

@theuni

Needed? Wouldn't it be a simple flip and less delete logic without it?

@theuni

Very nice overall. I have a few general org recommendations (as we discussed via mail) though I don't see any reason to call them blockers.

I'd prefer to see the symbol getters and pixmap creation/uploads in our gles renderer or base renderer. Reason being I have global domination plans for a render manager one of these days, so that we have a single processor for rendering, rather than everyone doing it themselves all over the show.

I'm also having trouble understanding why the pixmap upload/render are tied to vaapi. Is this just because that's it's first user? I ask because if this is a general kms/drm feature, It'd be useful for skin texture uploads as well (for off-thread uploads). If they're not tied to vaapi, see the first note above again :)

@gbeauchesne

@theuni: the pixmap upload could better fit VAAPI.cpp because the EGL/X11 path actually suits "desktop" OpenGL, GLESv1 and GLESv2. So, moving it to the GLES renderer may not be fully correct. I will try to move a few things to base renderer then.

@gbeauchesne

@theuni: wrt. quick buffer to fb swap/blit, there is vaPutSurface() that is specific to X11 and doesn't use any form of GL. On some occasions, you could even use an overlay. However, there could be some issues when rendering the UI on top of it. Some VA drivers support overlay + 3D UI in another plane though.

Please sign in to comment.
Something went wrong with that request. Please try again.