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