mask.c revision e360f91f152615b35857a4d008d0439a3c3285a8
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 fs_consts[12] = { 257 0.0f, 0.0f, 0.0f, 0.0f, /* not used */ 258 0.0f, 0.0f, 0.0f, 0.0f, /* not used */ 259 0.0f, 0.0f, 0.0f, coverage /* color */ 260 }; 261 void *fs; 262 263 if (x < 0) { 264 width += x; 265 x = 0; 266 } 267 if (y < 0) { 268 height += y; 269 y = 0; 270 } 271 272 fs = shaders_cache_fill(ctx->sc, VEGA_SOLID_FILL_SHADER); 273 274 if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, ~0, 275 NULL, NULL, 0, fs, (const void *) fs_consts, sizeof(fs_consts))) { 276 renderer_filter(ctx->renderer, x, y, width, height, 0, 0, 0, 0); 277 renderer_filter_end(ctx->renderer); 278 } 279 280#if DEBUG_MASKS 281 save_alpha_to_file(0); 282#endif 283} 284 285 286static void mask_using_texture(struct pipe_sampler_view *sampler_view, 287 VGboolean is_layer, 288 VGMaskOperation operation, 289 VGint x, VGint y, 290 VGint width, VGint height) 291{ 292 struct vg_context *ctx = vg_current_context(); 293 struct pipe_resource *dst = ctx->draw_buffer->alpha_mask_view->texture; 294 struct pipe_resource *texture = sampler_view->texture; 295 const struct pipe_sampler_state *samplers[2]; 296 struct pipe_sampler_view *views[2]; 297 struct pipe_sampler_state sampler; 298 VGint offsets[4], loc[4]; 299 const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f}; 300 void *fs; 301 302 if (!intersect_rectangles(dst->width0, dst->height0, 303 texture->width0, texture->height0, 304 x, y, width, height, 305 offsets, loc)) 306 return; 307#if 0 308 debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0], 309 offsets[1], offsets[2], offsets[3]); 310 debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0], 311 loc[1], loc[2], loc[3]); 312#endif 313 314 sampler = ctx->mask.sampler; 315 sampler.normalized_coords = 1; 316 samplers[0] = &sampler; 317 views[0] = sampler_view; 318 319 /* prepare our blend surface */ 320 vg_prepare_blend_surface_from_mask(ctx); 321 samplers[1] = &ctx->mask.sampler; 322 views[1] = ctx->draw_buffer->blend_texture_view; 323 324 fs = setup_mask_operation(operation); 325 326 if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, 327 ~0, samplers, views, 2, fs, (const void *) ones, sizeof(ones))) { 328 /* layer should be flipped when used as a texture */ 329 if (is_layer) { 330 offsets[1] += offsets[3]; 331 offsets[3] = -offsets[3]; 332 } 333 renderer_filter(ctx->renderer, 334 loc[0], loc[1], loc[2], loc[3], 335 offsets[0], offsets[1], offsets[2], offsets[3]); 336 renderer_filter_end(ctx->renderer); 337 } 338} 339 340 341#ifdef OPENVG_VERSION_1_1 342 343struct vg_mask_layer * mask_layer_create(VGint width, VGint height) 344{ 345 struct vg_context *ctx = vg_current_context(); 346 struct vg_mask_layer *mask = 0; 347 348 mask = CALLOC_STRUCT(vg_mask_layer); 349 vg_init_object(&mask->base, ctx, VG_OBJECT_MASK); 350 mask->width = width; 351 mask->height = height; 352 353 { 354 struct pipe_resource pt; 355 struct pipe_context *pipe = ctx->pipe; 356 struct pipe_screen *screen = ctx->pipe->screen; 357 struct pipe_sampler_view view_templ; 358 struct pipe_sampler_view *view = NULL; 359 struct pipe_resource *texture; 360 361 memset(&pt, 0, sizeof(pt)); 362 pt.target = PIPE_TEXTURE_2D; 363 pt.format = PIPE_FORMAT_B8G8R8A8_UNORM; 364 pt.last_level = 0; 365 pt.width0 = width; 366 pt.height0 = height; 367 pt.depth0 = 1; 368 pt.bind = PIPE_BIND_SAMPLER_VIEW; 369 370 texture = screen->resource_create(screen, &pt); 371 372 if (texture) { 373 u_sampler_view_default_template(&view_templ, texture, texture->format); 374 view = pipe->create_sampler_view(pipe, texture, &view_templ); 375 } 376 pipe_resource_reference(&texture, NULL); 377 mask->sampler_view = view; 378 } 379 380 vg_context_add_object(ctx, VG_OBJECT_MASK, mask); 381 382 return mask; 383} 384 385void mask_layer_destroy(struct vg_mask_layer *layer) 386{ 387 struct vg_context *ctx = vg_current_context(); 388 389 vg_context_remove_object(ctx, VG_OBJECT_MASK, layer); 390 pipe_sampler_view_reference(&layer->sampler_view, NULL); 391 FREE(layer); 392} 393 394void mask_layer_fill(struct vg_mask_layer *layer, 395 VGint x, VGint y, 396 VGint width, VGint height, 397 VGfloat value) 398{ 399 VGfloat alpha_color[4] = {0, 0, 0, 0}; 400 401 alpha_color[3] = value; 402 403 mask_resource_fill(layer->sampler_view->texture, 404 x, y, width, height, value); 405} 406 407void mask_copy(struct vg_mask_layer *layer, 408 VGint sx, VGint sy, 409 VGint dx, VGint dy, 410 VGint width, VGint height) 411{ 412 struct vg_context *ctx = vg_current_context(); 413 struct pipe_sampler_view *src = ctx->draw_buffer->alpha_mask_view; 414 struct pipe_surface *surf; 415 416 /* get the destination surface */ 417 surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen, 418 layer->sampler_view->texture, 0, 0, 0, PIPE_BIND_RENDER_TARGET); 419 if (surf && renderer_copy_begin(ctx->renderer, surf, VG_FALSE, src)) { 420 /* layer should be flipped when used as a texture */ 421 sy += height; 422 height = -height; 423 424 renderer_copy(ctx->renderer, 425 dx, dy, width, height, 426 sx, sy, width, height); 427 renderer_copy_end(ctx->renderer); 428 } 429 430 pipe_surface_reference(&surf, NULL); 431} 432 433static void mask_layer_render_to(struct vg_mask_layer *layer, 434 struct path *path, 435 VGbitfield paint_modes) 436{ 437 struct vg_context *ctx = vg_current_context(); 438 struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; 439 struct pipe_surface *surf; 440 441 surf = alpha_mask_surface(ctx, PIPE_BIND_RENDER_TARGET); 442 443 renderer_validate_for_mask_rendering(ctx->renderer, surf); 444 445 if (paint_modes & VG_FILL_PATH) { 446 path_fill(path, mat); 447 } 448 449 if (paint_modes & VG_STROKE_PATH){ 450 path_stroke(path, mat); 451 } 452} 453 454void mask_render_to(struct path *path, 455 VGbitfield paint_modes, 456 VGMaskOperation operation) 457{ 458 struct vg_context *ctx = vg_current_context(); 459 struct st_framebuffer *fb_buffers = ctx->draw_buffer; 460 struct vg_mask_layer *temp_layer; 461 VGint width, height; 462 463 width = fb_buffers->alpha_mask_view->texture->width0; 464 height = fb_buffers->alpha_mask_view->texture->height0; 465 466 temp_layer = mask_layer_create(width, height); 467 mask_layer_fill(temp_layer, 0, 0, width, height, 0.0f); 468 469 mask_layer_render_to(temp_layer, path, paint_modes); 470 471 mask_using_layer(temp_layer, operation, 0, 0, width, height); 472 473 mask_layer_destroy(temp_layer); 474} 475 476void mask_using_layer(struct vg_mask_layer *layer, 477 VGMaskOperation operation, 478 VGint x, VGint y, 479 VGint width, VGint height) 480{ 481 mask_using_texture(layer->sampler_view, VG_TRUE, operation, 482 x, y, width, height); 483} 484 485VGint mask_layer_width(struct vg_mask_layer *layer) 486{ 487 return layer->width; 488} 489 490VGint mask_layer_height(struct vg_mask_layer *layer) 491{ 492 return layer->height; 493} 494 495 496#endif 497 498void mask_using_image(struct vg_image *image, 499 VGMaskOperation operation, 500 VGint x, VGint y, 501 VGint width, VGint height) 502{ 503 mask_using_texture(image->sampler_view, VG_FALSE, operation, 504 x, y, width, height); 505} 506 507void mask_fill(VGint x, VGint y, VGint width, VGint height, 508 VGfloat value) 509{ 510 struct vg_context *ctx = vg_current_context(); 511 512#if DEBUG_MASKS 513 debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n", 514 x, y, width, height, 515 0.0f, 0.0f, 0.0f, value); 516#endif 517 518 mask_resource_fill(ctx->draw_buffer->alpha_mask_view->texture, 519 x, y, width, height, value); 520} 521 522VGint mask_bind_samplers(struct pipe_sampler_state **samplers, 523 struct pipe_sampler_view **sampler_views) 524{ 525 struct vg_context *ctx = vg_current_context(); 526 527 if (ctx->state.vg.masking) { 528 struct st_framebuffer *fb_buffers = ctx->draw_buffer; 529 530 samplers[1] = &ctx->mask.sampler; 531 sampler_views[1] = fb_buffers->alpha_mask_view; 532 return 1; 533 } else 534 return 0; 535} 536