kms: Implement the swap buffers notify feature

The KMS EGL platform now notifies when a swap is complete. The
notification is delayed until the application calls
cogl_context_dispatch. The GLX backend doesn't currently do this but I
think that is how it should behave to make it easier for the
application to handle locks and such.

Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
Neil Roberts 2011-12-19 19:28:30 +00:00
parent cfefff1500
commit f9d3ea03ec

View File

@ -68,6 +68,7 @@ typedef struct _CoglDisplayKMS
drmModeModeInfo mode;
drmModeCrtcPtr saved_crtc;
int width, height;
gboolean pending_swap_notify;
} CoglDisplayKMS;
typedef struct _CoglOnscreenKMS
@ -77,6 +78,7 @@ typedef struct _CoglOnscreenKMS
uint32_t next_fb_id;
struct gbm_bo *current_bo;
struct gbm_bo *next_bo;
gboolean pending_swap_notify;
} CoglOnscreenKMS;
static const char device_name[] = "/dev/dri/card0";
@ -313,13 +315,8 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
}
static void
page_flip_handler (int fd,
unsigned int frame,
unsigned int sec,
unsigned int usec,
void *data)
free_current_bo (CoglOnscreen *onscreen)
{
CoglOnscreen *onscreen = data;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
@ -339,12 +336,36 @@ page_flip_handler (int fd,
kms_onscreen->current_bo);
kms_onscreen->current_bo = NULL;
}
}
static void
page_flip_handler (int fd,
unsigned int frame,
unsigned int sec,
unsigned int usec,
void *data)
{
CoglOnscreen *onscreen = data;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglDisplay *display = context->display;
CoglDisplayEGL *egl_display = display->winsys;
CoglDisplayKMS *kms_display = egl_display->platform;
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;
/* We only want to notify that the swap is complete when the
application calls cogl_context_dispatch so instead of immediately
notifying we'll set a flag to remember to notify later */
kms_display->pending_swap_notify = TRUE;
kms_onscreen->pending_swap_notify = TRUE;
}
static void
@ -408,6 +429,19 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
}
}
static gboolean
_cogl_winsys_egl_context_init (CoglContext *context,
GError **error)
{
COGL_FLAGS_SET (context->features,
COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE);
COGL_FLAGS_SET (context->winsys_features,
COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
TRUE);
return TRUE;
}
static gboolean
_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
GError **error)
@ -474,6 +508,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
CoglContext *context = framebuffer->context;
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen;
@ -483,6 +518,12 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
kms_onscreen = egl_onscreen->platform;
/* If have a pending swap then block until it completes */
while (kms_onscreen->next_fb_id != 0)
handle_drm_event (kms_renderer);
free_current_bo (onscreen);
if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
@ -506,13 +547,39 @@ _cogl_winsys_poll_get_info (CoglContext *context,
int *n_poll_fds,
gint64 *timeout)
{
CoglRenderer *renderer = context->display->renderer;
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;
*poll_fds = &kms_renderer->poll_fd;
*n_poll_fds = 1;
*timeout = -1;
/* If we've already got a pending swap notify then we'll dispatch
immediately */
*timeout = kms_display->pending_swap_notify ? 0 : -1;
}
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)
{
_cogl_onscreen_notify_swap_buffers (onscreen);
kms_onscreen->pending_swap_notify = FALSE;
}
}
}
static void
@ -520,7 +587,10 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
const CoglPollFD *poll_fds,
int n_poll_fds)
{
CoglRenderer *renderer = context->display->renderer;
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;
int i;
@ -533,6 +603,14 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
break;
}
if (kms_display->pending_swap_notify)
{
g_list_foreach (context->framebuffers,
flush_pending_swap_notify_cb,
NULL);
kms_display->pending_swap_notify = FALSE;
}
}
static const CoglWinsysEGLVtable
@ -541,7 +619,8 @@ _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
.cleanup_context = _cogl_winsys_egl_cleanup_context,
.context_init = _cogl_winsys_egl_context_init
};
const CoglWinsysVtable *