Add fence API

cogl_framebuffer_add_fence creates a synchronisation fence, which will
invoke a user-specified callback when the GPU has finished executing all
commands provided to it up to that point in time.

Support is currently provided for GL 3.x's GL_ARB_sync extension, and
EGL's EGL_KHR_fence_sync (when used with OpenGL ES).

Signed-off-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Neil Roberts <neil@linux.intel.com>
Reviewed-by: Robert Bragg <robert@linux.intel.com>

https://bugzilla.gnome.org/show_bug.cgi?id=691752

(cherry picked from commit e6d37470da9294adc1554c0a8c91aa2af560ed9f)
This commit is contained in:
Daniel Stone 2013-01-10 17:13:34 -08:00 committed by Robert Bragg
parent 7b14b5e3da
commit ea7d3b8476
27 changed files with 656 additions and 4 deletions

View File

@ -133,6 +133,7 @@ cogl_experimental_h = \
$(srcdir)/cogl2-experimental.h \
$(srcdir)/cogl2-compatibility.h \
$(srcdir)/cogl-macros.h \
$(srcdir)/cogl-fence.h \
$(srcdir)/cogl-version.h \
$(srcdir)/cogl-error.h \
$(NULL)
@ -437,6 +438,8 @@ cogl_sources_c = \
$(srcdir)/cogl-error.c \
$(srcdir)/cogl-closure-list-private.h \
$(srcdir)/cogl-closure-list.c \
$(srcdir)/cogl-fence.c \
$(srcdir)/cogl-fence-private.h \
$(NULL)
if USE_GLIB

View File

@ -51,6 +51,8 @@
#include "cogl-gl-header.h"
#include "cogl-framebuffer-private.h"
#include "cogl-onscreen-private.h"
#include "cogl-fence-private.h"
#include "cogl-poll-private.h"
typedef struct
{
@ -306,6 +308,9 @@ struct _CoglContext
GHashTable *uniform_name_hash;
int n_uniform_names;
CoglPollSource *fences_poll_source;
CoglFenceList fences;
/* This defines a list of function pointers that Cogl uses from
either GL or GLES. All functions are accessed indirectly through
these pointers rather than linking to them directly */

View File

@ -477,6 +477,8 @@ cogl_context_new (CoglDisplay *display,
cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE))
GE (context, glEnable (GL_POINT_SPRITE));
COGL_TAILQ_INIT (&context->fences);
return context;
}

View File

@ -259,6 +259,7 @@ typedef enum _CoglFeatureID
COGL_FEATURE_ID_GLES2_CONTEXT,
COGL_FEATURE_ID_DEPTH_TEXTURE,
COGL_FEATURE_ID_PRESENTATION_TIME,
COGL_FEATURE_ID_FENCE,
/*< private >*/
_COGL_N_FEATURE_IDS /*< skip >*/

61
cogl/cogl-fence-private.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2012 Collabora Ltd.
*
* 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_FENCE_PRIVATE_H__
#define __COGL_FENCE_PRIVATE_H__
#include "cogl-fence.h"
#include "cogl-queue.h"
#include "cogl-winsys-private.h"
COGL_TAILQ_HEAD (CoglFenceList, CoglFenceClosure);
typedef enum
{
FENCE_TYPE_PENDING,
#ifdef GL_ARB_sync
FENCE_TYPE_GL_ARB,
#endif
FENCE_TYPE_WINSYS,
FENCE_TYPE_ERROR
} CoglFenceType;
struct _CoglFenceClosure
{
COGL_TAILQ_ENTRY (CoglFenceClosure) list;
CoglFramebuffer *framebuffer;
CoglFenceType type;
void *fence_obj;
CoglFenceCallback callback;
void *user_data;
};
void
_cogl_fence_submit (CoglFenceClosure *fence);
void
_cogl_fence_cancel_fences_for_framebuffer (CoglFramebuffer *framebuffer);
#endif /* __COGL_FENCE_PRIVATE_H__ */

228
cogl/cogl-fence.c Normal file
View File

