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