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