2016-05-07 15:07:46 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
2016-05-09 11:51:29 +00:00
|
|
|
* Copyright (C) 2011 Intel Corporation.
|
2016-05-07 15:07:46 +00:00
|
|
|
* Copyright (C) 2016 Red Hat
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2016-05-09 11:51:29 +00:00
|
|
|
* Authors:
|
|
|
|
* Rob Bradford <rob@linux.intel.com> (from cogl-winsys-egl-kms.c)
|
|
|
|
* Kristian Høgsberg (from eglkms.c)
|
|
|
|
* Benjamin Franzke (from eglkms.c)
|
|
|
|
* Robert Bragg <robert@linux.intel.com> (from cogl-winsys-egl-kms.c)
|
|
|
|
* Neil Roberts <neil@linux.intel.com> (from cogl-winsys-egl-kms.c)
|
|
|
|
* Jonas Ådahl <jadahl@redhat.com>
|
|
|
|
*
|
2016-05-07 15:07:46 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <gbm.h>
|
2016-05-09 13:22:01 +00:00
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <glib-object.h>
|
2016-05-09 11:51:29 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <xf86drm.h>
|
2016-05-07 15:07:46 +00:00
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
#include "backends/meta-backend-private.h"
|
2016-05-07 15:07:46 +00:00
|
|
|
#include "backends/native/meta-renderer-native.h"
|
2016-05-07 15:09:59 +00:00
|
|
|
#include "cogl/cogl.h"
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_KMS_FD,
|
|
|
|
|
|
|
|
PROP_LAST
|
|
|
|
};
|
2016-05-07 15:07:46 +00:00
|
|
|
|
|
|
|
struct _MetaRendererNative
|
|
|
|
{
|
|
|
|
MetaRenderer parent;
|
2016-05-07 15:09:59 +00:00
|
|
|
|
|
|
|
int kms_fd;
|
2016-05-09 13:22:01 +00:00
|
|
|
struct gbm_device *gbm;
|
|
|
|
CoglClosure *swap_notify_idle;
|
|
|
|
CoglBool page_flips_not_supported;
|
2016-05-07 15:07:46 +00:00
|
|
|
};
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *initable_iface);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (MetaRendererNative,
|
|
|
|
meta_renderer_native,
|
|
|
|
META_TYPE_RENDERER,
|
|
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
|
|
|
initable_iface_init))
|
2016-05-07 15:07:46 +00:00
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
|
|
|
|
static const CoglWinsysVtable *parent_vtable;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (egl_renderer->edpy != EGL_NO_DISPLAY)
|
|
|
|
eglTerminate (egl_renderer->edpy);
|
|
|
|
|
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
/* This needs to be disconnected before invoking the callbacks in
|
|
|
|
* case the callbacks cause it to be queued again */
|
2016-05-09 13:22:01 +00:00
|
|
|
_cogl_closure_disconnect (renderer_native->swap_notify_idle);
|
|
|
|
renderer_native->swap_notify_idle = NULL;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
if (kms_onscreen->current_fb_id)
|
|
|
|
{
|
2016-05-09 13:22:01 +00:00
|
|
|
drmModeRmFB (renderer_native->kms_fd,
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
/* 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 */
|
2016-05-09 13:22:01 +00:00
|
|
|
if (!renderer_native->swap_notify_idle)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2016-05-09 13:22:01 +00:00
|
|
|
renderer_native->swap_notify_idle =
|
2016-05-09 11:51:29 +00:00
|
|
|
_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
|
2016-05-09 13:22:01 +00:00
|
|
|
handle_drm_event (MetaRendererNative *renderer_native)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
drmEventContext evctx;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
if (renderer_native->page_flips_not_supported)
|
2016-05-09 11:51:29 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
memset (&evctx, 0, sizeof evctx);
|
|
|
|
evctx.version = DRM_EVENT_CONTEXT_VERSION;
|
|
|
|
evctx.page_flip_handler = page_flip_handler;
|
2016-05-09 13:22:01 +00:00
|
|
|
drmHandleEvent (renderer_native->kms_fd, &evctx);
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dispatch_kms_events (void *user_data, int revents)
|
|
|
|
{
|
|
|
|
CoglRenderer *renderer = user_data;
|
|
|
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
if (!revents)
|
|
|
|
return;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
handle_drm_event (renderer_native);
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
cogl_renderer->winsys = g_slice_new0 (CoglRendererEGL);
|
|
|
|
egl_renderer = cogl_renderer->winsys;
|
|
|
|
|
|
|
|
egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
|
2016-05-09 13:22:01 +00:00
|
|
|
egl_renderer->platform = renderer_native;
|
2016-05-09 11:51:29 +00:00
|
|
|
egl_renderer->edpy = EGL_NO_DISPLAY;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
if (renderer_native->gbm == NULL)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
_cogl_set_error (error, COGL_WINSYS_ERROR,
|
|
|
|
COGL_WINSYS_ERROR_INIT,
|
|
|
|
"Couldn't create gbm device");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
egl_renderer->edpy =
|
|
|
|
eglGetDisplay ((EGLNativeDisplayType) renderer_native->gbm);
|
2016-05-09 11:51:29 +00:00
|
|
|
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,
|
2016-05-09 13:22:01 +00:00
|
|
|
renderer_native->kms_fd,
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = kms_display->crtcs; l; l = l->next)
|
|
|
|
{
|
|
|
|
CoglKmsCrtc *crtc = l->data;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
int ret = drmModeSetCrtc (renderer_native->kms_fd,
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
if (!renderer_native->page_flips_not_supported)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2016-05-09 13:22:01 +00:00
|
|
|
ret = drmModePageFlip (renderer_native->kms_fd,
|
2016-05-09 11:51:29 +00:00
|
|
|
crtc->id, fb_id,
|
|
|
|
DRM_MODE_PAGE_FLIP_EVENT, flip);
|
|
|
|
if (ret != 0 && ret != -EACCES)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to flip: %m");
|
2016-05-09 13:22:01 +00:00
|
|
|
renderer_native->page_flips_not_supported = TRUE;
|
2016-05-09 11:51:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
flip->pending++;
|
|
|
|
}
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
if (renderer_native->page_flips_not_supported && needs_flip)
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
if ((egl_renderer->private_features &
|
|
|
|
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0)
|
|
|
|
{
|
|
|
|
kms_display->dummy_gbm_surface =
|
2016-05-09 13:22:01 +00:00
|
|
|
gbm_surface_create (renderer_native->gbm,
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
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)
|
2016-05-09 13:22:01 +00:00
|
|
|
handle_drm_event (renderer_native);
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
if (drmModeAddFB (renderer_native->kms_fd,
|
2016-05-09 11:51:29 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-05-09 13:22:01 +00:00
|
|
|
drmModeRmFB (renderer_native->kms_fd, kms_onscreen->next_fb_id);
|
2016-05-09 11:51:29 +00:00
|
|
|
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 */
|
2016-05-09 13:22:01 +00:00
|
|
|
if (renderer_native->page_flips_not_supported)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
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;
|
2016-05-09 13:22:01 +00:00
|
|
|
MetaRendererNative *renderer_native = egl_renderer->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
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 =
|
2016-05-09 13:22:01 +00:00
|
|
|
gbm_surface_create (renderer_native->gbm,
|
2016-05-09 11:51:29 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-05-09 13:22:01 +00:00
|
|
|
return renderer_native->gbm;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
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 */
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
new_surface = gbm_surface_create (renderer_native->gbm,
|
2016-05-09 11:51:29 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-05-09 01:59:54 +00:00
|
|
|
static CoglRenderer *
|
|
|
|
meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer)
|
|
|
|
{
|
|
|
|
CoglRenderer *cogl_renderer;
|
|
|
|
|
|
|
|
cogl_renderer = cogl_renderer_new ();
|
|
|
|
cogl_renderer_set_custom_winsys (cogl_renderer,
|
2016-05-09 11:51:29 +00:00
|
|
|
get_native_cogl_winsys_vtable);
|
2016-05-09 01:59:54 +00:00
|
|
|
|
|
|
|
return cogl_renderer;
|
|
|
|
}
|
|
|
|
|
2016-05-07 15:09:59 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_KMS_FD:
|
|
|
|
g_value_set_int (value, renderer_native->kms_fd);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_renderer_native_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_KMS_FD:
|
|
|
|
renderer_native->kms_fd = g_value_get_int (value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
|
|
|
g_clear_pointer (&renderer_native->gbm, gbm_device_destroy);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_renderer_native_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_initable_init (GInitable *initable,
|
|
|
|
GCancellable *cancellable,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (initable);
|
|
|
|
|
|
|
|
renderer_native->gbm = gbm_create_device (renderer_native->kms_fd);
|
|
|
|
if (!renderer_native->gbm)
|
|
|
|
{
|
|
|
|
g_set_error (error,
|
|
|
|
G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Failed to create gbm device");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *initable_iface)
|
|
|
|
{
|
|
|
|
initable_iface->init = meta_renderer_native_initable_init;
|
|
|
|
}
|
|
|
|
|
2016-05-07 15:07:46 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_init (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_renderer_native_class_init (MetaRendererNativeClass *klass)
|
|
|
|
{
|
2016-05-07 15:09:59 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2016-05-09 01:59:54 +00:00
|
|
|
MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
|
2016-05-07 15:09:59 +00:00
|
|
|
|
|
|
|
object_class->get_property = meta_renderer_native_get_property;
|
|
|
|
object_class->set_property = meta_renderer_native_set_property;
|
2016-05-09 13:22:01 +00:00
|
|
|
object_class->finalize = meta_renderer_native_finalize;
|
2016-05-07 15:09:59 +00:00
|
|
|
|
2016-05-09 01:59:54 +00:00
|
|
|
renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
|
|
|
|
|
2016-05-07 15:09:59 +00:00
|
|
|
g_object_class_install_property (object_class,
|
|
|
|
PROP_KMS_FD,
|
|
|
|
g_param_spec_int ("kms-fd",
|
|
|
|
"KMS fd",
|
|
|
|
"The KMS file descriptor",
|
|
|
|
0, G_MAXINT, 0,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY));
|
2016-05-07 15:07:46 +00:00
|
|
|
}
|
2016-05-09 13:22:01 +00:00
|
|
|
|
|
|
|
MetaRendererNative *
|
|
|
|
meta_renderer_native_new (int kms_fd,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native;
|
|
|
|
|
|
|
|
renderer_native = g_object_new (META_TYPE_RENDERER_NATIVE,
|
|
|
|
"kms-fd", kms_fd,
|
|
|
|
NULL);
|
|
|
|
if (!g_initable_init (G_INITABLE (renderer_native), NULL, error))
|
|
|
|
{
|
|
|
|
g_object_unref (renderer_native);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return renderer_native;
|
|
|
|
}
|