egl: Split out the KMS winsys as overrides of the EGL winsys

Instead of having #ifdefs to hook into the normal EGL winsys, the KMS
winsys now overrides any winsys functions that it wants. Where the
winsys wants to hook into a point within a function provided by the
EGL winsys there is a EGL-platform vtable which gets set on the EGL
renderer data during renderer_connect. The KMS-specific data on all of
the structures is now allocated separately by the KMS winsys and is
pointed to by a new 'platform' pointer in the EGL data.

Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
Neil Roberts 2011-12-09 16:10:01 +00:00
parent 93e6e2051f
commit dd75926c1a
7 changed files with 698 additions and 777 deletions

View File

@ -382,8 +382,6 @@ cogl_sources_c += \
endif
if SUPPORT_EGL_PLATFORM_KMS
cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-kms.c \
$(srcdir)/winsys/cogl-winsys-kms.h \
$(srcdir)/winsys/cogl-winsys-egl-kms.c \
$(srcdir)/winsys/cogl-winsys-egl-kms-private.h
endif

View File

@ -19,6 +19,8 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifndef __COGL_WINSYS_EGL_KMS_PRIVATE_H

View File

@ -21,6 +21,9 @@
*
*
* Authors:
* Rob Bradford <rob@linux.intel.com>
* Kristian Høgsberg (from eglkms.c)
* Benjamin Franzke (from eglkms.c)
* Robert Bragg <robert@linux.intel.com>
* Neil Roberts <neil@linux.intel.com>
*/
@ -29,8 +32,507 @@
#include "config.h"
#endif
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <glib.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "cogl-winsys-egl-kms-private.h"
#include "cogl-winsys-egl-private.h"
#include "cogl-renderer-private.h"
#include "cogl-framebuffer-private.h"
#include "cogl-onscreen-private.h"
static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
typedef struct _CoglRendererKMS
{
int fd;
struct gbm_device *gbm;
} CoglRendererKMS;
typedef struct _CoglDisplayKMS
{
drmModeConnector *connector;
drmModeEncoder *encoder;
drmModeModeInfo mode;
drmModeCrtcPtr saved_crtc;
int width, height;
} CoglDisplayKMS;
typedef struct _CoglOnscreenKMS
{
uint32_t fb_id[2];
struct gbm_bo *bo[2];
unsigned int fb, color_rb[2], depth_rb;
EGLImageKHR image[2];
int current_frame;
} CoglOnscreenKMS;
static const char device_name[] = "/dev/dri/card0";
static void
_cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
eglTerminate (egl_renderer->edpy);
g_slice_free (CoglRendererKMS, kms_renderer);
g_slice_free (CoglRendererEGL, egl_renderer);
}
static gboolean
_cogl_winsys_renderer_connect (CoglRenderer *renderer,
GError **error)
{
CoglRendererEGL *egl_renderer;
CoglRendererKMS *kms_renderer;
renderer->winsys = g_slice_new0 (CoglRendererEGL);
egl_renderer = renderer->winsys;
egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
egl_renderer->platform = g_slice_new0 (CoglRendererKMS);
kms_renderer = egl_renderer->platform;
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;
}
egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm);
if (egl_renderer->edpy == EGL_NO_DISPLAY)
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Couldn't get eglDisplay");
goto destroy_gbm_device;
}
if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
goto egl_terminate;
return TRUE;
egl_terminate:
eglTerminate (egl_renderer->edpy);
destroy_gbm_device:
gbm_device_destroy (kms_renderer->gbm);
close_fd:
close (kms_renderer->fd);
_cogl_winsys_renderer_disconnect (renderer);
return FALSE;
}
static gboolean
_cogl_winsys_egl_display_setup (CoglDisplay *display,
GError **error)
{
CoglDisplayEGL *egl_display = display->winsys;
CoglDisplayKMS *kms_display;
CoglRendererEGL *egl_renderer = display->renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
CoglEGLWinsysFeature surfaceless_feature = 0;
const char *surfaceless_feature_name = "";
drmModeRes *resources;
drmModeConnector *connector;
drmModeEncoder *encoder;
int i;
kms_display = g_slice_new0 (CoglDisplayKMS);
egl_display->platform = kms_display;
switch (display->renderer->driver)
{
case COGL_DRIVER_GL:
surfaceless_feature = COGL_EGL_WINSYS_FEATURE_SURFACELESS_OPENGL;
surfaceless_feature_name = "opengl";
break;
case COGL_DRIVER_GLES1:
surfaceless_feature = COGL_EGL_WINSYS_FEATURE_SURFACELESS_GLES1;
surfaceless_feature_name = "gles1";
break;
case COGL_DRIVER_GLES2:
surfaceless_feature = COGL_EGL_WINSYS_FEATURE_SURFACELESS_GLES2;
surfaceless_feature_name = "gles2";
break;
}
if (!(egl_renderer->private_features & surfaceless_feature))
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"EGL_KHR_surfaceless_%s extension not available",
surfaceless_feature_name);
return FALSE;
}
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,
encoder->crtc_id);
kms_display->connector = connector;
kms_display->encoder = encoder;
kms_display->mode = connector->modes[0];
kms_display->width = kms_display->mode.hdisplay;
kms_display->height = kms_display->mode.vdisplay;
return TRUE;
}
static void
_cogl_winsys_egl_display_destroy (CoglDisplay *display)
{
CoglDisplayEGL *egl_display = display->winsys;
g_slice_free (CoglDisplayKMS, egl_display->platform);
}
static gboolean
_cogl_winsys_egl_try_create_context (CoglDisplay *display,
EGLint *attribs,
GError **error)
{
CoglRenderer *renderer = display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglDisplayEGL *egl_display = display->winsys;
CoglDisplayKMS *kms_display = egl_display->platform;
egl_display->egl_context = eglCreateContext (egl_renderer->edpy,
NULL,
EGL_NO_CONTEXT,
attribs);
if (egl_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 (egl_renderer->edpy,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
egl_display->egl_context))
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_CONTEXT,
"Failed to make context current");
return FALSE;
}
egl_display->egl_surface_width = kms_display->width;
egl_display->egl_surface_height = kms_display->height;
return TRUE;
}
static void
_cogl_winsys_egl_cleanup_context (CoglDisplay *display)
{
CoglDisplayEGL *egl_display = display->winsys;
CoglDisplayKMS *kms_display = egl_display->platform;
CoglRenderer *renderer = display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
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);
}
static void
_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
{
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglDisplayEGL *egl_display = context->display->winsys;
CoglDisplayKMS *kms_display = egl_display->platform;
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
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");
}
}
static gboolean
_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
GError **error)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *context = framebuffer->context;
CoglDisplay *display = context->display;
CoglDisplayEGL *egl_display = display->winsys;
CoglDisplayKMS *kms_display = egl_display->platform;
CoglRenderer *renderer = display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen;
CoglOnscreenKMS *kms_onscreen;
int i;
_COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
onscreen->winsys = g_slice_new0 (CoglOnscreenEGL);
egl_onscreen = onscreen->winsys;
kms_onscreen = g_slice_new0 (CoglOnscreenKMS);
egl_onscreen->platform = kms_onscreen;
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_COMPONENT16,
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_onscreen_swap_buffers (onscreen);
_cogl_framebuffer_winsys_update_size (framebuffer,
egl_display->egl_surface_width,
egl_display->egl_surface_height);
return TRUE;
}
static void
_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *context = framebuffer->context;
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen;
int i;
/* If we never successfully allocated then there's nothing to do */
if (egl_onscreen == NULL)
return;
kms_onscreen = egl_onscreen->platform;
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]);
}
g_slice_free (CoglOnscreenKMS, kms_onscreen);
g_slice_free (CoglOnscreenEGL, onscreen->winsys);
onscreen->winsys = NULL;
}
static void
_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
{
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglDisplayEGL *egl_display = context->display->winsys;
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
eglMakeCurrent (egl_renderer->edpy,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
egl_display->egl_context);
}
static void
_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
{
_cogl_winsys_onscreen_bind (onscreen);
}
static const CoglWinsysEGLVtable
_cogl_winsys_egl_vtable =
{
.display_setup = _cogl_winsys_egl_display_setup,
.display_destroy = _cogl_winsys_egl_display_destroy,
.try_create_context = _cogl_winsys_egl_try_create_context,
.cleanup_context = _cogl_winsys_egl_cleanup_context
};
const CoglWinsysVtable *
_cogl_winsys_egl_kms_get_vtable (void)
@ -48,6 +550,20 @@ _cogl_winsys_egl_kms_get_vtable (void)
vtable.id = COGL_WINSYS_ID_EGL_KMS;
vtable.name = "EGL_KMS";
vtable.renderer_connect = _cogl_winsys_renderer_connect;
vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect;
vtable.onscreen_init = _cogl_winsys_onscreen_init;
vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit;
vtable.onscreen_bind = _cogl_winsys_onscreen_bind;
/* The KMS winsys doesn't support swap region */
vtable.onscreen_swap_region = NULL;
vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers;
vtable.onscreen_update_swap_throttled =
_cogl_winsys_onscreen_update_swap_throttled;
vtable_inited = TRUE;
}

