[mutter] MetaRendererNative: Add EGLDevice based rendering support
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] MetaRendererNative: Add EGLDevice based rendering support
- Date: Thu, 17 Nov 2016 16:08:37 +0000 (UTC)
commit 934184e236a354ad548acc9f6818701f8f41b1e3
Author: Jonas Ådahl <jadahl gmail com>
Date: Thu Aug 18 11:28:59 2016 +0800
MetaRendererNative: Add EGLDevice based rendering support
This commit adds support for using a EGLDevice and EGLStreams for
rendering on top of KMS instead of gbm. It is disabled by default; to
enable it pass --enable-egl-device to configure.
By default gbm is first tried, and if it fails, the EGLDevice path is
tried. If both fails, mutter will terminate just as before.
https://bugzilla.gnome.org/show_bug.cgi?id=773629
src/backends/native/meta-renderer-native.c | 747 ++++++++++++++++++++++++++--
src/backends/native/meta-renderer-native.h | 10 +
2 files changed, 712 insertions(+), 45 deletions(-)
---
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 05497d1..b1a183e 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -43,16 +43,23 @@
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <unistd.h>
#include <xf86drm.h>
#include "backends/meta-backend-private.h"
+#include "backends/meta-egl.h"
+#include "backends/meta-egl-ext.h"
#include "backends/meta-renderer-view.h"
#include "backends/native/meta-monitor-manager-kms.h"
#include "backends/native/meta-renderer-native.h"
#include "cogl/cogl.h"
#include "core/boxes-private.h"
+#ifndef EGL_DRM_MASTER_FD_EXT
+#define EGL_DRM_MASTER_FD_EXT 0x333C
+#endif
+
enum
{
PROP_0,
@@ -73,6 +80,19 @@ typedef struct _MetaOnscreenNative
struct gbm_bo *next_bo;
} gbm;
+#ifdef HAVE_EGL_DEVICE
+ struct {
+ EGLStreamKHR stream;
+
+ struct {
+ uint32_t fb_id;
+ uint32_t handle;
+ void *map;
+ uint64_t map_size;
+ } dumb_fb;
+ } egl;
+#endif
+
gboolean pending_queue_swap_notify;
gboolean pending_swap_notify;
@@ -89,15 +109,27 @@ struct _MetaRendererNative
int kms_fd;
char *kms_file_path;
+ MetaRendererNativeMode mode;
+
EGLDisplay egl_display;
struct {
struct gbm_device *device;
} gbm;
+#ifdef HAVE_EGL_DEVICE
+ struct {
+ EGLDeviceEXT device;
+
+ gboolean no_egl_output_drm_flip_event;
+ } egl;
+#endif
+
CoglClosure *swap_notify_idle;
int64_t frame_counter;
+
+ gboolean no_add_fb2;
};
static void
@@ -264,10 +296,23 @@ meta_renderer_native_add_egl_config_attributes (CoglDisplay *cogl_disp
CoglFramebufferConfig *config,
EGLint *attributes)
{
+ CoglRendererEGL *egl_renderer = cogl_display->renderer->winsys;
+ MetaRendererNative *renderer_native = egl_renderer->platform;
int i = 0;
- attributes[i++] = EGL_SURFACE_TYPE;
- attributes[i++] = EGL_WINDOW_BIT;
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ attributes[i++] = EGL_SURFACE_TYPE;
+ attributes[i++] = EGL_WINDOW_BIT;
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ attributes[i++] = EGL_SURFACE_TYPE;
+ attributes[i++] = EGL_STREAM_BIT_KHR;
+ break;
+#endif
+ }
return i;
}
@@ -396,6 +441,9 @@ on_crtc_flipped (GClosure *closure,
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
onscreen_native->pending_flips--;
if (onscreen_native->pending_flips == 0)
@@ -403,7 +451,17 @@ on_crtc_flipped (GClosure *closure,
onscreen_native->pending_queue_swap_notify = FALSE;
meta_onscreen_native_queue_swap_notify (onscreen);
- meta_onscreen_native_swap_drm_fb (onscreen);
+
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ meta_onscreen_native_swap_drm_fb (onscreen);
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ break;
+#endif
+ }
}
}
@@ -416,18 +474,27 @@ flip_closure_destroyed (MetaRendererView *view)
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
- if (onscreen_native->gbm.next_fb_id)
+ switch (renderer_native->mode)
{
- MetaBackend *backend = meta_get_backend ();
- MetaRenderer *renderer = meta_backend_get_renderer (backend);
- MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+ case META_RENDERER_NATIVE_MODE_GBM:
+ if (onscreen_native->gbm.next_fb_id)
+ {
+ drmModeRmFB (renderer_native->kms_fd, onscreen_native->gbm.next_fb_id);
+ gbm_surface_release_buffer (onscreen_native->gbm.surface,
+ onscreen_native->gbm.next_bo);
+ onscreen_native->gbm.next_bo = NULL;
+ onscreen_native->gbm.next_fb_id = 0;
+ }
- drmModeRmFB (renderer_native->kms_fd, onscreen_native->gbm.next_fb_id);
- gbm_surface_release_buffer (onscreen_native->gbm.surface,
- onscreen_native->gbm.next_bo);
- onscreen_native->gbm.next_bo = NULL;
- onscreen_native->gbm.next_fb_id = 0;
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ break;
+#endif
}
if (onscreen_native->pending_queue_swap_notify)
@@ -439,6 +506,49 @@ flip_closure_destroyed (MetaRendererView *view)
g_object_unref (view);
}
+#ifdef HAVE_EGL_DEVICE
+static void
+flip_egl_stream (MetaRendererNative *renderer_native,
+ MetaOnscreenNative *onscreen_native,
+ GClosure *flip_closure)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context =
+ clutter_backend_get_cogl_context (clutter_backend);
+ CoglDisplay *cogl_display = cogl_context->display;
+ CoglRendererEGL *egl_renderer = cogl_display->renderer->winsys;
+ EGLAttrib *acquire_attribs;
+ GError *error = NULL;
+
+ if (renderer_native->egl.no_egl_output_drm_flip_event)
+ return;
+
+ acquire_attribs = (EGLAttrib[]) {
+ EGL_DRM_FLIP_EVENT_DATA_NV,
+ (EGLAttrib) flip_closure,
+ EGL_NONE
+ };
+ if (!meta_egl_stream_consumer_acquire_attrib (egl,
+ egl_renderer->edpy,
+ onscreen_native->egl.stream,
+ acquire_attribs,
+ &error))
+ {
+ g_warning ("Failed to flip EGL stream (%s), relying on clock from now on",
+ error->message);
+ g_error_free (error);
+ renderer_native->egl.no_egl_output_drm_flip_event = TRUE;
+ return;
+ }
+
+ g_closure_ref (flip_closure);
+
+ return;
+}
+#endif /* HAVE_EGL_DEVICE */
+
static void
meta_onscreen_native_flip_crtc (MetaOnscreenNative *onscreen_native,
GClosure *flip_closure,
@@ -448,6 +558,8 @@ meta_onscreen_native_flip_crtc (MetaOnscreenNative *onscreen_native,
gboolean *fb_in_use)
{
MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
@@ -460,27 +572,55 @@ meta_onscreen_native_flip_crtc (MetaOnscreenNative *onscreen_native,
return;
}
- if (meta_monitor_manager_kms_flip_crtc (monitor_manager_kms,
- crtc,
- x, y,
- onscreen_native->gbm.next_fb_id,
- flip_closure,
- fb_in_use))
- onscreen_native->pending_flips++;
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ if (meta_monitor_manager_kms_flip_crtc (monitor_manager_kms,
+ crtc,
+ x, y,
+ onscreen_native->gbm.next_fb_id,
+ flip_closure,
+ fb_in_use))
+ onscreen_native->pending_flips++;
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ flip_egl_stream (renderer_native, onscreen_native, flip_closure);
+ onscreen_native->pending_flips++;
+ *fb_in_use = TRUE;
+ break;
+#endif
+ }
}
static void
meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
{
MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (monitor_manager);
MetaRendererView *view = onscreen_native->view;
- uint32_t next_fb_id = onscreen_native->gbm.next_fb_id;
+ uint32_t fb_id = 0;
MetaMonitorInfo *monitor_info;
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ fb_id = onscreen_native->gbm.next_fb_id;
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ fb_id = onscreen_native->egl.dumb_fb.fb_id;
+ break;
+#endif
+ }
+
+ g_assert (fb_id != 0);
+
monitor_info = meta_renderer_view_get_monitor_info (view);
if (monitor_info)
{
@@ -498,7 +638,7 @@ meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
meta_monitor_manager_kms_apply_crtc_mode (monitor_manager_kms,
crtc,
x, y,
- next_fb_id);
+ fb_id);
}
}
else
@@ -512,7 +652,7 @@ meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
meta_monitor_manager_kms_apply_crtc_mode (monitor_manager_kms,
crtc,
crtc->rect.x, crtc->rect.y,
- next_fb_id);
+ fb_id);
}
}
}
@@ -589,8 +729,21 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
*/
if (fb_in_use && onscreen_native->pending_flips == 0)
{
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+
meta_onscreen_native_queue_swap_notify (onscreen);
- meta_onscreen_native_swap_drm_fb (onscreen);
+
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ meta_onscreen_native_swap_drm_fb (onscreen);
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ break;
+#endif
+ }
}
onscreen_native->pending_queue_swap_notify = TRUE;
@@ -660,10 +813,23 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
rectangles,
n_rectangles);
- if (!gbm_get_next_fb_id (onscreen,
- &onscreen_native->gbm.next_bo,
- &onscreen_native->gbm.next_fb_id))
- return;
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ g_warn_if_fail (onscreen_native->gbm.next_bo == NULL &&
+ onscreen_native->gbm.next_fb_id == 0);
+
+ if (!gbm_get_next_fb_id (onscreen,
+ &onscreen_native->gbm.next_bo,
+ &onscreen_native->gbm.next_fb_id))
+ return;
+
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ break;
+#endif
+ }
/* If this is the first framebuffer to be presented then we now setup the
* crtc modes, else we flip from the previous buffer */
@@ -749,6 +915,232 @@ meta_renderer_native_create_surface_gbm (MetaRendererNative *renderer_native,
return TRUE;
}
+#ifdef HAVE_EGL_DEVICE
+static gboolean
+meta_renderer_native_create_surface_egl_device (MetaRendererNative *renderer_native,
+ MetaMonitorInfo *monitor_info,
+ int width,
+ int height,
+ EGLStreamKHR *out_egl_stream,
+ EGLSurface *out_egl_surface,
+ GError **error)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+ CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
+ CoglDisplayEGL *cogl_egl_display = cogl_display->winsys;
+ CoglRenderer *cogl_renderer = cogl_display->renderer;
+ CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
+ EGLDisplay egl_display = egl_renderer->edpy;
+ EGLConfig egl_config;
+ EGLStreamKHR egl_stream;
+ EGLSurface egl_surface;
+ EGLint num_layers;
+ EGLOutputLayerEXT output_layer;
+ EGLAttrib output_attribs[] = {
+ /*
+ * An "monitor_info" may have multiple outputs/crtcs in case its tiled,
+ * but as far as I can tell, EGL only allows you to pass one crtc_id, so
+ * lets pass the first one.
+ */
+ EGL_DRM_CRTC_EXT, monitor_info->outputs[0]->crtc->crtc_id,
+ EGL_NONE,
+ };
+ EGLint stream_attribs[] = {
+ EGL_STREAM_FIFO_LENGTH_KHR, 1,
+#ifdef EGL_EXT_stream_acquire_mode
+ EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
+#endif
+ EGL_NONE
+ };
+ EGLint stream_producer_attribs[] = {
+ EGL_WIDTH, width,
+ EGL_HEIGHT, height,
+ EGL_NONE
+ };
+
+ egl_stream = meta_egl_create_stream (egl, egl_display, stream_attribs, error);
+ if (egl_stream == EGL_NO_STREAM_KHR)
+ return FALSE;
+
+ if (!meta_egl_get_output_layers (egl, egl_display,
+ output_attribs,
+ &output_layer, 1, &num_layers,
+ error))
+ {
+ meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+ return FALSE;
+ }
+
+ if (num_layers < 1)
+ {
+ meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Unable to find output layers.");
+ return FALSE;
+ }
+
+ if (!meta_egl_stream_consumer_output (egl, egl_display,
+ egl_stream, output_layer,
+ error))
+ {
+ meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+ return FALSE;
+ }
+
+ egl_config = cogl_egl_display->egl_config;
+ egl_surface = meta_egl_create_stream_producer_surface (egl,
+ egl_display,
+ egl_config,
+ egl_stream,
+ stream_producer_attribs,
+ error);
+ if (egl_surface == EGL_NO_SURFACE)
+ {
+ meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+ return FALSE;
+ }
+
+ *out_egl_stream = egl_stream;
+ *out_egl_surface = egl_surface;
+
+ return TRUE;
+}
+
+static gboolean
+init_dumb_fb (MetaRendererNative *renderer_native,
+ MetaOnscreenNative *onscreen_native,
+ int width,
+ int height,
+ GError **error)
+{
+ struct drm_mode_create_dumb create_arg;
+ struct drm_mode_destroy_dumb destroy_arg;
+ struct drm_mode_map_dumb map_arg;
+ uint32_t fb_id = 0;
+ void *map;
+
+ create_arg = (struct drm_mode_create_dumb) {
+ .bpp = 32, /* RGBX8888 */
+ .width = width,
+ .height = height
+ };
+ if (drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_CREATE_DUMB,
+ &create_arg) != 0)
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to create dumb drm buffer: %s",
+ g_strerror (errno));
+ goto err_ioctl;
+ }
+
+ if (!renderer_native->no_add_fb2)
+ {
+ uint32_t handles[4] = { create_arg.handle, };
+ uint32_t pitches[4] = { create_arg.pitch, };
+ uint32_t offsets[4] = { 0 };
+
+ if (drmModeAddFB2 (renderer_native->kms_fd, width, height,
+ GBM_FORMAT_XRGB8888,
+ handles, pitches, offsets,
+ &fb_id, 0) != 0)
+ {
+ g_warning ("drmModeAddFB2 failed (%s), falling back to drmModeAddFB",
+ g_strerror (errno));
+ renderer_native->no_add_fb2 = TRUE;
+ }
+ }
+
+ if (renderer_native->no_add_fb2)
+ {
+ if (drmModeAddFB (renderer_native->kms_fd, width, height,
+ 24 /* depth of RGBX8888 */,
+ 32 /* bpp of RGBX8888 */,
+ create_arg.pitch,
+ create_arg.handle,
+ &fb_id) != 0)
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "drmModeAddFB failed: %s",
+ g_strerror (errno));
+ goto err_add_fb;
+ }
+ }
+
+ map_arg = (struct drm_mode_map_dumb) {
+ .handle = create_arg.handle
+ };
+ if (drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_MAP_DUMB,
+ &map_arg) != 0)
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to map dumb drm buffer: %s",
+ g_strerror (errno));
+ goto err_map_dumb;
+ }
+
+ map = mmap (NULL, create_arg.size, PROT_WRITE, MAP_SHARED,
+ renderer_native->kms_fd,
+ map_arg.offset);
+ if (map == MAP_FAILED)
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to mmap dumb drm buffer memory: %s",
+ g_strerror (errno));
+ goto err_mmap;
+ }
+
+ onscreen_native->egl.dumb_fb.fb_id = fb_id;
+ onscreen_native->egl.dumb_fb.handle = create_arg.handle;
+ onscreen_native->egl.dumb_fb.map = map;
+ onscreen_native->egl.dumb_fb.map_size = create_arg.size;
+
+ return TRUE;
+
+err_mmap:
+err_map_dumb:
+ drmModeRmFB (renderer_native->kms_fd, fb_id);
+
+err_add_fb:
+ destroy_arg = (struct drm_mode_destroy_dumb) {
+ .handle = create_arg.handle
+ };
+ drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+
+err_ioctl:
+ return FALSE;
+}
+
+static void
+release_dumb_fb (MetaRendererNative *renderer_native,
+ MetaOnscreenNative *onscreen_native)
+{
+ struct drm_mode_destroy_dumb destroy_arg;
+
+ if (!onscreen_native->egl.dumb_fb.map)
+ return;
+
+ munmap (onscreen_native->egl.dumb_fb.map,
+ onscreen_native->egl.dumb_fb.map_size);
+ onscreen_native->egl.dumb_fb.map = NULL;
+
+ drmModeRmFB (renderer_native->kms_fd,
+ onscreen_native->egl.dumb_fb.fb_id);
+
+ destroy_arg = (struct drm_mode_destroy_dumb) {
+ .handle = onscreen_native->egl.dumb_fb.handle
+ };
+ drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+}
+#endif /* HAVE_EGL_DEVICE */
+
static gboolean
meta_renderer_native_init_onscreen (CoglOnscreen *onscreen,
GError **error)
@@ -797,6 +1189,11 @@ meta_onscreen_native_allocate (CoglOnscreen *onscreen,
EGLSurface egl_surface;
int width;
int height;
+#ifdef HAVE_EGL_DEVICE
+ MetaRendererView *view;
+ MetaMonitorInfo *monitor_info;
+ EGLStreamKHR egl_stream;
+#endif
onscreen_native->pending_set_crtc = TRUE;
@@ -810,15 +1207,40 @@ meta_onscreen_native_allocate (CoglOnscreen *onscreen,
if (width == 0 || height == 0)
return TRUE;
- if (!meta_renderer_native_create_surface_gbm (renderer_native,
- width, height,
- &gbm_surface,
- &egl_surface,
- error))
- return FALSE;
+ switch (renderer_native->mode)
+ {
+ case META_RENDERER_NATIVE_MODE_GBM:
+ if (!meta_renderer_native_create_surface_gbm (renderer_native,
+ width, height,
+ &gbm_surface,
+ &egl_surface,
+ error))
+ return FALSE;
- onscreen_native->gbm.surface = gbm_surface;
- egl_onscreen->egl_surface = egl_surface;
+ onscreen_native->gbm.surface = gbm_surface;
+ egl_onscreen->egl_surface = egl_surface;
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ if (!init_dumb_fb (renderer_native, onscreen_native,
+ width, height, error))
+ return FALSE;
+
+ view = onscreen_native->view;
+ monitor_info = meta_renderer_view_get_monitor_info (view);
+ if (!meta_renderer_native_create_surface_egl_device (renderer_native,
+ monitor_info,
+ width, height,
+ &egl_stream,
+ &egl_surface,
+ error))
+ return FALSE;
+
+ onscreen_native->egl.stream = egl_stream;
+ egl_onscreen->egl_surface = egl_surface;
+ break;
+#endif /* HAVE_EGL_DEVICE */
+ }
return TRUE;
}
@@ -831,6 +1253,7 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ MetaRendererNative *renderer_native = egl_renderer->platform;
MetaOnscreenNative *onscreen_native;
/* If we never successfully allocated then there's nothing to do */
@@ -839,22 +1262,43 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
onscreen_native = egl_onscreen->platform;
- /* flip state takes a reference on the onscreen so there should
- * never be outstanding flips when we reach here. */
- g_return_if_fail (onscreen_native->gbm.next_fb_id == 0);
-
- free_current_bo (onscreen);
-
if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
egl_onscreen->egl_surface = EGL_NO_SURFACE;
}
- if (onscreen_native->gbm.surface)
+ switch (renderer_native->mode)
{
- gbm_surface_destroy (onscreen_native->gbm.surface);
- onscreen_native->gbm.surface = NULL;
+ case META_RENDERER_NATIVE_MODE_GBM:
+ /* flip state takes a reference on the onscreen so there should
+ * never be outstanding flips when we reach here. */
+ g_return_if_fail (onscreen_native->gbm.next_fb_id == 0);
+
+ free_current_bo (onscreen);
+
+ if (onscreen_native->gbm.surface)
+ {
+ gbm_surface_destroy (onscreen_native->gbm.surface);
+ onscreen_native->gbm.surface = NULL;
+ }
+ break;
+#ifdef HAVE_EGL_DEVICE
+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+ release_dumb_fb (renderer_native, onscreen_native);
+ if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
+ {
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+
+ meta_egl_destroy_stream (egl,
+ egl_renderer->edpy,
+ onscreen_native->egl.stream,
+ NULL);
+ onscreen_native->egl.stream = EGL_NO_STREAM_KHR;
+ }
+ break;
+#endif /* HAVE_EGL_DEVICE */
}
g_slice_free (MetaOnscreenNative, onscreen_native);
@@ -872,6 +1316,12 @@ _cogl_winsys_egl_vtable = {
.context_init = meta_renderer_native_init_egl_context
};
+MetaRendererNativeMode
+meta_renderer_native_get_mode (MetaRendererNative *renderer_native)
+{
+ return renderer_native->mode;
+}
+
struct gbm_device *
meta_renderer_native_get_gbm (MetaRendererNative *renderer_native)
{
@@ -1368,18 +1818,225 @@ init_gbm (MetaRendererNative *renderer_native,
renderer_native->egl_display = egl_display;
renderer_native->gbm.device = gbm_device;
+ renderer_native->mode = META_RENDERER_NATIVE_MODE_GBM;
return TRUE;
}
+#ifdef HAVE_EGL_DEVICE
+static const char *
+get_drm_device_file (MetaEgl *egl,
+ EGLDeviceEXT device,
+ GError **error)
+{
+ if (!meta_egl_egl_device_has_extensions (egl, device,
+ NULL,
+ "EGL_EXT_device_drm",
+ NULL))
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Missing required EGLDevice extension EGL_EXT_device_drm");
+ return NULL;
+ }
+
+ return meta_egl_query_device_string (egl, device,
+ EGL_DRM_DEVICE_FILE_EXT,
+ error);
+}
+
+static EGLDeviceEXT
+find_egl_device (MetaRendererNative *renderer_native,
+ GError **error)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+ char **missing_extensions;
+ EGLint num_devices;
+ EGLDeviceEXT *devices;
+ EGLDeviceEXT device;
+ EGLint i;
+
+ if (!meta_egl_has_extensions (egl,
+ EGL_NO_DISPLAY,
+ &missing_extensions,
+ "EGL_EXT_device_base",
+ NULL))
+ {
+ char *missing_extensions_str;
+
+ missing_extensions_str = g_strjoinv (", ", missing_extensions);
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Missing EGL extensions required for EGLDevice renderer: %s",
+ missing_extensions_str);
+ g_free (missing_extensions_str);
+ g_free (missing_extensions);
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ if (!meta_egl_query_devices (egl, 0, NULL, &num_devices, error))
+ return EGL_NO_DEVICE_EXT;
+
+ devices = g_new0 (EGLDeviceEXT, num_devices);
+ if (!meta_egl_query_devices (egl, num_devices, devices, &num_devices,
+ error))
+ {
+ g_free (devices);
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ device = EGL_NO_DEVICE_EXT;
+ for (i = 0; i < num_devices; i++)
+ {
+ const char *egl_device_drm_path;
+
+ g_clear_error (error);
+
+ egl_device_drm_path = get_drm_device_file (egl, devices[i], error);
+ if (!egl_device_drm_path)
+ continue;
+
+ if (g_str_equal (egl_device_drm_path, renderer_native->kms_file_path))
+ {
+ device = devices[i];
+ break;
+ }
+ }
+ g_free (devices);
+
+ if (device == EGL_NO_DEVICE_EXT)
+ {
+ if (!*error)
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to find matching EGLDeviceEXT");
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ return device;
+}
+
+static EGLDisplay
+get_egl_device_display (MetaRendererNative *renderer_native,
+ EGLDeviceEXT egl_device,
+ GError **error)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+ EGLint platform_attribs[] = {
+ EGL_DRM_MASTER_FD_EXT, renderer_native->kms_fd,
+ EGL_NONE
+ };
+
+ return meta_egl_get_platform_display (egl, EGL_PLATFORM_DEVICE_EXT,
+ (void *) egl_device,
+ platform_attribs,
+ error);
+}
+
+static gboolean
+init_egl_device (MetaRendererNative *renderer_native,
+ GError **error)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+ char **missing_extensions;
+ EGLDeviceEXT egl_device;
+ EGLDisplay egl_display;
+
+ if (!meta_is_stage_views_enabled())
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "EGLDevice requires stage views enabled");
+ return FALSE;
+ }
+
+ egl_device = find_egl_device (renderer_native, error);
+ if (egl_device == EGL_NO_DEVICE_EXT)
+ return FALSE;
+
+ egl_display = get_egl_device_display (renderer_native, egl_device, error);
+ if (egl_display == EGL_NO_DISPLAY)
+ return FALSE;
+
+ if (!meta_egl_initialize (egl, egl_display, error))
+ return FALSE;
+
+ if (!meta_egl_has_extensions (egl,
+ egl_display,
+ &missing_extensions,
+ "EGL_NV_output_drm_flip_event",
+ "EGL_EXT_output_base",
+ "EGL_EXT_output_drm",
+ "EGL_KHR_stream",
+ "EGL_KHR_stream_producer_eglsurface",
+ "EGL_EXT_stream_consumer_egloutput",
+ "EGL_EXT_stream_acquire_mode",
+ NULL))
+ {
+ char *missing_extensions_str;
+
+ missing_extensions_str = g_strjoinv (", ", missing_extensions);
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Missing EGL extensions required for EGLDevice renderer: %s",
+ missing_extensions_str);
+ g_free (missing_extensions_str);
+ g_free (missing_extensions);
+ return FALSE;
+ }
+
+ renderer_native->egl_display = egl_display;
+ renderer_native->egl.device = egl_device;
+ renderer_native->mode = META_RENDERER_NATIVE_MODE_EGL_DEVICE;
+
+ return TRUE;
+}
+#endif /* HAVE_EGL_DEVICE */
+
static gboolean
meta_renderer_native_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (initable);
+ GError *gbm_error = NULL;
+#ifdef HAVE_EGL_DEVICE
+ GError *egl_device_error = NULL;
+#endif
+
+ if (init_gbm (renderer_native, &gbm_error))
+ return TRUE;
- return init_gbm (renderer_native, error);
+#ifdef HAVE_EGL_DEVICE
+ if (init_egl_device (renderer_native, &egl_device_error))
+ {
+ g_error_free (gbm_error);
+ return TRUE;
+ }
+#endif
+
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to initialize renderer: "
+ "%s"
+#ifdef HAVE_EGL_DEVICE
+ ", %s"
+#endif
+ , gbm_error->message
+#ifdef HAVE_EGL_DEVICE
+ , egl_device_error->message
+#endif
+ );
+
+ g_error_free (gbm_error);
+#ifdef HAVE_EGL_DEVICE
+ g_error_free (egl_device_error);
+#endif
+
+ return FALSE;
}
static void
diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h
index 4b22d15..24cfdd3 100644
--- a/src/backends/native/meta-renderer-native.h
+++ b/src/backends/native/meta-renderer-native.h
@@ -35,10 +35,20 @@ G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native,
META, RENDERER_NATIVE,
MetaRenderer)
+typedef enum _MetaRendererNativeMode
+{
+ META_RENDERER_NATIVE_MODE_GBM,
+#ifdef HAVE_EGL_DEVICE
+ META_RENDERER_NATIVE_MODE_EGL_DEVICE
+#endif
+} MetaRendererNativeMode;
+
MetaRendererNative *meta_renderer_native_new (int kms_fd,
const char *kms_file_path,
GError **error);
+MetaRendererNativeMode meta_renderer_native_get_mode (MetaRendererNative *renderer_native);
+
struct gbm_device * meta_renderer_native_get_gbm (MetaRendererNative *renderer_native);
int meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]