@ -0,0 +1,228 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2012 Collabora Ltd.
*
* 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-fence.h"
#include "cogl-fence-private.h"
#include "cogl-context-private.h"
#include "cogl-winsys-private.h"
#define FENCE_CHECK_TIMEOUT 5000 /* microseconds */
void *
cogl_fence_closure_get_user_data (CoglFenceClosure *closure)
{
return closure->user_data;
}
static void
_cogl_fence_check (CoglFenceClosure *fence)
{
CoglContext *context = fence->framebuffer->context;
if (fence->type == FENCE_TYPE_WINSYS)
{
const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context);
CoglBool ret;
ret = winsys->fence_is_complete (context, fence->fence_obj);
if (!ret)
return;
}
#ifdef GL_ARB_sync
else if (fence->type == FENCE_TYPE_GL_ARB)
{
GLenum arb;
arb = context->glClientWaitSync (fence->fence_obj,
GL_SYNC_FLUSH_COMMANDS_BIT,
0);
if (arb != GL_ALREADY_SIGNALED && arb != GL_CONDITION_SATISFIED)
return;
}
#endif
fence->callback (NULL, /* dummy CoglFence object */
fence->user_data);
cogl_framebuffer_cancel_fence_callback (fence->framebuffer, fence);
}
static void
_cogl_fence_poll_dispatch (void *source, int revents)
{
CoglContext *context = source;
CoglFenceClosure *fence, *next;
COGL_TAILQ_FOREACH_SAFE (fence, &context->fences, list, next)
_cogl_fence_check (fence);
}
static int64_t
_cogl_fence_poll_prepare (void *source)
{
CoglContext *context = source;
GList *l;
/* If there are any pending fences in any of the journals then we
* need to flush the journal otherwise the fence will never be
* hit and the main loop might block forever */
for (l = context->framebuffers; l; l = l->next)
{
CoglFramebuffer *fb = l->data;
if (!COGL_TAILQ_EMPTY (&fb->journal->pending_fences))
_cogl_framebuffer_flush_journal (fb);
}
if (!COGL_TAILQ_EMPTY (&context->fences))
return FENCE_CHECK_TIMEOUT;
else
return -1;
}
void
_cogl_fence_submit (CoglFenceClosure *fence)
{
CoglContext *context = fence->framebuffer->context;
const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context);
fence->type = FENCE_TYPE_ERROR;
if (winsys->fence_add)
{
fence->fence_obj = winsys->fence_add (context);
if (fence->fence_obj)
{
fence->type = FENCE_TYPE_WINSYS;
goto done;
}
}
#ifdef GL_ARB_sync
if (context->glFenceSync)
{
fence->fence_obj = context->glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE,
0);
if (fence->fence_obj)
{
fence->type = FENCE_TYPE_GL_ARB;
goto done;
}
}
#endif
done:
COGL_TAILQ_INSERT_TAIL (&context->fences, fence, list);
if (!context->fences_poll_source)
{
context->fences_poll_source =
_cogl_poll_renderer_add_source (context->display->renderer,
_cogl_fence_poll_prepare,
_cogl_fence_poll_dispatch,
context);
}
}
CoglFenceClosure *
cogl_framebuffer_add_fence_callback (CoglFramebuffer *framebuffer,
CoglFenceCallback callback,
void *user_data)
{
CoglContext *context = framebuffer->context;
CoglJournal *journal = framebuffer->journal;
CoglFenceClosure *fence;
if (!COGL_FLAGS_GET (context->features, COGL_FEATURE_ID_FENCE))
return NULL;
fence = g_slice_new (CoglFenceClosure);
fence->framebuffer = framebuffer;
fence->callback = callback;
fence->user_data = user_data;
fence->fence_obj = NULL;
if (journal->entries->len)
{
COGL_TAILQ_INSERT_TAIL (&journal->pending_fences, fence, list);
fence->type = FENCE_TYPE_PENDING;
}
else
_cogl_fence_submit (fence);
return fence;
}
void
cogl_framebuffer_cancel_fence_callback (CoglFramebuffer *framebuffer,
CoglFenceClosure *fence)
{
CoglJournal *journal = framebuffer->journal;
CoglContext *context = framebuffer->context;
if (fence->type == FENCE_TYPE_PENDING)
{
COGL_TAILQ_REMOVE (&journal->pending_fences, fence, list);
}
else
{
COGL_TAILQ_REMOVE (&context->fences, fence, list);
if (fence->type == FENCE_TYPE_WINSYS)
{
const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context);
winsys->fence_destroy (context, fence->fence_obj);
}
#ifdef GL_ARB_sync
else if (fence->type == FENCE_TYPE_GL_ARB)
{
context->glDeleteSync (fence->fence_obj);
}
#endif
}
g_slice_free (CoglFenceClosure, fence);
}
void
_cogl_fence_cancel_fences_for_framebuffer (CoglFramebuffer *framebuffer)
{
CoglJournal *journal = framebuffer->journal;
CoglContext *context = framebuffer->context;
CoglFenceClosure *fence, *next;
while (!COGL_TAILQ_EMPTY (&journal->pending_fences))
{
fence = COGL_TAILQ_FIRST (&journal->pending_fences);
cogl_framebuffer_cancel_fence_callback (framebuffer, fence);
}
COGL_TAILQ_FOREACH_SAFE (fence, &context->fences, list, next)
{
if (fence->framebuffer == framebuffer)
cogl_framebuffer_cancel_fence_callback (framebuffer, fence);
}
}