View File

@ -28,9 +28,6 @@
#include "cogl-winsys-private.h"
#include "cogl-context.h"
#include "cogl-context-private.h"
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
#include "cogl-winsys-kms.h"
#endif
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
#include "cogl-xlib-renderer-private.h"
#include "cogl-xlib-display-private.h"
@ -40,6 +37,23 @@
#include <wayland-egl.h>
#endif
typedef struct _CoglWinsysEGLVtable
{
gboolean
(* display_setup) (CoglDisplay *display,
GError **error);
void
(* display_destroy) (CoglDisplay *display);
gboolean
(* try_create_context) (CoglDisplay *display,
EGLint *attribs,
GError **error);
void
(* cleanup_context) (CoglDisplay *display);
} CoglWinsysEGLVtable;
typedef enum _CoglEGLWinsysFeature
{
COGL_EGL_WINSYS_FEATURE_SWAP_REGION =1L<<0,
@ -72,9 +86,11 @@ 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
/* Data specific to the EGL platform */
void *platform;
/* vtable for platform specific parts */
const CoglWinsysEGLVtable *platform_vtable;
/* Function pointers for GLX specific extensions */
#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d)
@ -103,9 +119,6 @@ typedef struct _CoglDisplayEGL
struct wl_surface *wayland_surface;
struct wl_egl_window *wayland_egl_native_window;
#endif
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
CoglDisplayKMS kms_display;
#endif
#if defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \
@ -119,6 +132,9 @@ typedef struct _CoglDisplayEGL
EGLConfig egl_config;
gboolean found_egl_config;
gboolean stencil_disabled;
/* Platform specific display data */
void *platform;
} CoglDisplayEGL;
typedef struct _CoglContextEGL
@ -126,6 +142,32 @@ typedef struct _CoglContextEGL
EGLSurface current_surface;
} CoglContextEGL;
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
typedef struct _CoglOnscreenXlib
{
Window xwin;
gboolean is_foreign_xwin;
} CoglOnscreenXlib;
#endif
typedef struct _CoglOnscreenEGL
{
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
CoglOnscreenXlib _parent;
#endif
#ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT
struct wl_egl_window *wayland_egl_native_window;
struct wl_surface *wayland_surface;
struct wl_shell_surface *wayland_shell_surface;
#endif
EGLSurface egl_surface;
/* Platform specific data */
void *platform;
} CoglOnscreenEGL;
const CoglWinsysVtable *
_cogl_winsys_egl_get_vtable (void);
@ -141,4 +183,8 @@ _cogl_egl_destroy_image (CoglContext *ctx,
EGLImageKHR image);
#endif
gboolean
_cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
GError **error);
#endif /* __COGL_WINSYS_EGL_PRIVATE_H */

