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