136
cogl/cogl-fence.h Normal file
View File

@ -0,0 +1,136 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2012 Collabora Ltd.
*
* 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/>.
*
*
*/
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
#error "Only <cogl/cogl.h> can be included directly."
#endif
#ifndef __COGL_FENCE_H__
#define __COGL_FENCE_H__
#include <cogl/cogl-types.h>
#include <cogl/cogl-framebuffer.h>
/**
* SECTION:cogl-fence
* @short_description: Functions for notification of command completion
*
* Cogl allows notification of GPU command completion; users may mark
* points in the GPU command stream and receive notification when the GPU
* has executed to that point.
*/
/**
* CoglFence:
*
* An opaque object representing a fence. This type is currently
* unused but in the future may be used to pass extra information
* about the fence completion.
*
* Since: 2.0
* Stability: Unstable
*/
typedef struct _CoglFence CoglFence;
/**
* CoglFenceCallback:
* @fence: Unused. In the future this parameter may be used to pass
* extra information about the fence completion but for now it
* should be ignored.
* @user_data: The private data passed to cogl_framebuffer_add_fence_callback()
*
* The callback prototype used with
* cogl_framebuffer_add_fence_callback() for notification of GPU
* command completion.
*
* Since: 2.0
* Stability: Unstable
*/
typedef void (* CoglFenceCallback) (CoglFence *fence,
void *user_data);
/**
* CoglFenceClosure:
*
* An opaque type representing one future callback to be made when the
* GPU command stream has passed a certain point.
*
* Since: 2.0
* Stability: Unstable
*/
typedef struct _CoglFenceClosure CoglFenceClosure;
/**
* cogl_frame_closure_get_user_data:
* @closure: A #CoglFenceClosure returned from cogl_framebuffer_add_fence()
*
* Returns the user_data submitted to cogl_framebuffer_add_fence() which
* returned a given #CoglFenceClosure.
*
* Since: 2.0
* Stability: Unstable
*/
void *
cogl_fence_closure_get_user_data (CoglFenceClosure *closure);
/**
* cogl_framebuffer_add_fence_callback:
* @framebuffer: The #CoglFramebuffer the commands have been submitted to
* @callback: A #CoglFenceCallback to be called when all commands submitted
* to Cogl have been executed
* @user_data: Private data that will be passed to the callback
*
* Calls the provided callback when all previously-submitted commands have
* been executed by the GPU.
*
* Returns non-NULL if the fence succeeded, or %NULL if it was unable to
* be inserted and the callback will never be called. The user does not
* need to free the closure; it will be freed automatically when the
* callback is called, or cancelled.
*
* Since: 2.0
* Stability: Unstable
*/
CoglFenceClosure *
cogl_framebuffer_add_fence_callback (CoglFramebuffer *framebuffer,
CoglFenceCallback callback,
void *user_data);
/**
* cogl_framebuffer_cancel_fence_callback:
* @framebuffer: The #CoglFramebuffer the commands were submitted to
* @closure: The #CoglFenceClosure returned from
* cogl_framebuffer_add_fence_callback()
*
* Removes a fence previously submitted with
* cogl_framebuffer_add_fence_callback(); the callback will not be
* called.
*
* Since: 2.0
* Stability: Unstable
*/
void
cogl_framebuffer_cancel_fence_callback (CoglFramebuffer *framebuffer,
CoglFenceClosure *closure);
#endif /* __COGL_FENCE_H__ */

View File

