From 1b54c8023e45b5f5ca6575199acae49d78754fa7 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 7 Nov 2011 17:16:13 +0000 Subject: [PATCH] kms: Add first version of "baremetal" backend for EGL on KMS To start with this backend only supports creating a single CoglOnscreen framebuffer and will automatically set is up to display fullscreen on the first suitable crtc it can find. To compile this backend - get some dribbly black candles, sacrifice a goat and configure with: --enable-kms-egl-platform Note: There is currently a problem with using GLES2 with this winsys so you need to run with EGL_DRIVER=gl Note: If you have problems with mesa crashing in XCB during eglInitialize then you may need to explicitly run with EGL_PLATFORM=gbm Reviewed-by: Robert Bragg --- cogl/Makefile.am | 5 + cogl/winsys/cogl-winsys-egl.c | 128 +++++++++-- cogl/winsys/cogl-winsys-kms.c | 390 ++++++++++++++++++++++++++++++++++ cogl/winsys/cogl-winsys-kms.h | 104 +++++++++ configure.ac | 26 +++ 5 files changed, 639 insertions(+), 14 deletions(-) create mode 100644 cogl/winsys/cogl-winsys-kms.c create mode 100644 cogl/winsys/cogl-winsys-kms.h diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 51f6d4223..46a1a8c87 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -370,6 +370,11 @@ if SUPPORT_EGL_PLATFORM_WAYLAND cogl_public_h += \ $(srcdir)/cogl-wayland-renderer.h endif +if SUPPORT_EGL_PLATFORM_KMS +cogl_sources_c += \ + $(srcdir)/winsys/cogl-winsys-kms.c \ + $(srcdir)/winsys/cogl-winsys-kms.h +endif if SUPPORT_EGL cogl_sources_c += \ $(srcdir)/winsys/cogl-winsys-egl.c \ diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c index ec2842b9e..fe998ccb6 100644 --- a/cogl/winsys/cogl-winsys-egl.c +++ b/cogl/winsys/cogl-winsys-egl.c @@ -62,7 +62,12 @@ #include #endif +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT +#include "cogl-winsys-kms.h" +#endif + #include +#include #include #include #include @@ -106,6 +111,9 @@ typedef struct _CoglRendererEGL #ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT gboolean gdl_initialized; #endif +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + CoglRendererKMS kms_renderer; +#endif /* Function pointers for GLX specific extensions */ #define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d) @@ -137,8 +145,13 @@ typedef struct _CoglDisplayEGL EGLSurface dummy_surface; #elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \ defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) || \ - defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) + defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \ + defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT EGLSurface egl_surface; +#else + CoglDisplayKMS kms_display; +#endif int egl_surface_width; int egl_surface_height; gboolean have_onscreen; @@ -175,7 +188,11 @@ typedef struct _CoglOnscreenEGL struct wl_surface *wayland_surface; #endif +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + CoglOnscreenKMS kms_onscreen; +#else EGLSurface egl_surface; +#endif } CoglOnscreenEGL; #ifdef EGL_KHR_image_pixmap @@ -434,6 +451,11 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer, &egl_renderer->egl_version_major, &egl_renderer->egl_version_minor); +#elif defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) + if (!_cogl_winsys_kms_connect (&egl_renderer->kms_renderer, error)) + goto error; + egl_renderer->edpy = egl_renderer->kms_renderer.dpy; + status = EGL_TRUE; #else egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY); @@ -641,12 +663,14 @@ try_create_context (CoglDisplay *display, CoglXlibRenderer *xlib_renderer = display->renderer->winsys; #endif CoglRendererEGL *egl_renderer = display->renderer->winsys; +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT EGLDisplay edpy; EGLConfig config; EGLint config_count = 0; EGLBoolean status; - EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS]; EGLint attribs[3]; +#endif + EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS]; #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT XVisualInfo *xvisinfo; XSetWindowAttributes attrs; @@ -660,11 +684,12 @@ try_create_context (CoglDisplay *display, _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE); - edpy = egl_renderer->edpy; - if (display->renderer->driver == COGL_DRIVER_GL) eglBindAPI (EGL_OPENGL_API); +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + edpy = egl_renderer->edpy; + status = eglChooseConfig (edpy, cfg_attribs, &config, 1, @@ -695,7 +720,7 @@ try_create_context (CoglDisplay *display, error_message = "Unable to create a suitable EGL context"; goto fail; } - +#endif #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT xvisinfo = get_visual_info (display, config); @@ -907,14 +932,24 @@ try_create_context (CoglDisplay *display, EGL_HEIGHT, &egl_display->egl_surface_height); +#elif defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) + if (!_cogl_winsys_kms_create_context (&egl_renderer->kms_renderer, + &egl_display->kms_display, + error)) + return FALSE; + + egl_display->egl_surface_width = egl_display->kms_display.width; + egl_display->egl_surface_height = egl_display->kms_display.height; + egl_display->egl_context = egl_display->kms_display.egl_context; #else #error "Unknown EGL platform" #endif return TRUE; +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT fail: - +#endif g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "%s", error_message); @@ -930,6 +965,17 @@ cleanup_context (CoglDisplay *display) CoglXlibDisplay *xlib_display = display->winsys; CoglXlibRenderer *xlib_renderer = display->renderer->winsys; #endif +#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) + GError *error = NULL; + + if (!_cogl_winsys_kms_destroy_context (&egl_renderer->kms_renderer, + &egl_display->kms_display, + &error)) + { + g_critical (G_STRLOC ": Error cleaning up KMS rendering state: %s", error->message); + g_clear_error (&error); + } +#endif if (egl_display->egl_context != EGL_NO_CONTEXT) { @@ -1108,7 +1154,8 @@ _cogl_winsys_display_setup (CoglDisplay *display, GError **error) { CoglDisplayEGL *egl_display; -#ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT +#if defined (COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT) || \ + defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) CoglRendererEGL *egl_renderer = display->renderer->winsys; #endif @@ -1131,6 +1178,13 @@ _cogl_winsys_display_setup (CoglDisplay *display, } #endif +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + if (!_cogl_winsys_kms_display_setup (&egl_renderer->kms_renderer, + &egl_display->kms_display, + error)) + goto error; +#endif + if (!create_context (display, error)) goto error; @@ -1181,19 +1235,24 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, CoglOnscreenXlib *xlib_onscreen; Window xwin; #endif -#ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT +#if defined (COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT) || \ + defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) CoglRendererEGL *egl_renderer = display->renderer->winsys; #endif CoglOnscreenEGL *egl_onscreen; +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT EGLint attributes[MAX_EGL_CONFIG_ATTRIBS]; EGLConfig egl_config; EGLint config_count = 0; EGLBoolean status; gboolean need_stencil = egl_display->stencil_disabled ? FALSE : framebuffer->config.need_stencil; +#endif _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE); + +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT egl_attributes_from_framebuffer_config (display, &framebuffer->config, need_stencil, @@ -1222,7 +1281,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, g_return_val_if_fail (status == EGL_TRUE, TRUE); framebuffer->samples_per_pixel = samples; } - +#endif #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT /* FIXME: We need to explicitly Select for ConfigureNotify events. @@ -1384,7 +1443,8 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, #elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \ defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \ - defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) + defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) || \ + defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) if (egl_display->have_onscreen) { g_set_error (error, COGL_WINSYS_ERROR, @@ -1393,7 +1453,16 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, return FALSE; } +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + if (!_cogl_winsys_kms_onscreen_init (cogl_framebuffer_get_context (framebuffer), + &egl_renderer->kms_renderer, + &egl_display->kms_display, + &egl_onscreen->kms_onscreen, + error)) + return FALSE; +#else egl_onscreen->egl_surface = egl_display->egl_surface; +#endif _cogl_framebuffer_winsys_update_size (framebuffer, egl_display->egl_surface_width, @@ -1411,6 +1480,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT CoglXlibRenderer *xlib_renderer = context->display->renderer->winsys; CoglXlibTrapState old_state; @@ -1418,13 +1488,12 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) #elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) CoglDisplayEGL *egl_display = context->display->winsys; #endif - CoglRendererEGL *egl_renderer = context->display->renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; /* If we never successfully allocated then there's nothing to do */ if (egl_onscreen == NULL) return; - +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT if (egl_onscreen->egl_surface != EGL_NO_SURFACE) { if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface) @@ -1432,7 +1501,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) g_warning ("Failed to destroy EGL surface"); egl_onscreen->egl_surface = EGL_NO_SURFACE; } - +#endif #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT egl_display->have_onscreen = FALSE; #endif @@ -1469,6 +1538,11 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) } #endif +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + _cogl_winsys_kms_onscreen_deinit (&egl_renderer->kms_renderer, + &egl_onscreen->kms_onscreen); +#endif + g_slice_free (CoglOnscreenEGL, onscreen->winsys); onscreen->winsys = NULL; } @@ -1477,10 +1551,19 @@ static void _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; - CoglContextEGL *egl_context = context->winsys; CoglDisplayEGL *egl_display = context->display->winsys; CoglRendererEGL *egl_renderer = context->display->renderer->winsys; +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglContextEGL *egl_context = context->winsys; +#endif + +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + _cogl_winsys_kms_bind (&egl_renderer->kms_renderer, + &egl_display->kms_display); + return; + +#else if (egl_context->current_surface == egl_onscreen->egl_surface) return; @@ -1497,6 +1580,7 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) #elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \ defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \ defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) + return; #else #error "Unknown EGL platform" @@ -1515,6 +1599,8 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) eglSwapInterval (egl_renderer->edpy, 1); else eglSwapInterval (egl_renderer->edpy, 0); + +#endif } static void @@ -1522,6 +1608,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, const int *user_rectangles, int n_rectangles) { +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRendererEGL *egl_renderer = context->display->renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; @@ -1545,6 +1632,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, n_rectangles, rectangles) == EGL_FALSE) g_warning ("Error reported by eglSwapBuffersRegion"); +#endif } #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT @@ -1569,8 +1657,18 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRendererEGL *egl_renderer = context->display->renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + CoglDisplayEGL *egl_display = context->display->winsys; +#endif +#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT + _cogl_winsys_kms_swap_buffers (&egl_renderer->kms_renderer, + &egl_display->kms_display, + &egl_onscreen->kms_onscreen); + return; +#else eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface); +#endif #ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT /* @@ -1595,6 +1693,7 @@ _cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen) static void _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) { +#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglContextEGL *egl_context = context->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; @@ -1603,6 +1702,7 @@ _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) return; egl_context->current_surface = EGL_NO_SURFACE; +#endif _cogl_winsys_onscreen_bind (onscreen); } diff --git a/cogl/winsys/cogl-winsys-kms.c b/cogl/winsys/cogl-winsys-kms.c new file mode 100644 index 000000000..b4f202b26 --- /dev/null +++ b/cogl/winsys/cogl-winsys-kms.c @@ -0,0 +1,390 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Some code inspired by mesa demos eglkms.c. + * + * Authors: + * Rob Bradford + * Kristian Høgsberg (from eglkms.c) + * Benjamin Franzke (from eglkms.c) + */ + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" + +#include "cogl-util.h" +#include "cogl-winsys-egl-private.h" +#include "cogl-winsys-private.h" +#include "cogl-feature-private.h" +#include "cogl-context-private.h" +#include "cogl-framebuffer.h" +#include "cogl-onscreen-private.h" +#include "cogl-swap-chain-private.h" +#include "cogl-renderer-private.h" +#include "cogl-private.h" + +#include "cogl-winsys-kms.h" + +static const char device_name[] = "/dev/dri/card0"; + +static gboolean +setup_kms (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error) +{ + drmModeRes *resources; + drmModeConnector *connector; + drmModeEncoder *encoder; + int i; + + resources = drmModeGetResources (kms_renderer->fd); + if (!resources) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "drmModeGetResources failed"); + return FALSE; + } + + for (i = 0; i < resources->count_connectors; i++) + { + connector = drmModeGetConnector (kms_renderer->fd, resources->connectors[i]); + if (connector == NULL) + continue; + + if (connector->connection == DRM_MODE_CONNECTED && + connector->count_modes > 0) + break; + + drmModeFreeConnector(connector); + } + + if (i == resources->count_connectors) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "No currently active connector found"); + return FALSE; + } + + for (i = 0; i < resources->count_encoders; i++) + { + encoder = drmModeGetEncoder (kms_renderer->fd, resources->encoders[i]); + + if (encoder == NULL) + continue; + + if (encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder (encoder); + } + + kms_display->saved_crtc = drmModeGetCrtc (kms_renderer->fd, + kms_display->encoder->crtc_id); + + kms_display->connector = connector; + kms_display->encoder = encoder; + kms_display->mode = connector->modes[0]; + + return TRUE; +} + +gboolean +_cogl_winsys_kms_connect (CoglRendererKMS *kms_renderer, + GError **error) +{ + EGLint major, minor; + + kms_renderer->fd = open (device_name, O_RDWR); + if (kms_renderer->fd < 0) + { + /* Probably permissions error */ + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Couldn't open %s", device_name); + return FALSE; + } + + kms_renderer->gbm = gbm_create_device (kms_renderer->fd); + if (kms_renderer->gbm == NULL) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Couldn't create gbm device"); + goto close_fd; + } + + kms_renderer->dpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm); + if (kms_renderer->dpy == EGL_NO_DISPLAY) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Couldn't get eglDisplay"); + goto destroy_gbm_device; + } + + if (!eglInitialize (kms_renderer->dpy, &major, &minor)) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Couldn't initialize EGL"); + goto egl_terminate; + } + + return TRUE; +egl_terminate: + eglTerminate (kms_renderer->dpy); +destroy_gbm_device: + gbm_device_destroy (kms_renderer->gbm); +close_fd: + close (kms_renderer->fd); + + return FALSE; +} + +gboolean +_cogl_winsys_kms_display_setup (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error) +{ + if (!setup_kms (kms_renderer, kms_display, error)) + return FALSE; + + kms_display->width = kms_display->mode.hdisplay; + kms_display->height = kms_display->mode.vdisplay; + + return TRUE; +} + +gboolean +_cogl_winsys_kms_create_context (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error) +{ + kms_display->egl_context = eglCreateContext (kms_renderer->dpy, NULL, EGL_NO_CONTEXT, NULL); + + if (kms_display->egl_context == NULL) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Couldn't create EGL context"); + return FALSE; + } + + if (!eglMakeCurrent (kms_renderer->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, kms_display->egl_context)) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to make context current"); + return FALSE; + } + + return TRUE; +} + +gboolean +_cogl_winsys_kms_onscreen_init (CoglContext *context, + CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + CoglOnscreenKMS *kms_onscreen, + GError **error) +{ + int i; + + kms_onscreen->cogl_context = context; + + context->glGenRenderbuffers (2, kms_onscreen->color_rb); + + for (i = 0; i < 2; i++) + { + uint32_t handle, stride; + + kms_onscreen->bo[i] = + gbm_bo_create (kms_renderer->gbm, + kms_display->mode.hdisplay, kms_display->mode.vdisplay, + GBM_BO_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!kms_onscreen->bo[i]) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to allocate buffer"); + return FALSE; + } + + kms_onscreen->image[i] = _cogl_egl_create_image (context, + EGL_NATIVE_PIXMAP_KHR, + kms_onscreen->bo[i], + NULL); + + if (kms_onscreen->image[i] == EGL_NO_IMAGE_KHR) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to create EGL image"); + return FALSE; + } + + context->glBindRenderbuffer (GL_RENDERBUFFER_EXT, kms_onscreen->color_rb[i]); + context->glEGLImageTargetRenderbufferStorage (GL_RENDERBUFFER, kms_onscreen->image[i]); + context->glBindRenderbuffer (GL_RENDERBUFFER_EXT, 0); + + handle = gbm_bo_get_handle (kms_onscreen->bo[i]).u32; + stride = gbm_bo_get_pitch (kms_onscreen->bo[i]); + + if (drmModeAddFB (kms_renderer->fd, + kms_display->mode.hdisplay, kms_display->mode.vdisplay, + 24, 32, + stride, + handle, + &kms_onscreen->fb_id[i]) != 0) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to create framebuffer from buffer"); + return FALSE; + } + } + + context->glGenFramebuffers (1, &kms_onscreen->fb); + context->glBindFramebuffer (GL_FRAMEBUFFER_EXT, kms_onscreen->fb); + + context->glGenRenderbuffers(1, &kms_onscreen->depth_rb); + context->glBindRenderbuffer(GL_RENDERBUFFER_EXT, kms_onscreen->depth_rb); + context->glRenderbufferStorage(GL_RENDERBUFFER_EXT, + GL_DEPTH_COMPONENT, + kms_display->mode.hdisplay, kms_display->mode.vdisplay); + context->glBindRenderbuffer (GL_RENDERBUFFER_EXT, 0); + + context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + kms_onscreen->depth_rb); + + kms_onscreen->current_frame = 0; + _cogl_winsys_kms_swap_buffers (kms_renderer, kms_display, kms_onscreen); + + return TRUE; +} + +void +_cogl_winsys_kms_onscreen_deinit (CoglRendererKMS *kms_renderer, + CoglOnscreenKMS *kms_onscreen) +{ + int i; + + CoglContext *context = kms_onscreen->cogl_context; + + context->glBindFramebuffer (GL_FRAMEBUFFER_EXT, kms_onscreen->fb); + context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, + 0); + context->glDeleteRenderbuffers(2, kms_onscreen->color_rb); + context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + 0); + context->glDeleteRenderbuffers(1, &kms_onscreen->depth_rb); + + for (i = 0; i < 2; i++) + { + drmModeRmFB (kms_renderer->fd, kms_onscreen->fb_id[i]); + _cogl_egl_destroy_image (context, kms_onscreen->image[i]); + gbm_bo_destroy (kms_onscreen->bo[i]); + } +} + +gboolean +_cogl_winsys_kms_destroy_context (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error) +{ + int ret; + + /* Restore the saved CRTC - this failing should not propagate an error */ + ret = drmModeSetCrtc (kms_renderer->fd, + kms_display->saved_crtc->crtc_id, + kms_display->saved_crtc->buffer_id, + kms_display->saved_crtc->x, kms_display->saved_crtc->y, + &kms_display->connector->connector_id, 1, + &kms_display->saved_crtc->mode); + if (ret) + { + g_critical (G_STRLOC ": Error restoring saved CRTC"); + } + + drmModeFreeCrtc (kms_display->saved_crtc); + + return TRUE; +} + +void +_cogl_winsys_kms_swap_buffers (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + CoglOnscreenKMS *kms_onscreen) +{ + CoglContext *context = kms_onscreen->cogl_context; + + if (drmModeSetCrtc (kms_renderer->fd, + kms_display->encoder->crtc_id, + kms_onscreen->fb_id[kms_onscreen->current_frame], + 0, 0, + &kms_display->connector->connector_id, + 1, + &kms_display->mode) != 0) + { + g_error (G_STRLOC ": Setting CRTC failed"); + } + + /* Update frame that we're drawing to be the new one */ + kms_onscreen->current_frame ^= 1; + + context->glBindFramebuffer (GL_FRAMEBUFFER_EXT, kms_onscreen->fb); + context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, + kms_onscreen->color_rb[kms_onscreen->current_frame]); + + if (context->glCheckFramebufferStatus (GL_FRAMEBUFFER_EXT) != + GL_FRAMEBUFFER_COMPLETE) + { + g_error (G_STRLOC ": FBO not complete"); + } +} + +void +_cogl_winsys_kms_bind (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display) +{ + eglMakeCurrent (kms_renderer->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, kms_display->egl_context); +} diff --git a/cogl/winsys/cogl-winsys-kms.h b/cogl/winsys/cogl-winsys-kms.h new file mode 100644 index 000000000..c6c7de10d --- /dev/null +++ b/cogl/winsys/cogl-winsys-kms.h @@ -0,0 +1,104 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Authors: + * Rob Bradford + */ + +#ifndef _COGL_WINSYS_KMS_PRIVATE_H_ +#define _COGL_WINSYS_KMS_PRIVATE_H_ + +#include +#include +#include +#include +#include +#include + +#include "cogl-winsys-private.h" + +typedef struct _CoglRendererKMS +{ + int fd; + struct gbm_device *gbm; + EGLDisplay *dpy; +} CoglRendererKMS; + +typedef struct _CoglDisplayKMS +{ + EGLContext egl_context; + drmModeConnector *connector; + drmModeEncoder *encoder; + drmModeModeInfo mode; + drmModeCrtcPtr saved_crtc; + gint width, height; +} CoglDisplayKMS; + +typedef struct _CoglOnscreenKMS +{ + CoglContext *cogl_context; + + uint32_t fb_id[2]; + struct gbm_bo *bo[2]; + GLuint fb, color_rb[2], depth_rb; + EGLImageKHR image[2]; + gint current_frame; +} CoglOnscreenKMS; + +gboolean +_cogl_winsys_kms_connect (CoglRendererKMS *kms_renderer, + GError **error); + +gboolean +_cogl_winsys_kms_onscreen_init (CoglContext *context, + CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + CoglOnscreenKMS *kms_onscreen, + GError **error); +void +_cogl_winsys_kms_onscreen_deinit (CoglRendererKMS *kms_renderer, + CoglOnscreenKMS *kms_onscreen); + +gboolean +_cogl_winsys_kms_display_setup (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error); + +void +_cogl_winsys_kms_swap_buffers (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + CoglOnscreenKMS *kms_onscreen); + +void +_cogl_winsys_kms_bind (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display); + +gboolean +_cogl_winsys_kms_create_context (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error); + +gboolean +_cogl_winsys_kms_destroy_context (CoglRendererKMS *kms_renderer, + CoglDisplayKMS *kms_display, + GError **error); + +#endif /* _COGL_WINSYS_KMS_PRIVATE_H_ */ diff --git a/configure.ac b/configure.ac index 0f1786152..6f3c40f0e 100644 --- a/configure.ac +++ b/configure.ac @@ -755,6 +755,32 @@ AS_IF([test "x$enable_wayland_egl_platform" == "xyes"], AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_WAYLAND, [test "x$enable_wayland_egl_platform" = "xyes"]) + +AC_ARG_ENABLE( + [kms-egl-platform], + [AC_HELP_STRING([--enable-kms-egl-platform=@<:@no/yes@:>@], [Enable support for the Wayland egl platform @<:@default=no@:>@])], + [], + enable_kms_egl_platform=no +) +AS_IF([test "x$enable_kms_egl_platform" == "xyes"], + [ + EGL_PLATFORM_COUNT=$((EGL_PLATFORM_COUNT+1)) + NEED_EGL=yes + EGL_PLATFORMS="$EGL_PLATFORMS kms" + + PKG_CHECK_EXISTS([gbm], + [ + COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gbm" + COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES libdrm" + COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gl" + ], + [AC_MSG_ERROR([Unable to locate required kms libraries])]) + + COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_PLATFORM_KMS_SUPPORT" + ]) +AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_KMS, + [test "x$enable_kms_egl_platform" = "xyes"]) + AC_ARG_ENABLE( [wayland-egl-server], [AC_HELP_STRING([--enable-wayland-egl-server=@<:@no/yes@:>@], [Enable server side wayland support @<:@default=no@:>@])],