Home | History | Annotate | Download | only in vega
      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