Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / state_trackers / vega / mask.c
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 "mask.h"
28
29 #include "path.h"
30 #include "image.h"
31 #include "shaders_cache.h"
32 #include "renderer.h"
33 #include "asm_util.h"
34
35 #include "pipe/p_context.h"
36 #include "pipe/p_screen.h"
37 #include "util/u_inlines.h"
38 #include "util/u_format.h"
39 #include "util/u_memory.h"
40 #include "util/u_surface.h"
41 #include "util/u_sampler.h"
42
43 struct vg_mask_layer {
44    struct vg_object base;
45
46    VGint width;
47    VGint height;
48
49    struct pipe_sampler_view *sampler_view;
50 };
51
52 static INLINE VGboolean
53 intersect_rectangles(VGint dwidth, VGint dheight,
54                      VGint swidth, VGint sheight,
55                      VGint tx, VGint ty,
56                      VGint twidth, VGint theight,
57                      VGint *offsets,
58                      VGint *location)
59 {
60    if (tx + twidth <= 0 || tx >= dwidth)
61       return VG_FALSE;
62    if (ty + theight <= 0 || ty >= dheight)
63       return VG_FALSE;
64
65    offsets[0] = 0;
66    offsets[1] = 0;
67    location[0] = tx;
68    location[1] = ty;
69
70    if (tx < 0) {
71       offsets[0] -= tx;
72       location[0] = 0;
73
74       location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth));
75       offsets[2] = location[2];
76    } else {
77       offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth ));
78       location[2] = offsets[2];
79    }
80
81    if (ty < 0) {
82       offsets[1] -= ty;
83       location[1] = 0;
84
85       location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight));
86       offsets[3] = location[3];
87    } else {
88       offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight));
89       location[3] = offsets[3];
90    }
91
92    return VG_TRUE;
93 }
94
95 #if DEBUG_MASKS
96 static void read_alpha_mask(void * data, VGint dataStride,
97                             VGImageFormat dataFormat,
98                             VGint sx, VGint sy,
99                             VGint width, VGint height)
100 {
101    struct vg_context *ctx = vg_current_context();
102    struct pipe_context *pipe = ctx->pipe;
103
104    struct st_framebuffer *stfb = ctx->draw_buffer;
105    struct st_renderbuffer *strb = stfb->alpha_mask;
106
107    VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
108    VGfloat *df = (VGfloat*)temp;
109    VGint y = (stfb->height - sy) - 1, yStep = -1;
110    VGint i;
111    VGubyte *dst = (VGubyte *)data;
112    VGint xoffset = 0, yoffset = 0;
113
114    if (sx < 0) {
115       xoffset = -sx;
116       xoffset *= _vega_size_for_format(dataFormat);
117       width += sx;
118       sx = 0;
119    }
120    if (sy < 0) {
121       yoffset = -sy;
122       height += sy;
123       sy = 0;
124       y = (stfb->height - sy) - 1;
125       yoffset *= dataStride;
126    }
127
128    {
129       struct pipe_surface *surf;
130
131       surf = pipe->create_surface(pipe, strb->texture,  0, 0, 0,
132                                   PIPE_BIND_TRANSFER_READ);
133
134       /* Do a row at a time to flip image data vertically */
135       for (i = 0; i < height; i++) {
136 #if 0
137          debug_printf("%d-%d  == %d\n", sy, height, y);
138 #endif
139          pipe_get_tile_rgba(surf, sx, y, width, 1, df);
140          y += yStep;
141          _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
142                                     dst + yoffset + xoffset);
143          dst += dataStride;
144       }
145
146       pipe_surface_reference(&surf, NULL);
147    }
148 }
149
150 void save_alpha_to_file(const char *filename)
151 {
152    struct vg_context *ctx = vg_current_context();
153    struct st_framebuffer *stfb = ctx->draw_buffer;
154    VGint *data;
155    int i, j;
156
157    data = malloc(sizeof(int) * stfb->width * stfb->height);
158    read_alpha_mask(data, stfb->width * sizeof(int),
159                    VG_sRGBA_8888,
160                    0, 0, stfb->width, stfb->height);
161    fprintf(stderr, "/*---------- start */\n");
162    fprintf(stderr, "const int image_width = %d;\n",
163            stfb->width);
164    fprintf(stderr, "const int image_height = %d;\n",
165            stfb->height);
166    fprintf(stderr, "const int image_data = {\n");
167    for (i = 0; i < stfb->height; ++i) {
168       for (j = 0; j < stfb->width; ++j) {
169          int rgba = data[i * stfb->height + j];
170          int argb = 0;
171          argb = (rgba >> 8);
172          argb |= ((rgba & 0xff) << 24);
173          fprintf(stderr, "0x%x, ", argb);
174       }
175       fprintf(stderr, "\n");
176    }
177    fprintf(stderr, "};\n");
178    fprintf(stderr, "/*---------- end */\n");
179 }
180 #endif
181
182 /* setup mask shader */
183 static void *setup_mask_operation(VGMaskOperation operation)
184 {
185    struct vg_context *ctx = vg_current_context();
186    void *shader = 0;
187
188    switch (operation) {
189    case VG_UNION_MASK: {
190       if (!ctx->mask.union_fs) {
191          ctx->mask.union_fs = shader_create_from_text(ctx->pipe,
192                                                       union_mask_asm,
193                                                       200,
194                                                       PIPE_SHADER_FRAGMENT);
195       }
196       shader = ctx->mask.union_fs->driver;
197    }
198       break;
199    case VG_INTERSECT_MASK: {
200       if (!ctx->mask.intersect_fs) {
201          ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe,
202                                                           intersect_mask_asm,
203                                                           200,
204                                                           PIPE_SHADER_FRAGMENT);
205       }
206       shader = ctx->mask.intersect_fs->driver;
207    }
208       break;
209    case VG_SUBTRACT_MASK: {
210       if (!ctx->mask.subtract_fs) {
211          ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe,
212                                                          subtract_mask_asm,
213                                                          200,
214                                                          PIPE_SHADER_FRAGMENT);
215       }
216       shader = ctx->mask.subtract_fs->driver;
217    }
218       break;
219    case VG_SET_MASK: {
220       if (!ctx->mask.set_fs) {
221          ctx->mask.set_fs = shader_create_from_text(ctx->pipe,
222                                                     set_mask_asm,
223                                                     200,
224                                                     PIPE_SHADER_FRAGMENT);
225       }
226       shader = ctx->mask.set_fs->driver;
227    }
228       break;
229    default:
230          assert(0);
231       break;
232    }
233
234    return shader;
235 }
236
237 static void mask_resource_fill(struct pipe_resource *dst,
238                                int x, int y, int width, int height,
239                                VGfloat coverage)
240 {
241    struct vg_context *ctx = vg_current_context();
242    VGfloat fs_consts[12] = {
243       0.0f, 0.0f, 0.0f, 0.0f, /* not used */
244       0.0f, 0.0f, 0.0f, 0.0f, /* not used */
245       0.0f, 0.0f, 0.0f, coverage /* color */
246    };
247    void *fs;
248
249    if (x < 0) {
250       width += x;
251       x = 0;
252    }
253    if (y < 0) {
254       height += y;
255       y = 0;
256    }
257
258    fs = shaders_cache_fill(ctx->sc, VEGA_SOLID_FILL_SHADER);
259
260    if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, ~0,
261             NULL, NULL, 0, fs, (const void *) fs_consts, sizeof(fs_consts))) {
262       renderer_filter(ctx->renderer, x, y, width, height, 0, 0, 0, 0);
263       renderer_filter_end(ctx->renderer);
264    }
265
266 #if DEBUG_MASKS
267    save_alpha_to_file(0);
268 #endif
269 }
270
271
272 static void mask_using_texture(struct pipe_sampler_view *sampler_view,
273                                VGboolean is_layer,
274                                VGMaskOperation operation,
275                                VGint x, VGint y,
276                                VGint width, VGint height)
277 {
278    struct vg_context *ctx = vg_current_context();
279    struct pipe_sampler_view *dst_view = vg_get_surface_mask(ctx);
280    struct pipe_resource *dst = dst_view->texture;
281    struct pipe_resource *texture = sampler_view->texture;
282    const struct pipe_sampler_state *samplers[2];
283    struct pipe_sampler_view *views[2];
284    struct pipe_sampler_state sampler;
285    VGint offsets[4], loc[4];
286    const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f};
287    void *fs;
288
289    if (!intersect_rectangles(dst->width0, dst->height0,
290                              texture->width0, texture->height0,
291                              x, y, width, height,
292                              offsets, loc))
293       return;
294 #if 0
295    debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0],
296                 offsets[1], offsets[2], offsets[3]);
297    debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0],
298                 loc[1], loc[2], loc[3]);
299 #endif
300
301
302    sampler = ctx->mask.sampler;
303    sampler.normalized_coords = 1;
304    samplers[0] = &sampler;
305    views[0] = sampler_view;
306
307    /* prepare our blend surface */
308    samplers[1] = &ctx->mask.sampler;
309    views[1] = vg_prepare_blend_surface_from_mask(ctx);
310
311    fs = setup_mask_operation(operation);
312
313    if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE,
314             ~0, samplers, views, 2, fs, (const void *) ones, sizeof(ones))) {
315       /* layer should be flipped when used as a texture */
316       if (is_layer) {
317          offsets[1] += offsets[3];
318          offsets[3] = -offsets[3];
319       }
320       renderer_filter(ctx->renderer,
321             loc[0], loc[1], loc[2], loc[3],
322             offsets[0], offsets[1], offsets[2], offsets[3]);
323       renderer_filter_end(ctx->renderer);
324    }
325 }
326
327
328 #ifdef OPENVG_VERSION_1_1
329
330 struct vg_mask_layer * mask_layer_create(VGint width, VGint height)
331 {
332    struct vg_context *ctx = vg_current_context();
333    struct vg_mask_layer *mask = 0;
334
335    mask = CALLOC_STRUCT(vg_mask_layer);
336    vg_init_object(&mask->base, ctx, VG_OBJECT_MASK);
337    mask->width = width;
338    mask->height = height;
339
340    {
341       struct pipe_resource pt;
342       struct pipe_context *pipe = ctx->pipe;
343       struct pipe_screen *screen = ctx->pipe->screen;
344       struct pipe_sampler_view view_templ;
345       struct pipe_sampler_view *view = NULL;
346       struct pipe_resource *texture;
347
348       memset(&pt, 0, sizeof(pt));
349       pt.target = PIPE_TEXTURE_2D;
350       pt.format = PIPE_FORMAT_B8G8R8A8_UNORM;
351       pt.last_level = 0;
352       pt.width0 = width;
353       pt.height0 = height;
354       pt.depth0 = 1;
355       pt.array_size = 1;
356       pt.bind = PIPE_BIND_SAMPLER_VIEW;
357
358       texture = screen->resource_create(screen, &pt);
359
360       if (texture) {
361          u_sampler_view_default_template(&view_templ, texture, texture->format);
362          view = pipe->create_sampler_view(pipe, texture, &view_templ);
363       }
364       pipe_resource_reference(&texture, NULL);
365       mask->sampler_view = view;
366    }
367
368    vg_context_add_object(ctx, VG_OBJECT_MASK, mask);
369
370    return mask;
371 }
372
373 void mask_layer_destroy(struct vg_mask_layer *layer)
374 {
375    struct vg_context *ctx = vg_current_context();
376
377    vg_context_remove_object(ctx, VG_OBJECT_MASK, layer);
378    pipe_sampler_view_reference(&layer->sampler_view, NULL);
379    FREE(layer);
380 }
381
382 void mask_layer_fill(struct vg_mask_layer *layer,
383                      VGint x, VGint y,
384                      VGint width, VGint height,
385                      VGfloat value)
386 {
387    VGfloat alpha_color[4] = {0, 0, 0, 0};
388
389    alpha_color[3] = value;
390
391    mask_resource_fill(layer->sampler_view->texture,
392                       x, y, width, height, value);
393 }
394
395 void mask_copy(struct vg_mask_layer *layer,
396                VGint sx, VGint sy,
397                VGint dx, VGint dy,
398                VGint width, VGint height)
399 {
400    struct vg_context *ctx = vg_current_context();
401    struct pipe_sampler_view *src = vg_get_surface_mask(ctx);
402    struct pipe_surface *surf, surf_tmpl;
403
404    /* get the destination surface */
405    u_surface_default_template(&surf_tmpl, layer->sampler_view->texture,
406                               PIPE_BIND_RENDER_TARGET);
407    surf = ctx->pipe->create_surface(ctx->pipe, layer->sampler_view->texture,
408                                     &surf_tmpl);
409    if (surf && renderer_copy_begin(ctx->renderer, surf, VG_FALSE, src)) {
410       /* layer should be flipped when used as a texture */
411       sy += height;
412       height = -height;
413
414       renderer_copy(ctx->renderer,
415             dx, dy, width, height,
416             sx, sy, width, height);
417       renderer_copy_end(ctx->renderer);
418    }
419
420    pipe_surface_reference(&surf, NULL);
421 }
422
423 static void mask_layer_render_to(struct vg_mask_layer *layer,
424                                  struct path *path,
425                                  VGbitfield paint_modes)
426 {
427    struct vg_context *ctx = vg_current_context();
428    struct pipe_context *pipe = ctx->pipe;
429    struct pipe_sampler_view *view = vg_get_surface_mask(ctx);
430    struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
431    struct pipe_surface *surf, surf_tmpl;
432    u_surface_default_template(&surf_tmpl, view->texture,
433                               PIPE_BIND_RENDER_TARGET);
434    surf = pipe->create_surface(pipe, view->texture, &surf_tmpl);
435
436    renderer_validate_for_mask_rendering(ctx->renderer, surf, mat);
437
438    if (paint_modes & VG_FILL_PATH) {
439       path_fill(path);
440    }
441
442    if (paint_modes & VG_STROKE_PATH){
443       path_stroke(path);
444    }
445
446    pipe_surface_reference(&surf, NULL);
447 }
448
449 void mask_render_to(struct path *path,
450                     VGbitfield paint_modes,
451                     VGMaskOperation operation)
452 {
453    struct vg_context *ctx = vg_current_context();
454    struct st_framebuffer *stfb = ctx->draw_buffer;
455    struct vg_mask_layer *temp_layer;
456    VGint width, height;
457
458    width = stfb->width;
459    height = stfb->height;
460
461    temp_layer = mask_layer_create(width, height);
462    mask_layer_fill(temp_layer, 0, 0, width, height, 0.0f);
463
464    mask_layer_render_to(temp_layer, path, paint_modes);
465
466    mask_using_layer(temp_layer, operation, 0, 0, width, height);
467
468    mask_layer_destroy(temp_layer);
469 }
470
471 void mask_using_layer(struct vg_mask_layer *layer,
472                       VGMaskOperation operation,
473                       VGint x, VGint y,
474                       VGint width, VGint height)
475 {
476    mask_using_texture(layer->sampler_view, VG_TRUE, operation,
477                       x, y, width, height);
478 }
479
480 VGint mask_layer_width(struct vg_mask_layer *layer)
481 {
482    return layer->width;
483 }
484
485 VGint mask_layer_height(struct vg_mask_layer *layer)
486 {
487    return layer->height;
488 }
489
490
491 #endif
492
493 void mask_using_image(struct vg_image *image,
494                       VGMaskOperation operation,
495                       VGint x, VGint y,
496                       VGint width, VGint height)
497 {
498    mask_using_texture(image->sampler_view, VG_FALSE, operation,
499                       x, y, width, height);
500 }
501
502 void mask_fill(VGint x, VGint y, VGint width, VGint height,
503                VGfloat value)
504 {
505    struct vg_context *ctx = vg_current_context();
506    struct pipe_sampler_view *view = vg_get_surface_mask(ctx);
507
508 #if DEBUG_MASKS
509    debug_printf("mask_fill(%d, %d, %d, %d) with  rgba(%f, %f, %f, %f)\n",
510                 x, y, width, height,
511                 0.0f, 0.0f, 0.0f, value);
512 #endif
513
514    mask_resource_fill(view->texture, x, y, width, height, value);
515 }
516
517 VGint mask_bind_samplers(struct pipe_sampler_state **samplers,
518                          struct pipe_sampler_view **sampler_views)
519 {
520    struct vg_context *ctx = vg_current_context();
521
522    if (ctx->state.vg.masking) {
523       samplers[1] = &ctx->mask.sampler;
524       sampler_views[1] = vg_get_surface_mask(ctx);
525       return 1;
526    } else
527       return 0;
528 }