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