mask.c revision c91c38601234dc67fa356160cbe3bd389cac083a
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 VGboolean 52intersect_rectangles(VGint dwidth, VGint dheight, 53 VGint swidth, VGint sheight, 54 VGint tx, VGint ty, 55 VGint twidth, VGint theight, 56 VGint *offsets, 57 VGint *location) 58{ 59 if (tx + twidth <= 0 || tx >= dwidth) 60 return VG_FALSE; 61 if (ty + theight <= 0 || ty >= dheight) 62 return VG_FALSE; 63 64 offsets[0] = 0; 65 offsets[1] = 0; 66 location[0] = tx; 67 location[1] = ty; 68 69 if (tx < 0) { 70 offsets[0] -= tx; 71 location[0] = 0; 72 73 location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth)); 74 offsets[2] = location[2]; 75 } else { 76 offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth )); 77 location[2] = offsets[2]; 78 } 79 80 if (ty < 0) { 81 offsets[1] -= ty; 82 location[1] = 0; 83 84 location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight)); 85 offsets[3] = location[3]; 86 } else { 87 offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight)); 88 location[3] = offsets[3]; 89 } 90 91 return VG_TRUE; 92} 93 94#if DEBUG_MASKS 95static void read_alpha_mask(void * data, VGint dataStride, 96 VGImageFormat dataFormat, 97 VGint sx, VGint sy, 98 VGint width, VGint height) 99{ 100 struct vg_context *ctx = vg_current_context(); 101 struct pipe_context *pipe = ctx->pipe; 102 struct pipe_screen *screen = pipe->screen; 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 = screen->get_tex_surface(screen, 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.bind = PIPE_BIND_SAMPLER_VIEW; 358 359 texture = screen->resource_create(screen, &pt); 360 361 if (texture) { 362 u_sampler_view_default_template(&view_templ, texture, texture->format); 363 view = pipe->create_sampler_view(pipe, texture, &view_templ); 364 } 365 pipe_resource_reference(&texture, NULL); 366 mask->sampler_view = view; 367 } 368 369 vg_context_add_object(ctx, VG_OBJECT_MASK, mask); 370 371 return mask; 372} 373 374void mask_layer_destroy(struct vg_mask_layer *layer) 375{ 376 struct vg_context *ctx = vg_current_context(); 377 378 vg_context_remove_object(ctx, VG_OBJECT_MASK, layer); 379 pipe_sampler_view_reference(&layer->sampler_view, NULL); 380 FREE(layer); 381} 382 383void mask_layer_fill(struct vg_mask_layer *layer, 384 VGint x, VGint y, 385 VGint width, VGint height, 386 VGfloat value) 387{ 388 VGfloat alpha_color[4] = {0, 0, 0, 0}; 389 390 alpha_color[3] = value; 391 392 mask_resource_fill(layer->sampler_view->texture, 393 x, y, width, height, value); 394} 395 396void mask_copy(struct vg_mask_layer *layer, 397 VGint sx, VGint sy, 398 VGint dx, VGint dy, 399 VGint width, VGint height) 400{ 401 struct vg_context *ctx = vg_current_context(); 402 struct pipe_sampler_view *src = vg_get_surface_mask(ctx); 403 struct pipe_surface *surf; 404 405 /* get the destination surface */ 406 surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen, 407 layer->sampler_view->texture, 0, 0, 0, PIPE_BIND_RENDER_TARGET); 408 if (surf && renderer_copy_begin(ctx->renderer, surf, VG_FALSE, src)) { 409 /* layer should be flipped when used as a texture */ 410 sy += height; 411 height = -height; 412 413 renderer_copy(ctx->renderer, 414 dx, dy, width, height, 415 sx, sy, width, height); 416 renderer_copy_end(ctx->renderer); 417 } 418 419 pipe_surface_reference(&surf, NULL); 420} 421 422static void mask_layer_render_to(struct vg_mask_layer *layer, 423 struct path *path, 424 VGbitfield paint_modes) 425{ 426 struct vg_context *ctx = vg_current_context(); 427 struct pipe_screen *screen = ctx->pipe->screen; 428 struct pipe_sampler_view *view = vg_get_surface_mask(ctx); 429 struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; 430 struct pipe_surface *surf; 431 432 surf = screen->get_tex_surface(screen, view->texture, 433 0, 0, 0, PIPE_BIND_RENDER_TARGET); 434 435 renderer_validate_for_mask_rendering(ctx->renderer, surf); 436 437 if (paint_modes & VG_FILL_PATH) { 438 path_fill(path, mat); 439 } 440 441 if (paint_modes & VG_STROKE_PATH){ 442 path_stroke(path, mat); 443 } 444 445 pipe_surface_reference(&surf, NULL); 446} 447 448void mask_render_to(struct path *path, 449 VGbitfield paint_modes, 450 VGMaskOperation operation) 451{ 452 struct vg_context *ctx = vg_current_context(); 453 struct st_framebuffer *stfb = ctx->draw_buffer; 454 struct vg_mask_layer *temp_layer; 455 VGint width, height; 456 457 width = stfb->width; 458 height = stfb->height; 459 460 temp_layer = mask_layer_create(width, height); 461 mask_layer_fill(temp_layer, 0, 0, width, height, 0.0f); 462 463 mask_layer_render_to(temp_layer, path, paint_modes); 464 465 mask_using_layer(temp_layer, operation, 0, 0, width, height); 466 467 mask_layer_destroy(temp_layer); 468} 469 470void mask_using_layer(struct vg_mask_layer *layer, 471 VGMaskOperation operation, 472 VGint x, VGint y, 473 VGint width, VGint height) 474{ 475 mask_using_texture(layer->sampler_view, VG_TRUE, operation, 476 x, y, width, height); 477} 478 479VGint mask_layer_width(struct vg_mask_layer *layer) 480{ 481 return layer->width; 482} 483 484VGint mask_layer_height(struct vg_mask_layer *layer) 485{ 486 return layer->height; 487} 488 489 490#endif 491 492void mask_using_image(struct vg_image *image, 493 VGMaskOperation operation, 494 VGint x, VGint y, 495 VGint width, VGint height) 496{ 497 mask_using_texture(image->sampler_view, VG_FALSE, operation, 498 x, y, width, height); 499} 500 501void mask_fill(VGint x, VGint y, VGint width, VGint height, 502 VGfloat value) 503{ 504 struct vg_context *ctx = vg_current_context(); 505 struct pipe_sampler_view *view = vg_get_surface_mask(ctx); 506 507#if DEBUG_MASKS 508 debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n", 509 x, y, width, height, 510 0.0f, 0.0f, 0.0f, value); 511#endif 512 513 mask_resource_fill(view->texture, x, y, width, height, value); 514} 515 516VGint mask_bind_samplers(struct pipe_sampler_state **samplers, 517 struct pipe_sampler_view **sampler_views) 518{ 519 struct vg_context *ctx = vg_current_context(); 520 521 if (ctx->state.vg.masking) { 522 samplers[1] = &ctx->mask.sampler; 523 sampler_views[1] = vg_get_surface_mask(ctx); 524 return 1; 525 } else 526 return 0; 527} 528