mask.c revision 544dd4b11f7be76bb00fe29a60eaf2772dcc69ca
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 "pipe/p_inlines.h"
39#include "util/u_memory.h"
40
41struct vg_mask_layer {
42   struct vg_object base;
43
44   VGint width;
45   VGint height;
46
47   struct pipe_texture *texture;
48};
49
50static INLINE struct pipe_surface *
51alpha_mask_surface(struct vg_context *ctx, int usage)
52{
53   struct pipe_screen *screen = ctx->pipe->screen;
54   struct st_framebuffer *stfb = ctx->draw_buffer;
55   return screen->get_tex_surface(screen,
56                                  stfb->alpha_mask,
57                                  0, 0, 0,
58                                  usage);
59}
60
61static INLINE VGboolean
62intersect_rectangles(VGint dwidth, VGint dheight,
63                     VGint swidth, VGint sheight,
64                     VGint tx, VGint ty,
65                     VGint twidth, VGint theight,
66                     VGint *offsets,
67                     VGint *location)
68{
69   if (tx + twidth <= 0 || tx >= dwidth)
70      return VG_FALSE;
71   if (ty + theight <= 0 || ty >= dheight)
72      return VG_FALSE;
73
74   offsets[0] = 0;
75   offsets[1] = 0;
76   location[0] = tx;
77   location[1] = ty;
78
79   if (tx < 0) {
80      offsets[0] -= tx;
81      location[0] = 0;
82
83      location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth));
84      offsets[2] = location[2];
85   } else {
86      offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth ));
87      location[2] = offsets[2];
88   }
89
90   if (ty < 0) {
91      offsets[1] -= ty;
92      location[1] = 0;
93
94      location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight));
95      offsets[3] = location[3];
96   } else {
97      offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight));
98      location[3] = offsets[3];
99   }
100
101   return VG_TRUE;
102}
103
104#if DEBUG_MASKS
105static void read_alpha_mask(void * data, VGint dataStride,
106                            VGImageFormat dataFormat,
107                            VGint sx, VGint sy,
108                            VGint width, VGint height)
109{
110   struct vg_context *ctx = vg_current_context();
111   struct pipe_context *pipe = ctx->pipe;
112   struct pipe_screen *screen = pipe->screen;
113
114   struct st_framebuffer *stfb = ctx->draw_buffer;
115   struct st_renderbuffer *strb = stfb->alpha_mask;
116   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
117
118   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
119   VGfloat *df = (VGfloat*)temp;
120   VGint y = (fb->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 = (fb->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_BUFFER_USAGE_CPU_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 pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
167   VGint *data;
168   int i, j;
169
170   data = malloc(sizeof(int) * fb->width * fb->height);
171   read_alpha_mask(data, fb->width * sizeof(int),
172                   VG_sRGBA_8888,
173                   0, 0, fb->width, fb->height);
174   fprintf(stderr, "/*---------- start */\n");
175   fprintf(stderr, "const int image_width = %d;\n",
176           fb->width);
177   fprintf(stderr, "const int image_height = %d;\n",
178           fb->height);
179   fprintf(stderr, "const int image_data = {\n");
180   for (i = 0; i < fb->height; ++i) {
181      for (j = 0; j < fb->width; ++j) {
182         int rgba = data[i * fb->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
195static void setup_mask_framebuffer(struct pipe_surface *surf,
196                                   VGint surf_width, VGint surf_height)
197{
198   struct vg_context *ctx = vg_current_context();
199   struct pipe_framebuffer_state fb;
200
201   memset(&fb, 0, sizeof(fb));
202   fb.width = surf_width;
203   fb.height = surf_height;
204   fb.nr_cbufs = 1;
205   fb.cbufs[0] = surf;
206   {
207      VGint i;
208      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
209         fb.cbufs[i] = 0;
210   }
211   cso_set_framebuffer(ctx->cso_context, &fb);
212}
213
214
215/* setup shader constants */
216static void setup_mask_operation(VGMaskOperation operation)
217{
218   struct vg_context *ctx = vg_current_context();
219   struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf;
220   const VGint param_bytes = 4 * sizeof(VGfloat);
221   const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f};
222   void *shader = 0;
223
224   /* We always need to get a new buffer, to keep the drivers simple and
225    * avoid gratuitous rendering synchronization.
226    */
227   pipe_buffer_reference(&cbuf->buffer, NULL);
228
229   cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 1,
230                                     PIPE_BUFFER_USAGE_CONSTANT,
231                                     param_bytes);
232   if (cbuf->buffer) {
233      st_no_flush_pipe_buffer_write(ctx, cbuf->buffer,
234                                    0, param_bytes, ones);
235   }
236
237   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
238   switch (operation) {
239   case VG_UNION_MASK: {
240      if (!ctx->mask.union_fs) {
241         ctx->mask.union_fs = shader_create_from_text(ctx->pipe,
242                                                      union_mask_asm,
243                                                      200,
244                                                      PIPE_SHADER_FRAGMENT);
245      }
246      shader = ctx->mask.union_fs->driver;
247   }
248      break;
249   case VG_INTERSECT_MASK: {
250      if (!ctx->mask.intersect_fs) {
251         ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe,
252                                                          intersect_mask_asm,
253                                                          200,
254                                                          PIPE_SHADER_FRAGMENT);
255      }
256      shader = ctx->mask.intersect_fs->driver;
257   }
258      break;
259   case VG_SUBTRACT_MASK: {
260      if (!ctx->mask.subtract_fs) {
261         ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe,
262                                                         subtract_mask_asm,
263                                                         200,
264                                                         PIPE_SHADER_FRAGMENT);
265      }
266      shader = ctx->mask.subtract_fs->driver;
267   }
268      break;
269   case VG_SET_MASK: {
270      if (!ctx->mask.set_fs) {
271         ctx->mask.set_fs = shader_create_from_text(ctx->pipe,
272                                                    set_mask_asm,
273                                                    200,
274                                                    PIPE_SHADER_FRAGMENT);
275      }
276      shader = ctx->mask.set_fs->driver;
277   }
278      break;
279   default:
280         assert(0);
281      break;
282   }
283   cso_set_fragment_shader_handle(ctx->cso_context, shader);
284}
285
286static void setup_mask_samplers(struct pipe_texture *umask)
287{
288   struct vg_context *ctx = vg_current_context();
289   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
290   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
291   struct st_framebuffer *fb_buffers = ctx->draw_buffer;
292   struct pipe_texture *uprev = NULL;
293   struct pipe_sampler_state sampler;
294
295   uprev = fb_buffers->blend_texture;
296   sampler = ctx->mask.sampler;
297   sampler.normalized_coords = 1;
298
299   samplers[0] = NULL;
300   samplers[1] = NULL;
301   samplers[2] = NULL;
302   textures[0] = NULL;
303   textures[1] = NULL;
304   textures[2] = NULL;
305
306   samplers[0] = &sampler;
307   samplers[1] = &ctx->mask.sampler;
308
309   textures[0] = umask;
310   textures[1] = uprev;
311
312   cso_set_samplers(ctx->cso_context, 2,
313                    (const struct pipe_sampler_state **)samplers);
314   cso_set_sampler_textures(ctx->cso_context, 2, textures);
315}
316
317
318/* setup shader constants */
319static void setup_mask_fill(const VGfloat color[4])
320{
321   struct vg_context *ctx = vg_current_context();
322   struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf;
323   const VGint param_bytes = 4 * sizeof(VGfloat);
324
325   /* We always need to get a new buffer, to keep the drivers simple and
326    * avoid gratuitous rendering synchronization.
327    */
328   pipe_buffer_reference(&cbuf->buffer, NULL);
329
330   cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 1,
331                                     PIPE_BUFFER_USAGE_CONSTANT,
332                                     param_bytes);
333   if (cbuf->buffer) {
334      st_no_flush_pipe_buffer_write(ctx, cbuf->buffer, 0, param_bytes, color);
335   }
336
337   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
338   cso_set_fragment_shader_handle(ctx->cso_context,
339                                  shaders_cache_fill(ctx->sc,
340                                                     VEGA_SOLID_FILL_SHADER));
341}
342
343static void setup_mask_viewport()
344{
345   struct vg_context *ctx = vg_current_context();
346   vg_set_viewport(ctx, VEGA_Y0_TOP);
347}
348
349static void setup_mask_blend()
350{
351   struct vg_context *ctx = vg_current_context();
352
353   struct pipe_blend_state blend;
354
355   memset(&blend, 0, sizeof(struct pipe_blend_state));
356   blend.blend_enable = 1;
357   blend.colormask |= PIPE_MASK_R;
358   blend.colormask |= PIPE_MASK_G;
359   blend.colormask |= PIPE_MASK_B;
360   blend.colormask |= PIPE_MASK_A;
361   blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
362   blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
363   blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
364   blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
365
366   cso_set_blend(ctx->cso_context, &blend);
367}
368
369
370static void surface_fill(struct pipe_surface *surf,
371                         int surf_width, int surf_height,
372                         int x, int y, int width, int height,
373                         const VGfloat color[4])
374{
375   struct vg_context *ctx = vg_current_context();
376
377   if (x < 0) {
378      width += x;
379      x = 0;
380   }
381   if (y < 0) {
382      height += y;
383      y = 0;
384   }
385
386   cso_save_framebuffer(ctx->cso_context);
387   cso_save_blend(ctx->cso_context);
388   cso_save_fragment_shader(ctx->cso_context);
389   cso_save_viewport(ctx->cso_context);
390
391   setup_mask_blend();
392   setup_mask_fill(color);
393   setup_mask_framebuffer(surf, surf_width, surf_height);
394   setup_mask_viewport();
395
396   renderer_draw_quad(ctx->renderer, x, y,
397                      x + width, y + height, 0.0f/*depth should be disabled*/);
398
399
400   /* make sure rendering has completed */
401   ctx->pipe->flush(ctx->pipe,
402                    PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME,
403                    NULL);
404
405#if DEBUG_MASKS
406   save_alpha_to_file(0);
407#endif
408
409   cso_restore_blend(ctx->cso_context);
410   cso_restore_framebuffer(ctx->cso_context);
411   cso_restore_fragment_shader(ctx->cso_context);
412   cso_restore_viewport(ctx->cso_context);
413}
414
415
416static void mask_using_texture(struct pipe_texture *texture,
417                               VGMaskOperation operation,
418                               VGint x, VGint y,
419                               VGint width, VGint height)
420{
421   struct vg_context *ctx = vg_current_context();
422   struct pipe_surface *surface =
423      alpha_mask_surface(ctx, PIPE_BUFFER_USAGE_GPU_WRITE);
424   VGint offsets[4], loc[4];
425
426   if (!surface)
427      return;
428   if (!intersect_rectangles(surface->width, surface->height,
429                             texture->width[0], texture->height[0],
430                             x, y, width, height,
431                             offsets, loc))
432      return;
433#if 0
434   debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0],
435                offsets[1], offsets[2], offsets[3]);
436   debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0],
437                loc[1], loc[2], loc[3]);
438#endif
439
440   /* prepare our blend surface */
441   vg_prepare_blend_surface_from_mask(ctx);
442
443   cso_save_samplers(ctx->cso_context);
444   cso_save_sampler_textures(ctx->cso_context);
445   cso_save_framebuffer(ctx->cso_context);
446   cso_save_blend(ctx->cso_context);
447   cso_save_fragment_shader(ctx->cso_context);
448   cso_save_viewport(ctx->cso_context);
449
450   setup_mask_samplers(texture);
451   setup_mask_blend();
452   setup_mask_operation(operation);
453   setup_mask_framebuffer(surface, surface->width, surface->height);
454   setup_mask_viewport();
455
456   /* render the quad to propagate the rendering from stencil */
457   renderer_draw_texture(ctx->renderer, texture,
458                         offsets[0], offsets[1],
459                         offsets[0] + offsets[2], offsets[1] + offsets[3],
460                         loc[0], loc[1], loc[0] + loc[2], loc[1] + loc[3]);
461
462   /* make sure rendering has completed */
463   ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
464   cso_restore_blend(ctx->cso_context);
465   cso_restore_framebuffer(ctx->cso_context);
466   cso_restore_fragment_shader(ctx->cso_context);
467   cso_restore_samplers(ctx->cso_context);
468   cso_restore_sampler_textures(ctx->cso_context);
469   cso_restore_viewport(ctx->cso_context);
470
471   pipe_surface_reference(&surface, NULL);
472}
473
474
475#ifdef OPENVG_VERSION_1_1
476
477struct vg_mask_layer * mask_layer_create(VGint width, VGint height)
478{
479   struct vg_context *ctx = vg_current_context();
480   struct vg_mask_layer *mask = 0;
481
482   mask = CALLOC_STRUCT(vg_mask_layer);
483   vg_init_object(&mask->base, ctx, VG_OBJECT_MASK);
484   mask->width = width;
485   mask->height = height;
486
487   {
488      struct pipe_texture pt;
489      struct pipe_screen *screen = ctx->pipe->screen;
490
491      memset(&pt, 0, sizeof(pt));
492      pt.target = PIPE_TEXTURE_2D;
493      pt.format = PIPE_FORMAT_A8R8G8B8_UNORM;
494      pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &pt.block);
495      pt.last_level = 0;
496      pt.width[0] = width;
497      pt.height[0] = height;
498      pt.depth[0] = 1;
499      pt.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
500      pt.compressed = 0;
501
502      mask->texture = screen->texture_create(screen, &pt);
503   }
504
505   vg_context_add_object(ctx, VG_OBJECT_MASK, mask);
506
507   return mask;
508}
509
510void mask_layer_destroy(struct vg_mask_layer *layer)
511{
512   struct vg_context *ctx = vg_current_context();
513
514   vg_context_remove_object(ctx, VG_OBJECT_MASK, layer);
515   pipe_texture_release(&layer->texture);
516   free(layer);
517}
518
519void mask_layer_fill(struct vg_mask_layer *layer,
520                     VGint x, VGint y,
521                     VGint width, VGint height,
522                     VGfloat value)
523{
524   struct vg_context *ctx = vg_current_context();
525   VGfloat alpha_color[4] = {0, 0, 0, 0};
526   struct pipe_surface *surface;
527
528   alpha_color[3] = value;
529
530   surface = ctx->pipe->screen->get_tex_surface(
531      ctx->pipe->screen, layer->texture,
532      0, 0, 0,
533      PIPE_BUFFER_USAGE_GPU_WRITE);
534
535   surface_fill(surface,
536                layer->width, layer->height,
537                x, y, width, height, alpha_color);
538
539   ctx->pipe->screen->tex_surface_release(ctx->pipe->screen, &surface);
540}
541
542void mask_copy(struct vg_mask_layer *layer,
543               VGint sx, VGint sy,
544               VGint dx, VGint dy,
545               VGint width, VGint height)
546{
547    struct vg_context *ctx = vg_current_context();
548    struct st_framebuffer *fb_buffers = ctx->draw_buffer;
549
550    renderer_copy_texture(ctx->renderer,
551                          layer->texture,
552                          sx, sy,
553                          sx + width, sy + height,
554                          fb_buffers->alpha_mask,
555                          dx, dy,
556                          dx + width, dy + height);
557}
558
559static void mask_layer_render_to(struct vg_mask_layer *layer,
560                                 struct path *path,
561                                 VGbitfield paint_modes)
562{
563   struct vg_context *ctx = vg_current_context();
564   const VGfloat fill_color[4] = {1.f, 1.f, 1.f, 1.f};
565   struct pipe_screen *screen = ctx->pipe->screen;
566   struct pipe_surface *surface;
567
568   surface = screen->get_tex_surface(screen, layer->texture,  0, 0, 0,
569                                     PIPE_BUFFER_USAGE_GPU_WRITE);
570
571   cso_save_framebuffer(ctx->cso_context);
572   cso_save_fragment_shader(ctx->cso_context);
573   cso_save_viewport(ctx->cso_context);
574
575   setup_mask_blend();
576   setup_mask_fill(fill_color);
577   setup_mask_framebuffer(surface, layer->width, layer->height);
578   setup_mask_viewport();
579
580   if (paint_modes & VG_FILL_PATH) {
581      struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
582      path_fill(path, mat);
583   }
584
585   if (paint_modes & VG_STROKE_PATH){
586      path_stroke(path);
587   }
588
589
590   /* make sure rendering has completed */
591   ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
592
593   cso_restore_framebuffer(ctx->cso_context);
594   cso_restore_fragment_shader(ctx->cso_context);
595   cso_restore_viewport(ctx->cso_context);
596   ctx->state.dirty |= BLEND_DIRTY;
597
598   screen->tex_surface_release(ctx->pipe->screen, &surface);
599}
600
601void mask_render_to(struct path *path,
602                    VGbitfield paint_modes,
603                    VGMaskOperation operation)
604{
605   struct vg_context *ctx = vg_current_context();
606   struct st_framebuffer *fb_buffers = ctx->draw_buffer;
607   struct vg_mask_layer *temp_layer;
608   VGint width, height;
609
610   width = fb_buffers->alpha_mask->width[0];
611   height = fb_buffers->alpha_mask->width[0];
612
613   temp_layer = mask_layer_create(width, height);
614
615   mask_layer_render_to(temp_layer, path, paint_modes);
616
617   mask_using_layer(temp_layer, 0, 0, width, height,
618                    operation);
619
620   mask_layer_destroy(temp_layer);
621}
622
623void mask_using_layer(struct vg_mask_layer *layer,
624                      VGMaskOperation operation,
625                      VGint x, VGint y,
626                      VGint width, VGint height)
627{
628   mask_using_texture(layer->texture, operation,
629                      x, y, width, height);
630}
631
632VGint mask_layer_width(struct vg_mask_layer *layer)
633{
634   return layer->width;
635}
636
637VGint mask_layer_height(struct vg_mask_layer *layer)
638{
639   return layer->height;
640}
641
642
643#endif
644
645void mask_using_image(struct vg_image *image,
646                      VGMaskOperation operation,
647                      VGint x, VGint y,
648                      VGint width, VGint height)
649{
650   mask_using_texture(image->texture, operation,
651                      x, y, width, height);
652}
653
654void mask_fill(VGint x, VGint y, VGint width, VGint height,
655               VGfloat value)
656{
657   struct vg_context *ctx = vg_current_context();
658   VGfloat alpha_color[4] = {.0f, .0f, .0f, value};
659   struct pipe_surface *surf = alpha_mask_surface(
660      ctx, PIPE_BUFFER_USAGE_GPU_WRITE);
661
662#if DEBUG_MASKS
663   debug_printf("mask_fill(%d, %d, %d, %d) with  rgba(%f, %f, %f, %f)\n",
664                x, y, width, height,
665                alpha_color[0], alpha_color[1],
666                alpha_color[2], alpha_color[3]);
667   debug_printf("XXX %f  === %f \n",
668                alpha_color[3], value);
669#endif
670
671   surface_fill(surf, surf->width, surf->height,
672                x, y, width, height, alpha_color);
673
674   pipe_surface_reference(&surf, NULL);
675}
676
677VGint mask_bind_samplers(struct pipe_sampler_state **samplers,
678                         struct pipe_texture **textures)
679{
680   struct vg_context *ctx = vg_current_context();
681
682   if (ctx->state.vg.masking) {
683      struct st_framebuffer *fb_buffers = ctx->draw_buffer;
684
685      samplers[1] = &ctx->mask.sampler;
686      textures[1] = fb_buffers->alpha_mask;
687      return 1;
688   } else
689      return 0;
690}
691