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 
mix_pixels(VGuint p1,VGuint a,VGuint p2,VGuint b)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 
float4_to_argb(const VGfloat * clr)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 
create_gradient_data(const VGfloat * ramp_stops,VGint num,VGuint * data,VGint size)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 
create_gradient_texture(struct vg_paint * p)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 
create_gradient_sampler_view(struct vg_paint * p)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 
paint_create(struct vg_context * ctx)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 
paint_destroy(struct vg_paint * paint)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 
paint_set_color(struct vg_paint * paint,const VGfloat * color)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 
paint_color_buffer(struct vg_paint * paint,void * buffer)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 
paint_linear_gradient_buffer(struct vg_paint * paint,const struct matrix * inv,void * buffer)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 
paint_radial_gradient_buffer(struct vg_paint * paint,const struct matrix * inv,void * buffer)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 
paint_pattern_buffer(struct vg_paint * paint,const struct matrix * inv,void * buffer)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 
paint_set_type(struct vg_paint * paint,VGPaintType type)378 void paint_set_type(struct vg_paint *paint, VGPaintType type)
379 {
380    paint->type = type;
381 }
382 
paint_set_ramp_stops(struct vg_paint * paint,const VGfloat * stops,int num)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 
paint_set_colori(struct vg_paint * p,VGuint rgba)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 
paint_colori(struct vg_paint * p)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 
paint_set_linear_gradient(struct vg_paint * paint,const VGfloat * coords)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 
paint_set_spread_mode(struct vg_paint * paint,VGint mode)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 
paint_spread_mode(struct vg_paint * paint)472 VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint)
473 {
474    return paint->gradient.spread;
475 }
476 
paint_set_radial_gradient(struct vg_paint * paint,const VGfloat * values)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 
paint_set_pattern(struct vg_paint * paint,struct vg_image * img)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 
paint_set_pattern_tiling(struct vg_paint * paint,VGTilingMode mode)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 
paint_get_color(struct vg_paint * paint,VGfloat * color)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 
paint_ramp_stops(struct vg_paint * paint,VGfloat * stops,int num)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 
paint_linear_gradient(struct vg_paint * paint,VGfloat * coords)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 
paint_radial_gradient(struct vg_paint * paint,VGfloat * coords)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 
paint_num_ramp_stops(struct vg_paint * paint)548 int paint_num_ramp_stops(struct vg_paint *paint)
549 {
550    return paint->gradient.num_stops;
551 }
552 
paint_type(struct vg_paint * paint)553 VGPaintType paint_type(struct vg_paint *paint)
554 {
555    return paint->type;
556 }
557 
paint_set_coloriv(struct vg_paint * paint,const VGint * color)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 
paint_get_coloriv(struct vg_paint * paint,VGint * color)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 
paint_set_color_ramp_premultiplied(struct vg_paint * paint,VGboolean set)581 void paint_set_color_ramp_premultiplied(struct vg_paint *paint,
582                                         VGboolean set)
583 {
584    paint->gradient.color_ramps_premultiplied = set;
585 }
586 
paint_color_ramp_premultiplied(struct vg_paint * paint)587 VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint)
588 {
589    return paint->gradient.color_ramps_premultiplied;
590 }
591 
paint_set_ramp_stopsi(struct vg_paint * paint,const VGint * stops,int num)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 
paint_ramp_stopsi(struct vg_paint * paint,VGint * stops,int num)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 
paint_set_linear_gradienti(struct vg_paint * paint,const VGint * coords)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 
paint_linear_gradienti(struct vg_paint * paint,VGint * coords)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 
paint_set_radial_gradienti(struct vg_paint * paint,const VGint * values)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 
paint_radial_gradienti(struct vg_paint * paint,VGint * coords)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 
paint_pattern_tiling(struct vg_paint * paint)632 VGTilingMode paint_pattern_tiling(struct vg_paint *paint)
633 {
634    return paint->pattern.tiling_mode;
635 }
636 
paint_bind_samplers(struct vg_paint * paint,struct pipe_sampler_state ** samplers,struct pipe_sampler_view ** sampler_views)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 
paint_resolve_type(struct vg_paint * paint)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 
paint_is_degenerate(struct vg_paint * paint)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 
paint_constant_buffer_size(struct vg_paint * paint)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 
paint_fill_constant_buffer(struct vg_paint * paint,const struct matrix * mat,void * buffer)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 
paint_is_opaque(struct vg_paint * paint)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