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:
parent
7b14b5e3da
commit
ea7d3b8476
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
61
cogl/cogl-fence-private.h
Normal 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
228
cogl/cogl-fence.c
Normal 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
136
cogl/cogl-fence.h
Normal 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__ */
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 ()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
64
tests/conform/test-fence.c
Normal file
64
tests/conform/test-fence.c
Normal 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");
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user