Home | History | Annotate | Download | only in vega
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 VMware, Inc.  All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  **************************************************************************/
     26 
     27 #include "paint.h"
     28 
     29 #include "matrix.h"
     30 #include "image.h"
     31 
     32 #include "pipe/p_compiler.h"
     33 #include "util/u_inlines.h"
     34 
     35 #include "util/u_memory.h"
     36 #include "util/u_math.h"
     37 #include "util/u_sampler.h"
     38 
     39 #include "cso_cache/cso_context.h"
     40 
     41 struct vg_paint {
     42    struct vg_object base;
     43 
     44    VGPaintType type;
     45 
     46    struct {
     47       VGfloat color[4];
     48       VGint colori[4];
     49    } solid;
     50 
     51    struct {
     52       VGColorRampSpreadMode spread;
     53       VGuint color_data[1024];
     54       struct {
     55          VGfloat  coords[4];
     56          VGint  coordsi[4];
     57       } linear;
     58       struct {
     59          VGfloat vals[5];
     60          VGint valsi[5];
     61       } radial;
     62       struct pipe_sampler_view *sampler_view;
     63       struct pipe_sampler_state sampler;
     64 
     65       VGfloat *ramp_stops;
     66       VGint *ramp_stopsi;
     67       VGint    num_stops;
     68 
     69       VGboolean color_ramps_premultiplied;
     70    } gradient;
     71 
     72    struct {
     73       struct pipe_sampler_view *sampler_view;
     74       VGTilingMode tiling_mode;
     75       struct pipe_sampler_state sampler;
     76    } pattern;
     77 
     78    /* XXX next 3 all unneded? */
     79    struct pipe_resource *cbuf;
     80    struct pipe_shader_state fs_state;
     81    void *fs;
     82 };
     83 
     84 static INLINE VGuint mix_pixels(VGuint p1, VGuint a, VGuint p2, VGuint b)
     85 {
     86    VGuint t = (p1 & 0xff00ff) * a + (p2 & 0xff00ff) * b;
     87    t >>= 8; t &= 0xff00ff;
     88 
     89    p1 = ((p1 >> 8) & 0xff00ff) * a + ((p2 >> 8) & 0xff00ff) * b;
     90    p1 &= 0xff00ff00; p1 |= t;
     91 
     92    return p1;
     93 }
     94 
     95 static INLINE VGuint float4_to_argb(const VGfloat *clr)
     96 {
     97    return float_to_ubyte(clr[3]) << 24 |
     98       float_to_ubyte(clr[0]) << 16 |
     99       float_to_ubyte(clr[1]) << 8 |
    100       float_to_ubyte(clr[2]) << 0;
    101 }
    102 
    103 static INLINE void create_gradient_data(const VGfloat *ramp_stops,
    104                                         VGint num,
    105                                         VGuint *data,
    106                                         VGint size)
    107 {
    108    VGint i;
    109    VGint pos = 0;
    110    VGfloat fpos = 0, incr = 1.f / size;
    111    VGuint last_color;
    112 
    113    while (fpos < ramp_stops[0]) {
    114       data[pos] = float4_to_argb(ramp_stops + 1);
    115       fpos += incr;
    116       ++pos;
    117    }
    118 
    119    for (i = 0; i < num - 1; ++i) {
    120       VGint rcur  = 5 * i;
    121       VGint rnext = 5 * (i + 1);
    122       VGfloat delta = 1.f/(ramp_stops[rnext] - ramp_stops[rcur]);
    123       while (fpos < ramp_stops[rnext] && pos < size) {
    124          VGint dist = 256 * ((fpos - ramp_stops[rcur]) * delta);
    125          VGint idist = 256 - dist;
    126          VGuint current_color = float4_to_argb(ramp_stops + rcur + 1);
    127          VGuint next_color = float4_to_argb(ramp_stops + rnext + 1);
    128          data[pos] = mix_pixels(current_color, idist,
    129                                 next_color, dist);
    130          fpos += incr;
    131          ++pos;
    132       }
    133    }
    134 
    135    last_color = float4_to_argb(ramp_stops + ((num - 1) * 5 + 1));
    136    while (pos < size) {
    137       data[pos] = last_color;
    138       ++pos;
    139    }
    140    data[size-1] = last_color;
    141 }
    142 
    143 static INLINE struct pipe_resource *create_gradient_texture(struct vg_paint *p)
    144 {
    145    struct pipe_context *pipe = p->base.ctx->pipe;
    146    struct pipe_screen *screen = pipe->screen;
    147    struct pipe_resource *tex = 0;
    148    struct pipe_resource templ;
    149 
    150    memset(&templ, 0, sizeof(templ));
    151    templ.target = PIPE_TEXTURE_1D;
    152    templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
    153    templ.last_level = 0;
    154    templ.width0 = 1024;
    155    templ.height0 = 1;
    156    templ.depth0 = 1;
    157    templ.array_size = 1;
    158    templ.bind = PIPE_BIND_SAMPLER_VIEW;
    159 
    160    tex = screen->resource_create(screen, &templ);
    161 
    162    { /* upload color_data */
    163       struct pipe_transfer *transfer =
    164          pipe_get_transfer(p->base.ctx->pipe, tex, 0, 0,
    165                            PIPE_TRANSFER_WRITE, 0, 0, 1024, 1);
    166       void *map = pipe->transfer_map(pipe, transfer);
    167       memcpy(map, p->gradient.color_data, sizeof(VGint)*1024);
    168       pipe->transfer_unmap(pipe, transfer);
    169       pipe->transfer_destroy(pipe, transfer);
    170    }
    171 
    172    return tex;
    173 }
    174 
    175 static INLINE struct pipe_sampler_view *create_gradient_sampler_view(struct vg_paint *p)
    176 {
    177    struct pipe_context *pipe = p->base.ctx->pipe;
    178    struct pipe_resource *texture;
    179    struct pipe_sampler_view view_templ;
    180    struct pipe_sampler_view *view;
    181 
    182    texture = create_gradient_texture(p);
    183 
    184    if (!texture)
    185       return NULL;
    186 
    187    u_sampler_view_default_template(&view_templ, texture, texture->format);
    188    view = pipe->create_sampler_view(pipe, texture, &view_templ);
    189    /* want the texture to go away if the view is freed */
    190    pipe_resource_reference(&texture, NULL);
    191 
    192    return view;
    193 }
    194 
    195 struct vg_paint * paint_create(struct vg_context *ctx)
    196 {
    197    struct vg_paint *paint = CALLOC_STRUCT(vg_paint);
    198    const VGfloat default_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
    199    const VGfloat def_ling[] = {0.0f, 0.0f, 1.0f, 0.0f};
    200    const VGfloat def_radg[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
    201    vg_init_object(&paint->base, ctx, VG_OBJECT_PAINT);
    202    vg_context_add_object(ctx, &paint->base);
    203 
    204    paint->type = VG_PAINT_TYPE_COLOR;
    205    memcpy(paint->solid.color, default_color,
    206           4 * sizeof(VGfloat));
    207    paint->gradient.spread = VG_COLOR_RAMP_SPREAD_PAD;
    208    memcpy(paint->gradient.linear.coords, def_ling,
    209           4 * sizeof(VGfloat));
    210    memcpy(paint->gradient.radial.vals, def_radg,
    211           5 * sizeof(VGfloat));
    212 
    213    paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    214    paint->gradient.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    215    paint->gradient.sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
    216    paint->gradient.sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
    217    paint->gradient.sampler.normalized_coords = 1;
    218 
    219    memcpy(&paint->pattern.sampler,
    220           &paint->gradient.sampler,
    221           sizeof(struct pipe_sampler_state));
    222 
    223    return paint;
    224 }
    225 
    226 void paint_destroy(struct vg_paint *paint)
    227 {
    228    struct vg_context *ctx = paint->base.ctx;
    229    pipe_sampler_view_reference(&paint->gradient.sampler_view, NULL);
    230    if (paint->pattern.sampler_view)
    231       pipe_sampler_view_reference(&paint->pattern.sampler_view, NULL);
    232    if (ctx)
    233       vg_context_remove_object(ctx, &paint->base);
    234 
    235    free(paint->gradient.ramp_stopsi);
    236    free(paint->gradient.ramp_stops);
    237    FREE(paint);
    238 }
    239 
    240 void paint_set_color(struct vg_paint *paint,
    241                      const VGfloat *color)
    242 {
    243    paint->solid.color[0] = color[0];
    244    paint->solid.color[1] = color[1];
    245    paint->solid.color[2] = color[2];
    246    paint->solid.color[3] = color[3];
    247 
    248    paint->solid.colori[0] = FLT_TO_INT(color[0]);
    249    paint->solid.colori[1] = FLT_TO_INT(color[1]);
    250    paint->solid.colori[2] = FLT_TO_INT(color[2]);
    251    paint->solid.colori[3] = FLT_TO_INT(color[3]);
    252 }
    253 
    254 static INLINE void paint_color_buffer(struct vg_paint *paint, void *buffer)
    255 {
    256    VGfloat *map = (VGfloat*)buffer;
    257    memcpy(buffer, paint->solid.color, 4 * sizeof(VGfloat));
    258    map[4] = 0.f;
    259    map[5] = 1.f;
    260    map[6] = 2.f;
    261    map[7] = 4.f;
    262 }
    263 
    264 static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint,
    265                                                 const struct matrix *inv,
    266                                                 void *buffer)
    267 {
    268    VGfloat *map = (VGfloat*)buffer;
    269    VGfloat dd;
    270 
    271    map[0] = paint->gradient.linear.coords[2] - paint->gradient.linear.coords[0];
    272    map[1] = paint->gradient.linear.coords[3] - paint->gradient.linear.coords[1];
    273    dd = (map[0] * map[0] + map[1] * map[1]);
    274 
    275    map[2] = (dd > 0.0f) ? 1.f / dd : 0.f;
    276    map[3] = 1.f;
    277 
    278    map[4] = 0.f;
    279    map[5] = 1.f;
    280    map[6] = 2.f;
    281    map[7] = 4.f;
    282    {
    283       struct matrix mat;
    284       matrix_load_identity(&mat);
    285       /* VEGA_LINEAR_GRADIENT_SHADER expects the first point to be at (0, 0) */
    286       matrix_translate(&mat, -paint->gradient.linear.coords[0], -paint->gradient.linear.coords[1]);
    287       matrix_mult(&mat, inv);
    288 
    289       map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
    290       map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f;
    291       map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f;
    292    }
    293 #if 0
    294    debug_printf("Coords  (%f, %f, %f, %f)\n",
    295                 map[0], map[1], map[2], map[3]);
    296 #endif
    297 }
    298 
    299 
    300 static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint,
    301                                                 const struct matrix *inv,
    302                                                 void *buffer)
    303 {
    304    const VGfloat *center = &paint->gradient.radial.vals[0];
    305    const VGfloat *focal = &paint->gradient.radial.vals[2];
    306    VGfloat rr = paint->gradient.radial.vals[4];
    307    VGfloat *map = (VGfloat*)buffer;
    308    VGfloat dd, new_focal[2];
    309 
    310    rr *= rr;
    311 
    312    map[0] = center[0] - focal[0];
    313    map[1] = center[1] - focal[1];
    314    dd = map[0] * map[0] + map[1] * map[1];
    315 
    316    /* focal point must lie inside the circle */
    317    if (0.998f * rr < dd) {
    318       VGfloat scale;
    319 
    320       scale = (dd > 0.0f) ? sqrt(0.998f * rr / dd) : 0.0f;
    321       map[0] *= scale;
    322       map[1] *= scale;
    323 
    324       new_focal[0] = center[0] - map[0];
    325       new_focal[1] = center[1] - map[1];
    326       dd = map[0] * map[0] + map[1] * map[1];
    327       focal = new_focal;
    328    }
    329 
    330    map[2] = (rr > dd) ? rr - dd : 1.0f;
    331    map[3] = 1.f;
    332 
    333    map[4] = 0.f;
    334    map[5] = 1.f;
    335    map[6] = 2.f;
    336    map[7] = 4.f;
    337 
    338    {
    339       struct matrix mat;
    340       matrix_load_identity(&mat);
    341       matrix_translate(&mat, -focal[0], -focal[1]);
    342       matrix_mult(&mat, inv);
    343 
    344       map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
    345       map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f;
    346       map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f;
    347    }
    348 
    349 #if 0
    350    debug_printf("Coords  (%f, %f, %f, %f)\n",
    351                 map[0], map[1], map[2], map[3]);
    352 #endif
    353 }
    354 
    355 
    356 static INLINE void  paint_pattern_buffer(struct vg_paint *paint,
    357                                          const struct matrix *inv,
    358                                          void *buffer)
    359 {
    360    VGfloat *map = (VGfloat *)buffer;
    361    memcpy(map, paint->solid.color, 4 * sizeof(VGfloat));
    362 
    363    map[4] = 0.f;
    364    map[5] = 1.f;
    365    map[6] = paint->pattern.sampler_view->texture->width0;
    366    map[7] = paint->pattern.sampler_view->texture->height0;
    367    {
    368       struct matrix mat;
    369 
    370       memcpy(&mat, inv, sizeof(*inv));
    371 
    372       map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
    373       map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f;
    374       map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f;
    375    }
    376 }
    377 
    378 void paint_set_type(struct vg_paint *paint, VGPaintType type)
    379 {
    380    paint->type = type;
    381 }
    382 
    383 void paint_set_ramp_stops(struct vg_paint *paint, const VGfloat *stops,
    384                           int num)
    385 {
    386    const VGfloat default_stops[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
    387                                     1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
    388    VGint i;
    389    const VGint num_stops = num / 5;
    390    VGfloat last_coord;
    391 
    392    paint->gradient.num_stops = num;
    393    if (num) {
    394       free(paint->gradient.ramp_stops);
    395       paint->gradient.ramp_stops = malloc(sizeof(VGfloat)*num);
    396       memcpy(paint->gradient.ramp_stops, stops, sizeof(VGfloat)*num);
    397    } else
    398       return;
    399 
    400    /* stops must be in increasing order. the last stop is 1.0. if the
    401     * first one is bigger than 1 then the whole sequence is invalid*/
    402    if (stops[0] > 1) {
    403       stops = default_stops;
    404       num = 10;
    405    }
    406    last_coord = stops[0];
    407    for (i = 1; i < num_stops; ++i) {
    408       VGint idx = 5 * i;
    409       VGfloat coord = stops[idx];
    410       if (!floatsEqual(last_coord, coord) && coord < last_coord) {
    411          stops = default_stops;
    412          num = 10;
    413          break;
    414       }
    415       last_coord = coord;
    416    }
    417 
    418    create_gradient_data(stops, num / 5, paint->gradient.color_data,
    419                         1024);
    420 
    421    if (paint->gradient.sampler_view) {
    422       pipe_sampler_view_reference(&paint->gradient.sampler_view, NULL);
    423       paint->gradient.sampler_view = NULL;
    424    }
    425 
    426    paint->gradient.sampler_view = create_gradient_sampler_view(paint);
    427 }
    428 
    429 void paint_set_colori(struct vg_paint *p,
    430                       VGuint rgba)
    431 {
    432    p->solid.color[0] = ((rgba >> 24) & 0xff) / 255.f;
    433    p->solid.color[1] = ((rgba >> 16) & 0xff) / 255.f;
    434    p->solid.color[2] = ((rgba >>  8) & 0xff) / 255.f;
    435    p->solid.color[3] = ((rgba >>  0) & 0xff) / 255.f;
    436 }
    437 
    438 VGuint paint_colori(struct vg_paint *p)
    439 {
    440 #define F2B(f) (float_to_ubyte(f))
    441 
    442    return ((F2B(p->solid.color[0]) << 24) |
    443            (F2B(p->solid.color[1]) << 16) |
    444            (F2B(p->solid.color[2]) << 8)  |
    445            (F2B(p->solid.color[3]) << 0));
    446 #undef F2B
    447 }
    448 
    449 void paint_set_linear_gradient(struct vg_paint *paint,
    450                                const VGfloat *coords)
    451 {
    452    memcpy(paint->gradient.linear.coords, coords, sizeof(VGfloat) * 4);
    453 }
    454 
    455 void paint_set_spread_mode(struct vg_paint *paint,
    456                            VGint mode)
    457 {
    458    paint->gradient.spread = mode;
    459    switch(mode) {
    460    case VG_COLOR_RAMP_SPREAD_PAD:
    461       paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    462       break;
    463    case VG_COLOR_RAMP_SPREAD_REPEAT:
    464       paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
    465       break;
    466    case VG_COLOR_RAMP_SPREAD_REFLECT:
    467       paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
    468       break;
    469    }
    470 }
    471 
    472 VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint)
    473 {
    474    return paint->gradient.spread;
    475 }
    476 
    477 void paint_set_radial_gradient(struct vg_paint *paint,
    478                                const VGfloat *values)
    479 {
    480    memcpy(paint->gradient.radial.vals, values, sizeof(VGfloat) * 5);
    481 }
    482 
    483 void paint_set_pattern(struct vg_paint *paint,
    484                        struct vg_image *img)
    485 {
    486    if (paint->pattern.sampler_view)
    487       pipe_sampler_view_reference(&paint->pattern.sampler_view, NULL);
    488 
    489    paint->pattern.sampler_view = NULL;
    490    pipe_sampler_view_reference(&paint->pattern.sampler_view,
    491                                img->sampler_view);
    492 }
    493 
    494 void paint_set_pattern_tiling(struct vg_paint *paint,
    495                               VGTilingMode mode)
    496 {
    497    paint->pattern.tiling_mode = mode;
    498 
    499    switch(mode) {
    500    case VG_TILE_FILL:
    501       paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
    502       paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
    503       break;
    504    case VG_TILE_PAD:
    505       paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    506       paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    507       break;
    508    case VG_TILE_REPEAT:
    509       paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
    510       paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
    511       break;
    512    case VG_TILE_REFLECT:
    513       paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
    514       paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
    515       break;
    516    default:
    517       debug_assert("!Unknown tiling mode");
    518    }
    519 }
    520 
    521 void paint_get_color(struct vg_paint *paint,
    522                      VGfloat *color)
    523 {
    524    color[0] = paint->solid.color[0];
    525    color[1] = paint->solid.color[1];
    526    color[2] = paint->solid.color[2];
    527    color[3] = paint->solid.color[3];
    528 }
    529 
    530 void paint_ramp_stops(struct vg_paint *paint, VGfloat *stops,
    531                       int num)
    532 {
    533    memcpy(stops, paint->gradient.ramp_stops, sizeof(VGfloat)*num);
    534 }
    535 
    536 void paint_linear_gradient(struct vg_paint *paint,
    537                            VGfloat *coords)
    538 {
    539    memcpy(coords, paint->gradient.linear.coords, sizeof(VGfloat)*4);
    540 }
    541 
    542 void paint_radial_gradient(struct vg_paint *paint,
    543                            VGfloat *coords)
    544 {
    545    memcpy(coords, paint->gradient.radial.vals, sizeof(VGfloat)*5);
    546 }
    547 
    548 int paint_num_ramp_stops(struct vg_paint *paint)
    549 {
    550    return paint->gradient.num_stops;
    551 }
    552 
    553 VGPaintType paint_type(struct vg_paint *paint)
    554 {
    555    return paint->type;
    556 }
    557 
    558 void paint_set_coloriv(struct vg_paint *paint,
    559                       const VGint *color)
    560 {
    561    paint->solid.color[0] = color[0];
    562    paint->solid.color[1] = color[1];
    563    paint->solid.color[2] = color[2];
    564    paint->solid.color[3] = color[3];
    565 
    566    paint->solid.colori[0] = color[0];
    567    paint->solid.colori[1] = color[1];
    568    paint->solid.colori[2] = color[2];
    569    paint->solid.colori[3] = color[3];
    570 }
    571 
    572 void paint_get_coloriv(struct vg_paint *paint,
    573                       VGint *color)
    574 {
    575    color[0] = paint->solid.colori[0];
    576    color[1] = paint->solid.colori[1];
    577    color[2] = paint->solid.colori[2];
    578    color[3] = paint->solid.colori[3];
    579 }
    580 
    581 void paint_set_color_ramp_premultiplied(struct vg_paint *paint,
    582                                         VGboolean set)
    583 {
    584    paint->gradient.color_ramps_premultiplied = set;
    585 }
    586 
    587 VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint)
    588 {
    589    return paint->gradient.color_ramps_premultiplied;
    590 }
    591 
    592 void paint_set_ramp_stopsi(struct vg_paint *paint, const VGint *stops,
    593                            int num)
    594 {
    595    if (num) {
    596       free(paint->gradient.ramp_stopsi);
    597       paint->gradient.ramp_stopsi = malloc(sizeof(VGint)*num);
    598       memcpy(paint->gradient.ramp_stopsi, stops, sizeof(VGint)*num);
    599    }
    600 }
    601 
    602 void paint_ramp_stopsi(struct vg_paint *paint, VGint *stops,
    603                        int num)
    604 {
    605    memcpy(stops, paint->gradient.ramp_stopsi, sizeof(VGint)*num);
    606 }
    607 
    608 void paint_set_linear_gradienti(struct vg_paint *paint,
    609                                 const VGint *coords)
    610 {
    611    memcpy(paint->gradient.linear.coordsi, coords, sizeof(VGint) * 4);
    612 }
    613 
    614 void paint_linear_gradienti(struct vg_paint *paint,
    615                             VGint *coords)
    616 {
    617    memcpy(coords, paint->gradient.linear.coordsi, sizeof(VGint)*4);
    618 }
    619 
    620 void paint_set_radial_gradienti(struct vg_paint *paint,
    621                                 const VGint *values)
    622 {
    623    memcpy(paint->gradient.radial.valsi, values, sizeof(VGint) * 5);
    624 }
    625 
    626 void paint_radial_gradienti(struct vg_paint *paint,
    627                             VGint *coords)
    628 {
    629    memcpy(coords, paint->gradient.radial.valsi, sizeof(VGint)*5);
    630 }
    631 
    632 VGTilingMode paint_pattern_tiling(struct vg_paint *paint)
    633 {
    634    return paint->pattern.tiling_mode;
    635 }
    636 
    637 VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers,
    638                           struct pipe_sampler_view **sampler_views)
    639 {
    640    struct vg_context *ctx = vg_current_context();
    641 
    642    switch(paint->type) {
    643    case VG_PAINT_TYPE_LINEAR_GRADIENT:
    644    case VG_PAINT_TYPE_RADIAL_GRADIENT: {
    645       if (paint->gradient.sampler_view) {
    646          paint->gradient.sampler.min_img_filter = image_sampler_filter(ctx);
    647          paint->gradient.sampler.mag_img_filter = image_sampler_filter(ctx);
    648          samplers[0] = &paint->gradient.sampler;
    649          sampler_views[0] = paint->gradient.sampler_view;
    650          return 1;
    651       }
    652    }
    653       break;
    654    case VG_PAINT_TYPE_PATTERN: {
    655       memcpy(paint->pattern.sampler.border_color.f,
    656              ctx->state.vg.tile_fill_color,
    657              sizeof(VGfloat) * 4);
    658       paint->pattern.sampler.min_img_filter = image_sampler_filter(ctx);
    659       paint->pattern.sampler.mag_img_filter = image_sampler_filter(ctx);
    660       samplers[0] = &paint->pattern.sampler;
    661       sampler_views[0] = paint->pattern.sampler_view;
    662       return 1;
    663    }
    664       break;
    665    default:
    666       break;
    667    }
    668    return 0;
    669 }
    670 
    671 void paint_resolve_type(struct vg_paint *paint)
    672 {
    673    if (paint->type == VG_PAINT_TYPE_PATTERN &&
    674        !paint->pattern.sampler_view) {
    675       paint->type = VG_PAINT_TYPE_COLOR;
    676    }
    677 }
    678 
    679 VGboolean paint_is_degenerate(struct vg_paint *paint)
    680 {
    681    VGboolean degen;
    682    VGfloat *vals;
    683 
    684 
    685    switch (paint->type) {
    686    case VG_PAINT_TYPE_LINEAR_GRADIENT:
    687       vals = paint->gradient.linear.coords;
    688       /* two points are coincident */
    689       degen = (floatsEqual(vals[0], vals[2]) &&
    690                floatsEqual(vals[1], vals[3]));
    691       break;
    692    case VG_PAINT_TYPE_RADIAL_GRADIENT:
    693       vals = paint->gradient.radial.vals;
    694       /* radius <= 0 */
    695       degen = (vals[4] <= 0.0f);
    696       break;
    697    case VG_PAINT_TYPE_COLOR:
    698    case VG_PAINT_TYPE_PATTERN:
    699    default:
    700       degen = VG_FALSE;
    701       break;
    702    }
    703 
    704    return degen;
    705 }
    706 
    707 VGint paint_constant_buffer_size(struct vg_paint *paint)
    708 {
    709    switch(paint->type) {
    710    case VG_PAINT_TYPE_COLOR:
    711       return 8 * sizeof(VGfloat);/*4 color + 4 constants (0.f,1.f,2.f,4.f)*/
    712       break;
    713    case VG_PAINT_TYPE_LINEAR_GRADIENT:
    714       return 20 * sizeof(VGfloat);
    715       break;
    716    case VG_PAINT_TYPE_RADIAL_GRADIENT:
    717       return 20 * sizeof(VGfloat);
    718       break;
    719    case VG_PAINT_TYPE_PATTERN:
    720       return 20 * sizeof(VGfloat);
    721       break;
    722    default:
    723       debug_printf("Uknown paint type: %d\n", paint->type);
    724    }
    725 
    726    return 0;
    727 }
    728 
    729 void paint_fill_constant_buffer(struct vg_paint *paint,
    730                                 const struct matrix *mat,
    731                                 void *buffer)
    732 {
    733    switch(paint->type) {
    734    case VG_PAINT_TYPE_COLOR:
    735       paint_color_buffer(paint, buffer);
    736       break;
    737    case VG_PAINT_TYPE_LINEAR_GRADIENT:
    738       paint_linear_gradient_buffer(paint, mat, buffer);
    739       break;
    740    case VG_PAINT_TYPE_RADIAL_GRADIENT:
    741       paint_radial_gradient_buffer(paint, mat, buffer);
    742       break;
    743    case VG_PAINT_TYPE_PATTERN:
    744       paint_pattern_buffer(paint, mat, buffer);
    745       break;
    746 
    747    default:
    748       abort();
    749    }
    750 }
    751 
    752 VGboolean paint_is_opaque(struct vg_paint *paint)
    753 {
    754    /* TODO add other paint types and make sure PAINT_DIRTY gets set */
    755    return (paint->type == VG_PAINT_TYPE_COLOR &&
    756            floatsEqual(paint->solid.color[3], 1.0f));
    757 }
    758