kms-winsys: try to hobble along if driver doesn't support page flips
Some drivers ( like mgag200 ) don't yet support drmModePageFlip. This commit tries to emulate the functionality using drmWaitVBlank and drmModeSetCrtc in those cases. Failing all else, it just falls back to flipping right away. https://bugzilla.gnome.org/show_bug.cgi?id=746042
This commit is contained in:
parent
e215b9fefd
commit
4ae3216143
423
0001-kms-winsys-try-to-hobble-along-if-driver-doesn-t-sup.patch
Normal file
423
0001-kms-winsys-try-to-hobble-along-if-driver-doesn-t-sup.patch
Normal file
@ -0,0 +1,423 @@
|
||||
From 5c22141866e5335dd111b64349f6ff2ee484a6b4 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 11 Mar 2015 12:09:51 -0400
|
||||
Subject: [PATCH] kms-winsys: try to hobble along if driver doesn't support
|
||||
page flips
|
||||
|
||||
Some drivers ( like mgag200 ) don't yet support drmModePageFlip.
|
||||
|
||||
This commit tries to emulate the functionality using drmWaitVBlank
|
||||
and drmModeSetCrtc in those cases.
|
||||
|
||||
Failing all else, it just falls back to flipping right away.
|
||||
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=746042
|
||||
---
|
||||
cogl/winsys/cogl-winsys-egl-kms.c | 130 +++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 115 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
|
||||
index b06c1da..c66eb45 100644
|
||||
--- a/cogl/winsys/cogl-winsys-egl-kms.c
|
||||
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
|
||||
@@ -45,104 +45,107 @@
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <gbm.h>
|
||||
#include <glib.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cogl-winsys-egl-kms-private.h"
|
||||
#include "cogl-winsys-egl-private.h"
|
||||
#include "cogl-renderer-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-onscreen-private.h"
|
||||
#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;
|
||||
+ CoglBool vblank_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 setup_crtc_modes (CoglDisplay *display, int fb_id);
|
||||
|
||||
static void
|
||||
_cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
|
||||
{
|
||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||
CoglRendererKMS *kms_renderer = egl_renderer->platform;
|
||||
|
||||
eglTerminate (egl_renderer->edpy);
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -197,101 +200,168 @@ free_current_bo (CoglOnscreen *onscreen)
|
||||
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
|
||||
-page_flip_handler (int fd,
|
||||
- unsigned int frame,
|
||||
- unsigned int sec,
|
||||
- unsigned int usec,
|
||||
- void *data)
|
||||
+process_flip (CoglFlipKMS *flip)
|
||||
{
|
||||
- CoglFlipKMS *flip = data;
|
||||
-
|
||||
/* 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
|
||||
+process_vblank (CoglFlipKMS *flip)
|
||||
+{
|
||||
+ /* Normally the driver would set the next fb up for
|
||||
+ * scan out after vblank for us and then call the
|
||||
+ * page flip handler to clean things up.
|
||||
+ *
|
||||
+ * Not all drivers support the newer page flipping interface
|
||||
+ * that provides this functionality, though, so try to emulate
|
||||
+ * it
|
||||
+ */
|
||||
+ if (flip->pending == 1)
|
||||
+ {
|
||||
+ CoglOnscreen *onscreen = flip->onscreen;
|
||||
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
|
||||
+ CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
|
||||
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
+ CoglContext *context = framebuffer->context;
|
||||
+ CoglDisplay *display = context->display;
|
||||
+
|
||||
+ setup_crtc_modes (display, kms_onscreen->next_fb_id);
|
||||
+
|
||||
+ process_flip (flip);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+vblank_handler (int fd,
|
||||
+ unsigned int frame,
|
||||
+ unsigned int sec,
|
||||
+ unsigned int usec,
|
||||
+ void *data)
|
||||
+{
|
||||
+ CoglFlipKMS *flip = data;
|
||||
+
|
||||
+ process_vblank (flip);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+fake_vblank_timeout_handler (gpointer data)
|
||||
+{
|
||||
+ CoglFlipKMS *flip = data;
|
||||
+
|
||||
+ /* Normally the next fb would get setup for
|
||||
+ * scan out after a vblank interval.
|
||||
+ *
|
||||
+ * Not all drivers support vblank notification, though,
|
||||
+ * so this handler just processes things right away.
|
||||
+ */
|
||||
+ process_vblank (flip);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
handle_drm_event (CoglRendererKMS *kms_renderer)
|
||||
{
|
||||
drmEventContext evctx;
|
||||
|
||||
+ if (kms_renderer->page_flips_not_supported &&
|
||||
+ kms_renderer->vblank_not_supported)
|
||||
+ return;
|
||||
+
|
||||
memset (&evctx, 0, sizeof evctx);
|
||||
evctx.version = DRM_EVENT_CONTEXT_VERSION;
|
||||
- evctx.page_flip_handler = page_flip_handler;
|
||||
+ if (kms_renderer->page_flips_not_supported)
|
||||
+ evctx.vblank_handler = vblank_handler;
|
||||
+ else
|
||||
+ 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;
|
||||
|
||||
@@ -552,75 +622,105 @@ setup_crtc_modes (CoglDisplay *display, int fb_id)
|
||||
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;
|
||||
|
||||
for (l = kms_display->crtcs; l; l = l->next)
|
||||
{
|
||||
CoglKmsCrtc *crtc = l->data;
|
||||
- int ret;
|
||||
+ int ret = -1;
|
||||
|
||||
if (crtc->count == 0 || crtc->ignore)
|
||||
continue;
|
||||
|
||||
- ret = drmModePageFlip (kms_renderer->fd,
|
||||
- crtc->id, fb_id,
|
||||
- DRM_MODE_PAGE_FLIP_EVENT, flip);
|
||||
+ if (!kms_renderer->page_flips_not_supported)
|
||||
+ {
|
||||
+ ret = drmModePageFlip (kms_renderer->fd,
|
||||
+ crtc->id, fb_id,
|
||||
+ DRM_MODE_PAGE_FLIP_EVENT, flip);
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ g_warning ("Failed to flip: %m");
|
||||
+ kms_renderer->page_flips_not_supported = TRUE;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if (ret)
|
||||
+ if (kms_renderer->page_flips_not_supported)
|
||||
{
|
||||
- g_warning ("Failed to flip: %m");
|
||||
- continue;
|
||||
+ drmVBlank watch_for_next_vblank_operation = { 0 };
|
||||
+
|
||||
+ if (!kms_renderer->vblank_not_supported)
|
||||
+ {
|
||||
+ /* fall back to older way of waiting for vblanks directly
|
||||
+ */
|
||||
+ watch_for_next_vblank_operation.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
|
||||
+ watch_for_next_vblank_operation.request.sequence = 1;
|
||||
+ watch_for_next_vblank_operation.request.signal = (gulong) flip;
|
||||
+
|
||||
+ ret = drmWaitVBlank (kms_renderer->fd, &watch_for_next_vblank_operation);
|
||||
+
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ kms_renderer->vblank_not_supported = TRUE;
|
||||
+ g_warning ("Failed to fall back to waiting for vblanks directly: %m");
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
+ if (kms_renderer->page_flips_not_supported &&
|
||||
+ kms_renderer->vblank_not_supported)
|
||||
+ {
|
||||
+ g_idle_add (fake_vblank_timeout_handler, flip);
|
||||
+ }
|
||||
+
|
||||
flip->pending++;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
--
|
||||
2.3.1
|
||||
|
@ -6,13 +6,14 @@
|
||||
|
||||
Name: cogl
|
||||
Version: 1.20.0
|
||||
Release: 1%{?dist}
|
||||
Release: 2%{?dist}
|
||||
Summary: A library for using 3D graphics hardware to draw pretty pictures
|
||||
|
||||
Group: Development/Libraries
|
||||
License: LGPLv2+
|
||||
URL: http://www.clutter-project.org/
|
||||
Source0: http://download.gnome.org/sources/cogl/1.20/cogl-%{version}.tar.xz
|
||||
Patch0: 0001-kms-winsys-try-to-hobble-along-if-driver-doesn-t-sup.patch
|
||||
|
||||
BuildRequires: cairo-devel
|
||||
BuildRequires: chrpath
|
||||
@ -88,6 +89,7 @@ This package contains the installable tests for %{cogl}.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
%patch0 -p1 -b .fall-back-if-no-page-flips
|
||||
|
||||
%build
|
||||
CFLAGS="$RPM_OPT_FLAGS -fPIC"
|
||||
@ -152,6 +154,9 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/libcogl-pango.so
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Wed Mar 11 2015 Ray Strode <rstrode@redhat.com> 1.20.0-2
|
||||
- Try to fix wayland on mgag200
|
||||
|
||||
* Mon Feb 23 2015 Kalev Lember <kalevlember@gmail.com> - 1.20.0-1
|
||||
- Update to 1.20.0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user