onscreen: Add CoglFrameInfo and _add_frame_callback() api
Add a CoglFrameInfo object that tracks timing information for frames that are drawn. We track a frame counter and frame timing information for each CoglOnscreen. Internally a CoglFrameInfo is automatically created for each frame, delimited by cogl_onscreen_swap_buffers() or cogl_onscreen_swap_region() calls. CoglFrameInfos are delivered to applications via frame event callbacks that can be registered with a new cogl_onscreen_add_frame_callback() api. Two initial event types (dispatched on all platforms) have been defined; a _SYNC event used for throttling the frame rate of applications and a _COMPLETE event used so signify the end of a frame. Note: This new _add_frame_callback() api makes the cogl_onscreen_add_swap_complete_callback() api redundant and so it should be considered deprecated. Since the _add_swap_complete_callback() api is still experimental api, we will be looking to quickly migrate users to the new api so we can remove the old api. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 700401667db2522045e4623d78797b17f9184501)
This commit is contained in:
parent
5ce058c0e5
commit
24733abf68
@ -112,6 +112,7 @@ cogl_experimental_h = \
|
||||
$(srcdir)/cogl-clip-state.h \
|
||||
$(srcdir)/cogl-framebuffer.h \
|
||||
$(srcdir)/cogl-onscreen.h \
|
||||
$(srcdir)/cogl-frame-info.h \
|
||||
$(srcdir)/cogl-vector.h \
|
||||
$(srcdir)/cogl-euler.h \
|
||||
$(srcdir)/cogl-output.h \
|
||||
@ -384,6 +385,8 @@ cogl_sources_c = \
|
||||
$(srcdir)/cogl-spans.c \
|
||||
$(srcdir)/cogl-journal-private.h \
|
||||
$(srcdir)/cogl-journal.c \
|
||||
$(srcdir)/cogl-frame-info-private.h \
|
||||
$(srcdir)/cogl-frame-info.c \
|
||||
$(srcdir)/cogl-framebuffer-private.h \
|
||||
$(srcdir)/cogl-framebuffer.c \
|
||||
$(srcdir)/cogl-onscreen-private.h \
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "cogl-gpu-info-private.h"
|
||||
#include "cogl-gl-header.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-onscreen-private.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -190,6 +191,11 @@ struct _CoglContext
|
||||
gboolean have_last_offscreen_allocate_flags;
|
||||
CoglOffscreenAllocateFlags last_offscreen_allocate_flags;
|
||||
|
||||
GHashTable *swap_callback_closures;
|
||||
int next_swap_callback_id;
|
||||
|
||||
CoglOnscreenEventList onscreen_events_queue;
|
||||
|
||||
CoglGLES2Context *current_gles2_context;
|
||||
GQueue gles2_context_stack;
|
||||
|
||||
|
@ -312,6 +312,11 @@ cogl_context_new (CoglDisplay *display,
|
||||
context->current_draw_buffer_state_flushed = 0;
|
||||
context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
|
||||
|
||||
context->swap_callback_closures =
|
||||
g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
COGL_TAILQ_INIT (&context->onscreen_events_queue);
|
||||
|
||||
g_queue_init (&context->gles2_context_stack);
|
||||
|
||||
context->journal_flush_attributes_array =
|
||||
@ -507,6 +512,9 @@ _cogl_context_free (CoglContext *context)
|
||||
if (context->blit_texture_pipeline)
|
||||
cogl_object_unref (context->blit_texture_pipeline);
|
||||
|
||||
if (context->swap_callback_closures)
|
||||
g_hash_table_destroy (context->swap_callback_closures);
|
||||
|
||||
g_warn_if_fail (context->gles2_context_stack.length == 0);
|
||||
|
||||
if (context->journal_flush_attributes_array)
|
||||
|
@ -208,6 +208,8 @@ cogl_is_context (void *object);
|
||||
* suported.
|
||||
* @COGL_FEATURE_ID_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering
|
||||
* the depth buffer to a texture.
|
||||
* @COGL_FEATURE_ID_PRESENTATION_TIME: Whether frame presentation
|
||||
* time stamps will be recorded in #CoglFrameInfo objects.
|
||||
*
|
||||
* All the capabilities that can vary between different GPUs supported
|
||||
* by Cogl. Applications that depend on any of these features should explicitly
|
||||
@ -237,6 +239,7 @@ typedef enum _CoglFeatureID
|
||||
COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
|
||||
COGL_FEATURE_ID_GLES2_CONTEXT,
|
||||
COGL_FEATURE_ID_DEPTH_TEXTURE,
|
||||
COGL_FEATURE_ID_PRESENTATION_TIME,
|
||||
|
||||
/*< private >*/
|
||||
_COGL_N_FEATURE_IDS /*< skip >*/
|
||||
|
43
cogl/cogl-frame-info-private.h
Normal file
43
cogl/cogl-frame-info-private.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COGL_FRAME_INFO_PRIVATE_H
|
||||
#define __COGL_FRAME_INFO_PRIVATE_H
|
||||
|
||||
#include "cogl-frame-info.h"
|
||||
#include "cogl-object-private.h"
|
||||
|
||||
struct _CoglFrameInfo
|
||||
{
|
||||
CoglObject _parent;
|
||||
|
||||
int64_t frame_counter;
|
||||
int64_t presentation_time;
|
||||
float refresh_rate;
|
||||
|
||||
CoglOutput *output;
|
||||
};
|
||||
|
||||
CoglFrameInfo *_cogl_frame_info_new (void);
|
||||
|
||||
#endif /* __COGL_FRAME_INFO_PRIVATE_H */
|
72
cogl/cogl-frame-info.c
Normal file
72
cogl/cogl-frame-info.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cogl-frame-info-private.h"
|
||||
|
||||
static void _cogl_frame_info_free (CoglFrameInfo *info);
|
||||
|
||||
COGL_OBJECT_DEFINE (FrameInfo, frame_info);
|
||||
|
||||
CoglFrameInfo *
|
||||
_cogl_frame_info_new (void)
|
||||
{
|
||||
CoglFrameInfo *info;
|
||||
|
||||
info = g_slice_new0 (CoglFrameInfo);
|
||||
|
||||
return _cogl_frame_info_object_new (info);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_frame_info_free (CoglFrameInfo *info)
|
||||
{
|
||||
g_slice_free (CoglFrameInfo, info);
|
||||
}
|
||||
|
||||
int64_t
|
||||
cogl_frame_info_get_frame_counter (CoglFrameInfo *info)
|
||||
{
|
||||
return info->frame_counter;
|
||||
}
|
||||
|
||||
int64_t
|
||||
cogl_frame_info_get_presentation_time (CoglFrameInfo *info)
|
||||
{
|
||||
return info->presentation_time;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_frame_info_get_refresh_rate (CoglFrameInfo *info)
|
||||
{
|
||||
return info->refresh_rate;
|
||||
}
|
||||
|
||||
CoglOutput *
|
||||
cogl_frame_info_get_output (CoglFrameInfo *info)
|
||||
{
|
||||
return info->output;
|
||||
}
|
129
cogl/cogl-frame-info.h
Normal file
129
cogl/cogl-frame-info.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Owen Taylor <otaylor@redhat.com>
|
||||
*/
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_FRAME_INFO_H
|
||||
#define __COGL_FRAME_INFO_H
|
||||
|
||||
#include <cogl/cogl-types.h>
|
||||
#include <cogl/cogl-output.h>
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _CoglFrameInfo CoglFrameInfo;
|
||||
#define COGL_FRAME_INFO(X) ((CoglFrameInfo *)(X))
|
||||
|
||||
/**
|
||||
* cogl_is_frame_info:
|
||||
* @object: A #CoglObject pointer
|
||||
*
|
||||
* Gets whether the given object references a #CoglFrameInfo.
|
||||
*
|
||||
* Return value: %TRUE if the object references a #CoglFrameInfo
|
||||
* and %FALSE otherwise.
|
||||
* Since: 2.0
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglBool
|
||||
cogl_is_frame_info (void *object);
|
||||
|
||||
/**
|
||||
* cogl_frame_info_get_frame_counter:
|
||||
* @info: a #CoglFrameInfo object
|
||||
*
|
||||
* Gets the frame counter for the #CoglOnscreen that corresponds
|
||||
* to this frame.
|
||||
*
|
||||
* Return value: The frame counter value
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
int64_t cogl_frame_info_get_frame_counter (CoglFrameInfo *info);
|
||||
|
||||
/**
|
||||
* cogl_frame_info_get_presentation_time:
|
||||
* @info: a #CoglFrameInfo object
|
||||
*
|
||||
* Gets the presentation time for the frame. This is the time at which
|
||||
* the frame became visible to the user.
|
||||
*
|
||||
* The presentation time measured in nanoseconds is based on a
|
||||
* monotonic time source. The time source is not necessarily
|
||||
* correlated with system/wall clock time and may represent the time
|
||||
* elapsed since some undefined system event such as when the system
|
||||
* last booted.
|
||||
*
|
||||
* <note>Linux kernel version less that 3.8 can result in
|
||||
* non-monotonic timestamps being reported when using a drm based
|
||||
* OpenGL driver. Also some buggy Mesa drivers up to 9.0.1 may also
|
||||
* incorrectly report non-monotonic timestamps.</note>
|
||||
*
|
||||
* Return value: the presentation time for the frame
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
int64_t cogl_frame_info_get_presentation_time (CoglFrameInfo *info);
|
||||
|
||||
/**
|
||||
* cogl_frame_info_get_refresh_rate:
|
||||
* @info: a #CoglFrameInfo object
|
||||
*
|
||||
* Gets the refresh rate in Hertz for the output that the frame was on
|
||||
* at the time the frame was presented.
|
||||
*
|
||||
* <note>Some platforms can't associate a #CoglOutput with a
|
||||
* #CoglFrameInfo object but are able to report a refresh rate via
|
||||
* this api. Therefore if you need this information then this api is
|
||||
* more reliable than using cogl_frame_info_get_output() followed by
|
||||
* cogl_output_get_refresh_rate().</note>
|
||||
*
|
||||
* Return value: the refresh rate in Hertz
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
float cogl_frame_info_get_refresh_rate (CoglFrameInfo *info);
|
||||
|
||||
/**
|
||||
* cogl_frame_info_get_output:
|
||||
* @info: a #CoglFrameInfo object
|
||||
*
|
||||
* Gets the #CoglOutput that the swapped frame was presented to.
|
||||
*
|
||||
* Return value: The #CoglOutput that the frame was presented to, or
|
||||
* %NULL if this could not be determined.
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglOutput *
|
||||
cogl_frame_info_get_output (CoglFrameInfo *info);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_FRAME_INFO_H */
|
@ -50,7 +50,8 @@ typedef struct _CoglGLXDisplay
|
||||
GLXContext glx_context;
|
||||
GLXWindow dummy_glxwin;
|
||||
Window dummy_xwin;
|
||||
CoglBool pending_swap_notify;
|
||||
CoglBool pending_sync_notify;
|
||||
CoglBool pending_complete_notify;
|
||||
CoglBool pending_resize_notify;
|
||||
} CoglGLXDisplay;
|
||||
|
||||
|
@ -42,6 +42,15 @@ typedef struct _CoglGLXRenderer
|
||||
/* Vblank stuff */
|
||||
int dri_fd;
|
||||
|
||||
/* enumeration with relatioship between OML_sync_control
|
||||
* UST (unadjusted-system-time) and the system clock */
|
||||
enum {
|
||||
COGL_GLX_UST_IS_UNKNOWN,
|
||||
COGL_GLX_UST_IS_GETTIMEOFDAY,
|
||||
COGL_GLX_UST_IS_MONOTONIC_TIME,
|
||||
COGL_GLX_UST_IS_OTHER
|
||||
} ust_type;
|
||||
|
||||
/* GModule pointing to libGL which we use to get glX functions out of */
|
||||
GModule *libgl_module;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#ifndef __COGL_ONSCREEN_PRIVATE_H
|
||||
#define __COGL_ONSCREEN_PRIVATE_H
|
||||
|
||||
#include "cogl-onscreen.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-queue.h"
|
||||
|
||||
@ -33,17 +34,16 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
typedef struct _CoglSwapBuffersNotifyEntry CoglSwapBuffersNotifyEntry;
|
||||
COGL_TAILQ_HEAD (CoglFrameCallbackList, CoglFrameClosure);
|
||||
|
||||
COGL_TAILQ_HEAD (CoglSwapBuffersNotifyList, CoglSwapBuffersNotifyEntry);
|
||||
|
||||
struct _CoglSwapBuffersNotifyEntry
|
||||
struct _CoglFrameClosure
|
||||
{
|
||||
COGL_TAILQ_ENTRY (CoglSwapBuffersNotifyEntry) list_node;
|
||||
COGL_TAILQ_ENTRY (CoglFrameClosure) list_node;
|
||||
|
||||
CoglFrameCallback callback;
|
||||
|
||||
CoglSwapBuffersNotify callback;
|
||||
void *user_data;
|
||||
unsigned int id;
|
||||
CoglUserDataDestroyCallback destroy;
|
||||
};
|
||||
|
||||
typedef struct _CoglResizeNotifyEntry CoglResizeNotifyEntry;
|
||||
@ -59,6 +59,19 @@ struct _CoglResizeNotifyEntry
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
typedef struct _CoglOnscreenEvent CoglOnscreenEvent;
|
||||
|
||||
COGL_TAILQ_HEAD (CoglOnscreenEventList, CoglOnscreenEvent);
|
||||
|
||||
struct _CoglOnscreenEvent
|
||||
{
|
||||
COGL_TAILQ_ENTRY (CoglOnscreenEvent) list_node;
|
||||
|
||||
CoglOnscreen *onscreen;
|
||||
CoglFrameInfo *info;
|
||||
CoglFrameEvent type;
|
||||
};
|
||||
|
||||
struct _CoglOnscreen
|
||||
{
|
||||
CoglFramebuffer _parent;
|
||||
@ -75,11 +88,17 @@ struct _CoglOnscreen
|
||||
|
||||
CoglBool swap_throttled;
|
||||
|
||||
CoglSwapBuffersNotifyList swap_callbacks;
|
||||
CoglFrameCallbackList frame_closures;
|
||||
|
||||
CoglBool resizable;
|
||||
CoglResizeNotifyList resize_callbacks;
|
||||
|
||||
int64_t frame_counter;
|
||||
int64_t swap_frame_counter; /* frame counter at last all to
|
||||
* cogl_onscreen_swap_region() or
|
||||
* cogl_onscreen_swap_buffers() */
|
||||
GQueue pending_frame_infos;
|
||||
|
||||
void *winsys;
|
||||
};
|
||||
|
||||
@ -91,9 +110,15 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
|
||||
int width, int height);
|
||||
|
||||
void
|
||||
_cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen);
|
||||
_cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info);
|
||||
|
||||
void
|
||||
_cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info);
|
||||
|
||||
void
|
||||
_cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
|
||||
|
||||
void
|
||||
_cogl_dispatch_onscreen_events (CoglContext *context);
|
||||
|
||||
#endif /* __COGL_ONSCREEN_PRIVATE_H */
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-onscreen-private.h"
|
||||
#include "cogl-frame-info-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-onscreen-template-private.h"
|
||||
#include "cogl-context-private.h"
|
||||
@ -45,7 +46,7 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
|
||||
COGL_TAILQ_INIT (&onscreen->swap_callbacks);
|
||||
COGL_TAILQ_INIT (&onscreen->frame_closures);
|
||||
COGL_TAILQ_INIT (&onscreen->resize_callbacks);
|
||||
|
||||
framebuffer->config = onscreen_template->config;
|
||||
@ -115,7 +116,8 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
|
||||
CoglResizeNotifyEntry *resize_entry;
|
||||
CoglSwapBuffersNotifyEntry *swap_entry;
|
||||
CoglFrameClosure *frame_closure;
|
||||
CoglFrameInfo *frame_info;
|
||||
|
||||
while ((resize_entry = COGL_TAILQ_FIRST (&onscreen->resize_callbacks)))
|
||||
{
|
||||
@ -123,12 +125,20 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
|
||||
g_slice_free (CoglResizeNotifyEntry, resize_entry);
|
||||
}
|
||||
|
||||
while ((swap_entry = COGL_TAILQ_FIRST (&onscreen->swap_callbacks)))
|
||||
while ((frame_closure = COGL_TAILQ_FIRST (&onscreen->frame_closures)))
|
||||
{
|
||||
COGL_TAILQ_REMOVE (&onscreen->swap_callbacks, swap_entry, list_node);
|
||||
g_slice_free (CoglSwapBuffersNotifyEntry, swap_entry);
|
||||
COGL_TAILQ_REMOVE (&onscreen->frame_closures, frame_closure, list_node);
|
||||
|
||||
if (frame_closure->destroy)
|
||||
frame_closure->destroy (frame_closure->user_data);
|
||||
|
||||
g_slice_free (CoglFrameClosure, frame_closure);
|
||||
}
|
||||
|
||||
while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos)))
|
||||
cogl_object_unref (frame_info);
|
||||
g_queue_clear (&onscreen->pending_frame_infos);
|
||||
|
||||
if (framebuffer->context->window_buffer == COGL_FRAMEBUFFER (onscreen))
|
||||
framebuffer->context->window_buffer = NULL;
|
||||
|
||||
@ -141,22 +151,60 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
|
||||
g_free (onscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_onscreen_queue_event (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent type,
|
||||
CoglFrameInfo *info)
|
||||
{
|
||||
CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
|
||||
CoglOnscreenEvent *event = g_slice_new (CoglOnscreenEvent);
|
||||
|
||||
event->onscreen = cogl_object_ref (onscreen);
|
||||
event->info = cogl_object_ref (info);
|
||||
event->type = type;
|
||||
|
||||
COGL_TAILQ_INSERT_TAIL (&ctx->onscreen_events_queue, event, list_node);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_onscreen_swap_buffers (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
const CoglWinsysVtable *winsys;
|
||||
CoglFrameInfo *info;
|
||||
|
||||
_COGL_RETURN_IF_FAIL (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
|
||||
|
||||
info = _cogl_frame_info_new ();
|
||||
info->frame_counter = onscreen->frame_counter;
|
||||
g_queue_push_tail (&onscreen->pending_frame_infos, info);
|
||||
|
||||
/* FIXME: we shouldn't need to flush *all* journals here! */
|
||||
cogl_flush ();
|
||||
|
||||
winsys = _cogl_framebuffer_get_winsys (framebuffer);
|
||||
winsys->onscreen_swap_buffers (COGL_ONSCREEN (framebuffer));
|
||||
cogl_framebuffer_discard_buffers (framebuffer,
|
||||
COGL_BUFFER_BIT_COLOR |
|
||||
COGL_BUFFER_BIT_DEPTH |
|
||||
COGL_BUFFER_BIT_STENCIL);
|
||||
|
||||
if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
|
||||
{
|
||||
CoglFrameInfo *info;
|
||||
|
||||
g_warn_if_fail (onscreen->pending_frame_infos.length == 1);
|
||||
|
||||
info = g_queue_pop_tail (&onscreen->pending_frame_infos);
|
||||
|
||||
_cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
|
||||
_cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
|
||||
|
||||
cogl_object_unref (info);
|
||||
}
|
||||
|
||||
onscreen->frame_counter++;
|
||||
}
|
||||
|
||||
void
|
||||
@ -166,9 +214,14 @@ cogl_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
const CoglWinsysVtable *winsys;
|
||||
CoglFrameInfo *info;
|
||||
|
||||
_COGL_RETURN_IF_FAIL (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
|
||||
|
||||
info = _cogl_frame_info_new ();
|
||||
info->frame_counter = onscreen->frame_counter;
|
||||
g_queue_push_tail (&onscreen->pending_frame_infos, info);
|
||||
|
||||
/* FIXME: we shouldn't need to flush *all* journals here! */
|
||||
cogl_flush ();
|
||||
|
||||
@ -186,6 +239,22 @@ cogl_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
COGL_BUFFER_BIT_COLOR |
|
||||
COGL_BUFFER_BIT_DEPTH |
|
||||
COGL_BUFFER_BIT_STENCIL);
|
||||
|
||||
if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
|
||||
{
|
||||
CoglFrameInfo *info;
|
||||
|
||||
g_warn_if_fail (onscreen->pending_frame_infos.length == 1);
|
||||
|
||||
info = g_queue_pop_tail (&onscreen->pending_frame_infos);
|
||||
|
||||
_cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
|
||||
_cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
|
||||
|
||||
cogl_object_unref (info);
|
||||
}
|
||||
|
||||
onscreen->frame_counter++;
|
||||
}
|
||||
|
||||
int
|
||||
@ -286,38 +355,107 @@ cogl_win32_onscreen_get_window (CoglOnscreen *onscreen)
|
||||
|
||||
#endif /* COGL_HAS_WIN32_SUPPORT */
|
||||
|
||||
CoglFrameClosure *
|
||||
cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameCallback callback,
|
||||
void *user_data,
|
||||
CoglUserDataDestroyCallback destroy)
|
||||
{
|
||||
CoglFrameClosure *closure = g_slice_new0 (CoglFrameClosure);
|
||||
|
||||
closure->callback = callback;
|
||||
closure->user_data = user_data;
|
||||
closure->destroy = destroy;
|
||||
|
||||
COGL_TAILQ_INSERT_TAIL (&onscreen->frame_closures, closure, list_node);
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameClosure *closure)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (closure);
|
||||
|
||||
if (closure->destroy)
|
||||
closure->destroy (closure->user_data);
|
||||
|
||||
COGL_TAILQ_REMOVE (&onscreen->frame_closures, closure, list_node);
|
||||
|
||||
g_slice_free (CoglFrameClosure, closure);
|
||||
}
|
||||
|
||||
typedef struct _SwapBufferCallbackState
|
||||
{
|
||||
CoglSwapBuffersNotify callback;
|
||||
void *user_data;
|
||||
} SwapBufferCallbackState;
|
||||
|
||||
static void
|
||||
destroy_swap_buffers_callback_state (void *user_data)
|
||||
{
|
||||
g_slice_free (SwapBufferCallbackState, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
shim_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
SwapBufferCallbackState *state = user_data;
|
||||
|
||||
/* XXX: Note that technically it is a change in semantics for this
|
||||
* interface to forward _SYNC events here and also makes the api
|
||||
* name somewhat missleading.
|
||||
*
|
||||
* In practice though this interface is currently used by
|
||||
* applications for throttling, not because they are strictly
|
||||
* interested in knowing when a frame has been presented and so
|
||||
* forwarding _SYNC events should serve them better.
|
||||
*/
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||
CoglSwapBuffersNotify callback,
|
||||
void *user_data)
|
||||
{
|
||||
CoglSwapBuffersNotifyEntry *entry = g_slice_new0 (CoglSwapBuffersNotifyEntry);
|
||||
static int next_swap_buffers_callback_id = 0;
|
||||
CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
SwapBufferCallbackState *state = g_slice_new (SwapBufferCallbackState);
|
||||
CoglFrameClosure *closure;
|
||||
unsigned int id = ctx->next_swap_callback_id++;
|
||||
|
||||
entry->callback = callback;
|
||||
entry->user_data = user_data;
|
||||
entry->id = next_swap_buffers_callback_id++;
|
||||
state->callback = callback;
|
||||
state->user_data = user_data;
|
||||
|
||||
COGL_TAILQ_INSERT_TAIL (&onscreen->swap_callbacks, entry, list_node);
|
||||
closure =
|
||||
cogl_onscreen_add_frame_callback (onscreen,
|
||||
shim_swap_buffers_callback,
|
||||
state,
|
||||
destroy_swap_buffers_callback_state);
|
||||
|
||||
return entry->id;
|
||||
g_hash_table_insert (ctx->swap_callback_closures,
|
||||
GINT_TO_POINTER (id),
|
||||
closure);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||
unsigned int id)
|
||||
{
|
||||
CoglSwapBuffersNotifyEntry *entry;
|
||||
CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
CoglFrameClosure *closure = g_hash_table_lookup (ctx->swap_callback_closures,
|
||||
GINT_TO_POINTER (id));
|
||||
|
||||
COGL_TAILQ_FOREACH (entry, &onscreen->swap_callbacks, list_node)
|
||||
{
|
||||
if (entry->id == id)
|
||||
{
|
||||
COGL_TAILQ_REMOVE (&onscreen->swap_callbacks, entry, list_node);
|
||||
g_slice_free (CoglSwapBuffersNotifyEntry, entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_COGL_RETURN_IF_FAIL (closure);
|
||||
|
||||
cogl_onscreen_remove_frame_callback (onscreen, closure);
|
||||
}
|
||||
|
||||
void
|
||||
@ -365,16 +503,56 @@ cogl_onscreen_hide (CoglOnscreen *onscreen)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen)
|
||||
static void
|
||||
notify_event (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info)
|
||||
{
|
||||
CoglSwapBuffersNotifyEntry *entry, *tmp;
|
||||
CoglFrameClosure *entry, *tmp;
|
||||
|
||||
COGL_TAILQ_FOREACH_SAFE (entry,
|
||||
&onscreen->swap_callbacks,
|
||||
&onscreen->frame_closures,
|
||||
list_node,
|
||||
tmp)
|
||||
entry->callback (COGL_FRAMEBUFFER (onscreen), entry->user_data);
|
||||
{
|
||||
entry->callback (onscreen, event, info,
|
||||
entry->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_dispatch_onscreen_events (CoglContext *context)
|
||||
{
|
||||
CoglOnscreenEvent *event, *tmp;
|
||||
|
||||
COGL_TAILQ_FOREACH_SAFE (event,
|
||||
&context->onscreen_events_queue,
|
||||
list_node,
|
||||
tmp)
|
||||
{
|
||||
CoglOnscreen *onscreen = event->onscreen;
|
||||
CoglFrameInfo *info = event->info;
|
||||
|
||||
notify_event (onscreen, event->type, info);
|
||||
|
||||
cogl_object_unref (onscreen);
|
||||
cogl_object_unref (info);
|
||||
|
||||
COGL_TAILQ_REMOVE (&context->onscreen_events_queue, event, list_node);
|
||||
g_slice_free (CoglOnscreenEvent, event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info)
|
||||
{
|
||||
notify_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info)
|
||||
{
|
||||
notify_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
|
||||
}
|
||||
|
||||
void
|
||||
@ -468,3 +646,8 @@ cogl_onscreen_remove_resize_handler (CoglOnscreen *onscreen,
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen)
|
||||
{
|
||||
return onscreen->frame_counter;
|
||||
}
|
||||
|
@ -34,6 +34,8 @@
|
||||
|
||||
#include <cogl/cogl-context.h>
|
||||
#include <cogl/cogl-framebuffer.h>
|
||||
#include <cogl/cogl-frame-info.h>
|
||||
#include <cogl/cogl-object.h>
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
@ -380,6 +382,143 @@ cogl_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
const int *rectangles,
|
||||
int n_rectangles);
|
||||
|
||||
/**
|
||||
* CoglFrameEvent:
|
||||
* @COGL_FRAME_EVENT_SYNC: Notifies that the system compositor has
|
||||
* acknowledged a frame and is ready for a
|
||||
* new frame to be created.
|
||||
* @COGL_FRAME_EVENT_COMPLETE: Notifies that a frame has ended. This
|
||||
* is a good time for applications to
|
||||
* collect statistics about the frame
|
||||
* since the #CoglFrameInfo should hold
|
||||
* the most data at this point. No other
|
||||
* events should be expected after a
|
||||
* @COGL_FRAME_EVENT_COMPLETE event.
|
||||
*
|
||||
* Identifiers that are passed to #CoglFrameCallback functions
|
||||
* (registered using cogl_onscreen_add_frame_callback()) that
|
||||
* mark the progression of a frame in some way which usually
|
||||
* means that new information will have been accumulated in the
|
||||
* frame's corresponding #CoglFrameInfo object.
|
||||
*
|
||||
* The last event that will be sent for a frame will be a
|
||||
* @COGL_FRAME_EVENT_COMPLETE event and so these are a good
|
||||
* opportunity to collect statistics about a frame since the
|
||||
* #CoglFrameInfo should hold the most data at this point.
|
||||
*
|
||||
* <note>A frame may not be completed before the next frame can start
|
||||
* so applications should avoid needing to collect all statistics for
|
||||
* a particular frame before they can start a new frame.</note>
|
||||
*
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef enum _CoglFrameEvent
|
||||
{
|
||||
COGL_FRAME_EVENT_SYNC = 1,
|
||||
COGL_FRAME_EVENT_COMPLETE
|
||||
} CoglFrameEvent;
|
||||
|
||||
/**
|
||||
* CoglFrameCallback:
|
||||
* @onscreen: The onscreen that the frame is associated with
|
||||
* @event: A #CoglFrameEvent notifying how the frame has progressed
|
||||
* @info: The meta information, such as timing information, about
|
||||
* the frame that has progressed.
|
||||
* @user_data: The user pointer passed to
|
||||
* cogl_onscreen_add_frame_callback()
|
||||
*
|
||||
* Is a callback that can be registered via
|
||||
* cogl_onscreen_add_frame_callback() to be called when a frame
|
||||
* progresses in some notable way.
|
||||
*
|
||||
* Please see the documentation for #CoglFrameEvent and
|
||||
* cogl_onscreen_add_frame_callback() for more details about what
|
||||
* events can be notified.
|
||||
*
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef void (*CoglFrameCallback) (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* CoglFrameClosure:
|
||||
*
|
||||
* An opaque type that tracks a #CoglFrameCallback and associated user
|
||||
* data. A #CoglFrameClosure pointer will be returned from
|
||||
* cogl_onscreen_add_frame_callback() and it allows you to remove a
|
||||
* callback later using cogl_onscreen_remove_frame_callback().
|
||||
*
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef struct _CoglFrameClosure CoglFrameClosure;
|
||||
|
||||
/**
|
||||
* cogl_onscreen_add_frame_callback:
|
||||
* @onscreen: A #CoglOnscreen framebuffer
|
||||
* @callback: A callback function to call for frame events
|
||||
* @user_data: A private pointer to be passed to @callback
|
||||
* @destroy: An optional callback to destroy @user_data when the
|
||||
* @callback is removed or @onscreen is freed.
|
||||
*
|
||||
* Installs a @callback function that will be called for significant
|
||||
* events relating to the given @onscreen framebuffer.
|
||||
*
|
||||
* The @callback will be used to notify when the system compositor is
|
||||
* ready for this application to render a new frame. In this case
|
||||
* %COGL_FRAME_EVENT_SYNC will be passed as the event argument to the
|
||||
* given @callback in addition to the #CoglFrameInfo corresponding to
|
||||
* the frame beeing acknowledged by the compositor.
|
||||
*
|
||||
* The @callback will also be called to notify when the frame has
|
||||
* ended. In this case %COGL_FRAME_EVENT_COMPLETE will be passed as
|
||||
* the event argument to the given @callback in addition to the
|
||||
* #CoglFrameInfo corresponding to the newly presented frame. The
|
||||
* meaning of "ended" here simply means that no more timing
|
||||
* information will be collected within the corresponding
|
||||
* #CoglFrameInfo and so this is a good opportunity to analyse the
|
||||
* given info. It does not necessarily mean that the GPU has finished
|
||||
* rendering the corresponding frame.
|
||||
*
|
||||
* We highly recommend throttling your application according to
|
||||
* %COGL_FRAME_EVENT_SYNC events so that your application can avoid
|
||||
* wasting resources, drawing more frames than your system compositor
|
||||
* can display.
|
||||
*
|
||||
* Return value: a #CoglFrameClosure pointer that can be used to
|
||||
* remove the callback and associated @user_data later.
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglFrameClosure *
|
||||
cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameCallback callback,
|
||||
void *user_data,
|
||||
CoglUserDataDestroyCallback destroy);
|
||||
|
||||
/**
|
||||
* cogl_onscreen_remove_frame_callback:
|
||||
* @onscreen: A #CoglOnscreen
|
||||
* @closure: A #CoglFrameClosure returned from
|
||||
* cogl_onscreen_add_frame_callback()
|
||||
*
|
||||
* Removes a callback and associated user data that were previously
|
||||
* registered using cogl_onscreen_add_frame_callback().
|
||||
*
|
||||
* If a destroy callback was passed to
|
||||
* cogl_onscreen_add_frame_callback() to destroy the user data then
|
||||
* this will get called.
|
||||
*
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
void
|
||||
cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameClosure *closure);
|
||||
|
||||
typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer,
|
||||
void *user_data);
|
||||
@ -407,6 +546,7 @@ typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer,
|
||||
* the callback later.
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
* Deprecated: 1.14: Use cogl_onscreen_add_swap_complete_callback
|
||||
*/
|
||||
unsigned int
|
||||
cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||
@ -423,6 +563,7 @@ cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||
*
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
* Deprecated: 1.14: Use cogl_onscreen_remove_swap_complete_callback
|
||||
*/
|
||||
void
|
||||
cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||
@ -580,6 +721,21 @@ cogl_onscreen_remove_resize_handler (CoglOnscreen *onscreen,
|
||||
CoglBool
|
||||
cogl_is_onscreen (void *object);
|
||||
|
||||
/**
|
||||
* cogl_onscreen_get_frame_counter:
|
||||
*
|
||||
* Gets the value of the framebuffers frame counter. This is
|
||||
* a counter that increases by one each time
|
||||
* cogl_onscreen_swap_buffers() or cogl_onscreen_swap_region()
|
||||
* is called.
|
||||
*
|
||||
* Return value: the current frame counter value
|
||||
* Since: 1.14
|
||||
* Stability: unstable
|
||||
*/
|
||||
int64_t
|
||||
cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_ONSCREEN_H */
|
||||
|
@ -44,6 +44,13 @@ cogl_poll_get_info (CoglContext *context,
|
||||
_COGL_RETURN_IF_FAIL (n_poll_fds != NULL);
|
||||
_COGL_RETURN_IF_FAIL (timeout != NULL);
|
||||
|
||||
if (!COGL_TAILQ_EMPTY (&context->onscreen_events_queue))
|
||||
{
|
||||
*n_poll_fds = 0;
|
||||
*timeout = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
winsys = _cogl_context_get_winsys (context);
|
||||
|
||||
if (winsys->poll_get_info)
|
||||
@ -70,6 +77,9 @@ cogl_poll_dispatch (CoglContext *context,
|
||||
|
||||
_COGL_RETURN_IF_FAIL (cogl_is_context (context));
|
||||
|
||||
if (!COGL_TAILQ_EMPTY (&context->onscreen_events_queue))
|
||||
_cogl_dispatch_onscreen_events (context);
|
||||
|
||||
winsys = _cogl_context_get_winsys (context);
|
||||
|
||||
if (winsys->poll_dispatch)
|
||||
|
@ -83,5 +83,5 @@ cogl_sdl_handle_event (CoglContext *context, SDL_Event *event)
|
||||
void
|
||||
cogl_sdl_idle (CoglContext *context)
|
||||
{
|
||||
/* NOP since Cogl doesn't currently need to do anything when idle */
|
||||
_cogl_dispatch_onscreen_events (context);
|
||||
}
|
||||
|
@ -832,6 +832,9 @@ typedef enum _CoglWinsysFeature
|
||||
/* Avaiable if the age of the back buffer can be queried */
|
||||
COGL_WINSYS_FEATURE_BUFFER_AGE,
|
||||
|
||||
/* Avaiable if the winsys directly handles _SYNC and _COMPLETE events */
|
||||
COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
|
||||
|
||||
COGL_WINSYS_FEATURE_N_FEATURES
|
||||
} CoglWinsysFeature;
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
typedef struct _CoglX11Renderer
|
||||
{
|
||||
int damage_base;
|
||||
int randr_base;
|
||||
} CoglX11Renderer;
|
||||
|
||||
#endif /* __COGL_RENDERER_X11_PRIVATE_H */
|
||||
|
@ -105,6 +105,7 @@
|
||||
#include <cogl/cogl-snippet.h>
|
||||
#include <cogl/cogl-framebuffer.h>
|
||||
#include <cogl/cogl-onscreen.h>
|
||||
#include <cogl/cogl-frame-info.h>
|
||||
#include <cogl/cogl-poll.h>
|
||||
#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
|
||||
#include <cogl/cogl-kms-renderer.h>
|
||||
|
@ -754,9 +754,13 @@ _cogl_winsys_egl_context_init (CoglContext *context,
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -894,8 +898,13 @@ flush_pending_swap_notify_cb (void *data,
|
||||
|
||||
if (kms_onscreen->pending_swap_notify)
|
||||
{
|
||||
_cogl_onscreen_notify_swap_buffers (onscreen);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,8 @@ COGL_WINSYS_FEATURE_BEGIN (255, 255,
|
||||
"INTEL\0",
|
||||
"swap_event\0",
|
||||
0,
|
||||
COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT)
|
||||
COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT |
|
||||
COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)
|
||||
COGL_WINSYS_FEATURE_END ()
|
||||
|
||||
COGL_WINSYS_FEATURE_BEGIN (255, 255,
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "cogl-texture-2d-private.h"
|
||||
#include "cogl-texture-rectangle-private.h"
|
||||
#include "cogl-pipeline-opengl-private.h"
|
||||
#include "cogl-frame-info-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-onscreen-private.h"
|
||||
#include "cogl-swap-chain-private.h"
|
||||
@ -53,7 +54,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
@ -81,7 +84,8 @@ typedef struct _CoglOnscreenGLX
|
||||
CoglOnscreenXlib _parent;
|
||||
GLXDrawable glxwin;
|
||||
uint32_t last_swap_vsync_counter;
|
||||
CoglBool pending_swap_notify;
|
||||
CoglBool pending_sync_notify;
|
||||
CoglBool pending_complete_notify;
|
||||
CoglBool pending_resize_notify;
|
||||
} CoglOnscreenGLX;
|
||||
|
||||
@ -171,23 +175,146 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
|
||||
}
|
||||
|
||||
static void
|
||||
notify_swap_buffers (CoglContext *context, GLXDrawable drawable)
|
||||
ensure_ust_type (CoglRenderer *renderer,
|
||||
GLXDrawable drawable)
|
||||
{
|
||||
CoglOnscreen *onscreen = find_onscreen_for_xid (context, (uint32_t)drawable);
|
||||
CoglDisplay *display = context->display;
|
||||
CoglGLXDisplay *glx_display = display->winsys;
|
||||
CoglGLXRenderer *glx_renderer = renderer->winsys;
|
||||
CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
|
||||
int64_t ust;
|
||||
int64_t msc;
|
||||
int64_t sbc;
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
int64_t current_system_time;
|
||||
int64_t current_monotonic_time;
|
||||
|
||||
if (glx_renderer->ust_type != COGL_GLX_UST_IS_UNKNOWN)
|
||||
return;
|
||||
|
||||
glx_renderer->ust_type = COGL_GLX_UST_IS_OTHER;
|
||||
|
||||
if (glx_renderer->glXGetSyncValues == NULL)
|
||||
goto out;
|
||||
|
||||
if (!glx_renderer->glXGetSyncValues (xlib_renderer->xdpy, drawable,
|
||||
&ust, &msc, &sbc))
|
||||
goto out;
|
||||
|
||||
/* This is the time source that existing (buggy) linux drm drivers
|
||||
* use */
|
||||
gettimeofday (&tv, NULL);
|
||||
current_system_time = (tv.tv_sec * G_GINT64_CONSTANT (1000000)) + tv.tv_usec;
|
||||
|
||||
if (current_system_time > ust - 1000000 &&
|
||||
current_system_time < ust + 1000000)
|
||||
{
|
||||
glx_renderer->ust_type = COGL_GLX_UST_IS_GETTIMEOFDAY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* This is the time source that the newer (fixed) linux drm
|
||||
* drivers use (Linux >= 3.8) */
|
||||
clock_gettime (CLOCK_MONOTONIC, &ts);
|
||||
current_monotonic_time = (ts.tv_sec * G_GINT64_CONSTANT (1000000)) +
|
||||
(ts.tv_nsec / G_GINT64_CONSTANT (1000));
|
||||
|
||||
if (current_monotonic_time > ust - 1000000 &&
|
||||
current_monotonic_time < ust + 1000000)
|
||||
{
|
||||
glx_renderer->ust_type = COGL_GLX_UST_IS_MONOTONIC_TIME;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
COGL_NOTE (WINSYS, "Classified OML system time as: %s",
|
||||
glx_renderer->ust_type == COGL_GLX_UST_IS_GETTIMEOFDAY ? "gettimeofday" :
|
||||
(glx_renderer->ust_type == COGL_GLX_UST_IS_MONOTONIC_TIME ? "monotonic" :
|
||||
"other"));
|
||||
return;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
ust_to_nanoseconds (CoglRenderer *renderer,
|
||||
GLXDrawable drawable,
|
||||
int64_t ust)
|
||||
{
|
||||
CoglGLXRenderer *glx_renderer = renderer->winsys;
|
||||
|
||||
ensure_ust_type (renderer, drawable);
|
||||
|
||||
switch (glx_renderer->ust_type)
|
||||
{
|
||||
case COGL_GLX_UST_IS_UNKNOWN:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
case COGL_GLX_UST_IS_GETTIMEOFDAY:
|
||||
case COGL_GLX_UST_IS_MONOTONIC_TIME:
|
||||
return 1000 * ust;
|
||||
case COGL_GLX_UST_IS_OTHER:
|
||||
/* In this case the scale of UST is undefined so we can't easily
|
||||
* scale to nanoseconds.
|
||||
*
|
||||
* For example the driver may be reporting the rdtsc CPU counter
|
||||
* as UST values and so the scale would need to be determined
|
||||
* empirically.
|
||||
*
|
||||
* Potentially we could block for a known duration within
|
||||
* ensure_ust_type() to measure the timescale of UST but for now
|
||||
* we just ignore unknown time sources */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_sync_pending (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
|
||||
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
CoglGLXDisplay *glx_display = context->display->winsys;
|
||||
|
||||
glx_display->pending_sync_notify = TRUE;
|
||||
glx_onscreen->pending_sync_notify = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_complete_pending (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
|
||||
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
CoglGLXDisplay *glx_display = context->display->winsys;
|
||||
|
||||
glx_display->pending_complete_notify = TRUE;
|
||||
glx_onscreen->pending_complete_notify = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_swap_buffers (CoglContext *context, GLXBufferSwapComplete *swap_event)
|
||||
{
|
||||
CoglOnscreen *onscreen = find_onscreen_for_xid (context, (uint32_t)swap_event->drawable);
|
||||
CoglOnscreenGLX *glx_onscreen;
|
||||
|
||||
if (!onscreen)
|
||||
return;
|
||||
|
||||
glx_onscreen = onscreen->winsys;
|
||||
|
||||
/* 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 */
|
||||
glx_display->pending_swap_notify = TRUE;
|
||||
glx_onscreen->pending_swap_notify = TRUE;
|
||||
set_sync_pending (onscreen);
|
||||
|
||||
if (swap_event->ust != 0)
|
||||
{
|
||||
CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos);
|
||||
|
||||
info->presentation_time =
|
||||
ust_to_nanoseconds (context->display->renderer,
|
||||
glx_onscreen->glxwin,
|
||||
swap_event->ust);
|
||||
}
|
||||
|
||||
set_complete_pending (onscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -295,7 +422,7 @@ glx_event_filter_cb (XEvent *xevent, void *data)
|
||||
{
|
||||
GLXBufferSwapComplete *swap_event = (GLXBufferSwapComplete *) xevent;
|
||||
|
||||
notify_swap_buffers (context, swap_event->drawable);
|
||||
notify_swap_buffers (context, swap_event);
|
||||
|
||||
/* remove SwapComplete events from the queue */
|
||||
return COGL_FILTER_REMOVE;
|
||||
@ -434,8 +561,8 @@ update_base_winsys_features (CoglRenderer *renderer)
|
||||
COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
|
||||
TRUE);
|
||||
|
||||
if (glx_renderer->pf_glXWaitVideoSync ||
|
||||
glx_renderer->pf_glXWaitForMsc)
|
||||
if (glx_renderer->glXWaitVideoSync ||
|
||||
glx_renderer->glXWaitForMsc)
|
||||
COGL_FLAGS_SET (glx_renderer->base_winsys_features,
|
||||
COGL_WINSYS_FEATURE_VBLANK_WAIT,
|
||||
TRUE);
|
||||
@ -569,10 +696,16 @@ update_winsys_features (CoglContext *context, CoglError **error)
|
||||
COGL_FLAGS_SET (context->winsys_features,
|
||||
COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
|
||||
|
||||
if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
|
||||
COGL_FLAGS_SET (context->features,
|
||||
COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
|
||||
TRUE);
|
||||
if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
|
||||
{
|
||||
/* TODO: remove this deprecated feature */
|
||||
COGL_FLAGS_SET (context->features,
|
||||
COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
|
||||
TRUE);
|
||||
COGL_FLAGS_SET (context->features,
|
||||
COGL_FEATURE_ID_PRESENTATION_TIME,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -1111,7 +1244,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
|
||||
}
|
||||
|
||||
#ifdef GLX_INTEL_swap_event
|
||||
if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
|
||||
if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
|
||||
{
|
||||
GLXDrawable drawable =
|
||||
glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
|
||||
@ -1280,15 +1413,30 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_winsys_wait_for_vblank (CoglContext *ctx)
|
||||
_cogl_winsys_wait_for_gpu (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
CoglContext *ctx = framebuffer->context;
|
||||
|
||||
ctx->glFinish ();
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
CoglContext *ctx = framebuffer->context;
|
||||
CoglGLXRenderer *glx_renderer;
|
||||
CoglXlibRenderer *xlib_renderer;
|
||||
|
||||
glx_renderer = ctx->display->renderer->winsys;
|
||||
xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer);
|
||||
|
||||
if (glx_renderer->glXWaitForMsc ||
|
||||
glx_renderer->glXGetVideoSync)
|
||||
{
|
||||
CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos);
|
||||
|
||||
if (glx_renderer->glXWaitForMsc)
|
||||
{
|
||||
CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
|
||||
@ -1302,15 +1450,23 @@ _cogl_winsys_wait_for_vblank (CoglContext *ctx)
|
||||
glx_renderer->glXWaitForMsc (xlib_renderer->xdpy, drawable,
|
||||
0, 2, (msc + 1) % 2,
|
||||
&ust, &msc, &sbc);
|
||||
info->presentation_time = ust_to_nanoseconds (ctx->display->renderer,
|
||||
drawable,
|
||||
ust);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t current_count;
|
||||
struct timespec ts;
|
||||
|
||||
glx_renderer->glXGetVideoSync (¤t_count);
|
||||
glx_renderer->glXWaitVideoSync (2,
|
||||
(current_count + 1) % 2,
|
||||
¤t_count);
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &ts);
|
||||
info->presentation_time =
|
||||
ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1352,6 +1508,22 @@ _cogl_winsys_onscreen_get_buffer_age (CoglOnscreen *onscreen)
|
||||
return age;
|
||||
}
|
||||
|
||||
static void
|
||||
set_frame_info_output (CoglOnscreen *onscreen,
|
||||
CoglOutput *output)
|
||||
{
|
||||
CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos);
|
||||
|
||||
info->output = output;
|
||||
|
||||
if (output)
|
||||
{
|
||||
float refresh_rate = cogl_output_get_refresh_rate (output);
|
||||
if (refresh_rate != 0.0)
|
||||
info->refresh_rate = refresh_rate;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
const int *user_rectangles,
|
||||
@ -1369,6 +1541,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
uint32_t end_frame_vsync_counter = 0;
|
||||
CoglBool have_counter;
|
||||
CoglBool can_wait;
|
||||
int x_min = 0, x_max = 0, y_min = 0, y_max = 0;
|
||||
|
||||
/*
|
||||
* We assume that glXCopySubBuffer is synchronized which means it won't prevent multiple
|
||||
@ -1379,6 +1552,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
CoglBool blit_sub_buffer_is_synchronized =
|
||||
_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION_SYNCHRONIZED);
|
||||
|
||||
int framebuffer_width = cogl_framebuffer_get_width (framebuffer);
|
||||
int framebuffer_height = cogl_framebuffer_get_height (framebuffer);
|
||||
int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
|
||||
int i;
|
||||
@ -1390,7 +1564,24 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
for (i = 0; i < n_rectangles; i++)
|
||||
{
|
||||
int *rect = &rectangles[4 * i];
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
x_min = rect[0];
|
||||
x_max = rect[0] + rect[2];
|
||||
y_min = rect[1];
|
||||
y_max = rect[1] + rect[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
x_min = MIN (x_min, rect[0]);
|
||||
x_max = MAX (x_max, rect[0] + rect[2]);
|
||||
y_min = MIN (y_min, rect[1]);
|
||||
y_max = MAX (y_max, rect[1] + rect[3]);
|
||||
}
|
||||
|
||||
rect[1] = framebuffer_height - rect[1] - rect[3];
|
||||
|
||||
}
|
||||
|
||||
_cogl_framebuffer_flush_state (framebuffer,
|
||||
@ -1444,7 +1635,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
* additional extension so we can report the limited region of
|
||||
* the window damage to X/compositors.
|
||||
*/
|
||||
context->glFinish ();
|
||||
_cogl_winsys_wait_for_gpu (onscreen);
|
||||
|
||||
if (blit_sub_buffer_is_synchronized && have_counter && can_wait)
|
||||
{
|
||||
@ -1455,10 +1646,10 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
* any waits if we can see that the video sync count has
|
||||
* already progressed. */
|
||||
if (glx_onscreen->last_swap_vsync_counter == end_frame_vsync_counter)
|
||||
_cogl_winsys_wait_for_vblank (context);
|
||||
_cogl_winsys_wait_for_vblank (onscreen);
|
||||
}
|
||||
else if (can_wait)
|
||||
_cogl_winsys_wait_for_vblank (context);
|
||||
_cogl_winsys_wait_for_vblank (onscreen);
|
||||
|
||||
if (glx_renderer->glXCopySubBuffer)
|
||||
{
|
||||
@ -1516,6 +1707,36 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
||||
*/
|
||||
if (have_counter)
|
||||
glx_onscreen->last_swap_vsync_counter = end_frame_vsync_counter;
|
||||
|
||||
if (!xlib_onscreen->is_foreign_xwin)
|
||||
{
|
||||
CoglOutput *output;
|
||||
|
||||
x_min = CLAMP (x_min, 0, framebuffer_width);
|
||||
x_max = CLAMP (x_max, 0, framebuffer_width);
|
||||
y_min = CLAMP (y_min, 0, framebuffer_width);
|
||||
y_max = CLAMP (y_max, 0, framebuffer_height);
|
||||
|
||||
output =
|
||||
_cogl_xlib_renderer_output_for_rectangle (context->display->renderer,
|
||||
xlib_onscreen->x + x_min,
|
||||
xlib_onscreen->y + y_min,
|
||||
x_max - x_min,
|
||||
y_max - y_min);
|
||||
|
||||
set_frame_info_output (onscreen, output);
|
||||
}
|
||||
|
||||
/* XXX: we don't get SwapComplete events based on how we implement
|
||||
* the _swap_region() API but if cogl-onscreen.c knows we are
|
||||
* handling _SYNC and _COMPLETE events in the winsys then we need to
|
||||
* send fake events in this case.
|
||||
*/
|
||||
if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
|
||||
{
|
||||
set_sync_pending (onscreen);
|
||||
set_complete_pending (onscreen);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1575,16 +1796,16 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
|
||||
* obviously does not happen when we use _GLX_SWAP and let
|
||||
* the driver do the right thing
|
||||
*/
|
||||
context->glFinish ();
|
||||
_cogl_winsys_wait_for_gpu (onscreen);
|
||||
|
||||
if (have_counter && can_wait)
|
||||
{
|
||||
if (glx_onscreen->last_swap_vsync_counter ==
|
||||
end_frame_vsync_counter)
|
||||
_cogl_winsys_wait_for_vblank (context);
|
||||
_cogl_winsys_wait_for_vblank (onscreen);
|
||||
}
|
||||
else if (can_wait)
|
||||
_cogl_winsys_wait_for_vblank (context);
|
||||
_cogl_winsys_wait_for_vblank (onscreen);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1595,6 +1816,8 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
|
||||
if (have_counter)
|
||||
glx_onscreen->last_swap_vsync_counter =
|
||||
_cogl_winsys_get_vsync_counter (context);
|
||||
|
||||
set_frame_info_output (onscreen, xlib_onscreen->output);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@ -2257,7 +2480,9 @@ _cogl_winsys_poll_get_info (CoglContext *context,
|
||||
|
||||
/* If we've already got a pending swap notify then we'll dispatch
|
||||
immediately */
|
||||
if (glx_display->pending_swap_notify || glx_display->pending_resize_notify)
|
||||
if (glx_display->pending_sync_notify ||
|
||||
glx_display->pending_resize_notify ||
|
||||
glx_display->pending_complete_notify)
|
||||
*timeout = 0;
|
||||
}
|
||||
|
||||
@ -2272,10 +2497,22 @@ flush_pending_notifications_cb (void *data,
|
||||
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
||||
CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
|
||||
|
||||
if (glx_onscreen->pending_swap_notify)
|
||||
if (glx_onscreen->pending_sync_notify)
|
||||
{
|
||||
_cogl_onscreen_notify_swap_buffers (onscreen);
|
||||
glx_onscreen->pending_swap_notify = FALSE;
|
||||
CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos);
|
||||
|
||||
_cogl_onscreen_notify_frame_sync (onscreen, info);
|
||||
glx_onscreen->pending_sync_notify = FALSE;
|
||||
}
|
||||
|
||||
if (glx_onscreen->pending_complete_notify)
|
||||
{
|
||||
CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
|
||||
|
||||
_cogl_onscreen_notify_complete (onscreen, info);
|
||||
glx_onscreen->pending_complete_notify = FALSE;
|
||||
|
||||
cogl_object_unref (info);
|
||||
}
|
||||
|
||||
if (glx_onscreen->pending_resize_notify)
|
||||
@ -2298,13 +2535,16 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
|
||||
poll_fds,
|
||||
n_poll_fds);
|
||||
|
||||
if (glx_display->pending_swap_notify || glx_display->pending_resize_notify)
|
||||
if (glx_display->pending_sync_notify ||
|
||||
glx_display->pending_resize_notify ||
|
||||
glx_display->pending_complete_notify)
|
||||
{
|
||||
g_list_foreach (context->framebuffers,
|
||||
flush_pending_notifications_cb,
|
||||
NULL);
|
||||
glx_display->pending_swap_notify = FALSE;
|
||||
glx_display->pending_sync_notify = FALSE;
|
||||
glx_display->pending_resize_notify = FALSE;
|
||||
glx_display->pending_complete_notify = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user