Merge branch 'gallium-noblocks'
[mesa.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 #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
41 struct vg_mask_layer {
42 struct vg_object base;
43
44 VGint width;
45 VGint height;
46
47 struct pipe_texture *texture;
48 };
49
50 static INLINE struct pipe_surface *
51 alpha_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
61 static INLINE VGboolean
62 intersect_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
105 static 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
163 void 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
195 static 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 */
216 static 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
286 static 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 */
319 static 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
343 static void setup_mask_viewport()
344 {
345 struct vg_context *ctx = vg_current_context();
346 vg_set_viewport(ctx, VEGA_Y0_TOP);
347 }
348
349 static 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
370 static 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
416 static 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->width0, texture->height0,
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
477 struct 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 pt.last_level = 0;
495 pt.width0 = width;
496 pt.height0 = height;
497 pt.depth0 = 1;
498 pt.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
499 pt.compressed = 0;
500
501 mask->texture = screen->texture_create(screen, &pt);
502 }
503
504 vg_context_add_object(ctx, VG_OBJECT_MASK, mask);
505
506 return mask;
507 }
508
509 void mask_layer_destroy(struct vg_mask_layer *layer)
510 {
511 struct vg_context *ctx = vg_current_context();
512
513 vg_context_remove_object(ctx, VG_OBJECT_MASK, layer);
514 pipe_texture_release(&layer->texture);
515 free(layer);
516 }
517
518 void mask_layer_fill(struct vg_mask_layer *layer,
519 VGint x, VGint y,
520 VGint width, VGint height,
521 VGfloat value)
522 {
523 struct vg_context *ctx = vg_current_context();
524 VGfloat alpha_color[4] = {0, 0, 0, 0};
525 struct pipe_surface *surface;
526
527 alpha_color[3] = value;
528
529 surface = ctx->pipe->screen->get_tex_surface(
530 ctx->pipe->screen, layer->texture,
531 0, 0, 0,
532 PIPE_BUFFER_USAGE_GPU_WRITE);
533
534 surface_fill(surface,
535 layer->width, layer->height,
536 x, y, width, height, alpha_color);
537
538 ctx->pipe->screen->tex_surface_release(ctx->pipe->screen, &surface);
539 }
540
541 void mask_copy(struct vg_mask_layer *layer,
542 VGint sx, VGint sy,
543 VGint dx, VGint dy,
544 VGint width, VGint height)
545 {
546 struct vg_context *ctx = vg_current_context();
547 struct st_framebuffer *fb_buffers = ctx->draw_buffer;
548
549 renderer_copy_texture(ctx->renderer,
550 layer->texture,
551 sx, sy,
552 sx + width, sy + height,
553 fb_buffers->alpha_mask,
554 dx, dy,
555 dx + width, dy + height);
556 }
557
558 static void mask_layer_render_to(struct vg_mask_layer *layer,
559 struct path *path,
560 VGbitfield paint_modes)
561 {
562 struct vg_context *ctx = vg_current_context();
563 const VGfloat fill_color[4] = {1.f, 1.f, 1.f, 1.f};
564 struct pipe_screen *screen = ctx->pipe->screen;
565 struct pipe_surface *surface;
566
567 surface = screen->get_tex_surface(screen, layer->texture, 0, 0, 0,
568 PIPE_BUFFER_USAGE_GPU_WRITE);
569
570 cso_save_framebuffer(ctx->cso_context);
571 cso_save_fragment_shader(ctx->cso_context);
572 cso_save_viewport(ctx->cso_context);
573
574 setup_mask_blend();
575 setup_mask_fill(fill_color);
576 setup_mask_framebuffer(surface, layer->width, layer->height);
577 setup_mask_viewport();
578
579 if (paint_modes & VG_FILL_PATH) {
580 struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
581 path_fill(path, mat);
582 }
583
584 if (paint_modes & VG_STROKE_PATH){
585 path_stroke(path);
586 }
587
588
589 /* make sure rendering has completed */
590 ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
591
592 cso_restore_framebuffer(ctx->cso_context);
593 cso_restore_fragment_shader(ctx->cso_context);
594 cso_restore_viewport(ctx->cso_context);
595 ctx->state.dirty |= BLEND_DIRTY;
596
597 screen->tex_surface_release(ctx->pipe->screen, &surface);
598 }
599
600 void mask_render_to(struct path *path,
601 VGbitfield paint_modes,
602 VGMaskOperation operation)
603 {
604 struct vg_context *ctx = vg_current_context();
605 struct st_framebuffer *fb_buffers = ctx->draw_buffer;
606 struct vg_mask_layer *temp_layer;
607 VGint width, height;
608
609 width = fb_buffers->alpha_mask->width0;
610 height = fb_buffers->alpha_mask->width0;
611
612 temp_layer = mask_layer_create(width, height);
613
614 mask_layer_render_to(temp_layer, path, paint_modes);
615
616 mask_using_layer(temp_layer, 0, 0, width, height,
617 operation);
618
619 mask_layer_destroy(temp_layer);
620 }
621
622 void mask_using_layer(struct vg_mask_layer *layer,
623 VGMaskOperation operation,
624 VGint x, VGint y,
625 VGint width, VGint height)
626 {
627 mask_using_texture(layer->texture, operation,
628 x, y, width, height);
629 }
630
631 VGint mask_layer_width(struct vg_mask_layer *layer)
632 {
633 return layer->width;
634 }
635
636 VGint mask_layer_height(struct vg_mask_layer *layer)
637 {
638 return layer->height;
639 }
640
641
642 #endif
643
644 void mask_using_image(struct vg_image *image,
645 VGMaskOperation operation,
646 VGint x, VGint y,
647 VGint width, VGint height)
648 {
649 mask_using_texture(image->texture, operation,
650 x, y, width, height);
651 }
652
653 void mask_fill(VGint x, VGint y, VGint width, VGint height,
654 VGfloat value)
655 {
656 struct vg_context *ctx = vg_current_context();
657 VGfloat alpha_color[4] = {.0f, .0f, .0f, value};
658 struct pipe_surface *surf = alpha_mask_surface(
659 ctx, PIPE_BUFFER_USAGE_GPU_WRITE);
660
661 #if DEBUG_MASKS
662 debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n",
663 x, y, width, height,
664 alpha_color[0], alpha_color[1],
665 alpha_color[2], alpha_color[3]);
666 debug_printf("XXX %f === %f \n",
667 alpha_color[3], value);
668 #endif
669
670 surface_fill(surf, surf->width, surf->height,
671 x, y, width, height, alpha_color);
672
673 pipe_surface_reference(&surf, NULL);
674 }
675
676 VGint mask_bind_samplers(struct pipe_sampler_state **samplers,
677 struct pipe_texture **textures)
678 {
679 struct vg_context *ctx = vg_current_context();
680
681 if (ctx->state.vg.masking) {
682 struct st_framebuffer *fb_buffers = ctx->draw_buffer;
683
684 samplers[1] = &ctx->mask.sampler;
685 textures[1] = fb_buffers->alpha_mask;
686 return 1;
687 } else
688 return 0;
689 }