@ -171,6 +171,8 @@ _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
{
CoglContext *ctx = framebuffer->context;
_cogl_fence_cancel_fences_for_framebuffer (framebuffer);
_cogl_clip_state_destroy (&framebuffer->clip_state);
cogl_object_unref (framebuffer->modelview_stack);

View File

@ -27,6 +27,7 @@
#include "cogl-texture.h"
#include "cogl-object-private.h"
#include "cogl-clip-stack.h"
#include "cogl-fence-private.h"
#define COGL_JOURNAL_VBO_POOL_SIZE 8
@ -58,6 +59,8 @@ typedef struct _CoglJournal
int fast_read_pixel_count;
CoglFenceList pending_fences;
} CoglJournal;
/* To improve batching of geometry when submitting vertices to OpenGL we

View File

@ -154,6 +154,8 @@ _cogl_journal_new (CoglFramebuffer *framebuffer)
journal->entries = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
journal->vertices = g_array_new (FALSE, FALSE, sizeof (float));
COGL_TAILQ_INIT (&journal->pending_fences);
return _cogl_journal_object_new (journal);
}
@ -1267,6 +1269,18 @@ _cogl_journal_all_entries_within_bounds (CoglJournal *journal,
return TRUE;
}
static void
post_fences (CoglJournal *journal)
{
CoglFenceClosure *fence, *next;
COGL_TAILQ_FOREACH_SAFE (fence, &journal->pending_fences, list, next)
{
COGL_TAILQ_REMOVE (&journal->pending_fences, fence, list);
_cogl_fence_submit (fence);
}
}
/* XXX NB: When _cogl_journal_flush() returns all state relating
* to pipelines, all glEnable flags and current matrix state
* is undefined.
@ -1290,7 +1304,10 @@ _cogl_journal_flush (CoglJournal *journal)
0 /* no application private data */);
if (journal->entries->len == 0)
return;
{
post_fences (journal);
return;
}
framebuffer = journal->framebuffer;
ctx = framebuffer->context;
@ -1388,6 +1405,8 @@ _cogl_journal_flush (CoglJournal *journal)
_cogl_journal_discard (journal);
COGL_TIMER_STOP (_cogl_uprof_context, discard_timer);
post_fences (journal);
COGL_TIMER_STOP (_cogl_uprof_context, flush_timer);
}

View File

@ -56,7 +56,8 @@ typedef enum
COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS = 1L<<20,
COGL_PRIVATE_FEATURE_ALPHA_TEXTURES = 1L<<21,
COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE = 1L<<22,
COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL = 1L<<23
COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL = 1L<<23,
COGL_PRIVATE_FEATURE_OES_EGL_SYNC = 1L<<24
} CoglPrivateFeatureFlags;
/* Sometimes when evaluating pipelines, either during comparisons or

View File

@ -109,6 +109,7 @@
#include <cogl/cogl-onscreen.h>
#include <cogl/cogl-frame-info.h>
#include <cogl/cogl-poll.h>
#include <cogl/cogl-fence.h>
#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
#include <cogl/cogl-kms-renderer.h>
#include <cogl/cogl-kms-display.h>

View File

@ -981,3 +981,7 @@ _cogl_atlas_texture_new_with_size
_cogl_atlas_texture_remove_reorganize_callback
_cogl_context_get_default
#endif
cogl_fence_closure_get_user_data
cogl_framebuffer_add_fence_callback
cogl_framebuffer_cancel_fence_callback

View File

@ -597,6 +597,9 @@ _cogl_driver_update_features (CoglContext *ctx,
COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS |
COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL);
if (ctx->glFenceSync)
COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_FENCE, TRUE);
/* Cache features */
ctx->private_feature_flags |= private_flags;
ctx->feature_flags |= flags;

View File

@ -346,6 +346,12 @@ _cogl_driver_update_features (CoglContext *context,
if (_cogl_check_extension ("GL_EXT_unpack_subimage", gl_extensions))
private_flags |= COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE;
/* A nameless vendor implemented the extension, but got the case wrong
* per the spec. */
if (_cogl_check_extension ("GL_OES_EGL_sync", gl_extensions) ||
_cogl_check_extension ("GL_OES_egl_sync", gl_extensions))
private_flags |= COGL_PRIVATE_FEATURE_OES_EGL_SYNC;
/* Cache features */
context->private_feature_flags |= private_flags;
context->feature_flags |= flags;

View File

@ -297,3 +297,15 @@ COGL_EXT_FUNCTION (GLvoid *, glMapBufferRange,
GLsizeiptr length,
GLbitfield access))
COGL_EXT_END ()
COGL_EXT_BEGIN (sync, 3, 2,
0, /* not in either GLES */
"ARB:\0",
"sync\0")
COGL_EXT_FUNCTION (GLsync, glFenceSync,
(GLenum condition, GLbitfield flags))
COGL_EXT_FUNCTION (GLenum, glClientWaitSync,
(GLsync sync, GLbitfield flags, GLuint64 timeout))
COGL_EXT_FUNCTION (void, glDeleteSync,
(GLsync sync))
COGL_EXT_END ()

