cogl: Move context, device, and surface members to most fitting places

The buffer stack was moved from the surface to the device, as
mapped buffers are shared across all surfaces using the device
and more than one surface may be doing so. Stemming from this, if
a surface tries to map a buffer without first unmapping one that
has been mapped by another surface, it will trigger an error.

The parent backend functions were moved from the device to the
context, as it is possible that the context creation function could
be passed a non-cogl device. Prior to this change, many of the
subsurface tests segfaulted.

Signed-off-by: George Matsumura <gmmatsumura01@bvsd.org>
This commit is contained in:
George Matsumura 2020-06-29 13:37:20 -06:00
parent a3233bc5df
commit 75d843208c
6 changed files with 273 additions and 232 deletions

View file

@ -70,7 +70,6 @@ _cairo_boilerplate_cogl_create_offscreen_color_surface (const char *name,
{
cairo_device_t *device;
CoglTexture *tex;
CoglHandle offscreen;
CoglFramebuffer *fb;
cogl_closure_t *closure;
cairo_status_t status;
@ -81,8 +80,7 @@ _cairo_boilerplate_cogl_create_offscreen_color_surface (const char *name,
device = cairo_cogl_device_create (context);
tex = cogl_texture_2d_new_with_size (context, width, height);
cogl_texture_set_components (tex, COGL_TEXTURE_COMPONENTS_RGBA);
offscreen = cogl_offscreen_new_with_texture (tex);
fb = COGL_FRAMEBUFFER (offscreen);
fb = cogl_offscreen_new_with_texture (tex);
cogl_framebuffer_allocate (fb, NULL);
cogl_framebuffer_orthographic (fb, 0, 0,
@ -116,7 +114,6 @@ _cairo_boilerplate_cogl_create_onscreen_color_surface (const char *name,
void **abstract_closure)
{
cairo_device_t *device;
CoglOnscreen *onscreen;
CoglFramebuffer *fb;
cogl_closure_t *closure;
cairo_status_t status;
@ -125,10 +122,9 @@ _cairo_boilerplate_cogl_create_onscreen_color_surface (const char *name,
context = cogl_context_new (NULL, NULL);
device = cairo_cogl_device_create (context);
onscreen = cogl_onscreen_new (context, width, height);
fb = COGL_FRAMEBUFFER (onscreen);
fb = cogl_onscreen_new (context, width, height);
cogl_onscreen_show (onscreen);
cogl_onscreen_show (fb);
cogl_framebuffer_orthographic (fb, 0, 0,
cogl_framebuffer_get_width (fb),

View file

@ -38,12 +38,18 @@
typedef struct _cairo_cogl_context {
cairo_default_context_t base;
cairo_cogl_device_t *dev;
int path_ctm_age;
cairo_path_fixed_t user_path;
cairo_bool_t path_is_rectangle;
double x, y, width, height;
cairo_backend_t backend;
/* We save a copy of all the original backend methods that we override so
* we can chain up...
*/
cairo_backend_t backend_parent;
} cairo_cogl_context_t;
cairo_t *

View file

@ -58,6 +58,7 @@
#include "cairo-freed-pool-private.h"
#include "cairo-arc-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-surface-subsurface-inline.h"
#include <glib.h>
@ -75,7 +76,7 @@ _cairo_cogl_context_rectangle_real (cairo_cogl_context_t *cr,
double width, double height)
{
cairo_status_t status;
status = cr->dev->backend_parent.rectangle (cr, x, y, width, height);
status = cr->backend_parent.rectangle (cr, x, y, width, height);
if (unlikely (status))
return status;
@ -124,7 +125,7 @@ _cairo_cogl_context_restore (void *abstract_cr)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.restore (abstract_cr);
return cr->backend_parent.restore (abstract_cr);
}
static cairo_status_t
@ -139,7 +140,7 @@ _cairo_cogl_context_translate (void *abstract_cr, double tx, double ty)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.translate (abstract_cr, tx, ty);
return cr->backend_parent.translate (abstract_cr, tx, ty);
}
static cairo_status_t
@ -154,7 +155,7 @@ _cairo_cogl_context_scale (void *abstract_cr, double sx, double sy)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.scale (abstract_cr, sx, sy);
return cr->backend_parent.scale (abstract_cr, sx, sy);
}
static cairo_status_t
@ -169,7 +170,7 @@ _cairo_cogl_context_rotate (void *abstract_cr, double theta)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.rotate (abstract_cr, theta);
return cr->backend_parent.rotate (abstract_cr, theta);
}
static cairo_status_t
@ -184,7 +185,7 @@ _cairo_cogl_context_transform (void *abstract_cr, const cairo_matrix_t *matrix)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.transform (abstract_cr, matrix);
return cr->backend_parent.transform (abstract_cr, matrix);
}
static cairo_status_t
@ -199,7 +200,7 @@ _cairo_cogl_context_set_matrix (void *abstract_cr, const cairo_matrix_t *matrix)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.set_matrix (abstract_cr, matrix);
return cr->backend_parent.set_matrix (abstract_cr, matrix);
}
static cairo_status_t
@ -214,7 +215,7 @@ _cairo_cogl_context_set_identity_matrix (void *abstract_cr)
}
cr->path_ctm_age++;
return cr->dev->backend_parent.set_identity_matrix (abstract_cr);
return cr->backend_parent.set_identity_matrix (abstract_cr);
}
static cairo_status_t
@ -229,7 +230,7 @@ _cairo_cogl_context_new_path (void *abstract_cr)
return status;
}
status = cr->dev->backend_parent.new_path (abstract_cr);
status = cr->backend_parent.new_path (abstract_cr);
if (unlikely (status))
return status;
@ -252,7 +253,7 @@ _cairo_cogl_context_new_sub_path (void *abstract_cr)
return status;
}
status = cr->dev->backend_parent.new_sub_path (abstract_cr);
status = cr->backend_parent.new_sub_path (abstract_cr);
if (unlikely (status))
return status;
@ -274,7 +275,7 @@ _cairo_cogl_context_move_to (void *abstract_cr, double x, double y)
return status;
}
status = cr->dev->backend_parent.move_to (abstract_cr, x, y);
status = cr->backend_parent.move_to (abstract_cr, x, y);
if (unlikely (status))
return status;
@ -297,7 +298,7 @@ _cairo_cogl_context_line_to (void *abstract_cr, double x, double y)
return status;
}
status = cr->dev->backend_parent.line_to (abstract_cr, x, y);
status = cr->backend_parent.line_to (abstract_cr, x, y);
if (unlikely (status))
return status;
@ -328,7 +329,7 @@ _cairo_cogl_context_curve_to (void *abstract_cr,
return status;
}
status = cr->dev->backend_parent.curve_to (abstract_cr, x1, y1, x2, y2, x3, y3);
status = cr->backend_parent.curve_to (abstract_cr, x1, y1, x2, y2, x3, y3);
if (unlikely (status))
return status;
@ -366,7 +367,7 @@ _cairo_cogl_context_arc (void *abstract_cr,
return status;
}
status = cr->dev->backend_parent.arc (abstract_cr, xc, yc, radius, angle1, angle2, forward);
status = cr->backend_parent.arc (abstract_cr, xc, yc, radius, angle1, angle2, forward);
if (unlikely (status))
return status;
@ -419,7 +420,7 @@ _cairo_cogl_context_rel_move_to (void *abstract_cr, double dx, double dy)
return status;
}
status = cr->dev->backend_parent.rel_move_to (abstract_cr, dx, dy);
status = cr->backend_parent.rel_move_to (abstract_cr, dx, dy);
if (unlikely (status))
return status;
@ -442,7 +443,7 @@ _cairo_cogl_context_rel_line_to (void *abstract_cr, double dx, double dy)
return status;
}
status = cr->dev->backend_parent.rel_line_to (abstract_cr, dx, dy);
status = cr->backend_parent.rel_line_to (abstract_cr, dx, dy);
if (unlikely (status))
return status;
@ -474,7 +475,7 @@ _cairo_cogl_context_rel_curve_to (void *abstract_cr,
return status;
}
status = cr->dev->backend_parent.rel_curve_to (abstract_cr, dx1, dy1, dx2, dy2, dx3, dy3);
status = cr->backend_parent.rel_curve_to (abstract_cr, dx1, dy1, dx2, dy2, dx3, dy3);
if (unlikely (status))
return status;
@ -512,7 +513,7 @@ _cairo_cogl_context_arc_to (void *abstract_cr,
return status;
}
status = cr->dev->backend_parent.arc_to (abstract_cr, x1, y1, x2, y2, radius);
status = cr->backend_parent.arc_to (abstract_cr, x1, y1, x2, y2, radius);
if (unlikely (status))
return status;
#warning "FIXME"
@ -533,7 +534,7 @@ _cairo_cogl_rel_arc_to (void *cr,
return status;
}
status = cr->dev->backend_parent.rel_arc_to (abstract_cr, dx1, dy2, dx2, dy2, radius);
status = cr->backend_parent.rel_arc_to (abstract_cr, dx1, dy2, dx2, dy2, radius);
if (unlikely (status))
return status;
#warning "FIXME"
@ -552,7 +553,7 @@ _cairo_cogl_context_close_path (void *abstract_cr)
return status;
}
status = cr->dev->backend_parent.close_path (abstract_cr);
status = cr->backend_parent.close_path (abstract_cr);
if (unlikely (status))
return status;
@ -623,31 +624,55 @@ _cairo_cogl_surface_set_side_band_state (cairo_cogl_surface_t *surface,
}
}
static cairo_cogl_surface_t *
_cairo_cogl_get_cogl_surface (cairo_surface_t *target)
{
/* Collapse all nested subsurfaces. If another method of target
* surface redirection is added to cairo, we can add a test here. */
while (1) {
if (_cairo_surface_is_subsurface (target)) {
target = _cairo_surface_subsurface_get_target (target);
} else if (target->type == CAIRO_SURFACE_TYPE_COGL) {
return (cairo_cogl_surface_t *)target;
} else {
/* return NULL if the target is not a cogl surface */
return NULL;
}
}
}
static cairo_status_t
_cairo_cogl_context_fill (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
cairo_cogl_surface_t *surface =
_cairo_cogl_get_cogl_surface (cr->base.gstate->target);
if (cr->path_is_rectangle) {
status = _cairo_cogl_surface_fill_rectangle (cr->base.gstate->target,
cr->base.gstate->op,
cr->base.gstate->source,
cr->x,
cr->y,
cr->width,
cr->height,
&cr->base.gstate->ctm,
cr->base.gstate->clip);
if (status == CAIRO_STATUS_SUCCESS)
goto DONE;
_flush_cr_rectangle (cr);
if (surface) {
status = _cairo_cogl_surface_fill_rectangle ((cairo_surface_t *)surface,
cr->base.gstate->op,
cr->base.gstate->source,
cr->x,
cr->y,
cr->width,
cr->height,
&cr->base.gstate->ctm,
cr->base.gstate->clip);
if (status == CAIRO_STATUS_SUCCESS)
goto DONE;
}
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
_cairo_cogl_surface_set_side_band_state (surface, cr);
if (surface)
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->dev->backend_parent.fill (abstract_cr);
status = cr->backend_parent.fill (abstract_cr);
if (unlikely (status))
return status;
@ -664,14 +689,37 @@ _cairo_cogl_context_fill_preserve (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
cairo_cogl_surface_t *surface =
_cairo_cogl_get_cogl_surface (cr->base.gstate->target);
_cairo_cogl_surface_set_side_band_state (surface, cr);
if (cr->path_is_rectangle) {
if (surface) {
status = _cairo_cogl_surface_fill_rectangle ((cairo_surface_t *)surface,
cr->base.gstate->op,
cr->base.gstate->source,
cr->x,
cr->y,
cr->width,
cr->height,
&cr->base.gstate->ctm,
cr->base.gstate->clip);
if (status == CAIRO_STATUS_SUCCESS)
goto DONE;
}
status = cr->dev->backend_parent.fill_preserve (abstract_cr);
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
if (surface)
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->backend_parent.fill_preserve (abstract_cr);
if (unlikely (status))
return status;
DONE:
return CAIRO_STATUS_SUCCESS;
}
@ -680,11 +728,20 @@ _cairo_cogl_context_stroke (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
cairo_cogl_surface_t *surface =
_cairo_cogl_get_cogl_surface (cr->base.gstate->target);
_cairo_cogl_surface_set_side_band_state (surface, cr);
/* This operator can't use an accelerated rectangle path yet */
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.stroke (abstract_cr);
if (surface)
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->backend_parent.stroke (abstract_cr);
if (unlikely (status))
return status;
@ -700,11 +757,20 @@ _cairo_cogl_context_stroke_preserve (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
cairo_cogl_surface_t *surface =
_cairo_cogl_get_cogl_surface (cr->base.gstate->target);
_cairo_cogl_surface_set_side_band_state (surface, cr);
/* This operator can't use an accelerated rectangle path yet */
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.stroke_preserve (abstract_cr);
if (surface)
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->backend_parent.stroke_preserve (abstract_cr);
if (unlikely (status))
return status;
@ -716,8 +782,20 @@ _cairo_cogl_context_clip (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface =
_cairo_cogl_get_cogl_surface (cr->base.gstate->target);
status = cr->dev->backend_parent.clip (abstract_cr);
/* This operator can't use an accelerated rectangle path yet */
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
if (surface)
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->backend_parent.clip (abstract_cr);
if (unlikely (status))
return status;
@ -728,6 +806,31 @@ _cairo_cogl_context_clip (void *abstract_cr)
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_clip_preserve (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface =
_cairo_cogl_get_cogl_surface (cr->base.gstate->target);
/* This operator can't use an accelerated rectangle path yet */
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
if (surface)
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->backend_parent.clip_preserve (abstract_cr);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_cogl_context_destroy (void *abstract_cr)
{
@ -742,61 +845,9 @@ _cairo_cogl_context_destroy (void *abstract_cr)
_freed_pool_put (&context_pool, cr);
}
static cairo_pattern_t *
_cairo_cogl_context_pop_group (void *abstract_cr);
void
_cairo_cogl_context_set_custom_vtable_funcs (cairo_backend_t *backend);
/* Pushed surfaces often take the form of image or recording surfaces,
* which are unable to handle the rectangle fast path or tessellation
* cacheing. Therfore, we need to restore the vtable functions from the
* default context. */
static cairo_status_t
_cairo_cogl_context_push_group (void *abstract_cr, cairo_content_t content)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
/* Flush the values set in the side band to the normal path */
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
/* Just assume the ctm will be modified */
cr->path_ctm_age++;
status = cr->dev->backend_parent.push_group (abstract_cr, content);
if (unlikely (status))
return status;
/* Restore all the vtable functions except the popping function */
memcpy (&cr->dev->backend, &cr->dev->backend_parent, sizeof (cairo_backend_t));
cr->dev->backend.pop_group = _cairo_cogl_context_pop_group;
return CAIRO_STATUS_SUCCESS;
}
static cairo_pattern_t *
_cairo_cogl_context_pop_group (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_pattern_t *group_pattern;
/* The default popping function can still be found at
* backend_parent */
group_pattern = cr->dev->backend_parent.pop_group (abstract_cr);
/* Skip restoring the vtable funcs if we are popping to a pushed
* surface */
if (cr->base.gstate->target->type == CAIRO_SURFACE_TYPE_COGL)
_cairo_cogl_context_set_custom_vtable_funcs (&cr->dev->backend);
return group_pattern;
}
/* We want to hook into the frontend of the path construction APIs so
* we can build up a path description in user coordinates instead of
* backend coordinates so that we can recognize user coordinate
@ -806,7 +857,6 @@ _cairo_cogl_context_pop_group (void *abstract_cr)
cairo_t *
_cairo_cogl_context_create (void *target)
{
cairo_cogl_surface_t *surface = target;
cairo_cogl_context_t *cr;
cairo_status_t status;
@ -823,18 +873,12 @@ _cairo_cogl_context_create (void *target)
return _cairo_create_in_error (status);
}
cr->dev = (cairo_cogl_device_t *)surface->base.device;
memcpy (&cr->backend, cr->base.base.backend, sizeof (cairo_backend_t));
memcpy (&cr->backend_parent, cr->base.base.backend, sizeof (cairo_backend_t));
if (unlikely (cr->dev->backend_vtable_initialized == FALSE)) {
memcpy (&cr->dev->backend, cr->base.base.backend, sizeof (cairo_backend_t));
memcpy (&cr->dev->backend_parent, cr->base.base.backend, sizeof (cairo_backend_t));
_cairo_cogl_context_set_custom_vtable_funcs (&cr->backend);
_cairo_cogl_context_set_custom_vtable_funcs (&cr->dev->backend);
cr->dev->backend_vtable_initialized = TRUE;
}
cr->base.base.backend = &cr->dev->backend;
cr->base.base.backend = &cr->backend;
_cairo_path_fixed_init (&cr->user_path);
cr->path_is_rectangle = FALSE;
@ -849,9 +893,6 @@ _cairo_cogl_context_set_custom_vtable_funcs (cairo_backend_t *backend)
backend->restore = _cairo_cogl_context_restore;
backend->push_group = _cairo_cogl_context_push_group;
backend->pop_group = _cairo_cogl_context_pop_group;
backend->translate = _cairo_cogl_context_translate;
backend->scale = _cairo_cogl_context_scale;
backend->rotate = _cairo_cogl_context_rotate;
@ -886,4 +927,5 @@ _cairo_cogl_context_set_custom_vtable_funcs (cairo_backend_t *backend)
backend->stroke = _cairo_cogl_context_stroke;
backend->stroke_preserve = _cairo_cogl_context_stroke_preserve;
backend->clip = _cairo_cogl_context_clip;
backend->clip_preserve = _cairo_cogl_context_clip_preserve;
}

View file

@ -37,7 +37,7 @@
#include <cogl/cogl2-experimental.h>
#include <glib.h>
#define DUMP_GRADIENTS_TO_PNG
//#define DUMP_GRADIENTS_TO_PNG
static unsigned long
_cairo_cogl_linear_gradient_hash (unsigned int n_stops,
@ -568,9 +568,9 @@ _cairo_cogl_get_linear_gradient (cairo_cogl_device_t *device,
goto BAIL;
}
cogl_texture_set_components (COGL_TEXTURE (tex), components);
cogl_texture_set_components (tex, components);
entry->texture = COGL_TEXTURE (tex);
entry->texture = tex;
entry->compatibility = compatibilities;
un_padded_width = width - left_padding - right_padding;
@ -583,11 +583,10 @@ _cairo_cogl_get_linear_gradient (cairo_cogl_device_t *device,
entry->translate_x += (entry->scale_x / (float)un_padded_width) * (float)left_padding;
offscreen = cogl_offscreen_new_with_texture (tex);
cogl_framebuffer_orthographic (COGL_FRAMEBUFFER (offscreen),
0, 0, width, 1, -1, 100);
cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
COGL_BUFFER_BIT_COLOR,
0, 0, 0, 0);
cogl_framebuffer_orthographic (offscreen, 0, 0, width, 1, -1, 100);
cogl_framebuffer_clear4f (offscreen,
COGL_BUFFER_BIT_COLOR,
0, 0, 0, 0);
n_quads = n_stops - 1 + !!left_padding + !!right_padding;
n_vertices = 6 * n_quads;
@ -609,7 +608,7 @@ _cairo_cogl_get_linear_gradient (cairo_cogl_device_t *device,
n_vertices,
vertices);
pipeline = cogl_pipeline_new (device->cogl_context);
cogl_primitive_draw (prim, COGL_FRAMEBUFFER (offscreen), pipeline);
cogl_primitive_draw (prim, offscreen, pipeline);
cogl_object_unref (prim);
cogl_object_unref (offscreen);
@ -618,7 +617,7 @@ _cairo_cogl_get_linear_gradient (cairo_cogl_device_t *device,
gradient->cache_entry.size = _cairo_cogl_linear_gradient_size (gradient);
#ifdef DUMP_GRADIENTS_TO_PNG
dump_gradient_to_png (COGL_TEXTURE (tex));
dump_gradient_to_png (tex);
#endif
#warning "FIXME:"

View file

@ -51,18 +51,15 @@ typedef enum _cairo_cogl_template_type {
typedef struct _cairo_cogl_device {
cairo_device_t base;
cairo_bool_t backend_vtable_initialized;
cairo_backend_t backend;
/* We save a copy of all the original backend methods that we override so
* we can chain up...
*/
cairo_backend_t backend_parent;
CoglContext *cogl_context;
CoglTexture *dummy_texture;
CoglAttributeBuffer *buffer_stack;
size_t buffer_stack_size;
size_t buffer_stack_offset;
guint8 *buffer_stack_pointer;
/* This is a sparsely filled set of templates because we don't support
* the full range of operators that cairo has. All entries corresponding
* to unsupported operators are NULL.
@ -112,11 +109,6 @@ typedef struct _cairo_cogl_surface {
GQueue *journal;
CoglAttributeBuffer *buffer_stack;
size_t buffer_stack_size;
size_t buffer_stack_offset;
guint8 *buffer_stack_pointer;
cairo_clip_t *last_clip;
/* A small fifo of recently used cairo_clip_ts paired with CoglPrimitives

View file

@ -236,7 +236,8 @@ _cairo_cogl_surface_ensure_framebuffer (cairo_cogl_surface_t *surface)
if (surface->framebuffer)
return CAIRO_STATUS_SUCCESS;
surface->framebuffer = COGL_FRAMEBUFFER (cogl_offscreen_new_with_texture (surface->texture));
surface->framebuffer =
cogl_offscreen_new_with_texture (surface->texture);
if (!cogl_framebuffer_allocate (surface->framebuffer, &error)) {
g_error_free (error);
cogl_object_unref (surface->framebuffer);
@ -261,12 +262,10 @@ _cairo_cogl_surface_create_similar (void *abstract_surface,
cairo_cogl_surface_t *surface;
CoglTexture *texture;
cairo_status_t status;
CoglContext *cogl_context;
cogl_context = cogl_framebuffer_get_context(reference_surface->framebuffer);
texture = cogl_texture_2d_new_with_size (cogl_context, width,
height);
texture =
cogl_texture_2d_new_with_size (to_device(reference_surface->base.device)->cogl_context,
width, height);
if (!texture)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@ -452,16 +451,18 @@ static void
_cairo_cogl_journal_discard (cairo_cogl_surface_t *surface)
{
GList *l;
cairo_cogl_device_t *dev;
if (!surface->journal) {
assert (surface->last_clip == NULL);
return;
}
if (surface->buffer_stack && surface->buffer_stack_offset) {
cogl_buffer_unmap (COGL_BUFFER (surface->buffer_stack));
cogl_object_unref (surface->buffer_stack);
surface->buffer_stack = NULL;
dev = to_device(surface->base.device);
if (dev->buffer_stack && dev->buffer_stack_offset) {
cogl_buffer_unmap (dev->buffer_stack);
cogl_object_unref (dev->buffer_stack);
dev->buffer_stack = NULL;
}
for (l = surface->journal->head; l; l = l->next) {
@ -516,45 +517,42 @@ _cairo_cogl_journal_discard (cairo_cogl_surface_t *surface)
}
static CoglAttributeBuffer *
_cairo_cogl_surface_allocate_buffer_space (cairo_cogl_surface_t *surface,
size_t size,
size_t *offset,
void **pointer)
_cairo_cogl_device_allocate_buffer_space (cairo_cogl_device_t *dev,
size_t size,
size_t *offset,
void **pointer)
{
CoglContext *cogl_context =
cogl_framebuffer_get_context(surface->framebuffer);
/* XXX: In the Cogl journal we found it more efficient to have a pool of
* buffers that we re-cycle but for now we simply throw away our stack
* buffer each time we flush. */
if (unlikely (surface->buffer_stack &&
(surface->buffer_stack_size - surface->buffer_stack_offset) < size)) {
cogl_buffer_unmap (COGL_BUFFER (surface->buffer_stack));
cogl_object_unref (surface->buffer_stack);
surface->buffer_stack = NULL;
surface->buffer_stack_size *= 2;
if (unlikely (dev->buffer_stack &&
(dev->buffer_stack_size - dev->buffer_stack_offset) < size)) {
cogl_buffer_unmap (dev->buffer_stack);
cogl_object_unref (dev->buffer_stack);
dev->buffer_stack = NULL;
dev->buffer_stack_size *= 2;
}
if (unlikely (surface->buffer_stack_size < size))
surface->buffer_stack_size = size * 2;
if (unlikely (dev->buffer_stack_size < size))
dev->buffer_stack_size = size * 2;
if (unlikely (surface->buffer_stack == NULL)) {
surface->buffer_stack =
cogl_attribute_buffer_new (cogl_context,
surface->buffer_stack_size,
if (unlikely (dev->buffer_stack == NULL)) {
dev->buffer_stack =
cogl_attribute_buffer_new (dev->cogl_context,
dev->buffer_stack_size,
NULL);
surface->buffer_stack_pointer =
cogl_buffer_map (COGL_BUFFER (surface->buffer_stack),
dev->buffer_stack_pointer =
cogl_buffer_map (dev->buffer_stack,
COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD);
surface->buffer_stack_offset = 0;
dev->buffer_stack_offset = 0;
}
*pointer = surface->buffer_stack_pointer + surface->buffer_stack_offset;
*offset = surface->buffer_stack_offset;
*pointer = dev->buffer_stack_pointer + dev->buffer_stack_offset;
*offset = dev->buffer_stack_offset;
surface->buffer_stack_offset += size;
return cogl_object_ref (surface->buffer_stack);
dev->buffer_stack_offset += size;
return cogl_object_ref (dev->buffer_stack);
}
@ -564,29 +562,27 @@ _cairo_cogl_traps_to_triangles_buffer (cairo_cogl_surface_t *surface,
size_t *offset,
gboolean one_shot)
{
CoglContext *cogl_context =
cogl_framebuffer_get_context(surface->framebuffer);
CoglAttributeBuffer *buffer;
int n_traps = traps->num_traps;
int i;
CoglVertexP2 *triangles;
if (one_shot) {
buffer = _cairo_cogl_surface_allocate_buffer_space (surface,
n_traps * sizeof (CoglVertexP2) * 6,
offset,
(void **)&triangles);
buffer =
_cairo_cogl_device_allocate_buffer_space (to_device(surface->base.device),
n_traps * sizeof (CoglVertexP2) * 6,
offset,
(void **)&triangles);
if (!buffer)
return NULL;
} else {
buffer =
cogl_attribute_buffer_new (cogl_context,
cogl_attribute_buffer_new (to_device(surface->base.device)->cogl_context,
n_traps * sizeof (CoglVertexP2) * 6,
NULL);
if (!buffer)
return NULL;
triangles = cogl_buffer_map (COGL_BUFFER (buffer),
triangles = cogl_buffer_map (buffer,
COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD);
if (!triangles)
@ -626,7 +622,7 @@ _cairo_cogl_traps_to_triangles_buffer (cairo_cogl_surface_t *surface,
}
if (!one_shot)
cogl_buffer_unmap (COGL_BUFFER (buffer));
cogl_buffer_unmap (buffer);
return buffer;
}
@ -780,16 +776,23 @@ static void
_cairo_cogl_journal_flush (cairo_cogl_surface_t *surface)
{
GList *l;
cairo_cogl_device_t *dev;
int clip_stack_depth = 0;
int i;
if (!surface->journal)
return;
if (surface->buffer_stack && surface->buffer_stack_offset) {
cogl_buffer_unmap (COGL_BUFFER (surface->buffer_stack));
cogl_object_unref (surface->buffer_stack);
surface->buffer_stack = NULL;
dev = to_device(surface->base.device);
if (dev->buffer_stack && dev->buffer_stack_offset) {
cogl_buffer_unmap (dev->buffer_stack);
cogl_object_unref (dev->buffer_stack);
dev->buffer_stack = NULL;
}
if (_cairo_cogl_surface_ensure_framebuffer (surface)) {
g_warning ("Could not get framebuffer for flushing journal\n");
assert (0);
}
cogl_framebuffer_push_matrix (surface->framebuffer);
@ -1373,8 +1376,9 @@ _cairo_cogl_get_pot_texture (CoglContext *context,
int height = cogl_texture_get_height (texture);
int pot_width;
int pot_height;
CoglHandle offscreen = NULL;
CoglOffscreen *offscreen = NULL;
CoglTexture2D *pot = NULL;
CoglPipeline *pipeline;
GError *error;
pot_width = _cairo_cogl_util_next_p2 (width);
@ -1399,18 +1403,18 @@ _cairo_cogl_get_pot_texture (CoglContext *context,
break;
}
*pot_texture = COGL_TEXTURE (pot);
*pot_texture = pot;
if (!pot)
return CAIRO_INT_STATUS_NO_MEMORY;
cogl_texture_set_components (COGL_TEXTURE (tex),
cogl_texture_set_components (pot,
cogl_texture_get_components(texture));
/* Use the GPU to do a bilinear filtered scale from npot to pot... */
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (pot));
offscreen = cogl_offscreen_new_with_texture (pot);
error = NULL;
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error)) {
if (!cogl_framebuffer_allocate (offscreen, &error)) {
/* NB: if we don't pass an error then Cogl is allowed to simply abort
* automatically. */
g_error_free (error);
@ -1419,10 +1423,11 @@ _cairo_cogl_get_pot_texture (CoglContext *context,
return CAIRO_INT_STATUS_NO_MEMORY;
}
cogl_push_framebuffer (COGL_FRAMEBUFFER (offscreen));
cogl_set_source_texture (texture);
cogl_rectangle (-1, 1, 1, -1);
cogl_pop_framebuffer ();
pipeline = cogl_pipeline_new (context);
cogl_pipeline_set_layer_texture (pipeline, 1, texture);
cogl_framebuffer_draw_textured_rectangle (offscreen, pipeline,
-1, 1, 1, -1,
0, 0, 1, 1);
cogl_object_unref (offscreen);
}
@ -1432,7 +1437,7 @@ _cairo_cogl_get_pot_texture (CoglContext *context,
* be unrefed */
static CoglTexture *
_cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surface,
cairo_surface_t *abstract_surface)
cairo_surface_t *surface)
{
cairo_image_surface_t *image;
cairo_image_surface_t *acquired_image = NULL;
@ -1443,27 +1448,25 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surface,
GError *error = NULL;
cairo_surface_t *clone;
if (abstract_surface->device == reference_surface->base.device) {
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
_cairo_cogl_surface_flush (surface, 0);
return surface->texture ? cogl_object_ref (surface->texture) : NULL;
if (surface->device == reference_surface->base.device) {
_cairo_cogl_surface_flush ((cairo_cogl_surface_t *)surface, 0);
if (((cairo_cogl_surface_t *)surface)->texture)
return cogl_object_ref (((cairo_cogl_surface_t *)surface)->texture);
}
if (abstract_surface->type == CAIRO_SURFACE_TYPE_COGL) {
if (_cairo_surface_is_subsurface (abstract_surface)) {
cairo_cogl_surface_t *surface;
surface = (cairo_cogl_surface_t *)
_cairo_surface_subsurface_get_target (abstract_surface);
if (surface->base.device == reference_surface->base.device)
return surface->texture ? cogl_object_ref (surface->texture) : NULL;
if (surface->type == CAIRO_SURFACE_TYPE_COGL) {
if (_cairo_surface_is_subsurface (surface)) {
surface = _cairo_surface_subsurface_get_target (surface);
if (surface->device == reference_surface->base.device)
if (((cairo_cogl_surface_t *)surface)->texture)
return cogl_object_ref (((cairo_cogl_surface_t *)surface)->texture);
}
}
clone = _cairo_surface_has_snapshot (abstract_surface, &_cairo_cogl_surface_backend);
clone = _cairo_surface_has_snapshot (surface, &_cairo_cogl_surface_backend);
if (clone) {
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)clone;
return surface->texture ? cogl_object_ref (surface->texture) : NULL;
if (((cairo_cogl_surface_t *)clone)->texture)
return cogl_object_ref (((cairo_cogl_surface_t *)clone)->texture);
}
if (_cairo_surface_is_recording (surface)) {
@ -1490,16 +1493,18 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surface,
}
cairo_surface_destroy (clone);
return ((cairo_cogl_surface_t *)clone)->texture;
return texture;
}
// g_warning ("Uploading image surface to texture");
if (_cairo_surface_is_image (abstract_surface)) {
image = (cairo_image_surface_t *)abstract_surface;
if (_cairo_surface_is_image (surface)) {
image = (cairo_image_surface_t *)surface;
} else {
cairo_status_t status = _cairo_surface_acquire_source_image (abstract_surface,
&acquired_image, &image_extra);
cairo_status_t status =
_cairo_surface_acquire_source_image (surface,
&acquired_image,
&image_extra);
if (unlikely (status)) {
g_warning ("acquire_source_image failed: %s [%d]\n",
cairo_status_to_string (status), status);
@ -1537,9 +1542,9 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surface,
clone = _cairo_cogl_surface_create_full (to_device(reference_surface->base.device),
reference_surface->ignore_alpha,
NULL, COGL_TEXTURE (texture));
NULL, texture);
_cairo_surface_attach_snapshot (abstract_surface, clone, NULL);
_cairo_surface_attach_snapshot (surface, clone, NULL);
/* Attaching the snapshot will take a reference on the clone surface... */
cairo_surface_destroy (clone);
@ -1548,9 +1553,9 @@ BAIL:
if (image_clone)
cairo_surface_destroy (&image_clone->base);
if (acquired_image)
_cairo_surface_release_source_image (abstract_surface, acquired_image, image_extra);
_cairo_surface_release_source_image (surface, acquired_image, image_extra);
return COGL_TEXTURE (texture);
return texture;
}
/* NB: a reference for the texture is transferred to the caller which should
@ -1847,7 +1852,7 @@ _cairo_cogl_rectangle_new_p2t2t2 (CoglContext *cogl_context,
COGL_ATTRIBUTE_TYPE_FLOAT);
CoglPrimitive *prim;
cogl_buffer_set_data (COGL_BUFFER (buffer), 0, vertices, sizeof (vertices));
cogl_buffer_set_data (buffer, 0, vertices, sizeof (vertices));
/* The attributes will now keep the buffer alive... */
cogl_object_unref (buffer);
@ -2669,13 +2674,13 @@ _cairo_cogl_surface_create_full (cairo_cogl_device_t *dev,
surface->journal = NULL;
surface->buffer_stack = NULL;
surface->buffer_stack_size = 4096;
surface->last_clip = NULL;
surface->n_clip_updates_per_frame = 0;
surface->path_is_rectangle = FALSE;
surface->user_path = NULL;
_cairo_surface_init (&surface->base,
&_cairo_cogl_surface_backend,
&dev->base,
@ -2870,8 +2875,6 @@ cairo_cogl_device_create (CoglContext *cogl_context)
cairo_cogl_device_t *dev = g_new0 (cairo_cogl_device_t, 1);
cairo_status_t status;
dev->backend_vtable_initialized = FALSE;
dev->cogl_context = cogl_context;
dev->dummy_texture = cogl_texture_2d_new_with_size (cogl_context,
@ -2879,6 +2882,9 @@ cairo_cogl_device_create (CoglContext *cogl_context)
if (!dev->dummy_texture)
goto ERROR;
dev->buffer_stack = NULL;
dev->buffer_stack_size = 4096;
memset (dev->template_pipelines, 0, sizeof (dev->template_pipelines));
create_templates_for_op (dev, CAIRO_OPERATOR_SOURCE);
create_templates_for_op (dev, CAIRO_OPERATOR_OVER);