View File

@ -62,10 +62,6 @@
#include <android/native_window.h>
#endif
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
#include "cogl-winsys-kms.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
@ -82,32 +78,6 @@
#define MAX_EGL_CONFIG_ATTRIBS 30
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
typedef struct _CoglOnscreenXlib
{
Window xwin;
gboolean is_foreign_xwin;
} CoglOnscreenXlib;
#endif
typedef struct _CoglOnscreenEGL
{
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
CoglOnscreenXlib _parent;
#endif
#ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT
struct wl_egl_window *wayland_egl_native_window;
struct wl_surface *wayland_surface;
struct wl_shell_surface *wayland_shell_surface;
#endif
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
CoglOnscreenKMS kms_onscreen;
#endif
EGLSurface egl_surface;
} CoglOnscreenEGL;
#ifdef EGL_KHR_image_pixmap
typedef struct _CoglTexturePixmapEGL
{
@ -288,6 +258,27 @@ check_egl_extensions (CoglRenderer *renderer)
}
}
gboolean
_cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
GError **error)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
if (!eglInitialize (egl_renderer->edpy,
&egl_renderer->egl_version_major,
&egl_renderer->egl_version_minor))
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Couldn't initialize EGL");
return FALSE;
}
check_egl_extensions (renderer);
return TRUE;
}
static gboolean
_cogl_winsys_renderer_connect (CoglRenderer *renderer,
GError **error)
@ -296,7 +287,6 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
CoglXlibRenderer *xlib_renderer;
#endif
EGLBoolean status;
#ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
gdl_ret_t rc = GDL_SUCCESS;
gdl_display_info_t gdl_display_info;
@ -321,10 +311,6 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
egl_renderer->edpy =
eglGetDisplay ((NativeDisplayType) xlib_renderer->xdpy);
status = eglInitialize (egl_renderer->edpy,
&egl_renderer->egl_version_major,
&egl_renderer->egl_version_minor);
break;
#endif
@ -376,19 +362,6 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
egl_renderer->edpy =
eglGetDisplay ((EGLNativeDisplayType)egl_renderer->wayland_display);
status = eglInitialize (egl_renderer->edpy,
&egl_renderer->egl_version_major,
&egl_renderer->egl_version_minor);
break;
#endif
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
case COGL_WINSYS_ID_EGL_KMS:
if (!_cogl_winsys_kms_connect (&egl_renderer->kms_renderer, error))
goto error;
egl_renderer->edpy = egl_renderer->kms_renderer.dpy;
status = EGL_TRUE;
break;
#endif
@ -396,20 +369,11 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
case COGL_WINSYS_ID_EGL_ANDROID:
case COGL_WINSYS_ID_EGL_NULL:
egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
status = eglInitialize (egl_renderer->edpy,
&egl_renderer->egl_version_major,
&egl_renderer->egl_version_minor);
break;
}
if (status != EGL_TRUE)
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Failed to initialize EGL");
goto error;
}
if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
goto error;
#ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
if (renderer->winsys_vtable->id == COGL_WINSYS_ID_EGL_GDL)
@ -441,8 +405,6 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
}
#endif
check_egl_extensions (renderer);
return TRUE;
error:
@ -624,50 +586,53 @@ try_create_context (CoglDisplay *display,
#endif
const char *error_message;
egl_attributes_from_framebuffer_config (display,
&display->onscreen_template->config,
with_stencil_buffer,
cfg_attribs);
_COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE);
if (renderer->driver == COGL_DRIVER_GL)
eglBindAPI (EGL_OPENGL_API);
if (renderer->winsys_vtable->id != COGL_WINSYS_ID_EGL_KMS)
if (display->renderer->driver == COGL_DRIVER_GLES2)
{
edpy = egl_renderer->edpy;
attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
attribs[1] = 2;
attribs[2] = EGL_NONE;
}
else
attribs[0] = EGL_NONE;
status = eglChooseConfig (edpy,
cfg_attribs,
&config, 1,
&config_count);
if (status != EGL_TRUE || config_count == 0)
{
error_message = "Unable to find a usable EGL configuration";
goto fail;
}
/* Divert to the platform implementation if one is defined */
if (egl_renderer->platform_vtable &&
egl_renderer->platform_vtable->try_create_context)
return egl_renderer->platform_vtable->
try_create_context (display, attribs, error);
egl_display->egl_config = config;
egl_attributes_from_framebuffer_config (display,
&display->onscreen_template->config,
with_stencil_buffer,
cfg_attribs);
if (display->renderer->driver == COGL_DRIVER_GLES2)
{
attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
attribs[1] = 2;
attribs[2] = EGL_NONE;
}
else
attribs[0] = EGL_NONE;
edpy = egl_renderer->edpy;
egl_display->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
attribs);
if (egl_display->egl_context == EGL_NO_CONTEXT)
{
error_message = "Unable to create a suitable EGL context";
goto fail;
}
status = eglChooseConfig (edpy,
cfg_attribs,
&config, 1,
&config_count);
if (status != EGL_TRUE || config_count == 0)
{
error_message = "Unable to find a usable EGL configuration";
goto fail;
}
egl_display->egl_config = config;
egl_display->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
attribs);
if (egl_display->egl_context == EGL_NO_CONTEXT)
{
error_message = "Unable to create a suitable EGL context";
goto fail;
}
switch (renderer->winsys_vtable->id)
@ -897,19 +862,6 @@ try_create_context (CoglDisplay *display,
&egl_display->egl_surface_height);
break;
#endif
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
case COGL_WINSYS_ID_EGL_KMS:
if (!_cogl_winsys_kms_create_context (display->renderer,
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;
break;
#endif
}
return TRUE;
@ -932,21 +884,9 @@ cleanup_context (CoglDisplay *display)
CoglXlibRenderer *xlib_renderer = renderer->winsys;
#endif
#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
if (renderer->winsys_vtable->id == COGL_WINSYS_ID_EGL_KMS)
{
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_renderer->platform_vtable &&
egl_renderer->platform_vtable->cleanup_context)
egl_renderer->platform_vtable->cleanup_context (display);
if (egl_display->egl_context != EGL_NO_CONTEXT)
{
@ -1041,12 +981,17 @@ create_context (CoglDisplay *display, GError **error)
static void
_cogl_winsys_display_destroy (CoglDisplay *display)
{
CoglRendererEGL *egl_renderer = display->renderer->winsys;
CoglDisplayEGL *egl_display = display->winsys;
_COGL_RETURN_IF_FAIL (egl_display != NULL);
cleanup_context (display);
if (egl_renderer->platform_vtable &&
egl_renderer->platform_vtable->display_destroy)
egl_renderer->platform_vtable->display_destroy (display);
g_slice_free (CoglDisplayEGL, display->winsys);
display->winsys = NULL;
}
@ -1143,9 +1088,7 @@ _cogl_winsys_display_setup (CoglDisplay *display,
{
CoglDisplayEGL *egl_display;
CoglRenderer *renderer = display->renderer;
#ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
CoglRendererEGL *egl_renderer = renderer->winsys;
#endif
_COGL_RETURN_VAL_IF_FAIL (display->winsys == NULL, FALSE);
@ -1168,11 +1111,10 @@ _cogl_winsys_display_setup (CoglDisplay *display,
}
#endif
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
if (renderer->winsys_vtable->id == COGL_WINSYS_ID_EGL_KMS &&
!_cogl_winsys_kms_display_setup (display, error))
if (egl_renderer->platform_vtable &&
egl_renderer->platform_vtable->display_setup &&
!egl_renderer->platform_vtable->display_setup (display, error))
goto error;
#endif
if (!create_context (display, error))
goto error;
@ -1237,36 +1179,33 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
_COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
if (renderer->winsys_vtable->id != COGL_WINSYS_ID_EGL_KMS)
egl_attributes_from_framebuffer_config (display,
&framebuffer->config,
need_stencil,
attributes);
status = eglChooseConfig (egl_renderer->edpy,
attributes,
&egl_config, 1,
&config_count);
if (status != EGL_TRUE || config_count == 0)
{
egl_attributes_from_framebuffer_config (display,
&framebuffer->config,
need_stencil,
attributes);
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_ONSCREEN,
"Failed to find a suitable EGL configuration");
return FALSE;
}
status = eglChooseConfig (egl_renderer->edpy,
attributes,
&egl_config, 1,
&config_count);
if (status != EGL_TRUE || config_count == 0)
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_ONSCREEN,
"Failed to find a suitable EGL configuration");
return FALSE;
}
/* Update the real number of samples_per_pixel now that we have
* found an egl_config... */
if (framebuffer->config.samples_per_pixel)
{
EGLint samples;
status = eglGetConfigAttrib (egl_renderer->edpy,
egl_config,
EGL_SAMPLES, &samples);
g_return_val_if_fail (status == EGL_TRUE, TRUE);
framebuffer->samples_per_pixel = samples;
}
/* Update the real number of samples_per_pixel now that we have
* found an egl_config... */
if (framebuffer->config.samples_per_pixel)
{
EGLint samples;
status = eglGetConfigAttrib (egl_renderer->edpy,
egl_config,
EGL_SAMPLES, &samples);
g_return_val_if_fail (status == EGL_TRUE, TRUE);
framebuffer->samples_per_pixel = samples;
}
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
@ -1449,12 +1388,10 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
#if 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_KMS_SUPPORT)
defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT)
case COGL_WINSYS_ID_EGL_NULL:
case COGL_WINSYS_ID_EGL_ANDROID:
case COGL_WINSYS_ID_EGL_GDL:
case COGL_WINSYS_ID_EGL_KMS:
if (egl_display->have_onscreen)
{
@ -1464,20 +1401,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
return FALSE;
}
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
if (renderer->winsys_vtable->id == COGL_WINSYS_ID_EGL_KMS)
{
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
if (!_cogl_winsys_kms_onscreen_init (context,
&egl_renderer->kms_renderer,
&egl_display->kms_display,
&egl_onscreen->kms_onscreen,
error))
return FALSE;
}
else
#endif
egl_onscreen->egl_surface = egl_display->egl_surface;
egl_onscreen->egl_surface = egl_display->egl_surface;
_cogl_framebuffer_winsys_update_size (framebuffer,
egl_display->egl_surface_width,
@ -1514,8 +1438,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
/* If we never successfully allocated then there's nothing to do */
if (egl_onscreen == NULL)
return;
if (renderer->winsys_vtable->id != COGL_WINSYS_ID_EGL_KMS &&
egl_onscreen->egl_surface != EGL_NO_SURFACE)
if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
{
if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface)
== EGL_FALSE)
@ -1558,11 +1481,6 @@ _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;
}
@ -1575,15 +1493,6 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
if (renderer->winsys_vtable->id == COGL_WINSYS_ID_EGL_KMS)
{
_cogl_winsys_kms_bind (&egl_renderer->kms_renderer,
&egl_display->kms_display);
return;
}
#endif
#if defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \
@ -1647,32 +1556,29 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
int i;
if (renderer->winsys_vtable->id != COGL_WINSYS_ID_EGL_KMS)
/* eglSwapBuffersRegion expects rectangles relative to the
* bottom left corner but we are given rectangles relative to
* the top left so we need to flip them... */
memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
for (i = 0; i < n_rectangles; i++)
{
/* eglSwapBuffersRegion expects rectangles relative to the
* bottom left corner but we are given rectangles relative to
* the top left so we need to flip them... */
memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
for (i = 0; i < n_rectangles; i++)
{
int *rect = &rectangles[4 * i];
rect[1] = framebuffer_height - rect[1] - rect[3];
}
/* At least for eglSwapBuffers the EGL spec says that the surface to
swap must be bound to the current context. It looks like Mesa
also validates that this is the case for eglSwapBuffersRegion so
we must bind here too */
_cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
COGL_FRAMEBUFFER (onscreen),
COGL_FRAMEBUFFER_STATE_BIND);
if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
egl_onscreen->egl_surface,
n_rectangles,
rectangles) == EGL_FALSE)
g_warning ("Error reported by eglSwapBuffersRegion");
int *rect = &rectangles[4 * i];
rect[1] = framebuffer_height - rect[1] - rect[3];
}
/* At least for eglSwapBuffers the EGL spec says that the surface to
swap must be bound to the current context. It looks like Mesa
also validates that this is the case for eglSwapBuffersRegion so
we must bind here too */
_cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
COGL_FRAMEBUFFER (onscreen),
COGL_FRAMEBUFFER_STATE_BIND);
if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
egl_onscreen->egl_surface,
n_rectangles,
rectangles) == EGL_FALSE)
g_warning ("Error reported by eglSwapBuffersRegion");
#endif
}
@ -1703,19 +1609,6 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = 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
if (renderer->winsys_vtable->id == COGL_WINSYS_ID_EGL_KMS)
{
_cogl_winsys_kms_swap_buffers (&egl_renderer->kms_renderer,
&egl_display->kms_display,
&egl_onscreen->kms_onscreen);
return;
}
#endif
/* The specification for EGL (at least in 1.4) says that the surface
needs to be bound to the current context for the swap to work
@ -1761,18 +1654,13 @@ static void
_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
{
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglRenderer *renderer = context->display->renderer;
CoglContextEGL *egl_context = context->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
if (renderer->winsys_vtable->id != COGL_WINSYS_ID_EGL_KMS)
{
CoglContextEGL *egl_context = context->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
if (egl_context->current_surface != egl_onscreen->egl_surface)
return;
if (egl_context->current_surface != egl_onscreen->egl_surface)
return;
egl_context->current_surface = EGL_NO_SURFACE;
}
egl_context->current_surface = EGL_NO_SURFACE;
_cogl_winsys_onscreen_bind (onscreen);
}

View File

@ -1,426 +0,0 @@
/*
* 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
* <http://www.gnu.org/licenses/>.
*
* Some code inspired by mesa demos eglkms.c.
*
* Authors:
* Rob Bradford <rob@linux.intel.com>
* Kristian Høgsberg (from eglkms.c)
* Benjamin Franzke (from eglkms.c)
*/
#include <GL/gl.h>
#include <GL/glext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <fcntl.h>
#include <unistd.h>
#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";
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 (CoglDisplay *display, GError **error)
{
CoglDisplayEGL *egl_display = display->winsys;
CoglDisplayKMS *kms_display = &egl_display->kms_display;
CoglRendererEGL *egl_renderer = display->renderer->winsys;
CoglRendererKMS *kms_renderer = &egl_renderer->kms_renderer;
CoglEGLWinsysFeature surfaceless_feature = 0;
const char *surfaceless_feature_name = "";
drmModeRes *resources;
drmModeConnector *connector;
drmModeEncoder *encoder;
int i;
switch (display->renderer->driver)
{
case COGL_DRIVER_GL:
surfaceless_feature = COGL_EGL_WINSYS_FEATURE_SURFACELESS_OPENGL;
surfaceless_feature_name = "opengl";
break;
case COGL_DRIVER_GLES1:
surfaceless_feature = COGL_EGL_WINSYS_FEATURE_SURFACELESS_GLES1;
surfaceless_feature_name = "gles1";
break;
case COGL_DRIVER_GLES2:
surfaceless_feature = COGL_EGL_WINSYS_FEATURE_SURFACELESS_GLES2;
surfaceless_feature_name = "gles2";
break;
}
if (!(egl_renderer->private_features & surfaceless_feature))
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"EGL_KHR_surfaceless_%s extension not available",
surfaceless_feature_name);
return FALSE;
}
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,
encoder->crtc_id);
kms_display->connector = connector;
kms_display->encoder = encoder;
kms_display->mode = connector->modes[0];
kms_display->width = kms_display->mode.hdisplay;
kms_display->height = kms_display->mode.vdisplay;
return TRUE;
}
gboolean
_cogl_winsys_kms_create_context (CoglRenderer *renderer,
CoglDisplay *display,
GError **error)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglDisplayEGL *egl_display = display->winsys;
CoglRendererKMS *kms_renderer = &egl_renderer->kms_renderer;
CoglDisplayKMS *kms_display = &egl_display->kms_display;
EGLint attribs[3];
if (renderer->driver == COGL_DRIVER_GLES2)
{
attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
attribs[1] = 2;
attribs[2] = EGL_NONE;
}
else
attribs[0] = EGL_NONE;
kms_display->egl_context = eglCreateContext (kms_renderer->dpy,
NULL,
EGL_NO_CONTEXT,
attribs);
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_COMPONENT16,
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);
}

View File

@ -1,103 +0,0 @@
/*
* 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
* <http://www.gnu.org/licenses/>.
*
* Authors:
* Rob Bradford <rob@linux.intel.com>
*/
#ifndef _COGL_WINSYS_KMS_PRIVATE_H_
#define _COGL_WINSYS_KMS_PRIVATE_H_
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <glib.h>
#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;
int width, height;
} CoglDisplayKMS;
typedef struct _CoglOnscreenKMS
{
CoglContext *cogl_context;
uint32_t fb_id[2];
struct gbm_bo *bo[2];
unsigned int fb, color_rb[2], depth_rb;
EGLImageKHR image[2];
int 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 (CoglDisplay *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 (CoglRenderer *renderer,
CoglDisplay *display,
GError **error);
gboolean
_cogl_winsys_kms_destroy_context (CoglRendererKMS *kms_renderer,
CoglDisplayKMS *kms_display,
GError **error);
#endif /* _COGL_WINSYS_KMS_PRIVATE_H_ */