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
41struct 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
84static 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
95static 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
103static 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
143static 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
175static 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
195struct 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
226void 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
240void 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
254static 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
264static 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
300static 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
356static 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
378void paint_set_type(struct vg_paint *paint, VGPaintType type)
379{
380   paint->type = type;
381}
382
383void 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
429void 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
438VGuint 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
449void 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
455void 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
472VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint)
473{
474   return paint->gradient.spread;
475}
476
477void 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
483void 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
494void 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
521void 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
530void 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
536void paint_linear_gradient(struct vg_paint *paint,
537                           VGfloat *coords)
538{
539   memcpy(coords, paint->gradient.linear.coords, sizeof(VGfloat)*4);
540}
541
542void paint_radial_gradient(struct vg_paint *paint,
543                           VGfloat *coords)
544{
545   memcpy(coords, paint->gradient.radial.vals, sizeof(VGfloat)*5);
546}
547
548int paint_num_ramp_stops(struct vg_paint *paint)
549{
550   return paint->gradient.num_stops;
551}
552
553VGPaintType paint_type(struct vg_paint *paint)
554{
555   return paint->type;
556}
557
558void 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
572void 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
581void paint_set_color_ramp_premultiplied(struct vg_paint *paint,
582                                        VGboolean set)
583{
584   paint->gradient.color_ramps_premultiplied = set;
585}
586
587VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint)
588{
589   return paint->gradient.color_ramps_premultiplied;
590}
591
592void 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
602void 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
608void 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
614void paint_linear_gradienti(struct vg_paint *paint,
615                            VGint *coords)
616{
617   memcpy(coords, paint->gradient.linear.coordsi, sizeof(VGint)*4);
618}
619
620void 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
626void paint_radial_gradienti(struct vg_paint *paint,
627                            VGint *coords)
628{
629   memcpy(coords, paint->gradient.radial.valsi, sizeof(VGint)*5);
630}
631
632VGTilingMode paint_pattern_tiling(struct vg_paint *paint)
633{
634   return paint->pattern.tiling_mode;
635}
636
637VGint 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
671void 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
679VGboolean 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
707VGint 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
729void 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
752VGboolean 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