diff --git a/glamor/glamor.h b/glamor/glamor.h index 25f4506d2..ef13b7a66 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -43,6 +43,14 @@ #define GLAMOR_HOSTX 2 #define GLAMOR_VALID_FLAGS (GLAMOR_INVERTED_Y_AXIS | GLAMOR_HOSTX) +#define GLAMOR_EGL_EXTERNAL_BUFFER 3 + extern _X_EXPORT Bool glamor_init(ScreenPtr screen, unsigned int flags); extern _X_EXPORT void glamor_fini(ScreenPtr screen); extern _X_EXPORT void glamor_set_screen_pixmap_texture(ScreenPtr screen, int w, int h, unsigned int tex); + +extern _X_EXPORT Bool glamor_egl_init(ScreenPtr screen, int fd); +extern _X_EXPORT Bool glamor_create_egl_screen_image(ScreenPtr screen, int handle, int stride); +extern _X_EXPORT Bool glamor_close_egl_screen(ScreenPtr screen); +extern _X_EXPORT void glamor_free_egl_screen(int scrnIndex, int flags); + diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c new file mode 100644 index 000000000..a92993b7a --- /dev/null +++ b/glamor/glamor_egl.c @@ -0,0 +1,296 @@ +/* + * Copyright © 2010 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including + * the next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Zhigang Gong + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES +#define EGL_DISPLAY_NO_X_MESA + +#if GLAMOR_GLES2 +#include +#else +#include +#endif + +#define MESA_EGL_NO_X11_HEADERS +#include +#include + +#include + +#define GLAMOR_VERSION_MAJOR 0 +#define GLAMOR_VERSION_MINOR 1 +#define GLAMOR_VERSION_PATCH 0 + +static const char glamor_name[] = "glamor"; + +static void +glamor_identify(int flags) +{ + xf86Msg(X_INFO, "%s: OpenGL accelerated X.org driver based.\n", glamor_name); +} + +struct glamor_screen_private { + EGLDisplay display; + EGLContext context; + EGLImageKHR root; + EGLint major, minor; + + + CreateScreenResourcesProcPtr CreateScreenResources; + CloseScreenProcPtr CloseScreen; + int fd; + int front_buffer_handle; + int cpp; + + PFNEGLCREATEDRMIMAGEMESA egl_create_drm_image_mesa; + PFNEGLEXPORTDRMIMAGEMESA egl_export_drm_image_mesa; + PFNEGLCREATEIMAGEKHRPROC egl_create_image_khr; + +}; + +int xf86GlamorEGLPrivateIndex = -1; + +static struct glamor_screen_private* glamor_get_egl_screen_private(ScrnInfoPtr scrn) +{ + return (struct glamor_screen_private *) scrn->privates[xf86GlamorEGLPrivateIndex].ptr; +} + +static Bool +_glamor_create_egl_screen_image(ScrnInfoPtr scrn, int width, int height, int stride) +{ + + struct glamor_screen_private *glamor = glamor_get_egl_screen_private(scrn); + ScreenPtr screen = screenInfo.screens[scrn->scrnIndex]; + EGLImageKHR image; + GLuint texture; + EGLint attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_STRIDE_MESA, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA | + EGL_DRM_BUFFER_USE_SCANOUT_MESA, + EGL_NONE + }; + + if (glamor->root) { + eglDestroyImageKHR(glamor->display, glamor->root); + glamor->root = EGL_NO_IMAGE_KHR; + } + + attribs[1] = width; + attribs[3] = height; + attribs[5] = stride / 4; + image = glamor->egl_create_image_khr (glamor->display, + glamor->context, + EGL_DRM_BUFFER_MESA, + (void*)glamor->front_buffer_handle, + attribs); + if (image == EGL_NO_IMAGE_KHR) + return FALSE; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + + glamor_set_screen_pixmap_texture(screen, width, height, texture); + glamor->root = image; + return TRUE; +} + +Bool +glamor_create_egl_screen_image(ScreenPtr screen, int handle, int stride) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + struct glamor_screen_private *glamor = glamor_get_egl_screen_private(scrn); + struct drm_gem_flink flink; + flink.handle = handle; + + if (ioctl(glamor->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Couldn't flink front buffer handle\n"); + return FALSE; + } + + glamor->front_buffer_handle = flink.name; + + return _glamor_create_egl_screen_image(scrn, scrn->virtualX, scrn->virtualY, stride); +} + +Bool +glamor_close_egl_screen(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + struct glamor_screen_private *glamor = glamor_get_egl_screen_private(scrn); + glamor_fini(screen); + + eglDestroyImageKHR(glamor->display, glamor->root); + + + glamor->root = EGL_NO_IMAGE_KHR; + + return TRUE; +} + + + +static Bool +glamor_egl_has_extension(struct glamor_screen_private *glamor, char *extension) +{ + const char *egl_extensions; + char *pext; + int ext_len; + ext_len = strlen(extension); + + egl_extensions = (const char*)eglQueryString(glamor->display, EGL_EXTENSIONS); + pext = (char*)egl_extensions; + + if (pext == NULL || extension == NULL) + return FALSE; + while((pext = strstr(pext, extension)) != NULL) { + if (pext[ext_len] == ' ' || pext[ext_len] == '\0') + return TRUE; + pext += ext_len; + } + return FALSE; +} + + +Bool glamor_egl_init(ScreenPtr screen, int fd) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + struct glamor_screen_private *glamor; + const char *version; + EGLint config_attribs[] = { +#ifdef GLAMOR_GLES2 + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + + glamor_identify(0); + glamor = calloc(sizeof(*glamor), 1); + if (xf86GlamorEGLPrivateIndex == -1) + xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + + scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor; + + glamor->fd = fd; + glamor->display = eglGetDRMDisplayMESA(glamor->fd); +#ifndef GLAMOR_GLES2 + eglBindAPI(EGL_OPENGL_API); +#else + eglBindAPI(EGL_OPENGL_ES_API); +#endif + if (!eglInitialize(glamor->display, &glamor->major, &glamor->minor)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "eglInitialize() failed\n"); + return FALSE; + } + + version = eglQueryString(glamor->display, EGL_VERSION); + xf86Msg(X_INFO, "%s: EGL version %s:\n", glamor_name, version); + +#define GLAMOR_CHECK_EGL_EXTENSION(EXT) \ + if (!glamor_egl_has_extension(glamor, "EGL_" #EXT)) { \ + ErrorF("EGL_" #EXT "required.\n"); \ + return FALSE; \ + } + + GLAMOR_CHECK_EGL_EXTENSION(MESA_drm_image); + GLAMOR_CHECK_EGL_EXTENSION(KHR_gl_renderbuffer_image); +#ifdef GLAMOR_GLES2 + GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_gles2); +#else + GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_opengl); +#endif + + glamor->egl_export_drm_image_mesa = (PFNEGLEXPORTDRMIMAGEMESA) + eglGetProcAddress("eglExportDRMImageMESA"); + glamor->egl_create_image_khr = (PFNEGLCREATEIMAGEKHRPROC) + eglGetProcAddress("eglCreateImageKHR"); + + if (!glamor->egl_create_image_khr + || !glamor->egl_export_drm_image_mesa) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "eglGetProcAddress() failed\n"); + return FALSE; + } + + glamor->context = eglCreateContext(glamor->display, + NULL, EGL_NO_CONTEXT, config_attribs); + if (glamor->context == EGL_NO_CONTEXT) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to create EGL context\n"); + return FALSE; + } + + if (!eglMakeCurrent(glamor->display, + EGL_NO_SURFACE, EGL_NO_SURFACE, glamor->context)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to make EGL context current\n"); + return FALSE; + } + + if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to initialize glamor\n"); + return FALSE; + } + return TRUE; +} + +void +glamor_free_egl_screen(int scrnIndex, int flags) +{ + ScrnInfoPtr scrn = xf86Screens[scrnIndex]; + struct glamor_screen_private *glamor = glamor_get_egl_screen_private(scrn); + + if (glamor != NULL) + { + if (!(flags & GLAMOR_EGL_EXTERNAL_BUFFER)) { + eglMakeCurrent(glamor->display, + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + eglTerminate(glamor->display); + } + free(glamor); + } +} diff --git a/hw/xfree86/dixmods/Makefile.am b/hw/xfree86/dixmods/Makefile.am index 84c909b9c..ba4aeb402 100644 --- a/hw/xfree86/dixmods/Makefile.am +++ b/hw/xfree86/dixmods/Makefile.am @@ -34,6 +34,7 @@ INCLUDES = @XORG_INCS@ \ -I$(top_srcdir)/hw/xfree86/loader \ -I$(top_srcdir)/miext/shadow \ -I$(top_srcdir)/glx + libdbe_la_LDFLAGS = -avoid-version libdbe_la_LIBADD = $(top_builddir)/dbe/libdbe.la @@ -41,8 +42,8 @@ libdbe_la_SOURCES = dbemodule.c if GLAMOR libglamor_dix_la_LDFLAGS = -avoid-version libglamor_dix_la_LIBADD = $(top_builddir)/glamor/libglamor.la -libglamor_dix_la_SOURCES = glamor_module.c -libglamor_dix_la_CFLAGS = $(AM_CFLAGS) +libglamor_dix_la_SOURCES = glamor_module.c $(top_srcdir)/glamor/glamor_egl.c +libglamor_dix_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/glamor $(LIBDRM_CFLAGS) endif libfb_la_LDFLAGS = -avoid-version libfb_la_LIBADD = $(top_builddir)/fb/libfb.la