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 Linaro Limited
  7.  * Copyright © 2011 Samsung Electronics
  8.  *
  9.  * This library is free software; you can redistribute it and/or
  10.  * modify it either under the terms of the GNU Lesser General Public
  11.  * License version 2.1 as published by the Free Software Foundation
  12.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  13.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  14.  * notice, a recipient may use your version of this file under either
  15.  * the MPL or the LGPL.
  16.  *
  17.  * You should have received a copy of the LGPL along with this library
  18.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  20.  * You should have received a copy of the MPL along with this library
  21.  * in the file COPYING-MPL-1.1
  22.  *
  23.  * The contents of this file are subject to the Mozilla Public License
  24.  * Version 1.1 (the "License"); you may not use this file except in
  25.  * compliance with the License. You may obtain a copy of the License at
  26.  * http://www.mozilla.org/MPL/
  27.  *
  28.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  29.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  30.  * the specific language governing rights and limitations.
  31.  *
  32.  * The Original Code is the cairo graphics library.
  33.  *
  34.  * The Initial Developer of the Original Code is Red Hat, Inc.
  35.  *
  36.  * Contributor(s):
  37.  *      Benjamin Otte <otte@gnome.org>
  38.  *      Carl Worth <cworth@cworth.org>
  39.  *      Chris Wilson <chris@chris-wilson.co.uk>
  40.  *      Eric Anholt <eric@anholt.net>
  41.  *      Alexandros Frantzis <alexandros.frantzis@linaro.org>
  42.  *      Henry Song <hsong@sisa.samsung.com>
  43.  *      Martin Robinson <mrobinson@igalia.com>
  44.  */
  45.  
  46. #include "cairoint.h"
  47.  
  48. #include "cairo-gl-private.h"
  49.  
  50. #include "cairo-composite-rectangles-private.h"
  51. #include "cairo-clip-private.h"
  52. #include "cairo-error-private.h"
  53. #include "cairo-image-surface-private.h"
  54.  
  55. cairo_int_status_t
  56. _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
  57.                                 const cairo_pattern_t *pattern,
  58.                                 const cairo_rectangle_int_t *sample,
  59.                                 const cairo_rectangle_int_t *extents,
  60.                                 cairo_bool_t use_texgen)
  61. {
  62.     _cairo_gl_operand_destroy (&setup->src);
  63.     return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
  64.                                    sample, extents, use_texgen);
  65. }
  66.  
  67. void
  68. _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
  69.                                         const cairo_gl_operand_t *source)
  70. {
  71.     _cairo_gl_operand_destroy (&setup->src);
  72.     _cairo_gl_operand_copy (&setup->src, source);
  73. }
  74.  
  75. void
  76. _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
  77.                                       const cairo_color_t *color)
  78. {
  79.     _cairo_gl_operand_destroy (&setup->src);
  80.     _cairo_gl_solid_operand_init (&setup->src, color);
  81. }
  82.  
  83. cairo_int_status_t
  84. _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
  85.                               const cairo_pattern_t *pattern,
  86.                               const cairo_rectangle_int_t *sample,
  87.                               const cairo_rectangle_int_t *extents,
  88.                               cairo_bool_t use_texgen)
  89. {
  90.     _cairo_gl_operand_destroy (&setup->mask);
  91.     if (pattern == NULL)
  92.         return CAIRO_STATUS_SUCCESS;
  93.  
  94.     return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
  95.                                    sample, extents, use_texgen);
  96. }
  97.  
  98. void
  99. _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
  100.                                       const cairo_gl_operand_t *mask)
  101. {
  102.     _cairo_gl_operand_destroy (&setup->mask);
  103.     if (mask)
  104.         _cairo_gl_operand_copy (&setup->mask, mask);
  105. }
  106.  
  107. void
  108. _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
  109. {
  110.     setup->spans = TRUE;
  111. }
  112.  
  113. void
  114. _cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
  115. {
  116.     setup->multisample = TRUE;
  117. }
  118.  
  119. void
  120. _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
  121.                                      cairo_region_t *clip_region)
  122. {
  123.     setup->clip_region = clip_region;
  124. }
  125.  
  126. void
  127. _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
  128.                               cairo_clip_t *clip)
  129. {
  130.     setup->clip = clip;
  131. }
  132.  
  133. static void
  134. _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
  135.                                     cairo_gl_composite_t *setup)
  136. {
  137.     _cairo_gl_shader_bind_matrix4f(ctx, ctx->current_shader->mvp_location,
  138.                                    ctx->modelviewprojection_matrix);
  139.     _cairo_gl_operand_bind_to_shader (ctx, &setup->src,  CAIRO_GL_TEX_SOURCE);
  140.     _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
  141. }
  142.  
  143. static void
  144. _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
  145.                               GLuint              target,
  146.                               cairo_filter_t      filter)
  147. {
  148.     switch (filter) {
  149.     case CAIRO_FILTER_FAST:
  150.     case CAIRO_FILTER_NEAREST:
  151.         glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  152.         glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  153.         break;
  154.     case CAIRO_FILTER_GOOD:
  155.     case CAIRO_FILTER_BEST:
  156.     case CAIRO_FILTER_BILINEAR:
  157.         glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  158.         glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  159.         break;
  160.     default:
  161.     case CAIRO_FILTER_GAUSSIAN:
  162.         ASSERT_NOT_REACHED;
  163.     }
  164. }
  165.  
  166. static void
  167. _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
  168.                               GLuint              target,
  169.                               cairo_extend_t      extend)
  170. {
  171.     GLint wrap_mode;
  172.     assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
  173.             (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
  174.  
  175.     switch (extend) {
  176.     case CAIRO_EXTEND_NONE:
  177.         if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
  178.             wrap_mode = GL_CLAMP_TO_EDGE;
  179.         else
  180.             wrap_mode = GL_CLAMP_TO_BORDER;
  181.         break;
  182.     case CAIRO_EXTEND_PAD:
  183.         wrap_mode = GL_CLAMP_TO_EDGE;
  184.         break;
  185.     case CAIRO_EXTEND_REPEAT:
  186.         if (ctx->has_npot_repeat)
  187.             wrap_mode = GL_REPEAT;
  188.         else
  189.             wrap_mode = GL_CLAMP_TO_EDGE;
  190.         break;
  191.     case CAIRO_EXTEND_REFLECT:
  192.         if (ctx->has_npot_repeat)
  193.             wrap_mode = GL_MIRRORED_REPEAT;
  194.         else
  195.             wrap_mode = GL_CLAMP_TO_EDGE;
  196.         break;
  197.     default:
  198.         wrap_mode = 0;
  199.     }
  200.  
  201.     if (likely (wrap_mode)) {
  202.         glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
  203.         glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
  204.     }
  205. }
  206.  
  207.  
  208. static void
  209. _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
  210.                                  cairo_gl_tex_t      tex_unit,
  211.                                  cairo_gl_operand_t *operand,
  212.                                  unsigned int        vertex_offset,
  213.                                  cairo_bool_t        vertex_size_changed)
  214. {
  215.     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
  216.     cairo_bool_t needs_setup;
  217.  
  218.     /* XXX: we need to do setup when switching from shaders
  219.      * to no shaders (or back) */
  220.     needs_setup = vertex_size_changed;
  221.     needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
  222.                                                  operand,
  223.                                                  vertex_offset);
  224.  
  225.     if (needs_setup) {
  226.         _cairo_gl_composite_flush (ctx);
  227.         _cairo_gl_context_destroy_operand (ctx, tex_unit);
  228.     }
  229.  
  230.     memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
  231.     ctx->operands[tex_unit].vertex_offset = vertex_offset;
  232.  
  233.     if (! needs_setup)
  234.         return;
  235.  
  236.     switch (operand->type) {
  237.     default:
  238.     case CAIRO_GL_OPERAND_COUNT:
  239.         ASSERT_NOT_REACHED;
  240.     case CAIRO_GL_OPERAND_NONE:
  241.         break;
  242.         /* fall through */
  243.     case CAIRO_GL_OPERAND_CONSTANT:
  244.         break;
  245.     case CAIRO_GL_OPERAND_TEXTURE:
  246.         glActiveTexture (GL_TEXTURE0 + tex_unit);
  247.         glBindTexture (ctx->tex_target, operand->texture.tex);
  248.         _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
  249.                                       operand->texture.attributes.extend);
  250.         _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
  251.                                       operand->texture.attributes.filter);
  252.  
  253.         if (! operand->texture.texgen) {
  254.             dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
  255.                                            GL_FLOAT, GL_FALSE, ctx->vertex_size,
  256.                                            ctx->vb + vertex_offset);
  257.             dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
  258.         }
  259.         break;
  260.     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
  261.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
  262.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
  263.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
  264.         glActiveTexture (GL_TEXTURE0 + tex_unit);
  265.         glBindTexture (ctx->tex_target, operand->gradient.gradient->tex);
  266.         _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend);
  267.         _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
  268.  
  269.         if (! operand->gradient.texgen) {
  270.             dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
  271.                                            GL_FLOAT, GL_FALSE, ctx->vertex_size,
  272.                                            ctx->vb + vertex_offset);
  273.             dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
  274.         }
  275.         break;
  276.     }
  277. }
  278.  
  279. static void
  280. _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
  281.                                cairo_bool_t        spans_enabled,
  282.                                unsigned int        vertex_size,
  283.                                unsigned int        vertex_offset)
  284. {
  285.     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
  286.  
  287.     if (! spans_enabled) {
  288.         dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
  289.         ctx->spans = FALSE;
  290.         return;
  291.     }
  292.  
  293.     dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
  294.                                    GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
  295.                                    ctx->vb + vertex_offset);
  296.     dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
  297.     ctx->spans = TRUE;
  298. }
  299.  
  300. void
  301. _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
  302.                                    cairo_gl_tex_t tex_unit)
  303. {
  304.     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
  305.  
  306.     if  (!_cairo_gl_context_is_flushed (ctx))
  307.         _cairo_gl_composite_flush (ctx);
  308.  
  309.     switch (ctx->operands[tex_unit].type) {
  310.     default:
  311.     case CAIRO_GL_OPERAND_COUNT:
  312.         ASSERT_NOT_REACHED;
  313.     case CAIRO_GL_OPERAND_NONE:
  314.         break;
  315.         /* fall through */
  316.     case CAIRO_GL_OPERAND_CONSTANT:
  317.         break;
  318.     case CAIRO_GL_OPERAND_TEXTURE:
  319.         dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
  320.         break;
  321.     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
  322.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
  323.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
  324.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
  325.         dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
  326.         break;
  327.     }
  328.  
  329.     memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
  330. }
  331.  
  332. static void
  333. _cairo_gl_set_operator (cairo_gl_context_t *ctx,
  334.                         cairo_operator_t    op,
  335.                         cairo_bool_t        component_alpha)
  336. {
  337.     struct {
  338.         GLenum src;
  339.         GLenum dst;
  340.     } blend_factors[] = {
  341.         { GL_ZERO, GL_ZERO }, /* Clear */
  342.         { GL_ONE, GL_ZERO }, /* Source */
  343.         { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
  344.         { GL_DST_ALPHA, GL_ZERO }, /* In */
  345.         { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
  346.         { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
  347.  
  348.         { GL_ZERO, GL_ONE }, /* Dest */
  349.         { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
  350.         { GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
  351.         { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
  352.         { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
  353.  
  354.         { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
  355.         { GL_ONE, GL_ONE }, /* Add */
  356.     };
  357.     GLenum src_factor, dst_factor;
  358.  
  359.     assert (op < ARRAY_LENGTH (blend_factors));
  360.     /* different dst and component_alpha changes cause flushes elsewhere */
  361.     if (ctx->current_operator != op)
  362.         _cairo_gl_composite_flush (ctx);
  363.     ctx->current_operator = op;
  364.  
  365.     src_factor = blend_factors[op].src;
  366.     dst_factor = blend_factors[op].dst;
  367.  
  368.     /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
  369.      * due to texture filtering of GL_CLAMP_TO_BORDER.  So fix those
  370.      * bits in that case.
  371.      */
  372.     if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
  373.         if (src_factor == GL_ONE_MINUS_DST_ALPHA)
  374.             src_factor = GL_ZERO;
  375.         if (src_factor == GL_DST_ALPHA)
  376.             src_factor = GL_ONE;
  377.     }
  378.  
  379.     if (component_alpha) {
  380.         if (dst_factor == GL_ONE_MINUS_SRC_ALPHA)
  381.             dst_factor = GL_ONE_MINUS_SRC_COLOR;
  382.         if (dst_factor == GL_SRC_ALPHA)
  383.             dst_factor = GL_SRC_COLOR;
  384.     }
  385.  
  386.     if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
  387.         glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
  388.     } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
  389.         glBlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
  390.     } else {
  391.         glBlendFunc (src_factor, dst_factor);
  392.     }
  393. }
  394.  
  395. static cairo_status_t
  396. _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
  397.                                             cairo_gl_composite_t *setup)
  398. {
  399.     cairo_gl_shader_t *pre_shader = NULL;
  400.     cairo_status_t status;
  401.  
  402.     /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
  403.      * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
  404.      * is:
  405.      *     mask IN clip ? src OP dest : dest
  406.      * or more simply:
  407.      *     mask IN CLIP ? 0 : dest
  408.      *
  409.      * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
  410.      *
  411.      * The model we use in _cairo_gl_set_operator() is Render's:
  412.      *     src IN mask IN clip OP dest
  413.      * which would boil down to:
  414.      *     0 (bounded by the extents of the drawing).
  415.      *
  416.      * However, we can do a Render operation using an opaque source
  417.      * and DEST_OUT to produce:
  418.      *    1 IN mask IN clip DEST_OUT dest
  419.      * which is
  420.      *    mask IN clip ? 0 : dest
  421.      */
  422.     if (setup->op == CAIRO_OPERATOR_CLEAR) {
  423.         _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
  424.         setup->op = CAIRO_OPERATOR_DEST_OUT;
  425.     }
  426.  
  427.     /*
  428.      * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
  429.      * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
  430.      *
  431.      * From http://anholt.livejournal.com/32058.html:
  432.      *
  433.      * The trouble is that component-alpha rendering requires two different sources
  434.      * for blending: one for the source value to the blender, which is the
  435.      * per-channel multiplication of source and mask, and one for the source alpha
  436.      * for multiplying with the destination channels, which is the multiplication
  437.      * of the source channels by the mask alpha. So the equation for Over is:
  438.      *
  439.      * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
  440.      * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
  441.      * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
  442.      * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
  443.      *
  444.      * But we can do some simpler operations, right? How about PictOpOutReverse,
  445.      * which has a source factor of 0 and dest factor of (1 - source alpha). We
  446.      * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
  447.      * blenders pretty easily. So we can do a component-alpha OutReverse, which
  448.      * gets us:
  449.      *
  450.      * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
  451.      * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
  452.      * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
  453.      * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
  454.      *
  455.      * OK. And if an op doesn't use the source alpha value for the destination
  456.      * factor, then we can do the channel multiplication in the texture blenders
  457.      * to get the source value, and ignore the source alpha that we wouldn't use.
  458.      * We've supported this in the Radeon driver for a long time. An example would
  459.      * be PictOpAdd, which does:
  460.      *
  461.      * dst.A = src.A * mask.A + dst.A
  462.      * dst.R = src.R * mask.R + dst.R
  463.      * dst.G = src.G * mask.G + dst.G
  464.      * dst.B = src.B * mask.B + dst.B
  465.      *
  466.      * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
  467.      * after it, we get:
  468.      *
  469.      * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
  470.      * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
  471.      * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
  472.      * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
  473.      *
  474.      * This two-pass trickery could be avoided using a new GL extension that
  475.      * lets two values come out of the shader and into the blend unit.
  476.      */
  477.     if (setup->op == CAIRO_OPERATOR_OVER) {
  478.         setup->op = CAIRO_OPERATOR_ADD;
  479.         status = _cairo_gl_get_shader_by_type (ctx,
  480.                                                &setup->src,
  481.                                                &setup->mask,
  482.                                                setup->spans,
  483.                                                CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
  484.                                                &pre_shader);
  485.         if (unlikely (status))
  486.             return status;
  487.     }
  488.  
  489.     if (ctx->pre_shader != pre_shader)
  490.         _cairo_gl_composite_flush (ctx);
  491.     ctx->pre_shader = pre_shader;
  492.  
  493.     return CAIRO_STATUS_SUCCESS;
  494. }
  495.  
  496. static void
  497. _scissor_to_doubles (cairo_gl_surface_t *surface,
  498.                      double x1, double y1,
  499.                      double x2, double y2)
  500. {
  501.     double height;
  502.  
  503.     height = y2 - y1;
  504.     if (_cairo_gl_surface_is_texture (surface) == FALSE)
  505.         y1 = surface->height - (y1 + height);
  506.     glScissor (x1, y1, x2 - x1, height);
  507.     glEnable (GL_SCISSOR_TEST);
  508. }
  509.  
  510. void
  511. _cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
  512.                        const cairo_rectangle_int_t *r)
  513. {
  514.     _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
  515. }
  516.  
  517. static void
  518. _scissor_to_box (cairo_gl_surface_t     *surface,
  519.                  const cairo_box_t      *box)
  520. {
  521.     double x1, y1, x2, y2;
  522.     _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
  523.     _scissor_to_doubles (surface, x1, y1, x2, y2);
  524. }
  525.  
  526. static cairo_bool_t
  527. _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
  528.                                unsigned int size_per_vertex)
  529. {
  530.     cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex;
  531.     if (vertex_size_changed) {
  532.         ctx->vertex_size = size_per_vertex;
  533.         _cairo_gl_composite_flush (ctx);
  534.     }
  535.  
  536.     if (_cairo_gl_context_is_flushed (ctx)) {
  537.         ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
  538.                                            GL_FLOAT, GL_FALSE, size_per_vertex,
  539.                                            ctx->vb);
  540.         ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
  541.     }
  542.  
  543.     return vertex_size_changed;
  544. }
  545.  
  546. static void
  547. _disable_stencil_buffer (void)
  548. {
  549.     glDisable (GL_STENCIL_TEST);
  550.     glDepthMask (GL_FALSE);
  551. }
  552.  
  553. static cairo_int_status_t
  554. _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
  555.                                             cairo_gl_context_t *ctx,
  556.                                             int vertex_size)
  557. {
  558.     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
  559.  
  560.     cairo_gl_surface_t *dst = setup->dst;
  561.     cairo_clip_t *clip = setup->clip;
  562.  
  563.     if (clip->num_boxes == 1 && clip->path == NULL) {
  564.         _scissor_to_box (dst, &clip->boxes[0]);
  565.         goto disable_stencil_buffer_and_return;
  566.     }
  567.  
  568.     if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
  569.         status = CAIRO_INT_STATUS_UNSUPPORTED;
  570.         goto disable_stencil_buffer_and_return;
  571.     }
  572.  
  573.     /* We only want to clear the part of the stencil buffer
  574.      * that we are about to use. It also does not hurt to
  575.      * scissor around the painted clip. */
  576.     _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
  577.  
  578.     /* The clip is not rectangular, so use the stencil buffer. */
  579.     glDepthMask (GL_TRUE);
  580.     glEnable (GL_STENCIL_TEST);
  581.  
  582.     /* Texture surfaces have private depth/stencil buffers, so we can
  583.      * rely on any previous clip being cached there. */
  584.     if (_cairo_gl_surface_is_texture (setup->dst)) {
  585.         cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
  586.         if (_cairo_clip_equal (old_clip, setup->clip))
  587.             goto activate_stencil_buffer_and_return;
  588.  
  589.         if (old_clip) {
  590.             _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
  591.         }
  592.  
  593.         setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
  594.     }
  595.  
  596.     glClearStencil (0);
  597.     glClear (GL_STENCIL_BUFFER_BIT);
  598.  
  599.     glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
  600.     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
  601.     glColorMask (0, 0, 0, 0);
  602.  
  603.     status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
  604.  
  605.     if (unlikely (status)) {
  606.         glColorMask (1, 1, 1, 1);
  607.         goto disable_stencil_buffer_and_return;
  608.     }
  609.  
  610.     /* We want to only render to the stencil buffer, so draw everything now.
  611.        Flushing also unbinds the VBO, which we want to rebind for regular
  612.        drawing. */
  613.     _cairo_gl_composite_flush (ctx);
  614.     _cairo_gl_composite_setup_vbo (ctx, vertex_size);
  615.  
  616. activate_stencil_buffer_and_return:
  617.     glColorMask (1, 1, 1, 1);
  618.     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
  619.     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
  620.     return CAIRO_INT_STATUS_SUCCESS;
  621.  
  622. disable_stencil_buffer_and_return:
  623.     _disable_stencil_buffer ();
  624.     return status;
  625. }
  626.  
  627. static cairo_int_status_t
  628. _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
  629.                                     cairo_gl_context_t *ctx,
  630.                                     int vertex_size)
  631. {
  632.     cairo_bool_t clip_changing = TRUE;
  633.     cairo_bool_t clip_region_changing = TRUE;
  634.  
  635.     if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
  636.         goto disable_all_clipping;
  637.  
  638.     clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
  639.     clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
  640.     if (! _cairo_gl_context_is_flushed (ctx) &&
  641.         (clip_region_changing || clip_changing))
  642.         _cairo_gl_composite_flush (ctx);
  643.  
  644.     assert (!setup->clip_region || !setup->clip);
  645.  
  646.     /* setup->clip is only used by the msaa compositor and setup->clip_region
  647.      * only by the other compositors, so it's safe to wait to clean up obsolete
  648.      * clips. */
  649.     if (clip_region_changing) {
  650.         cairo_region_destroy (ctx->clip_region);
  651.         ctx->clip_region = cairo_region_reference (setup->clip_region);
  652.     }
  653.     if (clip_changing) {
  654.         _cairo_clip_destroy (ctx->clip);
  655.         ctx->clip = _cairo_clip_copy (setup->clip);
  656.     }
  657.  
  658.     /* For clip regions, we scissor right before drawing. */
  659.     if (setup->clip_region)
  660.         goto disable_all_clipping;
  661.  
  662.     if (setup->clip)
  663.         return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
  664.                                                            vertex_size);
  665. disable_all_clipping:
  666.     _disable_stencil_buffer ();
  667.     glDisable (GL_SCISSOR_TEST);
  668.     return CAIRO_INT_STATUS_SUCCESS;
  669. }
  670.  
  671. cairo_status_t
  672. _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
  673.                                      cairo_gl_context_t *ctx)
  674. {
  675.     unsigned int dst_size, src_size, mask_size, vertex_size;
  676.     cairo_status_t status;
  677.     cairo_gl_shader_t *shader;
  678.     cairo_bool_t component_alpha;
  679.     cairo_bool_t vertex_size_changed;
  680.  
  681.     component_alpha =
  682.         setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
  683.         setup->mask.texture.attributes.has_component_alpha;
  684.  
  685.     /* Do various magic for component alpha */
  686.     if (component_alpha) {
  687.         status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
  688.         if (unlikely (status))
  689.             return status;
  690.      } else {
  691.         if (ctx->pre_shader) {
  692.             _cairo_gl_composite_flush (ctx);
  693.             ctx->pre_shader = NULL;
  694.         }
  695.     }
  696.  
  697.     status = _cairo_gl_get_shader_by_type (ctx,
  698.                                            &setup->src,
  699.                                            &setup->mask,
  700.                                            setup->spans,
  701.                                            component_alpha ?
  702.                                            CAIRO_GL_SHADER_IN_CA_SOURCE :
  703.                                            CAIRO_GL_SHADER_IN_NORMAL,
  704.                                            &shader);
  705.     if (unlikely (status)) {
  706.         ctx->pre_shader = NULL;
  707.         return status;
  708.     }
  709.     if (ctx->current_shader != shader)
  710.         _cairo_gl_composite_flush (ctx);
  711.  
  712.     status = CAIRO_STATUS_SUCCESS;
  713.  
  714.     dst_size = 2 * sizeof (GLfloat);
  715.     src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
  716.     mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
  717.     vertex_size = dst_size + src_size + mask_size;
  718.  
  719.     if (setup->spans)
  720.         vertex_size += sizeof (GLfloat);
  721.  
  722.     vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size);
  723.  
  724.     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, vertex_size_changed);
  725.     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, vertex_size_changed);
  726.  
  727.     _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
  728.                                    dst_size + src_size + mask_size);
  729.  
  730.     _cairo_gl_set_operator (ctx, setup->op, component_alpha);
  731.  
  732.     if (_cairo_gl_context_is_flushed (ctx)) {
  733.         if (ctx->pre_shader) {
  734.             _cairo_gl_set_shader (ctx, ctx->pre_shader);
  735.             _cairo_gl_composite_bind_to_shader (ctx, setup);
  736.         }
  737.         _cairo_gl_set_shader (ctx, shader);
  738.         _cairo_gl_composite_bind_to_shader (ctx, setup);
  739.     }
  740.  
  741.     return status;
  742. }
  743.  
  744. cairo_status_t
  745. _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
  746.                            cairo_gl_context_t **ctx_out)
  747. {
  748.     cairo_gl_context_t *ctx;
  749.     cairo_status_t status;
  750.  
  751.     assert (setup->dst);
  752.  
  753.     status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
  754.     if (unlikely (status))
  755.         return status;
  756.  
  757.     _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
  758.     glEnable (GL_BLEND);
  759.  
  760.     status = _cairo_gl_set_operands_and_operator (setup, ctx);
  761.     if (unlikely (status))
  762.         goto FAIL;
  763.  
  764.     status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
  765.     if (unlikely (status))
  766.         goto FAIL;
  767.  
  768.     *ctx_out = ctx;
  769.  
  770. FAIL:
  771.     if (unlikely (status))
  772.         status = _cairo_gl_context_release (ctx, status);
  773.  
  774.     return status;
  775. }
  776.  
  777. static inline void
  778. _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
  779. {
  780.     cairo_array_t* indices = &ctx->tristrip_indices;
  781.     const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
  782.  
  783.     if (ctx->pre_shader) {
  784.         cairo_gl_shader_t *prev_shader = ctx->current_shader;
  785.  
  786.         _cairo_gl_set_shader (ctx, ctx->pre_shader);
  787.         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
  788.         glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
  789.  
  790.         _cairo_gl_set_shader (ctx, prev_shader);
  791.         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
  792.     }
  793.  
  794.     glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
  795.     _cairo_array_truncate (indices, 0);
  796. }
  797.  
  798. static inline void
  799. _cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
  800.                                     unsigned int count)
  801. {
  802.     if (! ctx->pre_shader) {
  803.         glDrawArrays (GL_TRIANGLES, 0, count);
  804.     } else {
  805.         cairo_gl_shader_t *prev_shader = ctx->current_shader;
  806.  
  807.         _cairo_gl_set_shader (ctx, ctx->pre_shader);
  808.         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
  809.         glDrawArrays (GL_TRIANGLES, 0, count);
  810.  
  811.         _cairo_gl_set_shader (ctx, prev_shader);
  812.         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
  813.         glDrawArrays (GL_TRIANGLES, 0, count);
  814.     }
  815. }
  816.  
  817. static void
  818. _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
  819.                                                      unsigned int count)
  820. {
  821.     int i, num_rectangles;
  822.  
  823.     if (!ctx->clip_region) {
  824.         _cairo_gl_composite_draw_triangles (ctx, count);
  825.         return;
  826.     }
  827.  
  828.     num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
  829.     for (i = 0; i < num_rectangles; i++) {
  830.         cairo_rectangle_int_t rect;
  831.  
  832.         cairo_region_get_rectangle (ctx->clip_region, i, &rect);
  833.  
  834.         _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
  835.         _cairo_gl_composite_draw_triangles (ctx, count);
  836.     }
  837. }
  838.  
  839. static void
  840. _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
  841. {
  842.     ctx->vb_offset = 0;
  843. }
  844.  
  845. void
  846. _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
  847. {
  848.     unsigned int count;
  849.     int i;
  850.  
  851.     if (_cairo_gl_context_is_flushed (ctx))
  852.         return;
  853.  
  854.     count = ctx->vb_offset / ctx->vertex_size;
  855.     _cairo_gl_composite_unmap_vertex_buffer (ctx);
  856.  
  857.     if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
  858.         _cairo_gl_composite_draw_tristrip (ctx);
  859.     } else {
  860.         assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
  861.         _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
  862.     }
  863.  
  864.     for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++)
  865.         _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
  866. }
  867.  
  868. static void
  869. _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
  870.                                     unsigned int n_vertices,
  871.                                     cairo_gl_primitive_type_t primitive_type)
  872. {
  873.     if (ctx->primitive_type != primitive_type) {
  874.         _cairo_gl_composite_flush (ctx);
  875.         ctx->primitive_type = primitive_type;
  876.     }
  877.  
  878.     if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
  879.         _cairo_gl_composite_flush (ctx);
  880. }
  881.  
  882. static inline void
  883. _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
  884.                                  GLfloat x, GLfloat y)
  885. {
  886.     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
  887.  
  888.     *vb++ = x;
  889.     *vb++ = y;
  890.  
  891.     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
  892.     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
  893.  
  894.     ctx->vb_offset += ctx->vertex_size;
  895. }
  896.  
  897. static inline void
  898. _cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
  899.                                        GLfloat x, GLfloat y, uint8_t alpha)
  900. {
  901.     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
  902.     union fi {
  903.         float f;
  904.         GLbyte bytes[4];
  905.     } fi;
  906.  
  907.     *vb++ = x;
  908.     *vb++ = y;
  909.  
  910.     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
  911.     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
  912.  
  913.     fi.bytes[0] = 0;
  914.     fi.bytes[1] = 0;
  915.     fi.bytes[2] = 0;
  916.     fi.bytes[3] = alpha;
  917.     *vb++ = fi.f;
  918.  
  919.     ctx->vb_offset += ctx->vertex_size;
  920. }
  921.  
  922. static void
  923. _cairo_gl_composite_emit_point (cairo_gl_context_t      *ctx,
  924.                                 const cairo_point_t     *point)
  925. {
  926.     _cairo_gl_composite_emit_vertex (ctx,
  927.                                      _cairo_fixed_to_double (point->x),
  928.                                      _cairo_fixed_to_double (point->y));
  929. }
  930.  
  931. static void
  932. _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
  933.                                GLfloat x1, GLfloat y1,
  934.                                GLfloat x2, GLfloat y2)
  935. {
  936.     _cairo_gl_composite_prepare_buffer (ctx, 6,
  937.                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
  938.  
  939.     _cairo_gl_composite_emit_vertex (ctx, x1, y1);
  940.     _cairo_gl_composite_emit_vertex (ctx, x2, y1);
  941.     _cairo_gl_composite_emit_vertex (ctx, x1, y2);
  942.  
  943.     _cairo_gl_composite_emit_vertex (ctx, x2, y1);
  944.     _cairo_gl_composite_emit_vertex (ctx, x2, y2);
  945.     _cairo_gl_composite_emit_vertex (ctx, x1, y2);
  946. }
  947.  
  948. cairo_gl_emit_rect_t
  949. _cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
  950. {
  951.     return _cairo_gl_composite_emit_rect;
  952. }
  953.  
  954. void
  955. _cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
  956.                              GLfloat x1, GLfloat y1,
  957.                              GLfloat x2, GLfloat y2)
  958. {
  959.     _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
  960. }
  961.  
  962. static void
  963. _cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
  964.                                GLfloat x1, GLfloat y1,
  965.                                GLfloat x2, GLfloat y2,
  966.                                uint8_t alpha)
  967. {
  968.     _cairo_gl_composite_prepare_buffer (ctx, 6,
  969.                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
  970.  
  971.     _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
  972.     _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
  973.     _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
  974.  
  975.     _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
  976.     _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
  977.     _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
  978. }
  979.  
  980. static void
  981. _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
  982.                                      GLfloat x1, GLfloat y1,
  983.                                      GLfloat x2, GLfloat y2,
  984.                                      uint8_t alpha)
  985. {
  986.     GLfloat *v;
  987.     union fi {
  988.         float f;
  989.         GLbyte bytes[4];
  990.     } fi;
  991.  
  992.     _cairo_gl_composite_prepare_buffer (ctx, 6,
  993.                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
  994.     v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
  995.  
  996.     v[15] = v[ 6] = v[0] = x1;
  997.     v[10] = v[ 4] = v[1] = y1;
  998.     v[12] = v[ 9] = v[3] = x2;
  999.     v[16] = v[13] = v[7] = y2;
  1000.  
  1001.     fi.bytes[0] = 0;
  1002.     fi.bytes[1] = 0;
  1003.     fi.bytes[2] = 0;
  1004.     fi.bytes[3] = alpha;
  1005.     v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
  1006.  
  1007.     ctx->vb_offset += 6*3 * sizeof(GLfloat);
  1008. }
  1009.  
  1010. cairo_gl_emit_span_t
  1011. _cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
  1012. {
  1013.     if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
  1014.             switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
  1015.             default:
  1016.             case CAIRO_GL_OPERAND_COUNT:
  1017.                     ASSERT_NOT_REACHED;
  1018.             case CAIRO_GL_OPERAND_NONE:
  1019.             case CAIRO_GL_OPERAND_CONSTANT:
  1020.                     break;
  1021.  
  1022.             case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
  1023.             case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
  1024.             case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
  1025.             case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
  1026.                     if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
  1027.                             return _cairo_gl_composite_emit_span;
  1028.                     break;
  1029.  
  1030.             case CAIRO_GL_OPERAND_TEXTURE:
  1031.                     if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
  1032.                             return _cairo_gl_composite_emit_span;
  1033.                     break;
  1034.             }
  1035.     }
  1036.  
  1037.     switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
  1038.     default:
  1039.     case CAIRO_GL_OPERAND_COUNT:
  1040.         ASSERT_NOT_REACHED;
  1041.     case CAIRO_GL_OPERAND_NONE:
  1042.     case CAIRO_GL_OPERAND_CONSTANT:
  1043.         break;
  1044.  
  1045.     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
  1046.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
  1047.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
  1048.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
  1049.         if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
  1050.                 return _cairo_gl_composite_emit_span;
  1051.         break;
  1052.  
  1053.     case CAIRO_GL_OPERAND_TEXTURE:
  1054.         if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
  1055.                 return _cairo_gl_composite_emit_span;
  1056.     }
  1057.  
  1058.     return _cairo_gl_composite_emit_solid_span;
  1059. }
  1060.  
  1061. static inline void
  1062. _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
  1063.                                        GLfloat x, GLfloat y,
  1064.                                        GLfloat glyph_x, GLfloat glyph_y)
  1065. {
  1066.     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
  1067.  
  1068.     *vb++ = x;
  1069.     *vb++ = y;
  1070.  
  1071.     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
  1072.  
  1073.     *vb++ = glyph_x;
  1074.     *vb++ = glyph_y;
  1075.  
  1076.     ctx->vb_offset += ctx->vertex_size;
  1077. }
  1078.  
  1079. static void
  1080. _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
  1081.                                 GLfloat x1, GLfloat y1,
  1082.                                 GLfloat x2, GLfloat y2,
  1083.                                 GLfloat glyph_x1, GLfloat glyph_y1,
  1084.                                 GLfloat glyph_x2, GLfloat glyph_y2)
  1085. {
  1086.     _cairo_gl_composite_prepare_buffer (ctx, 6,
  1087.                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
  1088.  
  1089.     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
  1090.     _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
  1091.     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
  1092.  
  1093.     _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
  1094.     _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
  1095.     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
  1096. }
  1097.  
  1098. static void
  1099. _cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
  1100.                                       GLfloat x1, GLfloat y1,
  1101.                                       GLfloat x2, GLfloat y2,
  1102.                                       GLfloat glyph_x1, GLfloat glyph_y1,
  1103.                                       GLfloat glyph_x2, GLfloat glyph_y2)
  1104. {
  1105.     GLfloat *v;
  1106.  
  1107.     _cairo_gl_composite_prepare_buffer (ctx, 6,
  1108.                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
  1109.  
  1110.     v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
  1111.  
  1112.     v[20] = v[ 8] = v[0] = x1;
  1113.     v[13] = v[ 5] = v[1] = y1;
  1114.     v[22] = v[10] = v[2] = glyph_x1;
  1115.     v[15] = v[ 7] = v[3] = glyph_y1;
  1116.  
  1117.     v[16] = v[12] = v[4] = x2;
  1118.     v[18] = v[14] = v[6] = glyph_x2;
  1119.  
  1120.     v[21] = v[17] = v[ 9] = y2;
  1121.     v[23] = v[19] = v[11] = glyph_y2;
  1122.  
  1123.     ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
  1124. }
  1125.  
  1126. cairo_gl_emit_glyph_t
  1127. _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
  1128. {
  1129.     switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
  1130.     default:
  1131.     case CAIRO_GL_OPERAND_COUNT:
  1132.         ASSERT_NOT_REACHED;
  1133.     case CAIRO_GL_OPERAND_NONE:
  1134.     case CAIRO_GL_OPERAND_CONSTANT:
  1135.         return _cairo_gl_composite_emit_solid_glyph;
  1136.  
  1137.     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
  1138.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
  1139.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
  1140.     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
  1141.     case CAIRO_GL_OPERAND_TEXTURE:
  1142.         return _cairo_gl_composite_emit_glyph;
  1143.     }
  1144. }
  1145.  
  1146. void
  1147. _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
  1148. {
  1149.     _cairo_gl_operand_destroy (&setup->src);
  1150.     _cairo_gl_operand_destroy (&setup->mask);
  1151. }
  1152.  
  1153. cairo_status_t
  1154. _cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
  1155.                                   cairo_operator_t op,
  1156.                                   cairo_bool_t assume_component_alpha)
  1157. {
  1158.     if (assume_component_alpha) {
  1159.         if (op != CAIRO_OPERATOR_CLEAR &&
  1160.             op != CAIRO_OPERATOR_OVER &&
  1161.             op != CAIRO_OPERATOR_ADD)
  1162.             return UNSUPPORTED ("unsupported component alpha operator");
  1163.     } else {
  1164.         if (! _cairo_gl_operator_is_supported (op))
  1165.             return UNSUPPORTED ("unsupported operator");
  1166.     }
  1167.  
  1168.     setup->op = op;
  1169.     return CAIRO_STATUS_SUCCESS;
  1170. }
  1171.  
  1172. cairo_status_t
  1173. _cairo_gl_composite_init (cairo_gl_composite_t *setup,
  1174.                           cairo_operator_t op,
  1175.                           cairo_gl_surface_t *dst,
  1176.                           cairo_bool_t assume_component_alpha)
  1177. {
  1178.     cairo_status_t status;
  1179.  
  1180.     memset (setup, 0, sizeof (cairo_gl_composite_t));
  1181.  
  1182.     status = _cairo_gl_composite_set_operator (setup, op,
  1183.                                                assume_component_alpha);
  1184.     if (status)
  1185.         return status;
  1186.  
  1187.     setup->dst = dst;
  1188.     setup->clip_region = dst->clip_region;
  1189.  
  1190.     return CAIRO_STATUS_SUCCESS;
  1191. }
  1192.  
  1193. static cairo_int_status_t
  1194. _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t   *ctx,
  1195.                                            int                   number_of_new_indices)
  1196. {
  1197.     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
  1198.     cairo_array_t *indices = &ctx->tristrip_indices;
  1199.     int number_of_indices = _cairo_array_num_elements (indices);
  1200.     unsigned short current_vertex_index = 0;
  1201.     int i;
  1202.  
  1203.     assert (number_of_new_indices > 0);
  1204.  
  1205.     /* If any preexisting triangle triangle strip indices exist on this
  1206.        context, we insert a set of degenerate triangles from the last
  1207.        preexisting vertex to our first one. */
  1208.     if (number_of_indices > 0) {
  1209.         const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
  1210.         current_vertex_index = indices_array[number_of_indices - 1];
  1211.  
  1212.         status = _cairo_array_append (indices, &current_vertex_index);
  1213.         if (unlikely (status))
  1214.             return status;
  1215.  
  1216.         current_vertex_index++;
  1217.         status =_cairo_array_append (indices, &current_vertex_index);
  1218.         if (unlikely (status))
  1219.             return status;
  1220.     }
  1221.  
  1222.     for (i = 0; i < number_of_new_indices; i++) {
  1223.         status = _cairo_array_append (indices, &current_vertex_index);
  1224.         current_vertex_index++;
  1225.         if (unlikely (status))
  1226.             return status;
  1227.     }
  1228.  
  1229.     return CAIRO_STATUS_SUCCESS;
  1230. }
  1231.  
  1232. cairo_int_status_t
  1233. _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t   *ctx,
  1234.                                            cairo_gl_composite_t *setup,
  1235.                                            const cairo_point_t  quad[4])
  1236. {
  1237.     _cairo_gl_composite_prepare_buffer (ctx, 4,
  1238.                                         CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
  1239.  
  1240.     _cairo_gl_composite_emit_point (ctx, &quad[0]);
  1241.     _cairo_gl_composite_emit_point (ctx, &quad[1]);
  1242.  
  1243.     /* Cairo stores quad vertices in counter-clockwise order, but we need to
  1244.        emit them from top to bottom in the triangle strip, so we need to reverse
  1245.        the order of the last two vertices. */
  1246.     _cairo_gl_composite_emit_point (ctx, &quad[3]);
  1247.     _cairo_gl_composite_emit_point (ctx, &quad[2]);
  1248.  
  1249.     return _cairo_gl_composite_append_vertex_indices (ctx, 4);
  1250. }
  1251.  
  1252. cairo_int_status_t
  1253. _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t       *ctx,
  1254.                                                cairo_gl_composite_t     *setup,
  1255.                                                const cairo_point_t       triangle[3])
  1256. {
  1257.     _cairo_gl_composite_prepare_buffer (ctx, 3,
  1258.                                         CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
  1259.  
  1260.     _cairo_gl_composite_emit_point (ctx, &triangle[0]);
  1261.     _cairo_gl_composite_emit_point (ctx, &triangle[1]);
  1262.     _cairo_gl_composite_emit_point (ctx, &triangle[2]);
  1263.     return _cairo_gl_composite_append_vertex_indices (ctx, 3);
  1264. }
  1265.