diff options
Diffstat (limited to 'src/cairo_gl_surface.c')
-rw-r--r-- | src/cairo_gl_surface.c | 308 |
1 files changed, 205 insertions, 103 deletions
diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c index 3a60302bd..b56fc5fc3 100644 --- a/src/cairo_gl_surface.c +++ b/src/cairo_gl_surface.c @@ -1,26 +1,25 @@ -/* - * Copyright © 2002 University of Southern California +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of the - * University of Southern California not be used in advertising or - * publicity pertaining to distribution of the software without - * specific, written prior permission. The University of Southern - * California makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express - * or implied warranty. + * appear in supporting documentation, and that the name of David + * Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. David Reveman makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. * - * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF - * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman <c99drn@cs.umu.se> */ @@ -91,17 +90,20 @@ struct cairo_gl_surface { (surface->features & GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK) #define CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT(surface) \ - ((surface->format->stencil_size >= \ - ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) || \ - CAIRO_GL_OFFSCREEN_SUPPORT (surface)) + (surface->format->stencil_size >= \ + ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) -#define CAIRO_GL_SURFACE_IS_OFFSCREEN(surface) \ - (surface->hints & GLITZ_HINT_OFFSCREEN_MASK) +#define CAIRO_GL_SURFACE_IS_DRAWABLE(surface) \ + ((surface->hints & GLITZ_HINT_OFFSCREEN_MASK)? \ + surface->format->draw.offscreen: surface->format->draw.onscreen) #define CAIRO_GL_SURFACE_IS_SOLID(surface) \ ((surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) && \ (surface->pattern.type == CAIRO_PATTERN_SOLID)) +#define CAIRO_GL_SURFACE_MULTISAMPLE(surface) \ + (surface->hints & GLITZ_HINT_MULTISAMPLE_MASK) + static void _cairo_gl_surface_destroy (void *abstract_surface) { @@ -130,6 +132,8 @@ _cairo_gl_surface_get_image (void *abstract_surface) int width, height; int rowstride; cairo_format_masks_t format; + glitz_pixel_buffer_t *buffer; + glitz_pixel_format_t pf; if (surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) return _cairo_pattern_get_image (&surface->pattern, @@ -138,23 +142,57 @@ _cairo_gl_surface_get_image (void *abstract_surface) width = glitz_surface_get_width (surface->surface); height = glitz_surface_get_height (surface->surface); - rowstride = (width * (surface->format->bpp / 8) + 3) & -4; + if (surface->format->red_size > 0) { + format.bpp = 32; + + if (surface->format->alpha_size > 0) + format.alpha_mask = 0xff000000; + else + format.alpha_mask = 0x0; + + format.red_mask = 0xff0000; + format.green_mask = 0xff00; + format.blue_mask = 0xff; + } else { + format.bpp = 8; + format.blue_mask = format.green_mask = format.red_mask = 0x0; + format.alpha_mask = 0xff; + } + + rowstride = (((width * format.bpp) / 8) + 3) & -4; - pixels = (char *) malloc (sizeof (char) * height * rowstride); + pf.masks.bpp = format.bpp; + pf.masks.alpha_mask = format.alpha_mask; + pf.masks.red_mask = format.red_mask; + pf.masks.green_mask = format.green_mask; + pf.masks.blue_mask = format.blue_mask; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = rowstride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - glitz_surface_read_pixels (surface->surface, 0, 0, width, height, pixels); + pixels = (char *) malloc (height * rowstride); + if (!pixels) + return NULL; - format.bpp = surface->format->bpp; - format.red_mask = surface->format->red_mask; - format.green_mask = surface->format->green_mask; - format.blue_mask = surface->format->blue_mask; - format.alpha_mask = surface->format->alpha_mask; + buffer = glitz_pixel_buffer_create_for_data (pixels, &pf); + if (!buffer) { + free (pixels); + return NULL; + } + + glitz_get_pixels (surface->surface, + 0, 0, + width, height, + buffer); + glitz_pixel_buffer_destroy (buffer); + image = (cairo_image_surface_t *) _cairo_image_surface_create_with_masks (pixels, &format, width, height, rowstride); - + _cairo_image_surface_assume_ownership_of_data (image); _cairo_image_surface_set_repeat (image, surface->base.repeat); @@ -168,10 +206,42 @@ _cairo_gl_surface_set_image (void *abstract_surface, cairo_image_surface_t *image) { cairo_gl_surface_t *surface = abstract_surface; + glitz_pixel_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (image->depth > 8) { + pf.masks.bpp = 32; + + if (surface->format->alpha_size) + pf.masks.alpha_mask = 0xff000000; + else + pf.masks.alpha_mask = 0x0; + + pf.masks.red_mask = 0xff0000; + pf.masks.green_mask = 0xff00; + pf.masks.blue_mask = 0xff; + } else { + pf.masks.bpp = 8; + pf.masks.alpha_mask = 0xff; + pf.masks.red_mask = pf.masks.green_mask = pf.masks.blue_mask = 0x0; + } + + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = (((image->width * pf.masks.bpp) / 8) + 3) & -4; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + buffer = glitz_pixel_buffer_create_for_data (image->data, &pf); + if (!buffer) + return CAIRO_STATUS_NO_MEMORY; - glitz_surface_draw_pixels (surface->surface, 0, 0, - image->width, image->height, image->data); + glitz_put_pixels (surface->surface, + 0, 0, + image->width, image->height, + buffer); + glitz_pixel_buffer_destroy (buffer); + return CAIRO_STATUS_SUCCESS; } @@ -204,16 +274,8 @@ _cairo_gl_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) static cairo_status_t _cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter) { - static glitz_convolution_t gaussian = { - { - {0, 1 << 16, 0}, - {1 << 16, 4 << 16, 1 << 16}, - {0, 1 << 16, 0} - } - }; cairo_gl_surface_t *surface = abstract_surface; glitz_filter_t gl_filter; - glitz_convolution_t *convolution = NULL; if (!surface->surface) return CAIRO_STATUS_SUCCESS; @@ -231,10 +293,6 @@ _cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter) case CAIRO_FILTER_NEAREST: gl_filter = GLITZ_FILTER_NEAREST; break; - case CAIRO_FILTER_GAUSSIAN: - if (CAIRO_GL_CONVOLUTION_SUPPORT (surface)) - convolution = &gaussian; - /* fall-through */ case CAIRO_FILTER_BILINEAR: gl_filter = GLITZ_FILTER_BILINEAR; break; @@ -243,7 +301,6 @@ _cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } glitz_surface_set_filter (surface->surface, gl_filter); - glitz_surface_set_convolution (surface->surface, convolution); return CAIRO_STATUS_SUCCESS; } @@ -321,15 +378,42 @@ _glitz_format (cairo_format_t format) static cairo_surface_t * _cairo_gl_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { cairo_gl_surface_t *src = abstract_src; glitz_surface_t *surface; cairo_surface_t *crsurface; + glitz_format_t *glitz_format; + unsigned long option_mask; + glitz_format_name_t format_name = _glitz_format (format); + + option_mask = GLITZ_FORMAT_OPTION_OFFSCREEN_MASK; + + if (drawable) + option_mask |= GLITZ_FORMAT_OPTION_READDRAW_MASK; + else + option_mask |= GLITZ_FORMAT_OPTION_READONLY_MASK; - surface = glitz_surface_create_similar (src->surface, - _glitz_format (format), + if (src->format->multisample.samples < 2) + option_mask |= GLITZ_FORMAT_OPTION_NO_MULTISAMPLE_MASK; + + glitz_format = + glitz_surface_find_similar_standard_format (src->surface, option_mask, + format_name); + if (glitz_format == NULL) { + option_mask &= ~GLITZ_FORMAT_OPTION_READDRAW_MASK; + glitz_format = + glitz_surface_find_similar_standard_format (src->surface, + option_mask, + format_name); + } + + if (glitz_format == NULL) + return NULL; + + surface = glitz_surface_create_similar (src->surface, glitz_format, width, height); if (surface == NULL) return NULL; @@ -352,7 +436,7 @@ _cairo_gl_surface_clone_similar (cairo_surface_t *src, src_image = _cairo_surface_get_image (src); clone = (cairo_gl_surface_t *) - _cairo_gl_surface_create_similar (template, format, + _cairo_gl_surface_create_similar (template, format, 0, src_image->width, src_image->height); if (clone == NULL) @@ -393,10 +477,8 @@ _cairo_gl_surface_composite (cairo_operator_t operator, if (glitz_surface_get_status (dst->surface)) return CAIRO_STATUS_NO_TARGET_SURFACE; - /* If destination surface is offscreen, then offscreen drawing support is - required. */ - if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) && - (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) + /* Make sure target surface is drawable */ + if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; /* We need multi-texturing or offscreen drawing when compositing with @@ -456,10 +538,8 @@ _cairo_gl_surface_fill_rectangles (void *abstract_surface, if (glitz_surface_get_status (surface->surface)) return CAIRO_STATUS_NO_TARGET_SURFACE; - /* If destination surface is offscreen, then offscreen drawing support is - required. */ - if (CAIRO_GL_SURFACE_IS_OFFSCREEN (surface) && - (!CAIRO_GL_OFFSCREEN_SUPPORT (surface))) + /* Make sure target surface is drawable */ + if (!CAIRO_GL_SURFACE_IS_DRAWABLE (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; glitz_color.red = color->red_short; @@ -498,6 +578,34 @@ _cairo_gl_surface_fill_trapezoids (cairo_gl_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +static int +_cairo_gl_extract_rectangle (cairo_trapezoid_t *trap, + cairo_rectangle_t *rect) +{ + if (trap->left.p1.x == trap->left.p2.x && + trap->right.p1.x == trap->right.p2.x && + trap->left.p1.y == trap->right.p1.y && + trap->left.p2.y == trap->right.p2.y && + _cairo_fixed_is_integer (trap->left.p1.x) && + _cairo_fixed_is_integer (trap->left.p1.y) && + _cairo_fixed_is_integer (trap->left.p2.x) && + _cairo_fixed_is_integer (trap->left.p2.y) && + _cairo_fixed_is_integer (trap->right.p1.x) && + _cairo_fixed_is_integer (trap->right.p1.y) && + _cairo_fixed_is_integer (trap->right.p2.x) && + _cairo_fixed_is_integer (trap->right.p2.y)) { + + rect->x = _cairo_fixed_integer_part (trap->left.p1.x); + rect->y = _cairo_fixed_integer_part (trap->left.p1.y); + rect->width = _cairo_fixed_integer_part (trap->right.p1.x) - rect->x; + rect->height = _cairo_fixed_integer_part (trap->left.p2.y) - rect->y; + + return 1; + } + + return 0; +} + static cairo_int_status_t _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, cairo_surface_t *generic_src, @@ -515,10 +623,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, if (glitz_surface_get_status (dst->surface)) return CAIRO_STATUS_NO_TARGET_SURFACE; - /* If destination surface is offscreen, then offscreen drawing support is - required. */ - if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) && - (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) + /* Make sure target surface is drawable */ + if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; /* Need to get current hints as clipping may have changed. */ @@ -527,13 +633,19 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, /* Solid source? */ if ((generic_src->backend == dst->base.backend) && (src->pattern.type == CAIRO_PATTERN_SOLID)) { + cairo_rectangle_t rect; - /* We can use fill trapezoids if only one trapezoid should be drawn or - if solid color alpha is 1.0. If composite trapezoid support - is missing we always use fill trapezoids. */ - if ((num_traps == 1) || - (src->pattern.color.alpha == 1.0) || - (!CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (dst))) + /* Check to see if we can represent these traps as a rectangle. */ + if (num_traps == 1 && _cairo_gl_extract_rectangle (traps, &rect)) + return _cairo_gl_surface_fill_rectangles (dst, operator, + &src->pattern.color, + &rect, 1); + + /* If we're not using software multi-sampling, then we can use + fill trapezoids if only one trapezoid should be drawn or if + solid color alpha is 1.0. */ + if ((!CAIRO_GL_SURFACE_MULTISAMPLE (dst)) && + (num_traps == 1 || src->pattern.color.alpha == 1.0)) return _cairo_gl_surface_fill_trapezoids (dst, operator, &src->pattern.color, traps, num_traps); @@ -578,17 +690,6 @@ _cairo_gl_surface_show_page (void *abstract_surface) } static void -_cario_gl_uint_to_power_of_two (unsigned int *value) -{ - unsigned int x = 1; - - while (x < *value) - x <<= 1; - - *value = x; -} - -static void _cairo_gl_create_color_range (cairo_pattern_t *pattern, unsigned char *data, unsigned int size) @@ -624,10 +725,17 @@ _cairo_gl_surface_create_pattern (void *abstract_surface, source = glitz_surface_create_solid (&color); } break; - case CAIRO_PATTERN_LINEAR: - case CAIRO_PATTERN_RADIAL: { - unsigned int color_range_size; + case CAIRO_PATTERN_RADIAL: + /* glitz doesn't support inner circle yet. */ + if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || + pattern->u.radial.center0.y != pattern->u.radial.center1.y) + return CAIRO_INT_STATUS_UNSUPPORTED; + /* fall-through */ + case CAIRO_PATTERN_LINEAR: { + int color_range_size; glitz_color_range_t *color_range; + int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); + int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); if (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -638,34 +746,28 @@ _cairo_gl_surface_create_pattern (void *abstract_surface, if (pattern->extend == CAIRO_EXTEND_REFLECT && (!CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT (surface))) return CAIRO_INT_STATUS_UNSUPPORTED; - - if (pattern->type == CAIRO_PATTERN_LINEAR) { - double dx, dy; - - dx = pattern->u.linear.point1.x - pattern->u.linear.point0.x; - dy = pattern->u.linear.point1.y - pattern->u.linear.point0.y; - - color_range_size = sqrt (dx * dx + dy * dy); - } else { - /* glitz doesn't support inner circle yet. */ - if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || - pattern->u.radial.center0.y != pattern->u.radial.center1.y) - return CAIRO_INT_STATUS_UNSUPPORTED; - - color_range_size = pattern->u.radial.radius1; - } - - if ((!CAIRO_GL_TEXTURE_NPOT_SUPPORT (surface))) - _cario_gl_uint_to_power_of_two (&color_range_size); - - color_range = glitz_color_range_create (color_range_size); + + /* TODO: how do we figure out the color range resolution? transforming + the gradient vector with the inverse of the pattern matrix should + give us a good hint. */ + color_range_size = 512; + + /* destination surface size less than color range size, an image + gradient is probably more efficient. */ + if ((width * height) <= color_range_size) + return CAIRO_INT_STATUS_UNSUPPORTED; + + color_range = glitz_color_range_create (surface->surface, + color_range_size); if (!color_range) return CAIRO_STATUS_NO_MEMORY; _cairo_gl_create_color_range (pattern, glitz_color_range_get_data (color_range), color_range_size); - + + glitz_color_range_put_back_data (color_range); + switch (pattern->extend) { case CAIRO_EXTEND_REPEAT: glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REPEAT); |