View File

@ -112,3 +112,23 @@ COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglSwapBuffersWithDamage,
const EGLint *rects,
EGLint n_rects))
COGL_WINSYS_FEATURE_END ()
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
COGL_WINSYS_FEATURE_BEGIN (fence_sync,
"KHR\0",
"fence_sync\0",
COGL_EGL_WINSYS_FEATURE_FENCE_SYNC)
COGL_WINSYS_FEATURE_FUNCTION (EGLSyncKHR, eglCreateSync,
(EGLDisplay dpy,
EGLenum type,
const EGLint *attrib_list))
COGL_WINSYS_FEATURE_FUNCTION (EGLint, eglClientWaitSync,
(EGLDisplay dpy,
EGLSyncKHR sync,
EGLint flags,
EGLTimeKHR timeout))
COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglDestroySync,
(EGLDisplay dpy,
EGLSyncKHR sync))
COGL_WINSYS_FEATURE_END ()
#endif

View File

@ -70,7 +70,8 @@ typedef enum _CoglEGLWinsysFeature
COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_X11_PIXMAP =1L<<1,
COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_WAYLAND_BUFFER =1L<<2,
COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT =1L<<3,
COGL_EGL_WINSYS_FEATURE_BUFFER_AGE =1L<<4
COGL_EGL_WINSYS_FEATURE_BUFFER_AGE =1L<<4,
COGL_EGL_WINSYS_FEATURE_FENCE_SYNC =1L<<5
} CoglEGLWinsysFeature;
typedef struct _CoglRendererEGL

View File

