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