Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2009 Eric Anholt
  4.  * Copyright © 2009 Chris Wilson
  5.  * Copyright © 2005,2010 Red Hat, Inc
  6.  * Copyright © 2011 Intel Corporation
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it either under the terms of the GNU Lesser General Public
  10.  * License version 2.1 as published by the Free Software Foundation
  11.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  12.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  13.  * notice, a recipient may use your version of this file under either
  14.  * the MPL or the LGPL.
  15.  *
  16.  * You should have received a copy of the LGPL along with this library
  17.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  19.  * You should have received a copy of the MPL along with this library
  20.  * in the file COPYING-MPL-1.1
  21.  *
  22.  * The contents of this file are subject to the Mozilla Public License
  23.  * Version 1.1 (the "License"); you may not use this file except in
  24.  * compliance with the License. You may obtain a copy of the License at
  25.  * http://www.mozilla.org/MPL/
  26.  *
  27.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  28.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  29.  * the specific language governing rights and limitations.
  30.  *
  31.  * The Original Code is the cairo graphics library.
  32.  *
  33.  * The Initial Developer of the Original Code is Red Hat, Inc.
  34.  *
  35.  * Contributor(s):
  36.  *      Benjamin Otte <otte@gnome.org>
  37.  *      Carl Worth <cworth@cworth.org>
  38.  *      Chris Wilson <chris@chris-wilson.co.uk>
  39.  *      Eric Anholt <eric@anholt.net>
  40.  */
  41.  
  42. #include "cairoint.h"
  43.  
  44. #include "cairo-gl-private.h"
  45.  
  46. #include "cairo-composite-rectangles-private.h"
  47. #include "cairo-compositor-private.h"
  48. #include "cairo-default-context-private.h"
  49. #include "cairo-error-private.h"
  50. #include "cairo-image-surface-private.h"
  51. #include "cairo-spans-compositor-private.h"
  52. #include "cairo-surface-backend-private.h"
  53.  
  54. typedef struct _cairo_gl_span_renderer {
  55.     cairo_span_renderer_t base;
  56.  
  57.     cairo_gl_composite_t setup;
  58.     double opacity;
  59.  
  60.     cairo_gl_emit_span_t emit;
  61.  
  62.     int xmin, xmax;
  63.     int ymin, ymax;
  64.  
  65.     cairo_gl_context_t *ctx;
  66. } cairo_gl_span_renderer_t;
  67.  
  68. static cairo_status_t
  69. _cairo_gl_bounded_opaque_spans (void *abstract_renderer,
  70.                                 int y, int height,
  71.                                 const cairo_half_open_span_t *spans,
  72.                                 unsigned num_spans)
  73. {
  74.     cairo_gl_span_renderer_t *r = abstract_renderer;
  75.     cairo_gl_emit_span_t emit = r->emit;
  76.  
  77.     if (num_spans == 0)
  78.         return CAIRO_STATUS_SUCCESS;
  79.  
  80.     do {
  81.         if (spans[0].coverage) {
  82.             emit (r->ctx,
  83.                   spans[0].x, y,
  84.                   spans[1].x, y + height,
  85.                   spans[0].coverage);
  86.         }
  87.  
  88.         spans++;
  89.     } while (--num_spans > 1);
  90.  
  91.     return CAIRO_STATUS_SUCCESS;
  92. }
  93.  
  94. static cairo_status_t
  95. _cairo_gl_bounded_spans (void *abstract_renderer,
  96.                          int y, int height,
  97.                          const cairo_half_open_span_t *spans,
  98.                          unsigned num_spans)
  99. {
  100.     cairo_gl_span_renderer_t *r = abstract_renderer;
  101.     cairo_gl_emit_span_t emit = r->emit;
  102.  
  103.     if (num_spans == 0)
  104.         return CAIRO_STATUS_SUCCESS;
  105.  
  106.     do {
  107.         if (spans[0].coverage) {
  108.             emit (r->ctx,
  109.                   spans[0].x, y,
  110.                   spans[1].x, y + height,
  111.                   r->opacity * spans[0].coverage);
  112.         }
  113.  
  114.         spans++;
  115.     } while (--num_spans > 1);
  116.  
  117.     return CAIRO_STATUS_SUCCESS;
  118. }
  119.  
  120. static cairo_status_t
  121. _cairo_gl_unbounded_spans (void *abstract_renderer,
  122.                            int y, int height,
  123.                            const cairo_half_open_span_t *spans,
  124.                            unsigned num_spans)
  125. {
  126.     cairo_gl_span_renderer_t *r = abstract_renderer;
  127.     cairo_gl_emit_span_t emit = r->emit;
  128.  
  129.     if (y > r->ymin) {
  130.         emit (r->ctx,
  131.               r->xmin, r->ymin,
  132.               r->xmax, y,
  133.               0);
  134.     }
  135.  
  136.     if (num_spans == 0) {
  137.         emit (r->ctx,
  138.               r->xmin, y,
  139.               r->xmax, y + height,
  140.               0);
  141.     } else {
  142.         if (spans[0].x != r->xmin) {
  143.             emit (r->ctx,
  144.                   r->xmin, y,
  145.                   spans[0].x,     y + height,
  146.                   0);
  147.         }
  148.  
  149.         do {
  150.             emit (r->ctx,
  151.                   spans[0].x, y,
  152.                   spans[1].x, y + height,
  153.                   r->opacity * spans[0].coverage);
  154.             spans++;
  155.         } while (--num_spans > 1);
  156.  
  157.         if (spans[0].x != r->xmax) {
  158.             emit (r->ctx,
  159.                   spans[0].x,     y,
  160.                   r->xmax, y + height,
  161.                   0);
  162.         }
  163.     }
  164.  
  165.     r->ymin = y + height;
  166.     return CAIRO_STATUS_SUCCESS;
  167. }
  168.  
  169. /* XXX */
  170. static cairo_status_t
  171. _cairo_gl_clipped_spans (void *abstract_renderer,
  172.                            int y, int height,
  173.                            const cairo_half_open_span_t *spans,
  174.                            unsigned num_spans)
  175. {
  176.     cairo_gl_span_renderer_t *r = abstract_renderer;
  177.     cairo_gl_emit_span_t emit = r->emit;
  178.  
  179.     if (y > r->ymin) {
  180.         emit (r->ctx,
  181.               r->xmin, r->ymin,
  182.               r->xmax, y,
  183.               0);
  184.     }
  185.  
  186.     if (num_spans == 0) {
  187.         emit (r->ctx,
  188.               r->xmin, y,
  189.               r->xmax, y + height,
  190.               0);
  191.     } else {
  192.         if (spans[0].x != r->xmin) {
  193.             emit (r->ctx,
  194.                   r->xmin, y,
  195.                   spans[0].x,     y + height,
  196.                   0);
  197.         }
  198.  
  199.         do {
  200.             emit (r->ctx,
  201.                   spans[0].x, y,
  202.                   spans[1].x, y + height,
  203.                   r->opacity * spans[0].coverage);
  204.             spans++;
  205.         } while (--num_spans > 1);
  206.  
  207.         if (spans[0].x != r->xmax) {
  208.             emit (r->ctx,
  209.                   spans[0].x,     y,
  210.                   r->xmax, y + height,
  211.                   0);
  212.         }
  213.     }
  214.  
  215.     r->ymin = y + height;
  216.     return CAIRO_STATUS_SUCCESS;
  217. }
  218.  
  219. static cairo_status_t
  220. _cairo_gl_finish_unbounded_spans (void *abstract_renderer)
  221. {
  222.     cairo_gl_span_renderer_t *r = abstract_renderer;
  223.     cairo_gl_emit_span_t emit = r->emit;
  224.  
  225.     if (r->ymax > r->ymin) {
  226.         emit (r->ctx,
  227.               r->xmin, r->ymin,
  228.               r->xmax, r->ymax,
  229.               0);
  230.     }
  231.  
  232.     return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
  233. }
  234.  
  235. static cairo_status_t
  236. _cairo_gl_finish_bounded_spans (void *abstract_renderer)
  237. {
  238.     cairo_gl_span_renderer_t *r = abstract_renderer;
  239.  
  240.     return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
  241. }
  242.  
  243. static void
  244. emit_aligned_boxes (cairo_gl_context_t *ctx,
  245.                     const cairo_boxes_t *boxes)
  246. {
  247.     const struct _cairo_boxes_chunk *chunk;
  248.     cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
  249.     int i;
  250.  
  251.     TRACE ((stderr, "%s: num_boxes=%d\n", __FUNCTION__, boxes->num_boxes));
  252.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  253.         for (i = 0; i < chunk->count; i++) {
  254.             int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  255.             int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  256.             int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  257.             int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  258.             emit (ctx, x1, y1, x2, y2);
  259.         }
  260.     }
  261. }
  262.  
  263. static cairo_int_status_t
  264. fill_boxes (void                *_dst,
  265.             cairo_operator_t     op,
  266.             const cairo_color_t *color,
  267.             cairo_boxes_t       *boxes)
  268. {
  269.     cairo_gl_composite_t setup;
  270.     cairo_gl_context_t *ctx;
  271.     cairo_int_status_t status;
  272.  
  273.     TRACE ((stderr, "%s\n", __FUNCTION__));
  274.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  275.     if (unlikely (status))
  276.         goto FAIL;
  277.  
  278.    _cairo_gl_composite_set_solid_source (&setup, color);
  279.  
  280.     status = _cairo_gl_composite_begin (&setup, &ctx);
  281.     if (unlikely (status))
  282.         goto FAIL;
  283.  
  284.     emit_aligned_boxes (ctx, boxes);
  285.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  286.  
  287. FAIL:
  288.     _cairo_gl_composite_fini (&setup);
  289.     return status;
  290. }
  291.  
  292. static cairo_int_status_t
  293. draw_image_boxes (void *_dst,
  294.                   cairo_image_surface_t *image,
  295.                   cairo_boxes_t *boxes,
  296.                   int dx, int dy)
  297. {
  298.     cairo_gl_surface_t *dst = _dst;
  299.     struct _cairo_boxes_chunk *chunk;
  300.     int i;
  301.  
  302.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  303.         for (i = 0; i < chunk->count; i++) {
  304.             cairo_box_t *b = &chunk->base[i];
  305.             int x = _cairo_fixed_integer_part (b->p1.x);
  306.             int y = _cairo_fixed_integer_part (b->p1.y);
  307.             int w = _cairo_fixed_integer_part (b->p2.x) - x;
  308.             int h = _cairo_fixed_integer_part (b->p2.y) - y;
  309.             cairo_status_t status;
  310.  
  311.             status = _cairo_gl_surface_draw_image (dst, image,
  312.                                                    x + dx, y + dy,
  313.                                                    w, h,
  314.                                                    x, y, TRUE);
  315.             if (unlikely (status))
  316.                 return status;
  317.         }
  318.     }
  319.  
  320.     return CAIRO_STATUS_SUCCESS;
  321. }
  322.  
  323. static cairo_int_status_t copy_boxes (void *_dst,
  324.                                       cairo_surface_t *_src,
  325.                                       cairo_boxes_t *boxes,
  326.                                       const cairo_rectangle_int_t *extents,
  327.                                       int dx, int dy)
  328. {
  329.     cairo_gl_surface_t *dst = _dst;
  330.     cairo_gl_surface_t *src = (cairo_gl_surface_t *)_src;
  331.     cairo_gl_composite_t setup;
  332.     cairo_gl_context_t *ctx;
  333.     cairo_int_status_t status;
  334.  
  335.     TRACE ((stderr, "%s\n", __FUNCTION__));
  336.     if (! _cairo_gl_surface_is_texture (src))
  337.         return CAIRO_INT_STATUS_UNSUPPORTED;
  338.  
  339.     if (src->base.device != dst->base.device)
  340.         return CAIRO_INT_STATUS_UNSUPPORTED;
  341.  
  342.     status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE, _dst, FALSE);
  343.     if (unlikely (status))
  344.         goto FAIL;
  345.  
  346.     _cairo_gl_composite_set_source_operand (&setup, &src->operand);
  347.     _cairo_gl_operand_translate (&setup.src, -dx, -dy);
  348.  
  349.     status = _cairo_gl_composite_begin (&setup, &ctx);
  350.     if (unlikely (status))
  351.         goto FAIL;
  352.  
  353.     emit_aligned_boxes (ctx, boxes);
  354.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  355.  
  356. FAIL:
  357.     _cairo_gl_composite_fini (&setup);
  358.     return status;
  359. }
  360.  
  361. static cairo_int_status_t
  362. composite_boxes (void                   *_dst,
  363.                  cairo_operator_t       op,
  364.                  cairo_surface_t        *abstract_src,
  365.                  cairo_surface_t        *abstract_mask,
  366.                  int                    src_x,
  367.                  int                    src_y,
  368.                  int                    mask_x,
  369.                  int                    mask_y,
  370.                  int                    dst_x,
  371.                  int                    dst_y,
  372.                  cairo_boxes_t          *boxes,
  373.                  const cairo_rectangle_int_t  *extents)
  374. {
  375.     cairo_gl_composite_t setup;
  376.     cairo_gl_context_t *ctx;
  377.     cairo_int_status_t status;
  378.     cairo_gl_operand_t tmp_operand;
  379.     cairo_gl_operand_t *src_operand;
  380.  
  381.     TRACE ((stderr, "%s mask=(%d,%d), dst=(%d, %d)\n", __FUNCTION__,
  382.             mask_x, mask_y, dst_x, dst_y));
  383.  
  384.     if (abstract_mask) {
  385.         if (op == CAIRO_OPERATOR_CLEAR) {
  386.             _cairo_gl_solid_operand_init (&tmp_operand, CAIRO_COLOR_WHITE);
  387.             src_operand = &tmp_operand;
  388.             op = CAIRO_OPERATOR_DEST_OUT;
  389.         } else if (op == CAIRO_OPERATOR_SOURCE) {
  390.             /* requires a LERP in the shader between dest and source */
  391.             return CAIRO_INT_STATUS_UNSUPPORTED;
  392.         } else
  393.             src_operand = source_to_operand (abstract_src);
  394.     } else
  395.         src_operand = source_to_operand (abstract_src);
  396.  
  397.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  398.     if (unlikely (status))
  399.         goto FAIL;
  400.  
  401.     _cairo_gl_composite_set_source_operand (&setup,
  402.                                             src_operand);
  403.     _cairo_gl_operand_translate (&setup.src, -src_x, -src_y);
  404.  
  405.     _cairo_gl_composite_set_mask_operand (&setup,
  406.                                           source_to_operand (abstract_mask));
  407.     _cairo_gl_operand_translate (&setup.mask, -mask_x, -mask_y);
  408.  
  409.     status = _cairo_gl_composite_begin (&setup, &ctx);
  410.     if (unlikely (status))
  411.         goto FAIL;
  412.  
  413.     emit_aligned_boxes (ctx, boxes);
  414.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  415.  
  416. FAIL:
  417.     _cairo_gl_composite_fini (&setup);
  418.     if (src_operand == &tmp_operand)
  419.         _cairo_gl_operand_destroy (&tmp_operand);
  420.     return status;
  421. }
  422.  
  423. static cairo_int_status_t
  424. _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t    *_r,
  425.                               const cairo_composite_rectangles_t *composite,
  426.                               cairo_antialias_t                  antialias,
  427.                               cairo_bool_t                       needs_clip)
  428. {
  429.     cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *)_r;
  430.     const cairo_pattern_t *source = &composite->source_pattern.base;
  431.     cairo_operator_t op = composite->op;
  432.     cairo_int_status_t status;
  433.  
  434.     if (op == CAIRO_OPERATOR_SOURCE) {
  435.         if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
  436.                                         &composite->source_sample_area))
  437.             return CAIRO_INT_STATUS_UNSUPPORTED;
  438.         op = CAIRO_OPERATOR_OVER;
  439.     }
  440.  
  441.     /* XXX earlier! */
  442.     if (op == CAIRO_OPERATOR_CLEAR) {
  443.         source = &_cairo_pattern_white.base;
  444.         op = CAIRO_OPERATOR_DEST_OUT;
  445.     } else if (composite->surface->is_clear &&
  446.                (op == CAIRO_OPERATOR_SOURCE ||
  447.                 op == CAIRO_OPERATOR_OVER ||
  448.                 op == CAIRO_OPERATOR_ADD)) {
  449.         op = CAIRO_OPERATOR_SOURCE;
  450.     } else if (op == CAIRO_OPERATOR_SOURCE) {
  451.         /* no lerp equivalent without some major PITA */
  452.         return CAIRO_INT_STATUS_UNSUPPORTED;
  453.     } else if (! _cairo_gl_operator_is_supported (op))
  454.         return CAIRO_INT_STATUS_UNSUPPORTED;
  455.  
  456.     status = _cairo_gl_composite_init (&r->setup,
  457.                                        op, (cairo_gl_surface_t *)composite->surface,
  458.                                        FALSE);
  459.     if (unlikely (status))
  460.         goto FAIL;
  461.  
  462.     status = _cairo_gl_composite_set_source (&r->setup, source,
  463.                                              &composite->source_sample_area,
  464.                                              &composite->unbounded,
  465.                                              TRUE);
  466.     if (unlikely (status))
  467.         goto FAIL;
  468.  
  469.     r->opacity = 1.0;
  470.     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
  471.         r->opacity = composite->mask_pattern.solid.color.alpha;
  472.     } else {
  473.         status = _cairo_gl_composite_set_mask (&r->setup,
  474.                                                &composite->mask_pattern.base,
  475.                                                &composite->mask_sample_area,
  476.                                                &composite->unbounded,
  477.                                                TRUE);
  478.         if (unlikely (status))
  479.             goto FAIL;
  480.     }
  481.  
  482.     _cairo_gl_composite_set_spans (&r->setup);
  483.  
  484.     status = _cairo_gl_composite_begin (&r->setup, &r->ctx);
  485.     if (unlikely (status))
  486.         goto FAIL;
  487.  
  488.     r->emit = _cairo_gl_context_choose_emit_span (r->ctx);
  489.     if (composite->is_bounded) {
  490.         if (r->opacity == 1.)
  491.             r->base.render_rows = _cairo_gl_bounded_opaque_spans;
  492.         else
  493.             r->base.render_rows = _cairo_gl_bounded_spans;
  494.         r->base.finish = _cairo_gl_finish_bounded_spans;
  495.     } else {
  496.         if (needs_clip)
  497.             r->base.render_rows = _cairo_gl_clipped_spans;
  498.         else
  499.             r->base.render_rows = _cairo_gl_unbounded_spans;
  500.         r->base.finish = _cairo_gl_finish_unbounded_spans;
  501.         r->xmin = composite->unbounded.x;
  502.         r->xmax = composite->unbounded.x + composite->unbounded.width;
  503.         r->ymin = composite->unbounded.y;
  504.         r->ymax = composite->unbounded.y + composite->unbounded.height;
  505.     }
  506.  
  507.     return CAIRO_STATUS_SUCCESS;
  508.  
  509. FAIL:
  510.     return status;
  511. }
  512.  
  513. static void
  514. _cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
  515.                               cairo_int_status_t status)
  516. {
  517.     cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *) _r;
  518.  
  519.     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
  520.         return;
  521.  
  522.     if (status == CAIRO_INT_STATUS_SUCCESS)
  523.         r->base.finish (r);
  524.  
  525.     _cairo_gl_composite_fini (&r->setup);
  526. }
  527.  
  528. const cairo_compositor_t *
  529. _cairo_gl_span_compositor_get (void)
  530. {
  531.     static cairo_spans_compositor_t spans;
  532.     static cairo_compositor_t shape;
  533.  
  534.     if (spans.base.delegate == NULL) {
  535.         /* The fallback to traps here is essentially just for glyphs... */
  536.         _cairo_shape_mask_compositor_init (&shape,
  537.                                            _cairo_gl_traps_compositor_get());
  538.         shape.glyphs = NULL;
  539.  
  540.         _cairo_spans_compositor_init (&spans, &shape);
  541.         spans.fill_boxes = fill_boxes;
  542.         spans.draw_image_boxes = draw_image_boxes;
  543.         spans.copy_boxes = copy_boxes;
  544.         //spans.check_composite_boxes = check_composite_boxes;
  545.         spans.pattern_to_surface = _cairo_gl_pattern_to_source;
  546.         spans.composite_boxes = composite_boxes;
  547.         //spans.check_span_renderer = check_span_renderer;
  548.         spans.renderer_init = _cairo_gl_span_renderer_init;
  549.         spans.renderer_fini = _cairo_gl_span_renderer_fini;
  550.     }
  551.  
  552.     return &spans.base;
  553. }
  554.