@ -504,6 +504,10 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
}
if ((egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_FENCE_SYNC) &&
(context->private_feature_flags & COGL_PRIVATE_FEATURE_OES_EGL_SYNC))
COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_FENCE, TRUE);
/* NB: We currently only support creating standalone GLES2 contexts
* for offscreen rendering and so we need a dummy (non-visible)
* surface to be able to bind those contexts */
@ -902,6 +906,45 @@ _cogl_winsys_restore_context (CoglContext *ctx)
egl_display->egl_context);
}
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
static void *
_cogl_winsys_fence_add (CoglContext *context)
{
CoglRendererEGL *renderer = context->display->renderer->winsys;
void *ret;
if (renderer->pf_eglCreateSync)
ret = renderer->pf_eglCreateSync (renderer->edpy,
EGL_SYNC_FENCE_KHR,
NULL);
else
ret = NULL;
return ret;
}
static CoglBool
_cogl_winsys_fence_is_complete (CoglContext *context, void *fence)
{
CoglRendererEGL *renderer = context->display->renderer->winsys;
EGLint ret;
ret = renderer->pf_eglClientWaitSync (renderer->edpy,
fence,
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
0);
return (ret == EGL_CONDITION_SATISFIED_KHR);
}
static void
_cogl_winsys_fence_destroy (CoglContext *context, void *fence)
{
CoglRendererEGL *renderer = context->display->renderer->winsys;
renderer->pf_eglDestroySync (renderer->edpy, fence);
}
#endif
static CoglWinsysVtable _cogl_winsys_vtable =
{
.constraints = COGL_RENDERER_CONSTRAINT_USES_EGL |
@ -936,6 +979,12 @@ static CoglWinsysVtable _cogl_winsys_vtable =
.save_context = _cogl_winsys_save_context,
.set_gles2_context = _cogl_winsys_set_gles2_context,
.restore_context = _cogl_winsys_restore_context,
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
.fence_add = _cogl_winsys_fence_add,
.fence_is_complete = _cogl_winsys_fence_is_complete,
.fence_destroy = _cogl_winsys_fence_destroy,
#endif
};
/* XXX: we use a function because no doubt someone will complain

View File

@ -185,6 +185,15 @@ typedef struct _CoglWinsysVtable
void
(*destroy_gles2_context) (CoglGLES2Context *gles2_ctx);
void *
(*fence_add) (CoglContext *ctx);
CoglBool
(*fence_is_complete) (CoglContext *ctx, void *fence);
void
(*fence_destroy) (CoglContext *ctx, void *fence);
} CoglWinsysVtable;
CoglBool

View File

@ -143,6 +143,7 @@
<xi:include href="xml/cogl-vector.xml"/>
<xi:include href="xml/cogl-euler.xml"/>
<xi:include href="xml/cogl-quaternion.xml"/>
<xi:include href="xml/cogl-fence.xml"/>
<xi:include href="xml/cogl-version.xml"/>
</section>

View File

@ -961,6 +961,17 @@ cogl_vector3_dot_product
cogl_vector3_distance
</SECTION>
<SECTION>
<FILE>cogl-fence</FILE>
<TITLE>GPU synchronisation fences</TITLE>
CoglFence
CoglFenceCallback
CoglFenceClosure
cogl_fence_closure_get_user_data
cogl_framebuffer_add_fence_callback
cogl_framebuffer_cancel_fence_callback
</SECTION>
<SECTION>
<FILE>cogl-version</FILE>
<TITLE>Versioning utility macros</TITLE>

View File

@ -66,6 +66,7 @@ test_sources = \
test-primitive-and-journal.c \
test-copy-replace-texture.c \
test-pipeline-cache-unrefs-texture.c \
test-fence.c \
$(NULL)
test_conformance_SOURCES = $(common_sources) $(test_sources)

View File

@ -132,6 +132,8 @@ main (int argc, char **argv)
ADD_TEST (test_euler_quaternion, 0, 0);
ADD_TEST (test_fence, TEST_REQUIREMENT_FENCE, 0);
g_printerr ("Unknown test name \"%s\"\n", argv[1]);
return 1;

View File

@ -0,0 +1,64 @@
#include <cogl/cogl.h>
/* These will be redefined in config.h */
#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
#undef COGL_ENABLE_EXPERIMENTAL_API
#include "test-utils.h"
#include "config.h"
#include <cogl/cogl-util.h>
/* I'm writing this on the train after having dinner at a churrascuria. */
#define MAGIC_CHUNK_O_DATA ((void *) 0xdeadbeef)
static GMainLoop *loop;
gboolean
timeout (void *user_data)
{
g_assert (!"timeout not reached");
return FALSE;
}
void
callback (CoglFence *fence,
void *user_data)
{
int fb_width = cogl_framebuffer_get_width (test_fb);
int fb_height = cogl_framebuffer_get_height (test_fb);
test_utils_check_pixel (test_fb, fb_width - 1, fb_height - 1, 0x00ff0000);
g_assert (user_data == MAGIC_CHUNK_O_DATA && "callback data not mangled");
g_main_loop_quit (loop);
}
void
test_fence (void)
{
GSource *cogl_source;
int fb_width = cogl_framebuffer_get_width (test_fb);
int fb_height = cogl_framebuffer_get_height (test_fb);
CoglFenceClosure *closure;
cogl_source = cogl_glib_source_new (test_ctx, G_PRIORITY_DEFAULT);
g_source_attach (cogl_source, NULL);
loop = g_main_loop_new (NULL, TRUE);
cogl_framebuffer_orthographic (test_fb, 0, 0, fb_width, fb_height, -1, 100);
cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR,
0.0f, 1.0f, 0.0f, 0.0f);
closure = cogl_framebuffer_add_fence_callback (test_fb,
callback,
MAGIC_CHUNK_O_DATA);
g_assert (closure != NULL);
g_timeout_add_seconds (5, timeout, NULL);
g_main_loop_run (loop);
if (cogl_test_verbose ())
g_print ("OK\n");
}

View File

@ -71,6 +71,12 @@ check_flags (TestFlags flags,
return FALSE;
}
if (flags & TEST_REQUIREMENT_FENCE &&
!cogl_has_feature (test_ctx, COGL_FEATURE_ID_FENCE))
{
return FALSE;
}
if (flags & TEST_KNOWN_FAILURE)
{
return FALSE;

View File

@ -20,7 +20,8 @@ typedef enum _TestFlags
TEST_REQUIREMENT_GLES2_CONTEXT = 1<<6,
TEST_REQUIREMENT_MAP_WRITE = 1<<7,
TEST_REQUIREMENT_GLSL = 1<<8,
TEST_REQUIREMENT_OFFSCREEN = 1<<9
TEST_REQUIREMENT_OFFSCREEN = 1<<9,
TEST_REQUIREMENT_FENCE = 1<<10
} TestFlags;
extern CoglContext *test_ctx;