diff --git a/cogl/cogl/Makefile.am b/cogl/cogl/Makefile.am index fe0f3fb31..902a1dda9 100644 --- a/cogl/cogl/Makefile.am +++ b/cogl/cogl/Makefile.am @@ -430,14 +430,6 @@ endif if SUPPORT_WAYLAND_EGL_SERVER cogl_experimental_h += cogl-wayland-server.h endif -if SUPPORT_EGL_PLATFORM_KMS -cogl_experimental_h += \ - cogl-kms-renderer.h \ - cogl-kms-display.h -cogl_sources_c += \ - winsys/cogl-winsys-egl-kms.c \ - winsys/cogl-winsys-egl-kms-private.h -endif if SUPPORT_EGL_PLATFORM_XLIB cogl_sources_c += \ winsys/cogl-winsys-egl-x11.c \ @@ -474,7 +466,7 @@ libmutter_cogl_la_LDFLAGS = \ -avoid-version \ -export-dynamic \ -rpath $(mutterlibdir) \ - -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_egl_kms_get_vtable|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_vtable).*" + -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_vtable|_cogl_winsys_egl_get_vtable|_cogl_closure_disconnect|_cogl_onscreen_notify_complete|_cogl_onscreen_notify_frame_sync|_cogl_winsys_egl_renderer_connect_common|_cogl_winsys_error_quark|_cogl_set_error|_cogl_poll_renderer_add_fd|_cogl_poll_renderer_add_idle|_cogl_framebuffer_winsys_update_size|_cogl_winsys_egl_make_current).*" libmutter_cogl_la_SOURCES = $(cogl_sources_c) nodist_libmutter_cogl_la_SOURCES = $(BUILT_SOURCES) diff --git a/cogl/cogl/cogl-kms-display.h b/cogl/cogl/cogl-kms-display.h deleted file mode 100644 index ebf6471ad..000000000 --- a/cogl/cogl/cogl-kms-display.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __COGL_KMS_DISPLAY_H__ -#define __COGL_KMS_DISPLAY_H__ - -#include -#include - -#include - -COGL_BEGIN_DECLS - -/** - * cogl_kms_display_queue_modes_reset: - * @display: A #CoglDisplay - * - * Asks Cogl to explicitly reset the crtc output modes at the next - * #CoglOnscreen swap_buffers request. For applications that support - * VT switching they may want to re-assert the output modes when - * switching back to the applications VT since the modes are often not - * correctly restored automatically. - * - * The @display must have been either explicitly setup via - * cogl_display_setup() or implicitily setup by having created a - * context using the @display - * - * Since: 2.0 - * Stability: unstable - */ -void -cogl_kms_display_queue_modes_reset (CoglDisplay *display); - -typedef struct { - uint32_t id; - uint32_t x, y; - drmModeModeInfo mode; - - uint32_t *connectors; - uint32_t count; - - CoglBool ignore; -} CoglKmsCrtc; - -/** - * cogl_kms_display_set_layout: - * @onscreen: a #CoglDisplay - * @width: the framebuffer width - * @height: the framebuffer height - * @crtcs: the array of #CoglKmsCrtc structure with the desired CRTC layout - * - * Configures @display to use a framebuffer sized @width x @height, covering - * the CRTCS in @crtcs. - * @width and @height must be within the driver framebuffer limits, and @crtcs - * must be valid KMS API IDs. - * - * Calling this function overrides the automatic mode setting done by Cogl, - * and for this reason must be called before the first call to cogl_onscreen_swap_buffers(). - * - * If you want to restore the default behaviour, you can call this function - * with @width and @height set to -1. - * - * Stability: unstable - */ -CoglBool -cogl_kms_display_set_layout (CoglDisplay *display, - int width, - int height, - CoglKmsCrtc **crtcs, - int n_crtcs, - CoglError **error); - - -/** - * cogl_kms_display_set_ignore_crtc: - * @onscreen: a #CoglDisplay - * @id: KMS output id - * @ignore: Ignore ouput or not - * - * Tells cogl to ignore (or stop ignoring) a ctrc which means - * it never flips buffers at this crtc. - * - * Stability: unstable - */ -void -cogl_kms_display_set_ignore_crtc (CoglDisplay *display, - uint32_t id, - CoglBool ignore); -COGL_END_DECLS -#endif /* __COGL_KMS_DISPLAY_H__ */ diff --git a/cogl/cogl/cogl-kms-renderer.h b/cogl/cogl/cogl-kms-renderer.h deleted file mode 100644 index 4e4948e56..000000000 --- a/cogl/cogl/cogl-kms-renderer.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2011 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __COGL_KMS_RENDERER_H__ -#define __COGL_KMS_RENDERER_H__ - -#include -#include - -COGL_BEGIN_DECLS - -/** - * cogl_kms_renderer_set_kms_fd: - * @renderer: A #CoglRenderer - * @fd: The fd to kms to use - * - * Sets the file descriptor Cogl should use to communicate - * to the kms driver. If -1 (the default), then Cogl will - * open its own FD by trying to open "/dev/dri/card0". - * - * Since: 1.18 - * Stability: unstable - */ -void -cogl_kms_renderer_set_kms_fd (CoglRenderer *renderer, - int fd); - -/** - * cogl_kms_renderer_get_kms_fd: - * @renderer: A #CoglRenderer - * - * Queries the file descriptor Cogl is using internally for - * communicating with the kms driver. - * - * Return value: The kms file descriptor or -1 if no kms file - * desriptor has been opened by Cogl. - * Stability: unstable - */ -int -cogl_kms_renderer_get_kms_fd (CoglRenderer *renderer); - -struct gbm_device * -cogl_kms_renderer_get_gbm (CoglRenderer *renderer); -COGL_END_DECLS -#endif /* __COGL_KMS_RENDERER_H__ */ diff --git a/cogl/cogl/cogl-mutter.h b/cogl/cogl/cogl-mutter.h index 672bede0f..d490a9cb6 100644 --- a/cogl/cogl/cogl-mutter.h +++ b/cogl/cogl/cogl-mutter.h @@ -38,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/cogl/cogl/cogl-renderer-private.h b/cogl/cogl/cogl-renderer-private.h index 81d956fde..8627b6cc6 100644 --- a/cogl/cogl/cogl-renderer-private.h +++ b/cogl/cogl/cogl-renderer-private.h @@ -76,10 +76,6 @@ struct _CoglRenderer [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)]; GModule *libgl_module; -#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) - int kms_fd; -#endif - /* List of callback functions that will be given every native event */ GSList *event_filters; void *winsys; diff --git a/cogl/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c index 027216318..51a04ffdd 100644 --- a/cogl/cogl/cogl-renderer.c +++ b/cogl/cogl/cogl-renderer.c @@ -55,9 +55,6 @@ #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT #include "cogl-winsys-egl-x11-private.h" #endif -#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT -#include "cogl-winsys-egl-kms-private.h" -#endif #ifdef COGL_HAS_GLX_SUPPORT #include "cogl-winsys-glx-private.h" #endif @@ -166,9 +163,6 @@ static CoglWinsysVtableGetter _cogl_winsys_vtable_getters[] = #endif #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT _cogl_winsys_egl_xlib_get_vtable, -#endif -#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT - _cogl_winsys_egl_kms_get_vtable, #endif _cogl_winsys_stub_get_vtable, }; @@ -243,10 +237,6 @@ cogl_renderer_new (void) renderer->xlib_enable_event_retrieval = TRUE; #endif -#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT - renderer->kms_fd = -1; -#endif - return _cogl_renderer_object_new (renderer); } diff --git a/cogl/cogl/cogl-renderer.h b/cogl/cogl/cogl-renderer.h index 20c79068c..88a8c082d 100644 --- a/cogl/cogl/cogl-renderer.h +++ b/cogl/cogl/cogl-renderer.h @@ -161,7 +161,6 @@ cogl_renderer_new (void); * @COGL_WINSYS_ID_STUB: Use the no-op stub backend * @COGL_WINSYS_ID_GLX: Use the GLX window system binding API * @COGL_WINSYS_ID_EGL_XLIB: Use EGL with the X window system via XLib - * @COGL_WINSYS_ID_EGL_KMS: Use EGL with the KMS platform * * Identifies specific window system backends that Cogl supports. * @@ -174,7 +173,7 @@ typedef enum COGL_WINSYS_ID_STUB, COGL_WINSYS_ID_GLX, COGL_WINSYS_ID_EGL_XLIB, - COGL_WINSYS_ID_EGL_KMS, + COGL_WINSYS_ID_CUSTOM, } CoglWinsysID; /** diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h index 778fdda5a..3d4ad0b5d 100644 --- a/cogl/cogl/cogl.h +++ b/cogl/cogl/cogl.h @@ -138,10 +138,6 @@ #include #include #include -#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT) -#include -#include -#endif #ifdef COGL_HAS_GLIB_SUPPORT #include #endif diff --git a/cogl/cogl/winsys/cogl-winsys-egl-kms-private.h b/cogl/cogl/winsys/cogl-winsys-egl-kms-private.h deleted file mode 100644 index dea05db47..000000000 --- a/cogl/cogl/winsys/cogl-winsys-egl-kms-private.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2011 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * Authors: - * Neil Roberts - */ - -#ifndef __COGL_WINSYS_EGL_KMS_PRIVATE_H -#define __COGL_WINSYS_EGL_KMS_PRIVATE_H - -#include "cogl-winsys-private.h" - -const CoglWinsysVtable * -_cogl_winsys_egl_kms_get_vtable (void); - -#endif /* __COGL_WINSYS_EGL_KMS_PRIVATE_H */ diff --git a/cogl/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/cogl/winsys/cogl-winsys-egl-kms.c deleted file mode 100644 index 271059c7d..000000000 --- a/cogl/cogl/winsys/cogl-winsys-egl-kms.c +++ /dev/null @@ -1,1335 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2011 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * Authors: - * Rob Bradford - * Kristian Høgsberg (from eglkms.c) - * Benjamin Franzke (from eglkms.c) - * Robert Bragg - * Neil Roberts - */ - -#ifdef HAVE_CONFIG_H -#include "cogl-config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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" -#include "cogl-kms-renderer.h" -#include "cogl-kms-display.h" -#include "cogl-version.h" -#include "cogl-error-private.h" -#include "cogl-poll-private.h" - -static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable; - -static const CoglWinsysVtable *parent_vtable; - -typedef struct _CoglRendererKMS -{ - int fd; - int opened_fd; - struct gbm_device *gbm; - CoglClosure *swap_notify_idle; - CoglBool page_flips_not_supported; -} CoglRendererKMS; - -typedef struct _CoglOutputKMS -{ - drmModeConnector *connector; - drmModeEncoder *encoder; - drmModeCrtc *saved_crtc; - drmModeModeInfo *modes; - int n_modes; - drmModeModeInfo mode; -} CoglOutputKMS; - -typedef struct _CoglDisplayKMS -{ - GList *outputs; - GList *crtcs; - - int width, height; - CoglBool pending_set_crtc; - struct gbm_surface *dummy_gbm_surface; - - CoglOnscreen *onscreen; -} CoglDisplayKMS; - -typedef struct _CoglFlipKMS -{ - CoglOnscreen *onscreen; - int pending; -} CoglFlipKMS; - -typedef struct _CoglOnscreenKMS -{ - struct gbm_surface *surface; - uint32_t current_fb_id; - uint32_t next_fb_id; - struct gbm_bo *current_bo; - struct gbm_bo *next_bo; - CoglBool pending_swap_notify; - - EGLSurface *pending_egl_surface; - struct gbm_surface *pending_surface; -} 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; - - if (egl_renderer->edpy != EGL_NO_DISPLAY) - eglTerminate (egl_renderer->edpy); - - if (kms_renderer->gbm != NULL) - gbm_device_destroy (kms_renderer->gbm); - - if (kms_renderer->opened_fd >= 0) - close (kms_renderer->opened_fd); - - g_slice_free (CoglRendererKMS, kms_renderer); - g_slice_free (CoglRendererEGL, egl_renderer); -} - -static void -flush_pending_swap_notify_cb (void *data, - void *user_data) -{ - CoglFramebuffer *framebuffer = data; - - if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) - { - CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); - CoglOnscreenEGL *egl_onscreen = onscreen->winsys; - CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; - - if (kms_onscreen->pending_swap_notify) - { - CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos); - - _cogl_onscreen_notify_frame_sync (onscreen, info); - _cogl_onscreen_notify_complete (onscreen, info); - kms_onscreen->pending_swap_notify = FALSE; - - cogl_object_unref (info); - } - } -} - -static void -flush_pending_swap_notify_idle (void *user_data) -{ - CoglContext *context = user_data; - CoglRendererEGL *egl_renderer = context->display->renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - - /* This needs to be disconnected before invoking the callbacks in - * case the callbacks cause it to be queued again */ - _cogl_closure_disconnect (kms_renderer->swap_notify_idle); - kms_renderer->swap_notify_idle = NULL; - - g_list_foreach (context->framebuffers, - flush_pending_swap_notify_cb, - NULL); -} - -static void -free_current_bo (CoglOnscreen *onscreen) -{ - CoglOnscreenEGL *egl_onscreen = onscreen->winsys; - CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; - CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; - CoglRenderer *renderer = context->display->renderer; - CoglRendererEGL *egl_renderer = renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - - if (kms_onscreen->current_fb_id) - { - drmModeRmFB (kms_renderer->fd, - kms_onscreen->current_fb_id); - kms_onscreen->current_fb_id = 0; - } - if (kms_onscreen->current_bo) - { - gbm_surface_release_buffer (kms_onscreen->surface, - kms_onscreen->current_bo); - kms_onscreen->current_bo = NULL; - } -} - -static void -queue_swap_notify_for_onscreen (CoglOnscreen *onscreen) -{ - CoglOnscreenEGL *egl_onscreen = onscreen->winsys; - CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; - CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; - CoglRenderer *renderer = context->display->renderer; - CoglRendererEGL *egl_renderer = renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - - /* We only want to notify that the swap is complete when the - * application calls cogl_context_dispatch so instead of - * immediately notifying we queue an idle callback */ - if (!kms_renderer->swap_notify_idle) - { - kms_renderer->swap_notify_idle = - _cogl_poll_renderer_add_idle (renderer, - flush_pending_swap_notify_idle, - context, - NULL); - } - - kms_onscreen->pending_swap_notify = TRUE; -} - -static void -process_flip (CoglFlipKMS *flip) -{ - /* We're only ready to dispatch a swap notification once all outputs - * have flipped... */ - flip->pending--; - if (flip->pending == 0) - { - CoglOnscreen *onscreen = flip->onscreen; - CoglOnscreenEGL *egl_onscreen = onscreen->winsys; - CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; - - queue_swap_notify_for_onscreen (onscreen); - - free_current_bo (onscreen); - - kms_onscreen->current_fb_id = kms_onscreen->next_fb_id; - kms_onscreen->next_fb_id = 0; - - kms_onscreen->current_bo = kms_onscreen->next_bo; - kms_onscreen->next_bo = NULL; - - cogl_object_unref (flip->onscreen); - - g_slice_free (CoglFlipKMS, flip); - } -} - -static void -page_flip_handler (int fd, - unsigned int frame, - unsigned int sec, - unsigned int usec, - void *data) -{ - CoglFlipKMS *flip = data; - - process_flip (flip); -} - -static void -handle_drm_event (CoglRendererKMS *kms_renderer) -{ - drmEventContext evctx; - - if (kms_renderer->page_flips_not_supported) - return; - - memset (&evctx, 0, sizeof evctx); - evctx.version = DRM_EVENT_CONTEXT_VERSION; - evctx.page_flip_handler = page_flip_handler; - drmHandleEvent (kms_renderer->fd, &evctx); -} - -static void -dispatch_kms_events (void *user_data, int revents) -{ - CoglRenderer *renderer = user_data; - CoglRendererEGL *egl_renderer = renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - - if (!revents) - return; - - handle_drm_event (kms_renderer); -} - -static CoglBool -_cogl_winsys_renderer_connect (CoglRenderer *renderer, - CoglError **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 = -1; - kms_renderer->opened_fd = -1; - - egl_renderer->edpy = EGL_NO_DISPLAY; - - if (renderer->kms_fd >= 0) - { - kms_renderer->fd = renderer->kms_fd; - } - else - { - kms_renderer->opened_fd = open (device_name, O_RDWR); - kms_renderer->fd = kms_renderer->opened_fd; - if (kms_renderer->fd < 0) - { - /* Probably permissions error */ - _cogl_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) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_INIT, - "Couldn't create gbm device"); - goto fail; - } - - egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm); - if (egl_renderer->edpy == EGL_NO_DISPLAY) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_INIT, - "Couldn't get eglDisplay"); - goto fail; - } - - if (!_cogl_winsys_egl_renderer_connect_common (renderer, error)) - goto fail; - - _cogl_poll_renderer_add_fd (renderer, - kms_renderer->fd, - COGL_POLL_FD_EVENT_IN, - NULL, /* no prepare callback */ - dispatch_kms_events, - renderer); - - return TRUE; - -fail: - _cogl_winsys_renderer_disconnect (renderer); - - return FALSE; -} - -static CoglBool -is_connector_excluded (int id, - int *excluded_connectors, - int n_excluded_connectors) -{ - int i; - for (i = 0; i < n_excluded_connectors; i++) - if (excluded_connectors[i] == id) - return TRUE; - return FALSE; -} - -static drmModeConnector * -find_connector (int fd, - drmModeRes *resources, - int *excluded_connectors, - int n_excluded_connectors) -{ - int i; - - for (i = 0; i < resources->count_connectors; i++) - { - drmModeConnector *connector = - drmModeGetConnector (fd, resources->connectors[i]); - - if (connector && - connector->connection == DRM_MODE_CONNECTED && - connector->count_modes > 0 && - !is_connector_excluded (connector->connector_id, - excluded_connectors, - n_excluded_connectors)) - return connector; - drmModeFreeConnector(connector); - } - return NULL; -} - -static CoglBool -find_mirror_modes (drmModeModeInfo *modes0, - int n_modes0, - drmModeModeInfo *modes1, - int n_modes1, - drmModeModeInfo *mode1_out, - drmModeModeInfo *mode0_out) -{ - int i; - for (i = 0; i < n_modes0; i++) - { - int j; - drmModeModeInfo *mode0 = &modes0[i]; - for (j = 0; j < n_modes1; j++) - { - drmModeModeInfo *mode1 = &modes1[j]; - if (mode1->hdisplay == mode0->hdisplay && - mode1->vdisplay == mode0->vdisplay) - { - *mode0_out = *mode0; - *mode1_out = *mode1; - return TRUE; - } - } - } - return FALSE; -} - -static drmModeModeInfo builtin_1024x768 = -{ - 63500, /* clock */ - 1024, 1072, 1176, 1328, 0, - 768, 771, 775, 798, 0, - 59920, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, - 0, - "1024x768" -}; - -static CoglBool -is_panel (int type) -{ - return (type == DRM_MODE_CONNECTOR_LVDS || - type == DRM_MODE_CONNECTOR_eDP); -} - -static CoglOutputKMS * -find_output (int _index, - int fd, - drmModeRes *resources, - int *excluded_connectors, - int n_excluded_connectors, - CoglError **error) -{ - char *connector_env_name = g_strdup_printf ("COGL_KMS_CONNECTOR%d", _index); - char *mode_env_name; - drmModeConnector *connector; - drmModeEncoder *encoder; - CoglOutputKMS *output; - drmModeModeInfo *modes; - int n_modes; - - if (getenv (connector_env_name)) - { - unsigned long id = strtoul (getenv (connector_env_name), NULL, 10); - connector = drmModeGetConnector (fd, id); - } - else - connector = NULL; - g_free (connector_env_name); - - if (connector == NULL) - connector = find_connector (fd, resources, - excluded_connectors, n_excluded_connectors); - if (connector == NULL) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_INIT, - "No currently active connector found"); - return NULL; - } - - /* XXX: At this point it seems connector->encoder_id may be an invalid id of 0 - * even though the connector is marked as connected. Referencing ->encoders[0] - * seems more reliable. */ - encoder = drmModeGetEncoder (fd, connector->encoders[0]); - - output = g_slice_new0 (CoglOutputKMS); - output->connector = connector; - output->encoder = encoder; - output->saved_crtc = drmModeGetCrtc (fd, encoder->crtc_id); - - if (is_panel (connector->connector_type)) - { - n_modes = connector->count_modes + 1; - modes = g_new (drmModeModeInfo, n_modes); - memcpy (modes, connector->modes, - sizeof (drmModeModeInfo) * connector->count_modes); - /* TODO: parse EDID */ - modes[n_modes - 1] = builtin_1024x768; - } - else - { - n_modes = connector->count_modes; - modes = g_new (drmModeModeInfo, n_modes); - memcpy (modes, connector->modes, - sizeof (drmModeModeInfo) * n_modes); - } - - mode_env_name = g_strdup_printf ("COGL_KMS_CONNECTOR%d_MODE", _index); - if (getenv (mode_env_name)) - { - const char *name = getenv (mode_env_name); - int i; - CoglBool found = FALSE; - drmModeModeInfo mode; - - for (i = 0; i < n_modes; i++) - { - if (strcmp (modes[i].name, name) == 0) - { - found = TRUE; - break; - } - } - if (!found) - { - g_free (mode_env_name); - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_INIT, - "COGL_KMS_CONNECTOR%d_MODE of %s could not be found", - _index, name); - return NULL; - } - n_modes = 1; - mode = modes[i]; - g_free (modes); - modes = g_new (drmModeModeInfo, 1); - modes[0] = mode; - } - g_free (mode_env_name); - - output->modes = modes; - output->n_modes = n_modes; - - return output; -} - -static void -setup_crtc_modes (CoglDisplay *display, int fb_id) -{ - CoglDisplayEGL *egl_display = display->winsys; - CoglDisplayKMS *kms_display = egl_display->platform; - CoglRendererEGL *egl_renderer = display->renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - GList *l; - - for (l = kms_display->crtcs; l; l = l->next) - { - CoglKmsCrtc *crtc = l->data; - - int ret = drmModeSetCrtc (kms_renderer->fd, - crtc->id, - fb_id, crtc->x, crtc->y, - crtc->connectors, crtc->count, - crtc->count ? &crtc->mode : NULL); - if (ret) - g_warning ("Failed to set crtc mode %s: %m", crtc->mode.name); - } -} - -static void -flip_all_crtcs (CoglDisplay *display, CoglFlipKMS *flip, int fb_id) -{ - CoglDisplayEGL *egl_display = display->winsys; - CoglDisplayKMS *kms_display = egl_display->platform; - CoglRendererEGL *egl_renderer = display->renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - GList *l; - gboolean needs_flip = FALSE; - - for (l = kms_display->crtcs; l; l = l->next) - { - CoglKmsCrtc *crtc = l->data; - int ret = 0; - - if (crtc->count == 0 || crtc->ignore) - continue; - - needs_flip = TRUE; - - if (!kms_renderer->page_flips_not_supported) - { - ret = drmModePageFlip (kms_renderer->fd, - crtc->id, fb_id, - DRM_MODE_PAGE_FLIP_EVENT, flip); - if (ret != 0 && ret != -EACCES) - { - g_warning ("Failed to flip: %m"); - kms_renderer->page_flips_not_supported = TRUE; - break; - } - } - - if (ret == 0) - flip->pending++; - } - - if (kms_renderer->page_flips_not_supported && needs_flip) - flip->pending = 1; -} - -static void -crtc_free (CoglKmsCrtc *crtc) -{ - g_free (crtc->connectors); - g_slice_free (CoglKmsCrtc, crtc); -} - -static CoglKmsCrtc * -crtc_copy (CoglKmsCrtc *from) -{ - CoglKmsCrtc *new; - - new = g_slice_new (CoglKmsCrtc); - - *new = *from; - new->connectors = g_memdup (from->connectors, from->count * sizeof(uint32_t)); - - return new; -} - -static CoglBool -_cogl_winsys_egl_display_setup (CoglDisplay *display, - CoglError **error) -{ - CoglDisplayEGL *egl_display = display->winsys; - CoglDisplayKMS *kms_display; - CoglRendererEGL *egl_renderer = display->renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - drmModeRes *resources; - CoglOutputKMS *output0, *output1; - CoglBool mirror; - CoglKmsCrtc *crtc0, *crtc1; - - kms_display = g_slice_new0 (CoglDisplayKMS); - egl_display->platform = kms_display; - - resources = drmModeGetResources (kms_renderer->fd); - if (!resources) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_INIT, - "drmModeGetResources failed"); - return FALSE; - } - - /* Force a full modeset / drmModeSetCrtc on - * the first swap buffers call. - */ - kms_display->pending_set_crtc = TRUE; - - if (kms_renderer->opened_fd < 0) - return TRUE; - - output0 = find_output (0, - kms_renderer->fd, - resources, - NULL, - 0, /* n excluded connectors */ - error); - if (!output0) - return FALSE; - - kms_display->outputs = g_list_append (kms_display->outputs, output0); - - if (getenv ("COGL_KMS_MIRROR")) - mirror = TRUE; - else - mirror = FALSE; - - if (mirror) - { - int exclude_connector = output0->connector->connector_id; - output1 = find_output (1, - kms_renderer->fd, - resources, - &exclude_connector, - 1, /* n excluded connectors */ - error); - if (!output1) - return FALSE; - - kms_display->outputs = g_list_append (kms_display->outputs, output1); - - if (!find_mirror_modes (output0->modes, output0->n_modes, - output1->modes, output1->n_modes, - &output0->mode, - &output1->mode)) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_INIT, - "Failed to find matching modes for mirroring"); - return FALSE; - } - } - else - { - output0->mode = output0->modes[0]; - output1 = NULL; - } - - crtc0 = g_slice_new (CoglKmsCrtc); - crtc0->id = output0->encoder->crtc_id; - crtc0->x = 0; - crtc0->y = 0; - crtc0->mode = output0->mode; - crtc0->connectors = g_new (uint32_t, 1); - crtc0->connectors[0] = output0->connector->connector_id; - crtc0->count = 1; - kms_display->crtcs = g_list_prepend (kms_display->crtcs, crtc0); - - if (output1) - { - crtc1 = g_slice_new (CoglKmsCrtc); - crtc1->id = output1->encoder->crtc_id; - crtc1->x = 0; - crtc1->y = 0; - crtc1->mode = output1->mode; - crtc1->connectors = g_new (uint32_t, 1); - crtc1->connectors[0] = output1->connector->connector_id; - crtc1->count = 1; - kms_display->crtcs = g_list_prepend (kms_display->crtcs, crtc1); - } - - kms_display->width = output0->mode.hdisplay; - kms_display->height = output0->mode.vdisplay; - - return TRUE; -} - -static void -output_free (int fd, CoglOutputKMS *output) -{ - if (output->modes) - g_free (output->modes); - - if (output->encoder) - drmModeFreeEncoder (output->encoder); - - if (output->connector) - { - if (output->saved_crtc) - { - int ret = drmModeSetCrtc (fd, - output->saved_crtc->crtc_id, - output->saved_crtc->buffer_id, - output->saved_crtc->x, - output->saved_crtc->y, - &output->connector->connector_id, 1, - &output->saved_crtc->mode); - if (ret) - g_warning (G_STRLOC ": Error restoring saved CRTC"); - } - drmModeFreeConnector (output->connector); - } - - g_slice_free (CoglOutputKMS, output); -} - -static void -_cogl_winsys_egl_display_destroy (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; - GList *l; - - for (l = kms_display->outputs; l; l = l->next) - output_free (kms_renderer->fd, l->data); - g_list_free (kms_display->outputs); - kms_display->outputs = NULL; - - g_list_free_full (kms_display->crtcs, (GDestroyNotify) crtc_free); - - g_slice_free (CoglDisplayKMS, egl_display->platform); -} - -static CoglBool -_cogl_winsys_egl_context_created (CoglDisplay *display, - CoglError **error) -{ - 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; - - if ((egl_renderer->private_features & - COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0) - { - kms_display->dummy_gbm_surface = - gbm_surface_create (kms_renderer->gbm, - 16, 16, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_RENDERING); - if (!kms_display->dummy_gbm_surface) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_CONTEXT, - "Failed to create dummy GBM surface"); - return FALSE; - } - - egl_display->dummy_surface = - eglCreateWindowSurface (egl_renderer->edpy, - egl_display->egl_config, - (EGLNativeWindowType) - kms_display->dummy_gbm_surface, - NULL); - if (egl_display->dummy_surface == EGL_NO_SURFACE) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_CONTEXT, - "Failed to create dummy EGL surface"); - return FALSE; - } - } - - if (!_cogl_winsys_egl_make_current (display, - egl_display->dummy_surface, - egl_display->dummy_surface, - egl_display->egl_context)) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_CONTEXT, - "Failed to make context current"); - return FALSE; - } - - 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; - - if (egl_display->dummy_surface != EGL_NO_SURFACE) - { - eglDestroySurface (egl_renderer->edpy, egl_display->dummy_surface); - egl_display->dummy_surface = EGL_NO_SURFACE; - } - - if (kms_display->dummy_gbm_surface != NULL) - { - gbm_surface_destroy (kms_display->dummy_gbm_surface); - kms_display->dummy_gbm_surface = NULL; - } -} - -static void -_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, - const int *rectangles, - int n_rectangles) -{ - 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; - uint32_t handle, stride; - CoglFlipKMS *flip; - - /* If we already have a pending swap then block until it completes */ - while (kms_onscreen->next_fb_id != 0) - handle_drm_event (kms_renderer); - - if (kms_onscreen->pending_egl_surface) - { - eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface); - egl_onscreen->egl_surface = kms_onscreen->pending_egl_surface; - kms_onscreen->pending_egl_surface = NULL; - - _cogl_framebuffer_winsys_update_size (COGL_FRAMEBUFFER (kms_display->onscreen), - kms_display->width, kms_display->height); - context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND; - } - parent_vtable->onscreen_swap_buffers_with_damage (onscreen, - rectangles, - n_rectangles); - - if (kms_onscreen->pending_surface) - { - free_current_bo (onscreen); - if (kms_onscreen->surface) - gbm_surface_destroy (kms_onscreen->surface); - kms_onscreen->surface = kms_onscreen->pending_surface; - kms_onscreen->pending_surface = NULL; - } - /* Now we need to set the CRTC to whatever is the front buffer */ - kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface); - -#if (COGL_VERSION_ENCODE (COGL_GBM_MAJOR, COGL_GBM_MINOR, COGL_GBM_MICRO) >= \ - COGL_VERSION_ENCODE (8, 1, 0)) - stride = gbm_bo_get_stride (kms_onscreen->next_bo); -#else - stride = gbm_bo_get_pitch (kms_onscreen->next_bo); -#endif - handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32; - - if (drmModeAddFB (kms_renderer->fd, - kms_display->width, - kms_display->height, - 24, /* depth */ - 32, /* bpp */ - stride, - handle, - &kms_onscreen->next_fb_id)) - { - g_warning ("Failed to create new back buffer handle: %m"); - gbm_surface_release_buffer (kms_onscreen->surface, - kms_onscreen->next_bo); - kms_onscreen->next_bo = NULL; - kms_onscreen->next_fb_id = 0; - return; - } - - /* If this is the first framebuffer to be presented then we now setup the - * crtc modes, else we flip from the previous buffer */ - if (kms_display->pending_set_crtc) - { - setup_crtc_modes (context->display, kms_onscreen->next_fb_id); - kms_display->pending_set_crtc = FALSE; - } - - flip = g_slice_new0 (CoglFlipKMS); - flip->onscreen = onscreen; - - flip_all_crtcs (context->display, flip, kms_onscreen->next_fb_id); - - if (flip->pending == 0) - { - drmModeRmFB (kms_renderer->fd, kms_onscreen->next_fb_id); - gbm_surface_release_buffer (kms_onscreen->surface, - kms_onscreen->next_bo); - kms_onscreen->next_bo = NULL; - kms_onscreen->next_fb_id = 0; - g_slice_free (CoglFlipKMS, flip); - flip = NULL; - - queue_swap_notify_for_onscreen (onscreen); - } - else - { - /* Ensure the onscreen remains valid while it has any pending flips... */ - cogl_object_ref (flip->onscreen); - - /* Process flip right away if we can't wait for vblank */ - if (kms_renderer->page_flips_not_supported) - { - setup_crtc_modes (context->display, kms_onscreen->next_fb_id); - process_flip (flip); - } - } -} - -static CoglBool -_cogl_winsys_egl_context_init (CoglContext *context, - CoglError **error) -{ - COGL_FLAGS_SET (context->features, - COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE); - /* TODO: remove this deprecated feature */ - COGL_FLAGS_SET (context->winsys_features, - COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, - TRUE); - COGL_FLAGS_SET (context->winsys_features, - COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, - TRUE); - - return TRUE; -} - -static CoglBool -_cogl_winsys_onscreen_init (CoglOnscreen *onscreen, - CoglError **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; - - _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE); - - if (kms_display->onscreen) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Cannot have multiple onscreens in the KMS platform"); - return FALSE; - } - - kms_display->onscreen = onscreen; - - onscreen->winsys = g_slice_new0 (CoglOnscreenEGL); - egl_onscreen = onscreen->winsys; - - kms_onscreen = g_slice_new0 (CoglOnscreenKMS); - egl_onscreen->platform = kms_onscreen; - - /* If a kms_fd is set then the display width and height - * won't be available until cogl_kms_display_set_layout - * is called. In that case, defer creating the surface - * until then. - */ - if (kms_display->width == 0 || - kms_display->height == 0) - return TRUE; - - kms_onscreen->surface = - gbm_surface_create (kms_renderer->gbm, - kms_display->width, - kms_display->height, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT | - GBM_BO_USE_RENDERING); - - if (!kms_onscreen->surface) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Failed to allocate surface"); - return FALSE; - } - - egl_onscreen->egl_surface = - eglCreateWindowSurface (egl_renderer->edpy, - egl_display->egl_config, - (EGLNativeWindowType) kms_onscreen->surface, - NULL); - if (egl_onscreen->egl_surface == EGL_NO_SURFACE) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Failed to allocate surface"); - return FALSE; - } - - _cogl_framebuffer_winsys_update_size (framebuffer, - kms_display->width, - kms_display->height); - - return TRUE; -} - -static void -_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) -{ - 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 = context->display->renderer; - CoglRendererEGL *egl_renderer = renderer->winsys; - CoglOnscreenEGL *egl_onscreen = onscreen->winsys; - CoglOnscreenKMS *kms_onscreen; - - /* If we never successfully allocated then there's nothing to do */ - if (egl_onscreen == NULL) - return; - - kms_display->onscreen = NULL; - - kms_onscreen = 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 (kms_onscreen->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 (kms_onscreen->surface) - { - gbm_surface_destroy (kms_onscreen->surface); - kms_onscreen->surface = NULL; - } - - g_slice_free (CoglOnscreenKMS, kms_onscreen); - g_slice_free (CoglOnscreenEGL, onscreen->winsys); - onscreen->winsys = NULL; -} - -static const CoglWinsysEGLVtable -_cogl_winsys_egl_vtable = - { - .display_setup = _cogl_winsys_egl_display_setup, - .display_destroy = _cogl_winsys_egl_display_destroy, - .context_created = _cogl_winsys_egl_context_created, - .cleanup_context = _cogl_winsys_egl_cleanup_context, - .context_init = _cogl_winsys_egl_context_init - }; - -const CoglWinsysVtable * -_cogl_winsys_egl_kms_get_vtable (void) -{ - static CoglBool vtable_inited = FALSE; - static CoglWinsysVtable vtable; - - if (!vtable_inited) - { - /* The EGL_KMS winsys is a subclass of the EGL winsys so we - start by copying its vtable */ - - parent_vtable = _cogl_winsys_egl_get_vtable (); - vtable = *parent_vtable; - - 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; - - /* The KMS winsys doesn't support swap region */ - vtable.onscreen_swap_region = NULL; - vtable.onscreen_swap_buffers_with_damage = - _cogl_winsys_onscreen_swap_buffers_with_damage; - - vtable_inited = TRUE; - } - - return &vtable; -} - -void -cogl_kms_renderer_set_kms_fd (CoglRenderer *renderer, - int fd) -{ - _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); - /* NB: Renderers are considered immutable once connected */ - _COGL_RETURN_IF_FAIL (!renderer->connected); - - renderer->kms_fd = fd; -} - -struct gbm_device * -cogl_kms_renderer_get_gbm (CoglRenderer *renderer) -{ - _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL); - if (renderer->connected) - { - CoglRendererEGL *egl_renderer = renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - return kms_renderer->gbm; - } - else - return NULL; -} - -int -cogl_kms_renderer_get_kms_fd (CoglRenderer *renderer) -{ - _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), -1); - - if (renderer->connected) - { - CoglRendererEGL *egl_renderer = renderer->winsys; - CoglRendererKMS *kms_renderer = egl_renderer->platform; - return kms_renderer->fd; - } - else - return -1; -} - -void -cogl_kms_display_queue_modes_reset (CoglDisplay *display) -{ - if (display->setup) - { - CoglDisplayEGL *egl_display = display->winsys; - CoglDisplayKMS *kms_display = egl_display->platform; - kms_display->pending_set_crtc = TRUE; - } -} - -CoglBool -cogl_kms_display_set_layout (CoglDisplay *display, - int width, - int height, - CoglKmsCrtc **crtcs, - int n_crtcs, - CoglError **error) -{ - 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; - GList *crtc_list; - int i; - - if ((width != kms_display->width || - height != kms_display->height) && - kms_display->onscreen) - { - CoglOnscreenEGL *egl_onscreen = kms_display->onscreen->winsys; - CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; - struct gbm_surface *new_surface; - EGLSurface new_egl_surface; - - /* Need to drop the GBM surface and create a new one */ - - new_surface = gbm_surface_create (kms_renderer->gbm, - width, height, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT | - GBM_BO_USE_RENDERING); - - if (!new_surface) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Failed to allocate new surface"); - return FALSE; - } - - new_egl_surface = - eglCreateWindowSurface (egl_renderer->edpy, - egl_display->egl_config, - (EGLNativeWindowType) new_surface, - NULL); - if (new_egl_surface == EGL_NO_SURFACE) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Failed to allocate new surface"); - gbm_surface_destroy (new_surface); - return FALSE; - } - - if (kms_onscreen->pending_egl_surface) - eglDestroySurface (egl_renderer->edpy, kms_onscreen->pending_egl_surface); - if (kms_onscreen->pending_surface) - gbm_surface_destroy (kms_onscreen->pending_surface); - - /* If there's already a surface, wait until the next swap to switch - * it out, otherwise, if we're just starting up we can use the new - * surface right away. - */ - if (kms_onscreen->surface != NULL) - { - kms_onscreen->pending_surface = new_surface; - kms_onscreen->pending_egl_surface = new_egl_surface; - } - else - { - CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (kms_display->onscreen); - - kms_onscreen->surface = new_surface; - egl_onscreen->egl_surface = new_egl_surface; - - _cogl_framebuffer_winsys_update_size (framebuffer, width, height); - } - } - - kms_display->width = width; - kms_display->height = height; - - g_list_free_full (kms_display->crtcs, (GDestroyNotify) crtc_free); - - crtc_list = NULL; - for (i = 0; i < n_crtcs; i++) - { - crtc_list = g_list_prepend (crtc_list, crtc_copy (crtcs[i])); - } - crtc_list = g_list_reverse (crtc_list); - kms_display->crtcs = crtc_list; - - kms_display->pending_set_crtc = TRUE; - - return TRUE; -} - - -void -cogl_kms_display_set_ignore_crtc (CoglDisplay *display, - uint32_t id, - CoglBool ignore) -{ - CoglDisplayEGL *egl_display = display->winsys; - CoglDisplayKMS *kms_display = egl_display->platform; - GList *l; - - for (l = kms_display->crtcs; l; l = l->next) - { - CoglKmsCrtc *crtc = l->data; - if (crtc->id == id) - { - crtc->ignore = ignore; - break; - } - } -} diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index c20c3ec60..921944186 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -34,7 +34,9 @@ #include #include -#include "meta-monitor-manager-private.h" +#include "backends/meta-backend-private.h" +#include "backends/meta-monitor-manager-private.h" +#include "backends/native/meta-renderer-native.h" #include "meta/boxes.h" #ifndef DRM_CAP_CURSOR_WIDTH @@ -657,7 +659,6 @@ static void meta_cursor_renderer_native_init (MetaCursorRendererNative *native) { MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native); - CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); MetaMonitorManager *monitors; monitors = meta_monitor_manager_get (); @@ -667,9 +668,12 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native) #if defined(CLUTTER_WINDOWING_EGL) if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) { - CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx)); - priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); - priv->gbm = cogl_kms_renderer_get_gbm (cogl_renderer); + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + + priv->drm_fd = meta_renderer_native_get_kms_fd (renderer_native); + priv->gbm = meta_renderer_native_get_gbm (renderer_native); uint64_t width, height; if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 && diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c index 5991fc740..ea28e5a3d 100644 --- a/src/backends/native/meta-launcher.c +++ b/src/backends/native/meta-launcher.c @@ -45,6 +45,7 @@ #include "backends/meta-backend-private.h" #include "meta-cursor-renderer-native.h" #include "meta-idle-monitor-native.h" +#include "meta-renderer-native.h" G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref) @@ -108,21 +109,20 @@ get_seat_proxy (GCancellable *cancellable, static void session_unpause (void) { - ClutterBackend *clutter_backend; - CoglContext *cogl_context; - CoglDisplay *cogl_display; + MetaBackend *backend; + MetaRenderer *renderer; - clutter_backend = clutter_get_default_backend (); - cogl_context = clutter_backend_get_cogl_context (clutter_backend); - cogl_display = cogl_context_get_display (cogl_context); - cogl_kms_display_queue_modes_reset (cogl_display); + backend = meta_get_backend (); + renderer = meta_backend_get_renderer (backend); + meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer)); clutter_evdev_reclaim_devices (); clutter_egl_thaw_master_clock (); { MetaBackend *backend = meta_get_backend (); - MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (backend); + MetaCursorRendererNative *cursor_renderer_native = + META_CURSOR_RENDERER_NATIVE (meta_backend_get_cursor_renderer (backend)); ClutterActor *stage = meta_backend_get_stage (backend); /* When we mode-switch back, we need to immediately queue a redraw @@ -130,7 +130,7 @@ session_unpause (void) * update. */ clutter_actor_queue_redraw (stage); - meta_cursor_renderer_native_force_update (META_CURSOR_RENDERER_NATIVE (renderer)); + meta_cursor_renderer_native_force_update (cursor_renderer_native); meta_idle_monitor_native_reset_idletime (meta_idle_monitor_get_core ()); } } diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index a28ef7907..51aed365c 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -25,6 +25,8 @@ #include "meta-monitor-manager-kms.h" #include "meta-monitor-config.h" +#include "meta-backend-private.h" +#include "meta-renderer-native.h" #include #include @@ -952,9 +954,8 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, MetaPowerSave mode) { MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); - ClutterBackend *backend; - CoglContext *cogl_context; - CoglDisplay *cogl_display; + MetaBackend *backend; + MetaRenderer *renderer; uint64_t state; unsigned i; @@ -995,13 +996,13 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, } } - backend = clutter_get_default_backend (); - cogl_context = clutter_backend_get_cogl_context (backend); - cogl_display = cogl_context_get_display (cogl_context); + backend = meta_get_backend (); + renderer = meta_backend_get_renderer (backend); for (i = 0; i < manager->n_crtcs; i++) - cogl_kms_display_set_ignore_crtc (cogl_display, manager->crtcs[i].crtc_id, - mode != META_POWER_SAVE_ON); + meta_renderer_native_set_ignore_crtc (META_RENDERER_NATIVE (renderer), + manager->crtcs[i].crtc_id, + mode != META_POWER_SAVE_ON); } static void @@ -1061,9 +1062,8 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, unsigned int n_outputs) { MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); - ClutterBackend *backend; - CoglContext *cogl_context; - CoglDisplay *cogl_display; + MetaBackend *backend; + MetaRenderer *renderer; unsigned i; GPtrArray *cogl_crtcs; int screen_width, screen_height; @@ -1191,13 +1191,15 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, crtc->current_mode = NULL; } - backend = clutter_get_default_backend (); - cogl_context = clutter_backend_get_cogl_context (backend); - cogl_display = cogl_context_get_display (cogl_context); + backend = meta_get_backend (); + renderer = meta_backend_get_renderer (backend); error = NULL; - ok = cogl_kms_display_set_layout (cogl_display, screen_width, screen_height, - (CoglKmsCrtc**)cogl_crtcs->pdata, cogl_crtcs->len, &error); + ok = meta_renderer_native_set_layout (META_RENDERER_NATIVE (renderer), + screen_width, screen_height, + (CoglKmsCrtc**)cogl_crtcs->pdata, + cogl_crtcs->len, + &error); g_ptr_array_unref (cogl_crtcs); if (!ok) @@ -1296,17 +1298,11 @@ on_uevent (GUdevClient *client, static void meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) { - ClutterBackend *backend; - CoglContext *cogl_context; - CoglDisplay *cogl_display; - CoglRenderer *cogl_renderer; + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); - backend = clutter_get_default_backend (); - cogl_context = clutter_backend_get_cogl_context (backend); - cogl_display = cogl_context_get_display (cogl_context); - cogl_renderer = cogl_display_get_renderer (cogl_display); - - manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); + manager_kms->fd = meta_renderer_native_get_kms_fd (renderer_native); drmSetClientCap (manager_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 16e2aa47c..f5a1f4842 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -1,6 +1,7 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* + * Copyright (C) 2011 Intel Corporation. * Copyright (C) 2016 Red Hat * * Permission is hereby granted, free of charge, to any person @@ -23,14 +24,28 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * Written by: - * Jonas Ådahl + * Authors: + * Rob Bradford (from cogl-winsys-egl-kms.c) + * Kristian Høgsberg (from eglkms.c) + * Benjamin Franzke (from eglkms.c) + * Robert Bragg (from cogl-winsys-egl-kms.c) + * Neil Roberts (from cogl-winsys-egl-kms.c) + * Jonas Ådahl + * */ #include "config.h" +#include +#include #include +#include +#include +#include +#include +#include +#include "backends/meta-backend-private.h" #include "backends/native/meta-renderer-native.h" #include "cogl/cogl.h" @@ -52,16 +67,932 @@ struct _MetaRendererNative G_DEFINE_TYPE (MetaRendererNative, meta_renderer_native, META_TYPE_RENDERER) +static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable; +static const CoglWinsysVtable *parent_vtable; + +typedef struct _CoglRendererKMS +{ + int fd; + struct gbm_device *gbm; + CoglClosure *swap_notify_idle; + CoglBool page_flips_not_supported; +} CoglRendererKMS; + +typedef struct _CoglDisplayKMS +{ + GList *crtcs; + + int width, height; + CoglBool pending_set_crtc; + struct gbm_surface *dummy_gbm_surface; + + CoglOnscreen *onscreen; +} CoglDisplayKMS; + +typedef struct _CoglFlipKMS +{ + CoglOnscreen *onscreen; + int pending; +} CoglFlipKMS; + +typedef struct _CoglOnscreenKMS +{ + struct gbm_surface *surface; + uint32_t current_fb_id; + uint32_t next_fb_id; + struct gbm_bo *current_bo; + struct gbm_bo *next_bo; + CoglBool pending_swap_notify; + + EGLSurface *pending_egl_surface; + struct gbm_surface *pending_surface; +} CoglOnscreenKMS; + +static void +_cogl_winsys_renderer_disconnect (CoglRenderer *renderer) +{ + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + + if (egl_renderer->edpy != EGL_NO_DISPLAY) + eglTerminate (egl_renderer->edpy); + + if (kms_renderer->gbm != NULL) + gbm_device_destroy (kms_renderer->gbm); + + g_slice_free (CoglRendererKMS, kms_renderer); + g_slice_free (CoglRendererEGL, egl_renderer); +} + +static void +flush_pending_swap_notify_cb (void *data, + void *user_data) +{ + CoglFramebuffer *framebuffer = data; + + if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) + { + CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; + + if (kms_onscreen->pending_swap_notify) + { + CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos); + + _cogl_onscreen_notify_frame_sync (onscreen, info); + _cogl_onscreen_notify_complete (onscreen, info); + kms_onscreen->pending_swap_notify = FALSE; + + cogl_object_unref (info); + } + } +} + +static void +flush_pending_swap_notify_idle (void *user_data) +{ + CoglContext *context = user_data; + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + + /* This needs to be disconnected before invoking the callbacks in + * case the callbacks cause it to be queued again */ + _cogl_closure_disconnect (kms_renderer->swap_notify_idle); + kms_renderer->swap_notify_idle = NULL; + + g_list_foreach (context->framebuffers, + flush_pending_swap_notify_cb, + NULL); +} + +static void +free_current_bo (CoglOnscreen *onscreen) +{ + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *renderer = context->display->renderer; + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + + if (kms_onscreen->current_fb_id) + { + drmModeRmFB (kms_renderer->fd, + kms_onscreen->current_fb_id); + kms_onscreen->current_fb_id = 0; + } + if (kms_onscreen->current_bo) + { + gbm_surface_release_buffer (kms_onscreen->surface, + kms_onscreen->current_bo); + kms_onscreen->current_bo = NULL; + } +} + +static void +queue_swap_notify_for_onscreen (CoglOnscreen *onscreen) +{ + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *renderer = context->display->renderer; + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + + /* We only want to notify that the swap is complete when the + * application calls cogl_context_dispatch so instead of + * immediately notifying we queue an idle callback */ + if (!kms_renderer->swap_notify_idle) + { + kms_renderer->swap_notify_idle = + _cogl_poll_renderer_add_idle (renderer, + flush_pending_swap_notify_idle, + context, + NULL); + } + + kms_onscreen->pending_swap_notify = TRUE; +} + +static void +process_flip (CoglFlipKMS *flip) +{ + /* We're only ready to dispatch a swap notification once all outputs + * have flipped... */ + flip->pending--; + if (flip->pending == 0) + { + CoglOnscreen *onscreen = flip->onscreen; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; + + queue_swap_notify_for_onscreen (onscreen); + + free_current_bo (onscreen); + + kms_onscreen->current_fb_id = kms_onscreen->next_fb_id; + kms_onscreen->next_fb_id = 0; + + kms_onscreen->current_bo = kms_onscreen->next_bo; + kms_onscreen->next_bo = NULL; + + cogl_object_unref (flip->onscreen); + + g_slice_free (CoglFlipKMS, flip); + } +} + +static void +page_flip_handler (int fd, + unsigned int frame, + unsigned int sec, + unsigned int usec, + void *data) +{ + CoglFlipKMS *flip = data; + + process_flip (flip); +} + +static void +handle_drm_event (CoglRendererKMS *kms_renderer) +{ + drmEventContext evctx; + + if (kms_renderer->page_flips_not_supported) + return; + + memset (&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.page_flip_handler = page_flip_handler; + drmHandleEvent (kms_renderer->fd, &evctx); +} + +static void +dispatch_kms_events (void *user_data, int revents) +{ + CoglRenderer *renderer = user_data; + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + + if (!revents) + return; + + handle_drm_event (kms_renderer); +} + +static CoglBool +_cogl_winsys_renderer_connect (CoglRenderer *cogl_renderer, + CoglError **error) +{ + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + CoglRendererEGL *egl_renderer; + CoglRendererKMS *kms_renderer; + + cogl_renderer->winsys = g_slice_new0 (CoglRendererEGL); + egl_renderer = cogl_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 = meta_renderer_native_get_kms_fd (renderer_native); + + egl_renderer->edpy = EGL_NO_DISPLAY; + + kms_renderer->gbm = gbm_create_device (kms_renderer->fd); + if (kms_renderer->gbm == NULL) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Couldn't create gbm device"); + goto fail; + } + + egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm); + if (egl_renderer->edpy == EGL_NO_DISPLAY) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Couldn't get eglDisplay"); + goto fail; + } + + if (!_cogl_winsys_egl_renderer_connect_common (cogl_renderer, error)) + goto fail; + + _cogl_poll_renderer_add_fd (cogl_renderer, + kms_renderer->fd, + COGL_POLL_FD_EVENT_IN, + NULL, /* no prepare callback */ + dispatch_kms_events, + cogl_renderer); + + return TRUE; + +fail: + _cogl_winsys_renderer_disconnect (cogl_renderer); + + return FALSE; +} + +static void +setup_crtc_modes (CoglDisplay *display, int fb_id) +{ + CoglDisplayEGL *egl_display = display->winsys; + CoglDisplayKMS *kms_display = egl_display->platform; + CoglRendererEGL *egl_renderer = display->renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + GList *l; + + for (l = kms_display->crtcs; l; l = l->next) + { + CoglKmsCrtc *crtc = l->data; + + int ret = drmModeSetCrtc (kms_renderer->fd, + crtc->id, + fb_id, crtc->x, crtc->y, + crtc->connectors, crtc->count, + crtc->count ? &crtc->mode : NULL); + if (ret) + g_warning ("Failed to set crtc mode %s: %m", crtc->mode.name); + } +} + +static void +flip_all_crtcs (CoglDisplay *display, CoglFlipKMS *flip, int fb_id) +{ + CoglDisplayEGL *egl_display = display->winsys; + CoglDisplayKMS *kms_display = egl_display->platform; + CoglRendererEGL *egl_renderer = display->renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + GList *l; + gboolean needs_flip = FALSE; + + for (l = kms_display->crtcs; l; l = l->next) + { + CoglKmsCrtc *crtc = l->data; + int ret = 0; + + if (crtc->count == 0 || crtc->ignore) + continue; + + needs_flip = TRUE; + + if (!kms_renderer->page_flips_not_supported) + { + ret = drmModePageFlip (kms_renderer->fd, + crtc->id, fb_id, + DRM_MODE_PAGE_FLIP_EVENT, flip); + if (ret != 0 && ret != -EACCES) + { + g_warning ("Failed to flip: %m"); + kms_renderer->page_flips_not_supported = TRUE; + break; + } + } + + if (ret == 0) + flip->pending++; + } + + if (kms_renderer->page_flips_not_supported && needs_flip) + flip->pending = 1; +} + +static void +crtc_free (CoglKmsCrtc *crtc) +{ + g_free (crtc->connectors); + g_slice_free (CoglKmsCrtc, crtc); +} + +static CoglKmsCrtc * +crtc_copy (CoglKmsCrtc *from) +{ + CoglKmsCrtc *new; + + new = g_slice_new (CoglKmsCrtc); + + *new = *from; + new->connectors = g_memdup (from->connectors, from->count * sizeof(uint32_t)); + + return new; +} + +static CoglBool +_cogl_winsys_egl_display_setup (CoglDisplay *display, + CoglError **error) +{ + CoglDisplayEGL *egl_display = display->winsys; + CoglDisplayKMS *kms_display; + CoglRendererEGL *egl_renderer = display->renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + + kms_display = g_slice_new0 (CoglDisplayKMS); + egl_display->platform = kms_display; + + /* Force a full modeset / drmModeSetCrtc on + * the first swap buffers call. + */ + kms_display->pending_set_crtc = TRUE; + + return TRUE; +} + +static void +_cogl_winsys_egl_display_destroy (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; + GList *l; + + g_list_free_full (kms_display->crtcs, (GDestroyNotify) crtc_free); + + g_slice_free (CoglDisplayKMS, egl_display->platform); +} + +static CoglBool +_cogl_winsys_egl_context_created (CoglDisplay *display, + CoglError **error) +{ + 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; + + if ((egl_renderer->private_features & + COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0) + { + kms_display->dummy_gbm_surface = + gbm_surface_create (kms_renderer->gbm, + 16, 16, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_RENDERING); + if (!kms_display->dummy_gbm_surface) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to create dummy GBM surface"); + return FALSE; + } + + egl_display->dummy_surface = + eglCreateWindowSurface (egl_renderer->edpy, + egl_display->egl_config, + (EGLNativeWindowType) + kms_display->dummy_gbm_surface, + NULL); + if (egl_display->dummy_surface == EGL_NO_SURFACE) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to create dummy EGL surface"); + return FALSE; + } + } + + if (!_cogl_winsys_egl_make_current (display, + egl_display->dummy_surface, + egl_display->dummy_surface, + egl_display->egl_context)) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to make context current"); + return FALSE; + } + + 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; + + if (egl_display->dummy_surface != EGL_NO_SURFACE) + { + eglDestroySurface (egl_renderer->edpy, egl_display->dummy_surface); + egl_display->dummy_surface = EGL_NO_SURFACE; + } + + if (kms_display->dummy_gbm_surface != NULL) + { + gbm_surface_destroy (kms_display->dummy_gbm_surface); + kms_display->dummy_gbm_surface = NULL; + } +} + +static void +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) +{ + 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; + uint32_t handle, stride; + CoglFlipKMS *flip; + + /* If we already have a pending swap then block until it completes */ + while (kms_onscreen->next_fb_id != 0) + handle_drm_event (kms_renderer); + + if (kms_onscreen->pending_egl_surface) + { + eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface); + egl_onscreen->egl_surface = kms_onscreen->pending_egl_surface; + kms_onscreen->pending_egl_surface = NULL; + + _cogl_framebuffer_winsys_update_size (COGL_FRAMEBUFFER (kms_display->onscreen), + kms_display->width, kms_display->height); + context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND; + } + parent_vtable->onscreen_swap_buffers_with_damage (onscreen, + rectangles, + n_rectangles); + + if (kms_onscreen->pending_surface) + { + free_current_bo (onscreen); + if (kms_onscreen->surface) + gbm_surface_destroy (kms_onscreen->surface); + kms_onscreen->surface = kms_onscreen->pending_surface; + kms_onscreen->pending_surface = NULL; + } + /* Now we need to set the CRTC to whatever is the front buffer */ + kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface); + + stride = gbm_bo_get_stride (kms_onscreen->next_bo); + handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32; + + if (drmModeAddFB (kms_renderer->fd, + kms_display->width, + kms_display->height, + 24, /* depth */ + 32, /* bpp */ + stride, + handle, + &kms_onscreen->next_fb_id)) + { + g_warning ("Failed to create new back buffer handle: %m"); + gbm_surface_release_buffer (kms_onscreen->surface, + kms_onscreen->next_bo); + kms_onscreen->next_bo = NULL; + kms_onscreen->next_fb_id = 0; + return; + } + + /* If this is the first framebuffer to be presented then we now setup the + * crtc modes, else we flip from the previous buffer */ + if (kms_display->pending_set_crtc) + { + setup_crtc_modes (context->display, kms_onscreen->next_fb_id); + kms_display->pending_set_crtc = FALSE; + } + + flip = g_slice_new0 (CoglFlipKMS); + flip->onscreen = onscreen; + + flip_all_crtcs (context->display, flip, kms_onscreen->next_fb_id); + + if (flip->pending == 0) + { + drmModeRmFB (kms_renderer->fd, kms_onscreen->next_fb_id); + gbm_surface_release_buffer (kms_onscreen->surface, + kms_onscreen->next_bo); + kms_onscreen->next_bo = NULL; + kms_onscreen->next_fb_id = 0; + g_slice_free (CoglFlipKMS, flip); + flip = NULL; + + queue_swap_notify_for_onscreen (onscreen); + } + else + { + /* Ensure the onscreen remains valid while it has any pending flips... */ + cogl_object_ref (flip->onscreen); + + /* Process flip right away if we can't wait for vblank */ + if (kms_renderer->page_flips_not_supported) + { + setup_crtc_modes (context->display, kms_onscreen->next_fb_id); + process_flip (flip); + } + } +} + +static CoglBool +_cogl_winsys_egl_context_init (CoglContext *context, + CoglError **error) +{ + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE); + /* TODO: remove this deprecated feature */ + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, + TRUE); + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, + TRUE); + + return TRUE; +} + +static CoglBool +_cogl_winsys_onscreen_init (CoglOnscreen *onscreen, + CoglError **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; + + _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE); + + if (kms_display->onscreen) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Cannot have multiple onscreens in the KMS platform"); + return FALSE; + } + + kms_display->onscreen = onscreen; + + onscreen->winsys = g_slice_new0 (CoglOnscreenEGL); + egl_onscreen = onscreen->winsys; + + kms_onscreen = g_slice_new0 (CoglOnscreenKMS); + egl_onscreen->platform = kms_onscreen; + + /* If a kms_fd is set then the display width and height + * won't be available until meta_renderer_native_set_layout + * is called. In that case, defer creating the surface + * until then. + */ + if (kms_display->width == 0 || + kms_display->height == 0) + return TRUE; + + kms_onscreen->surface = + gbm_surface_create (kms_renderer->gbm, + kms_display->width, + kms_display->height, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | + GBM_BO_USE_RENDERING); + + if (!kms_onscreen->surface) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Failed to allocate surface"); + return FALSE; + } + + egl_onscreen->egl_surface = + eglCreateWindowSurface (egl_renderer->edpy, + egl_display->egl_config, + (EGLNativeWindowType) kms_onscreen->surface, + NULL); + if (egl_onscreen->egl_surface == EGL_NO_SURFACE) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Failed to allocate surface"); + return FALSE; + } + + _cogl_framebuffer_winsys_update_size (framebuffer, + kms_display->width, + kms_display->height); + + return TRUE; +} + +static void +_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) +{ + 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 = context->display->renderer; + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglOnscreenKMS *kms_onscreen; + + /* If we never successfully allocated then there's nothing to do */ + if (egl_onscreen == NULL) + return; + + kms_display->onscreen = NULL; + + kms_onscreen = 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 (kms_onscreen->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 (kms_onscreen->surface) + { + gbm_surface_destroy (kms_onscreen->surface); + kms_onscreen->surface = NULL; + } + + g_slice_free (CoglOnscreenKMS, kms_onscreen); + g_slice_free (CoglOnscreenEGL, onscreen->winsys); + onscreen->winsys = NULL; +} + +static const CoglWinsysEGLVtable +_cogl_winsys_egl_vtable = { + .display_setup = _cogl_winsys_egl_display_setup, + .display_destroy = _cogl_winsys_egl_display_destroy, + .context_created = _cogl_winsys_egl_context_created, + .cleanup_context = _cogl_winsys_egl_cleanup_context, + .context_init = _cogl_winsys_egl_context_init +}; + +struct gbm_device * +meta_renderer_native_get_gbm (MetaRendererNative *renderer_native) +{ + ClutterBackend *clutter_backend = clutter_get_default_backend (); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); + CoglRenderer *renderer = cogl_display->renderer; + + if (renderer->connected) + { + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + return kms_renderer->gbm; + } + else + { + return NULL; + } +} + +int +meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native) +{ + return renderer_native->kms_fd; +} + +void +meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native) +{ + ClutterBackend *clutter_backend = clutter_get_default_backend (); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); + + if (cogl_display->setup) + { + CoglDisplayEGL *egl_display = cogl_display->winsys; + CoglDisplayKMS *kms_display = egl_display->platform; + kms_display->pending_set_crtc = TRUE; + } +} + +gboolean +meta_renderer_native_set_layout (MetaRendererNative *renderer_native, + int width, + int height, + CoglKmsCrtc **crtcs, + int n_crtcs, + GError **error) +{ + ClutterBackend *clutter_backend = clutter_get_default_backend (); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); + CoglDisplayEGL *egl_display = cogl_display->winsys; + CoglDisplayKMS *kms_display = egl_display->platform; + CoglRenderer *renderer = cogl_display->renderer; + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglRendererKMS *kms_renderer = egl_renderer->platform; + GList *crtc_list; + int i; + + if ((width != kms_display->width || + height != kms_display->height) && + kms_display->onscreen) + { + CoglOnscreenEGL *egl_onscreen = kms_display->onscreen->winsys; + CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; + struct gbm_surface *new_surface; + EGLSurface new_egl_surface; + + /* Need to drop the GBM surface and create a new one */ + + new_surface = gbm_surface_create (kms_renderer->gbm, + width, height, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | + GBM_BO_USE_RENDERING); + + if (!new_surface) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Failed to allocate new surface"); + return FALSE; + } + + new_egl_surface = + eglCreateWindowSurface (egl_renderer->edpy, + egl_display->egl_config, + (EGLNativeWindowType) new_surface, + NULL); + if (new_egl_surface == EGL_NO_SURFACE) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Failed to allocate new surface"); + gbm_surface_destroy (new_surface); + return FALSE; + } + + if (kms_onscreen->pending_egl_surface) + eglDestroySurface (egl_renderer->edpy, kms_onscreen->pending_egl_surface); + if (kms_onscreen->pending_surface) + gbm_surface_destroy (kms_onscreen->pending_surface); + + /* If there's already a surface, wait until the next swap to switch + * it out, otherwise, if we're just starting up we can use the new + * surface right away. + */ + if (kms_onscreen->surface != NULL) + { + kms_onscreen->pending_surface = new_surface; + kms_onscreen->pending_egl_surface = new_egl_surface; + } + else + { + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (kms_display->onscreen); + + kms_onscreen->surface = new_surface; + egl_onscreen->egl_surface = new_egl_surface; + + _cogl_framebuffer_winsys_update_size (framebuffer, width, height); + } + } + + kms_display->width = width; + kms_display->height = height; + + g_list_free_full (kms_display->crtcs, (GDestroyNotify) crtc_free); + + crtc_list = NULL; + for (i = 0; i < n_crtcs; i++) + { + crtc_list = g_list_prepend (crtc_list, crtc_copy (crtcs[i])); + } + crtc_list = g_list_reverse (crtc_list); + kms_display->crtcs = crtc_list; + + kms_display->pending_set_crtc = TRUE; + + return TRUE; +} + +void +meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native, + uint32_t id, + gboolean ignore) +{ + ClutterBackend *clutter_backend = clutter_get_default_backend (); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); + CoglDisplayEGL *egl_display = cogl_display->winsys; + CoglDisplayKMS *kms_display = egl_display->platform; + GList *l; + + for (l = kms_display->crtcs; l; l = l->next) + { + CoglKmsCrtc *crtc = l->data; + if (crtc->id == id) + { + crtc->ignore = ignore; + break; + } + } +} + +static const CoglWinsysVtable * +get_native_cogl_winsys_vtable (void) +{ + static CoglBool vtable_inited = FALSE; + static CoglWinsysVtable vtable; + + if (!vtable_inited) + { + /* The this winsys is a subclass of the EGL winsys so we + start by copying its vtable */ + + parent_vtable = _cogl_winsys_egl_get_vtable (); + vtable = *parent_vtable; + + vtable.id = COGL_WINSYS_ID_CUSTOM; + 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; + + /* The KMS winsys doesn't support swap region */ + vtable.onscreen_swap_region = NULL; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; + + vtable_inited = TRUE; + } + + return &vtable; +} + static CoglRenderer * meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer) { - MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); CoglRenderer *cogl_renderer; cogl_renderer = cogl_renderer_new (); cogl_renderer_set_custom_winsys (cogl_renderer, - _cogl_winsys_egl_kms_get_vtable); - cogl_kms_renderer_set_kms_fd (cogl_renderer, renderer_native->kms_fd); + get_native_cogl_winsys_vtable); return cogl_renderer; } diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index ce6a66fa0..4ac4cba81 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -26,12 +26,41 @@ #define META_RENDERER_NATIVE_H #include +#include #include "backends/meta-renderer.h" +typedef struct { + uint32_t id; + uint32_t x, y; + drmModeModeInfo mode; + + uint32_t *connectors; + uint32_t count; + + CoglBool ignore; +} CoglKmsCrtc; + #define META_TYPE_RENDERER_NATIVE (meta_renderer_native_get_type ()) G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native, META, RENDERER_NATIVE, MetaRenderer) +struct gbm_device * meta_renderer_native_get_gbm (MetaRendererNative *renderer_native); + +int meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native); + +void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); + +gboolean meta_renderer_native_set_layout (MetaRendererNative *renderer_native, + int width, + int height, + CoglKmsCrtc **crtcs, + int n_crtcs, + GError **error); + +void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native, + uint32_t id, + gboolean ignore); + #endif /* META_RENDERER_NATIVE_H */