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