
The previous implementation was dereferencing the sample pointer in order to get the offset to subtract from the member pointer. The resulting value is then only used to get a pointer to the member in order to calculate the offset so it doesn't actually read from the memory location and shouldn't cause any problems. However this is probably technically invalid and could have undefined behaviour. It looks like clang takes advantage of this undefined behaviour and doesn't actually offset the pointer. It also generates a warning when it does this. This patch splits the _cogl_container_of macro into two implementations. Previously the macro was always used in the list iterator macros like this: SomeType *sample = _cogl_container_of(list_node, sample, link) Instead of doing that there is now a new macro called _cogl_list_set_iterator which explicitly assigns to the sample pointer with an initial value before assigning to it again with the real offset. This redundant initialisation gets optimised out by compiler. The second macro is still called _cogl_container_of but instead of taking a sample pointer it just directly takes the type name. That way it can use the standard offsetof macro. https://bugzilla.gnome.org/show_bug.cgi?id=723530 Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 1efed1e0a2bce706eb4901979ed4e717bb13e4e2)
230 lines
6.0 KiB
C
230 lines
6.0 KiB
C
/*
|
|
* 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, *tmp;
|
|
|
|
_cogl_list_for_each_safe (fence, tmp, &context->fences, link)
|
|
_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_list_empty (&fb->journal->pending_fences))
|
|
_cogl_framebuffer_flush_journal (fb);
|
|
}
|
|
|
|
if (!_cogl_list_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_list_insert (context->fences.prev, &fence->link);
|
|
|
|
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_list_insert (journal->pending_fences.prev, &fence->link);
|
|
fence->type = FENCE_TYPE_PENDING;
|
|
}
|
|
else
|
|
_cogl_fence_submit (fence);
|
|
|
|
return fence;
|
|
}
|
|
|
|
void
|
|
cogl_framebuffer_cancel_fence_callback (CoglFramebuffer *framebuffer,
|
|
CoglFenceClosure *fence)
|
|
{
|
|
CoglContext *context = framebuffer->context;
|
|
|
|
if (fence->type == FENCE_TYPE_PENDING)
|
|
{
|
|
_cogl_list_remove (&fence->link);
|
|
}
|
|
else
|
|
{
|
|
_cogl_list_remove (&fence->link);
|
|
|
|
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, *tmp;
|
|
|
|
while (!_cogl_list_empty (&journal->pending_fences))
|
|
{
|
|
fence = _cogl_container_of (journal->pending_fences.next,
|
|
CoglFenceClosure,
|
|
link);
|
|
cogl_framebuffer_cancel_fence_callback (framebuffer, fence);
|
|
}
|
|
|
|
_cogl_list_for_each_safe (fence, tmp, &context->fences, link)
|
|
{
|
|
if (fence->framebuffer == framebuffer)
|
|
cogl_framebuffer_cancel_fence_callback (framebuffer, fence);
|
|
}
|
|
}
|