1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
25 **************************************************************************/
32 #include "pipe/p_compiler.h"
33 #include "util/u_inlines.h"
35 #include "util/u_memory.h"
36 #include "util/u_math.h"
37 #include "util/u_sampler.h"
39 #include "cso_cache/cso_context.h"
42 struct vg_object base;
52 VGColorRampSpreadMode spread;
53 VGuint color_data[1024];
62 struct pipe_sampler_view *sampler_view;
63 struct pipe_sampler_state sampler;
69 VGboolean color_ramps_premultiplied;
73 struct pipe_sampler_view *sampler_view;
74 VGTilingMode tiling_mode;
75 struct pipe_sampler_state sampler;
78 /* XXX next 3 all unneded? */
79 struct pipe_resource *cbuf;
80 struct pipe_shader_state fs_state;
84 static INLINE VGuint mix_pixels(VGuint p1, VGuint a, VGuint p2, VGuint b)
86 VGuint t = (p1 & 0xff00ff) * a + (p2 & 0xff00ff) * b;
87 t >>= 8; t &= 0xff00ff;
89 p1 = ((p1 >> 8) & 0xff00ff) * a + ((p2 >> 8) & 0xff00ff) * b;
90 p1 &= 0xff00ff00; p1 |= t;
95 static INLINE VGuint float4_to_argb(const VGfloat *clr)
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;
103 static INLINE void create_gradient_data(const VGfloat *ramp_stops,
110 VGfloat fpos = 0, incr = 1.f / size;
113 while (fpos < ramp_stops[0]) {
114 data[pos] = float4_to_argb(ramp_stops + 1);
119 for (i = 0; i < num - 1; ++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,
135 last_color = float4_to_argb(ramp_stops + ((num - 1) * 5 + 1));
137 data[pos] = last_color;
140 data[size-1] = last_color;
143 static INLINE struct pipe_resource *create_gradient_texture(struct vg_paint *p)
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;
150 memset(&templ, 0, sizeof(templ));
151 templ.target = PIPE_TEXTURE_1D;
152 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
153 templ.last_level = 0;
157 templ.array_size = 1;
158 templ.bind = PIPE_BIND_SAMPLER_VIEW;
160 tex = screen->resource_create(screen, &templ);
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);
175 static INLINE struct pipe_sampler_view *create_gradient_sampler_view(struct vg_paint *p)
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;
182 texture = create_gradient_texture(p);
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);
195 struct vg_paint * paint_create(struct vg_context *ctx)
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, VG_OBJECT_PAINT, paint);
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));
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;
219 memcpy(&paint->pattern.sampler,
220 &paint->gradient.sampler,
221 sizeof(struct pipe_sampler_state));
226 void paint_destroy(struct vg_paint *paint)
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);
233 vg_context_remove_object(ctx, VG_OBJECT_PAINT, paint);
235 free(paint->gradient.ramp_stopsi);
236 free(paint->gradient.ramp_stops);
240 void paint_set_color(struct vg_paint *paint,
241 const VGfloat *color)
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];
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]);
254 static INLINE void paint_color_buffer(struct vg_paint *paint, void *buffer)
256 VGfloat *map = (VGfloat*)buffer;
257 memcpy(buffer, paint->solid.color, 4 * sizeof(VGfloat));
264 static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint,
265 const struct matrix *inv,
268 VGfloat *map = (VGfloat*)buffer;
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]);
275 map[2] = (dd > 0.0f) ? 1.f / dd : 0.f;
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);
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;
294 debug_printf("Coords (%f, %f, %f, %f)\n",
295 map[0], map[1], map[2], map[3]);
300 static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint,
301 const struct matrix *inv,
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];
312 map[0] = center[0] - focal[0];
313 map[1] = center[1] - focal[1];
314 dd = map[0] * map[0] + map[1] * map[1];
316 /* focal point must lie inside the circle */
317 if (0.998f * rr < dd) {
320 scale = (dd > 0.0f) ? sqrt(0.998f * rr / dd) : 0.0f;
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];
330 map[2] = (rr > dd) ? rr - dd : 1.0f;
340 matrix_load_identity(&mat);
341 matrix_translate(&mat, -focal[0], -focal[1]);
342 matrix_mult(&mat, inv);
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;
350 debug_printf("Coords (%f, %f, %f, %f)\n",
351 map[0], map[1], map[2], map[3]);
356 static INLINE void paint_pattern_buffer(struct vg_paint *paint,
357 const struct matrix *inv,
360 VGfloat *map = (VGfloat *)buffer;
361 memcpy(map, paint->solid.color, 4 * sizeof(VGfloat));
365 map[6] = paint->pattern.sampler_view->texture->width0;
366 map[7] = paint->pattern.sampler_view->texture->height0;
370 memcpy(&mat, inv, sizeof(*inv));
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;
378 void paint_set_type(struct vg_paint *paint, VGPaintType type)
383 void paint_set_ramp_stops(struct vg_paint *paint, const VGfloat *stops,
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};
389 const VGint num_stops = num / 5;
392 paint->gradient.num_stops = 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);
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*/
403 stops = default_stops;
406 last_coord = stops[0];
407 for (i = 1; i < num_stops; ++i) {
409 VGfloat coord = stops[idx];
410 if (!floatsEqual(last_coord, coord) && coord < last_coord) {
411 stops = default_stops;
418 create_gradient_data(stops, num / 5, paint->gradient.color_data,
421 if (paint->gradient.sampler_view) {
422 pipe_sampler_view_reference(&paint->gradient.sampler_view, NULL);
423 paint->gradient.sampler_view = NULL;
426 paint->gradient.sampler_view = create_gradient_sampler_view(paint);
429 void paint_set_colori(struct vg_paint *p,
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;
438 VGuint paint_colori(struct vg_paint *p)
440 #define F2B(f) (float_to_ubyte(f))
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));
449 void paint_set_linear_gradient(struct vg_paint *paint,
450 const VGfloat *coords)
452 memcpy(paint->gradient.linear.coords, coords, sizeof(VGfloat) * 4);
455 void paint_set_spread_mode(struct vg_paint *paint,
458 paint->gradient.spread = mode;
460 case VG_COLOR_RAMP_SPREAD_PAD:
461 paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
463 case VG_COLOR_RAMP_SPREAD_REPEAT:
464 paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
466 case VG_COLOR_RAMP_SPREAD_REFLECT:
467 paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
472 VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint)
474 return paint->gradient.spread;
477 void paint_set_radial_gradient(struct vg_paint *paint,
478 const VGfloat *values)
480 memcpy(paint->gradient.radial.vals, values, sizeof(VGfloat) * 5);
483 void paint_set_pattern(struct vg_paint *paint,
484 struct vg_image *img)
486 if (paint->pattern.sampler_view)
487 pipe_sampler_view_reference(&paint->pattern.sampler_view, NULL);
489 paint->pattern.sampler_view = NULL;
490 pipe_sampler_view_reference(&paint->pattern.sampler_view,
494 void paint_set_pattern_tiling(struct vg_paint *paint,
497 paint->pattern.tiling_mode = mode;
501 paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
502 paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
505 paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
506 paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
509 paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
510 paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
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;
517 debug_assert("!Unknown tiling mode");
521 void paint_get_color(struct vg_paint *paint,
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];
530 void paint_ramp_stops(struct vg_paint *paint, VGfloat *stops,
533 memcpy(stops, paint->gradient.ramp_stops, sizeof(VGfloat)*num);
536 void paint_linear_gradient(struct vg_paint *paint,
539 memcpy(coords, paint->gradient.linear.coords, sizeof(VGfloat)*4);
542 void paint_radial_gradient(struct vg_paint *paint,
545 memcpy(coords, paint->gradient.radial.vals, sizeof(VGfloat)*5);
548 int paint_num_ramp_stops(struct vg_paint *paint)
550 return paint->gradient.num_stops;
553 VGPaintType paint_type(struct vg_paint *paint)
558 void paint_set_coloriv(struct vg_paint *paint,
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];
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];
572 void paint_get_coloriv(struct vg_paint *paint,
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];
581 void paint_set_color_ramp_premultiplied(struct vg_paint *paint,
584 paint->gradient.color_ramps_premultiplied = set;
587 VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint)
589 return paint->gradient.color_ramps_premultiplied;
592 void paint_set_ramp_stopsi(struct vg_paint *paint, const VGint *stops,
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);
602 void paint_ramp_stopsi(struct vg_paint *paint, VGint *stops,
605 memcpy(stops, paint->gradient.ramp_stopsi, sizeof(VGint)*num);
608 void paint_set_linear_gradienti(struct vg_paint *paint,
611 memcpy(paint->gradient.linear.coordsi, coords, sizeof(VGint) * 4);
614 void paint_linear_gradienti(struct vg_paint *paint,
617 memcpy(coords, paint->gradient.linear.coordsi, sizeof(VGint)*4);
620 void paint_set_radial_gradienti(struct vg_paint *paint,
623 memcpy(paint->gradient.radial.valsi, values, sizeof(VGint) * 5);
626 void paint_radial_gradienti(struct vg_paint *paint,
629 memcpy(coords, paint->gradient.radial.valsi, sizeof(VGint)*5);
632 VGTilingMode paint_pattern_tiling(struct vg_paint *paint)
634 return paint->pattern.tiling_mode;
637 VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers,
638 struct pipe_sampler_view **sampler_views)
640 struct vg_context *ctx = vg_current_context();
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;
654 case VG_PAINT_TYPE_PATTERN: {
655 memcpy(paint->pattern.sampler.border_color,
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;
671 void paint_resolve_type(struct vg_paint *paint)
673 if (paint->type == VG_PAINT_TYPE_PATTERN &&
674 !paint->pattern.sampler_view) {
675 paint->type = VG_PAINT_TYPE_COLOR;
679 VGboolean paint_is_degenerate(struct vg_paint *paint)
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]));
692 case VG_PAINT_TYPE_RADIAL_GRADIENT:
693 vals = paint->gradient.radial.vals;
695 degen = (vals[4] <= 0.0f);
697 case VG_PAINT_TYPE_COLOR:
698 case VG_PAINT_TYPE_PATTERN:
707 VGint paint_constant_buffer_size(struct vg_paint *paint)
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)*/
713 case VG_PAINT_TYPE_LINEAR_GRADIENT:
714 return 20 * sizeof(VGfloat);
716 case VG_PAINT_TYPE_RADIAL_GRADIENT:
717 return 20 * sizeof(VGfloat);
719 case VG_PAINT_TYPE_PATTERN:
720 return 20 * sizeof(VGfloat);
723 debug_printf("Uknown paint type: %d\n", paint->type);
729 void paint_fill_constant_buffer(struct vg_paint *paint,
730 const struct matrix *mat,
733 switch(paint->type) {
734 case VG_PAINT_TYPE_COLOR:
735 paint_color_buffer(paint, buffer);
737 case VG_PAINT_TYPE_LINEAR_GRADIENT:
738 paint_linear_gradient_buffer(paint, mat, buffer);
740 case VG_PAINT_TYPE_RADIAL_GRADIENT:
741 paint_radial_gradient_buffer(paint, mat, buffer);
743 case VG_PAINT_TYPE_PATTERN:
744 paint_pattern_buffer(paint, mat, buffer);
752 VGboolean paint_is_opaque(struct vg_paint *paint)
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));