2013-06-26 20:26:40 +00:00
|
|
|
/*
|
|
|
|
* Cogl
|
|
|
|
*
|
|
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Intel Corporation.
|
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "cogl-types.h"
|
2014-01-02 03:33:03 +00:00
|
|
|
#include "cogl-context-private.h"
|
2013-06-26 20:26:40 +00:00
|
|
|
#include "cogl-framebuffer-private.h"
|
|
|
|
#include "cogl-framebuffer-deprecated.h"
|
|
|
|
|
2014-01-02 03:33:03 +00:00
|
|
|
typedef struct _CoglFramebufferStackEntry
|
|
|
|
{
|
|
|
|
CoglFramebuffer *draw_buffer;
|
|
|
|
CoglFramebuffer *read_buffer;
|
|
|
|
} CoglFramebufferStackEntry;
|
|
|
|
|
|
|
|
|
|
|
|
static CoglFramebufferStackEntry *
|
|
|
|
create_stack_entry (CoglFramebuffer *draw_buffer,
|
|
|
|
CoglFramebuffer *read_buffer)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *entry = g_slice_new (CoglFramebufferStackEntry);
|
|
|
|
|
|
|
|
entry->draw_buffer = draw_buffer;
|
|
|
|
entry->read_buffer = read_buffer;
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
GSList *
|
|
|
|
_cogl_create_framebuffer_stack (void)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *entry;
|
|
|
|
GSList *stack = NULL;
|
|
|
|
|
|
|
|
entry = create_stack_entry (NULL, NULL);
|
|
|
|
|
|
|
|
return g_slist_prepend (stack, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_free_framebuffer_stack (GSList *stack)
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = stack; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *entry = l->data;
|
|
|
|
|
|
|
|
if (entry->draw_buffer)
|
|
|
|
cogl_object_unref (entry->draw_buffer);
|
|
|
|
|
|
|
|
if (entry->read_buffer)
|
|
|
|
cogl_object_unref (entry->draw_buffer);
|
|
|
|
|
|
|
|
g_slice_free (CoglFramebufferStackEntry, entry);
|
|
|
|
}
|
|
|
|
g_slist_free (stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
notify_buffers_changed (CoglFramebuffer *old_draw_buffer,
|
|
|
|
CoglFramebuffer *new_draw_buffer,
|
|
|
|
CoglFramebuffer *old_read_buffer,
|
|
|
|
CoglFramebuffer *new_read_buffer)
|
|
|
|
{
|
|
|
|
/* XXX: To support the deprecated cogl_set_draw_buffer API we keep
|
|
|
|
* track of the last onscreen framebuffer that was set so that it
|
|
|
|
* can be restored if the COGL_WINDOW_BUFFER enum is used. A
|
|
|
|
* reference isn't taken to the framebuffer because otherwise we
|
|
|
|
* would have a circular reference between the context and the
|
|
|
|
* framebuffer. Instead the pointer is set to NULL in
|
|
|
|
* _cogl_onscreen_free as a kind of a cheap weak reference */
|
|
|
|
if (new_draw_buffer &&
|
|
|
|
new_draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
|
|
|
|
new_draw_buffer->context->window_buffer = new_draw_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the current framebuffer without checking if it's already the
|
|
|
|
* current framebuffer. This is used by cogl_pop_framebuffer while
|
|
|
|
* the top of the stack is currently not up to date. */
|
|
|
|
static void
|
|
|
|
_cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer,
|
|
|
|
CoglFramebuffer *read_buffer)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *entry;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
_COGL_RETURN_IF_FAIL (ctx != NULL);
|
|
|
|
_COGL_RETURN_IF_FAIL (draw_buffer && read_buffer ?
|
|
|
|
draw_buffer->context == read_buffer->context : TRUE);
|
|
|
|
|
|
|
|
entry = ctx->framebuffer_stack->data;
|
|
|
|
|
|
|
|
notify_buffers_changed (entry->draw_buffer,
|
|
|
|
draw_buffer,
|
|
|
|
entry->read_buffer,
|
|
|
|
read_buffer);
|
|
|
|
|
|
|
|
if (draw_buffer)
|
|
|
|
cogl_object_ref (draw_buffer);
|
|
|
|
if (entry->draw_buffer)
|
|
|
|
cogl_object_unref (entry->draw_buffer);
|
|
|
|
|
|
|
|
if (read_buffer)
|
|
|
|
cogl_object_ref (read_buffer);
|
|
|
|
if (entry->read_buffer)
|
|
|
|
cogl_object_unref (entry->read_buffer);
|
|
|
|
|
|
|
|
entry->draw_buffer = draw_buffer;
|
|
|
|
entry->read_buffer = read_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_cogl_set_framebuffers (CoglFramebuffer *draw_buffer,
|
|
|
|
CoglFramebuffer *read_buffer)
|
|
|
|
{
|
|
|
|
CoglFramebuffer *current_draw_buffer;
|
|
|
|
CoglFramebuffer *current_read_buffer;
|
|
|
|
|
|
|
|
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer));
|
|
|
|
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer));
|
|
|
|
|
|
|
|
current_draw_buffer = cogl_get_draw_framebuffer ();
|
|
|
|
current_read_buffer = _cogl_get_read_framebuffer ();
|
|
|
|
|
|
|
|
if (current_draw_buffer != draw_buffer ||
|
|
|
|
current_read_buffer != read_buffer)
|
|
|
|
_cogl_set_framebuffers_real (draw_buffer, read_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cogl_set_framebuffer (CoglFramebuffer *framebuffer)
|
|
|
|
{
|
|
|
|
_cogl_set_framebuffers (framebuffer, framebuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: deprecated API */
|
|
|
|
void
|
|
|
|
cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle)
|
|
|
|
{
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
if (target == COGL_WINDOW_BUFFER)
|
|
|
|
handle = ctx->window_buffer;
|
|
|
|
|
|
|
|
/* This is deprecated public API. The public API doesn't currently
|
|
|
|
really expose the concept of separate draw and read buffers so
|
|
|
|
for the time being this actually just sets both buffers */
|
|
|
|
cogl_set_framebuffer (handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglFramebuffer *
|
|
|
|
cogl_get_draw_framebuffer (void)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *entry;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NULL);
|
|
|
|
|
|
|
|
g_assert (ctx->framebuffer_stack);
|
|
|
|
|
|
|
|
entry = ctx->framebuffer_stack->data;
|
|
|
|
|
|
|
|
return entry->draw_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglFramebuffer *
|
|
|
|
_cogl_get_read_framebuffer (void)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *entry;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NULL);
|
|
|
|
|
|
|
|
g_assert (ctx->framebuffer_stack);
|
|
|
|
|
|
|
|
entry = ctx->framebuffer_stack->data;
|
|
|
|
|
|
|
|
return entry->read_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
|
|
|
|
CoglFramebuffer *read_buffer)
|
|
|
|
{
|
|
|
|
CoglContext *ctx;
|
|
|
|
CoglFramebuffer *old_draw_buffer, *old_read_buffer;
|
|
|
|
|
|
|
|
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer));
|
|
|
|
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer));
|
|
|
|
|
|
|
|
ctx = draw_buffer->context;
|
|
|
|
_COGL_RETURN_IF_FAIL (ctx != NULL);
|
|
|
|
_COGL_RETURN_IF_FAIL (draw_buffer->context == read_buffer->context);
|
|
|
|
|
|
|
|
_COGL_RETURN_IF_FAIL (ctx->framebuffer_stack != NULL);
|
|
|
|
|
|
|
|
/* Copy the top of the stack so that when we call cogl_set_framebuffer
|
|
|
|
it will still know what the old framebuffer was */
|
|
|
|
old_draw_buffer = cogl_get_draw_framebuffer ();
|
|
|
|
if (old_draw_buffer)
|
|
|
|
cogl_object_ref (old_draw_buffer);
|
|
|
|
old_read_buffer = _cogl_get_read_framebuffer ();
|
|
|
|
if (old_read_buffer)
|
|
|
|
cogl_object_ref (old_read_buffer);
|
|
|
|
ctx->framebuffer_stack =
|
|
|
|
g_slist_prepend (ctx->framebuffer_stack,
|
|
|
|
create_stack_entry (old_draw_buffer,
|
|
|
|
old_read_buffer));
|
|
|
|
|
|
|
|
_cogl_set_framebuffers (draw_buffer, read_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cogl_push_framebuffer (CoglFramebuffer *buffer)
|
|
|
|
{
|
|
|
|
_cogl_push_framebuffers (buffer, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: deprecated API */
|
|
|
|
void
|
|
|
|
cogl_push_draw_buffer (void)
|
|
|
|
{
|
|
|
|
cogl_push_framebuffer (cogl_get_draw_framebuffer ());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cogl_pop_framebuffer (void)
|
|
|
|
{
|
|
|
|
CoglFramebufferStackEntry *to_pop;
|
|
|
|
CoglFramebufferStackEntry *to_restore;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
g_assert (ctx->framebuffer_stack != NULL);
|
|
|
|
g_assert (ctx->framebuffer_stack->next != NULL);
|
|
|
|
|
|
|
|
to_pop = ctx->framebuffer_stack->data;
|
|
|
|
to_restore = ctx->framebuffer_stack->next->data;
|
|
|
|
|
|
|
|
if (to_pop->draw_buffer != to_restore->draw_buffer ||
|
|
|
|
to_pop->read_buffer != to_restore->read_buffer)
|
|
|
|
notify_buffers_changed (to_pop->draw_buffer,
|
|
|
|
to_restore->draw_buffer,
|
|
|
|
to_pop->read_buffer,
|
|
|
|
to_restore->read_buffer);
|
|
|
|
|
|
|
|
cogl_object_unref (to_pop->draw_buffer);
|
|
|
|
cogl_object_unref (to_pop->read_buffer);
|
|
|
|
g_slice_free (CoglFramebufferStackEntry, to_pop);
|
|
|
|
|
|
|
|
ctx->framebuffer_stack =
|
|
|
|
g_slist_delete_link (ctx->framebuffer_stack,
|
|
|
|
ctx->framebuffer_stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: deprecated API */
|
|
|
|
void
|
|
|
|
cogl_pop_draw_buffer (void)
|
|
|
|
{
|
|
|
|
cogl_pop_framebuffer ();
|
|
|
|
}
|
|
|
|
|
2013-06-26 20:26:40 +00:00
|
|
|
CoglPixelFormat
|
|
|
|
cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer)
|
|
|
|
{
|
|
|
|
return framebuffer->internal_format;
|
|
|
|
}
|