mask.c revision a84a1e344f544ec4da61809d4f09853a94d93e07
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_surface.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 VGboolean 53intersect_rectangles(VGint dwidth, VGint dheight, 54 VGint swidth, VGint sheight, 55 VGint tx, VGint ty, 56 VGint twidth, VGint theight, 57 VGint *offsets, 58 VGint *location) 59{ 60 if (tx + twidth <= 0 || tx >= dwidth) 61 return VG_FALSE; 62 if (ty + theight <= 0 || ty >= dheight) 63 return VG_FALSE; 64 65 offsets[0] = 0; 66 offsets[1] = 0; 67 location[0] = tx; 68 location[1] = ty; 69 70 if (tx < 0) { 71 offsets[0] -= tx; 72 location[0] = 0; 73 74 location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth)); 75 offsets[2] = location[2]; 76 } else { 77 offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth )); 78 location[2] = offsets[2]; 79 } 80 81 if (ty < 0) { 82 offsets[1] -= ty; 83 location[1] = 0; 84 85 location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight)); 86 offsets[3] = location[3]; 87 } else { 88 offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight)); 89 location[3] = offsets[3]; 90 } 91 92 return VG_TRUE; 93} 94 95#if DEBUG_MASKS 96static void read_alpha_mask(void * data, VGint dataStride, 97 VGImageFormat dataFormat, 98 VGint sx, VGint sy, 99 VGint width, VGint height) 100{ 101 struct vg_context *ctx = vg_current_context(); 102 struct pipe_context *pipe = ctx->pipe; 103 104 struct st_framebuffer *stfb = ctx->draw_buffer; 105 struct st_renderbuffer *strb = stfb->alpha_mask; 106 107 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; 108 VGfloat *df = (VGfloat*)temp; 109 VGint y = (stfb->height - sy) - 1, yStep = -1; 110 VGint i; 111 VGubyte *dst = (VGubyte *)data; 112 VGint xoffset = 0, yoffset = 0; 113 114 /* make sure rendering has completed */ 115 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 116 if (sx < 0) { 117 xoffset = -sx; 118 xoffset *= _vega_size_for_format(dataFormat); 119 width += sx; 120 sx = 0; 121 } 122 if (sy < 0) { 123 yoffset = -sy; 124 height += sy; 125 sy = 0; 126 y = (stfb->height - sy) - 1; 127 yoffset *= dataStride; 128 } 129 130 { 131 struct pipe_surface *surf; 132 133 surf = pipe->create_surface(pipe, strb->texture, 0, 0, 0, 134 PIPE_BIND_TRANSFER_READ); 135 136 /* Do a row at a time to flip image data vertically */ 137 for (i = 0; i < height; i++) { 138#if 0 139 debug_printf("%d-%d == %d\n", sy, height, y); 140#endif 141 pipe_get_tile_rgba(surf, sx, y, width, 1, df); 142 y += yStep; 143 _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, 144 dst + yoffset + xoffset); 145 dst += dataStride; 146 } 147 148 pipe_surface_reference(&surf, NULL); 149 } 150} 151 152void save_alpha_to_file(const char *filename) 153{ 154 struct vg_context *ctx = vg_current_context(); 155 struct st_framebuffer *stfb = ctx->draw_buffer; 156 VGint *data; 157 int i, j; 158 159 data = malloc(sizeof(int) * stfb->width * stfb->height); 160 read_alpha_mask(data, stfb->width * sizeof(int), 161 VG_sRGBA_8888, 162 0, 0, stfb->width, stfb->height); 163 fprintf(stderr, "/*---------- start */\n"); 164 fprintf(stderr, "const int image_width = %d;\n", 165 stfb->width); 166 fprintf(stderr, "const int image_height = %d;\n", 167 stfb->height); 168 fprintf(stderr, "const int image_data = {\n"); 169 for (i = 0; i < stfb->height; ++i) { 170 for (j = 0; j < stfb->width; ++j) { 171 int rgba = data[i * stfb->height + j]; 172 int argb = 0; 173 argb = (rgba >> 8); 174 argb |= ((rgba & 0xff) << 24); 175 fprintf(stderr, "0x%x, ", argb); 176 } 177 fprintf(stderr, "\n"); 178 } 179 fprintf(stderr, "};\n"); 180 fprintf(stderr, "/*---------- end */\n"); 181} 182#endif 183 184/* setup mask shader */ 185static void *setup_mask_operation(VGMaskOperation operation) 186{ 187 struct vg_context *ctx = vg_current_context(); 188 void *shader = 0; 189 190 switch (operation) { 191 case VG_UNION_MASK: { 192 if (!ctx->mask.union_fs) { 193 ctx->mask.union_fs = shader_create_from_text(ctx->pipe, 194 union_mask_asm, 195 200, 196 PIPE_SHADER_FRAGMENT); 197 } 198 shader = ctx->mask.union_fs->driver; 199 } 200 break; 201 case VG_INTERSECT_MASK: { 202 if (!ctx->mask.intersect_fs) { 203 ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe, 204 intersect_mask_asm, 205 200, 206 PIPE_SHADER_FRAGMENT); 207 } 208 shader = ctx->mask.intersect_fs->driver; 209 } 210 break; 211 case VG_SUBTRACT_MASK: { 212 if (!ctx->mask.subtract_fs) { 213 ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe, 214 subtract_mask_asm, 215 200, 216 PIPE_SHADER_FRAGMENT); 217 } 218 shader = ctx->mask.subtract_fs->driver; 219 } 220 break; 221 case VG_SET_MASK: { 222 if (!ctx->mask.set_fs) { 223 ctx->mask.set_fs = shader_create_from_text(ctx->pipe, 224 set_mask_asm, 225 200, 226 PIPE_SHADER_FRAGMENT); 227 } 228 shader = ctx->mask.set_fs->driver; 229 } 230 break; 231 default: 232 assert(0); 233 break; 234 } 235 236 return shader; 237} 238 239static void mask_resource_fill(struct pipe_resource *dst, 240 int x, int y, int width, int height, 241 VGfloat coverage) 242{ 243 struct vg_context *ctx = vg_current_context(); 244 VGfloat fs_consts[12] = { 245 0.0f, 0.0f, 0.0f, 0.0f, /* not used */ 246 0.0f, 0.0f, 0.0f, 0.0f, /* not used */ 247 0.0f, 0.0f, 0.0f, coverage /* color */ 248 }; 249 void *fs; 250 251 if (x < 0) { 252 width += x; 253 x = 0; 254 } 255 if (y < 0) { 256 height += y; 257 y = 0; 258 } 259 260 fs = shaders_cache_fill(ctx->sc, VEGA_SOLID_FILL_SHADER); 261 262 if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, ~0, 263 NULL, NULL, 0, fs, (const void *) fs_consts, sizeof(fs_consts))) { 264 renderer_filter(ctx->renderer, x, y, width, height, 0, 0, 0, 0); 265 renderer_filter_end(ctx->renderer); 266 } 267 268#if DEBUG_MASKS 269 save_alpha_to_file(0); 270#endif 271} 272 273 274static void mask_using_texture(struct pipe_sampler_view *sampler_view, 275 VGboolean is_layer, 276 VGMaskOperation operation, 277 VGint x, VGint y, 278 VGint width, VGint height) 279{ 280 struct vg_context *ctx = vg_current_context(); 281 struct pipe_sampler_view *dst_view = vg_get_surface_mask(ctx); 282 struct pipe_resource *dst = dst_view->texture; 283 struct pipe_resource *texture = sampler_view->texture; 284 const struct pipe_sampler_state *samplers[2]; 285 struct pipe_sampler_view *views[2]; 286 struct pipe_sampler_state sampler; 287 VGint offsets[4], loc[4]; 288 const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f}; 289 void *fs; 290 291 if (!intersect_rectangles(dst->width0, dst->height0, 292 texture->width0, texture->height0, 293 x, y, width, height, 294 offsets, loc)) 295 return; 296#if 0 297 debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0], 298 offsets[1], offsets[2], offsets[3]); 299 debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0], 300 loc[1], loc[2], loc[3]); 301#endif 302 303 304 sampler = ctx->mask.sampler; 305 sampler.normalized_coords = 1; 306 samplers[0] = &sampler; 307 views[0] = sampler_view; 308 309 /* prepare our blend surface */ 310 samplers[1] = &ctx->mask.sampler; 311 views[1] = vg_prepare_blend_surface_from_mask(ctx); 312 313 fs = setup_mask_operation(operation); 314 315 if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, 316 ~0, samplers, views, 2, fs, (const void *) ones, sizeof(ones))) { 317 /* layer should be flipped when used as a texture */ 318 if (is_layer) { 319 offsets[1] += offsets[3]; 320 offsets[3] = -offsets[3]; 321 } 322 renderer_filter(ctx->renderer, 323 loc[0], loc[1], loc[2], loc[3], 324 offsets[0], offsets[1], offsets[2], offsets[3]); 325 renderer_filter_end(ctx->renderer); 326 } 327} 328 329 330#ifdef OPENVG_VERSION_1_1 331 332struct vg_mask_layer * mask_layer_create(VGint width, VGint height) 333{ 334 struct vg_context *ctx = vg_current_context(); 335 struct vg_mask_layer *mask = 0; 336 337 mask = CALLOC_STRUCT(vg_mask_layer); 338 vg_init_object(&mask->base, ctx, VG_OBJECT_MASK); 339 mask->width = width; 340 mask->height = height; 341 342 { 343 struct pipe_resource pt; 344 struct pipe_context *pipe = ctx->pipe; 345 struct pipe_screen *screen = ctx->pipe->screen; 346 struct pipe_sampler_view view_templ; 347 struct pipe_sampler_view *view = NULL; 348 struct pipe_resource *texture; 349 350 memset(&pt, 0, sizeof(pt)); 351 pt.target = PIPE_TEXTURE_2D; 352 pt.format = PIPE_FORMAT_B8G8R8A8_UNORM; 353 pt.last_level = 0; 354 pt.width0 = width; 355 pt.height0 = height; 356 pt.depth0 = 1; 357 pt.array_size = 1; 358 pt.bind = PIPE_BIND_SAMPLER_VIEW; 359 360 texture = screen->resource_create(screen, &pt); 361 362 if (texture) { 363 u_sampler_view_default_template(&view_templ, texture, texture->format); 364 view = pipe->create_sampler_view(pipe, texture, &view_templ); 365 } 366 pipe_resource_reference(&texture, NULL); 367 mask->sampler_view = view; 368 } 369 370 vg_context_add_object(ctx, VG_OBJECT_MASK, mask); 371 372 return mask; 373} 374 375void mask_layer_destroy(struct vg_mask_layer *layer) 376{ 377 struct vg_context *ctx = vg_current_context(); 378 379 vg_context_remove_object(ctx, VG_OBJECT_MASK, layer); 380 pipe_sampler_view_reference(&layer->sampler_view, NULL); 381 FREE(layer); 382} 383 384void mask_layer_fill(struct vg_mask_layer *layer, 385 VGint x, VGint y, 386 VGint width, VGint height, 387 VGfloat value) 388{ 389 VGfloat alpha_color[4] = {0, 0, 0, 0}; 390 391 alpha_color[3] = value; 392 393 mask_resource_fill(layer->sampler_view->texture, 394 x, y, width, height, value); 395} 396 397void mask_copy(struct vg_mask_layer *layer, 398 VGint sx, VGint sy, 399 VGint dx, VGint dy, 400 VGint width, VGint height) 401{ 402 struct vg_context *ctx = vg_current_context(); 403 struct pipe_sampler_view *src = vg_get_surface_mask(ctx); 404 struct pipe_surface *surf, surf_tmpl; 405 406 /* get the destination surface */ 407 u_surface_default_template(&surf_tmpl, layer->sampler_view->texture, 408 PIPE_BIND_RENDER_TARGET); 409 surf = ctx->pipe->create_surface(ctx->pipe, layer->sampler_view->texture, 410 &surf_tmpl); 411 if (surf && renderer_copy_begin(ctx->renderer, surf, VG_FALSE, src)) { 412 /* layer should be flipped when used as a texture */ 413 sy += height; 414 height = -height; 415 416 renderer_copy(ctx->renderer, 417 dx, dy, width, height, 418 sx, sy, width, height); 419 renderer_copy_end(ctx->renderer); 420 } 421 422 pipe_surface_reference(&surf, NULL); 423} 424 425static void mask_layer_render_to(struct vg_mask_layer *layer, 426 struct path *path, 427 VGbitfield paint_modes) 428{ 429 struct vg_context *ctx = vg_current_context(); 430 struct pipe_context *pipe = ctx->pipe; 431 struct pipe_sampler_view *view = vg_get_surface_mask(ctx); 432 struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; 433 struct pipe_surface *surf, surf_tmpl; 434 u_surface_default_template(&surf_tmpl, view->texture, 435 PIPE_BIND_RENDER_TARGET); 436 surf = pipe->create_surface(pipe, view->texture, &surf_tmpl); 437 438 renderer_validate_for_mask_rendering(ctx->renderer, surf, mat); 439 440 if (paint_modes & VG_FILL_PATH) { 441 path_fill(path); 442 } 443 444 if (paint_modes & VG_STROKE_PATH){ 445 path_stroke(path); 446 } 447 448 pipe_surface_reference(&surf, NULL); 449} 450 451void mask_render_to(struct path *path, 452 VGbitfield paint_modes, 453 VGMaskOperation operation) 454{ 455 struct vg_context *ctx = vg_current_context(); 456 struct st_framebuffer *stfb = ctx->draw_buffer; 457 struct vg_mask_layer *temp_layer; 458 VGint width, height; 459 460 width = stfb->width; 461 height = stfb->height; 462 463 temp_layer = mask_layer_create(width, height); 464 mask_layer_fill(temp_layer, 0, 0, width, height, 0.0f); 465 466 mask_layer_render_to(temp_layer, path, paint_modes); 467 468 mask_using_layer(temp_layer, operation, 0, 0, width, height); 469 470 mask_layer_destroy(temp_layer); 471} 472 473void mask_using_layer(struct vg_mask_layer *layer, 474 VGMaskOperation operation, 475 VGint x, VGint y, 476 VGint width, VGint height) 477{ 478 mask_using_texture(layer->sampler_view, VG_TRUE, operation, 479 x, y, width, height); 480} 481 482VGint mask_layer_width(struct vg_mask_layer *layer) 483{ 484 return layer->width; 485} 486 487VGint mask_layer_height(struct vg_mask_layer *layer) 488{ 489 return layer->height; 490} 491 492 493#endif 494 495void mask_using_image(struct vg_image *image, 496 VGMaskOperation operation, 497 VGint x, VGint y, 498 VGint width, VGint height) 499{ 500 mask_using_texture(image->sampler_view, VG_FALSE, operation, 501 x, y, width, height); 502} 503 504void mask_fill(VGint x, VGint y, VGint width, VGint height, 505 VGfloat value) 506{ 507 struct vg_context *ctx = vg_current_context(); 508 struct pipe_sampler_view *view = vg_get_surface_mask(ctx); 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(view->texture, x, y, width, height, value); 517} 518 519VGint mask_bind_samplers(struct pipe_sampler_state **samplers, 520 struct pipe_sampler_view **sampler_views) 521{ 522 struct vg_context *ctx = vg_current_context(); 523 524 if (ctx->state.vg.masking) { 525 samplers[1] = &ctx->mask.sampler; 526 sampler_views[1] = vg_get_surface_mask(ctx); 527 return 1; 528 } else 529 return 0; 530} 531