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 "vg_context.h"
     28 
     29 #include "paint.h"
     30 #include "renderer.h"
     31 #include "shaders_cache.h"
     32 #include "shader.h"
     33 #include "vg_manager.h"
     34 #include "api.h"
     35 #include "mask.h"
     36 #include "handle.h"
     37 
     38 #include "pipe/p_context.h"
     39 #include "util/u_inlines.h"
     40 
     41 #include "cso_cache/cso_context.h"
     42 
     43 #include "util/u_memory.h"
     44 #include "util/u_blit.h"
     45 #include "util/u_sampler.h"
     46 #include "util/u_surface.h"
     47 #include "util/u_format.h"
     48 
     49 struct vg_context *_vg_context = 0;
     50 
     51 struct vg_context * vg_current_context(void)
     52 {
     53    return _vg_context;
     54 }
     55 
     56 /**
     57  * A depth/stencil rb will be needed regardless of what the visual says.
     58  */
     59 static boolean
     60 choose_depth_stencil_format(struct vg_context *ctx)
     61 {
     62    struct pipe_screen *screen = ctx->pipe->screen;
     63    enum pipe_format formats[] = {
     64       PIPE_FORMAT_Z24_UNORM_S8_UINT,
     65       PIPE_FORMAT_S8_UINT_Z24_UNORM,
     66       PIPE_FORMAT_NONE
     67    };
     68    enum pipe_format *fmt;
     69 
     70    for (fmt = formats; *fmt != PIPE_FORMAT_NONE; fmt++) {
     71       if (screen->is_format_supported(screen, *fmt,
     72                PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL))
     73          break;
     74    }
     75 
     76    ctx->ds_format = *fmt;
     77 
     78    return (ctx->ds_format != PIPE_FORMAT_NONE);
     79 }
     80 
     81 void vg_set_current_context(struct vg_context *ctx)
     82 {
     83    _vg_context = ctx;
     84    api_make_dispatch_current((ctx) ? ctx->dispatch : NULL);
     85 }
     86 
     87 struct vg_context * vg_create_context(struct pipe_context *pipe,
     88                                       const void *visual,
     89                                       struct vg_context *share)
     90 {
     91    struct vg_context *ctx;
     92 
     93    ctx = CALLOC_STRUCT(vg_context);
     94 
     95    ctx->pipe = pipe;
     96    if (!choose_depth_stencil_format(ctx)) {
     97       FREE(ctx);
     98       return NULL;
     99    }
    100 
    101    ctx->dispatch = api_create_dispatch();
    102 
    103    vg_init_state(&ctx->state.vg);
    104    ctx->state.dirty = ALL_DIRTY;
    105 
    106    ctx->cso_context = cso_create_context(pipe);
    107 
    108    ctx->default_paint = paint_create(ctx);
    109    ctx->state.vg.stroke_paint = ctx->default_paint;
    110    ctx->state.vg.fill_paint = ctx->default_paint;
    111 
    112 
    113    ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    114    ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    115    ctx->mask.sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    116    ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    117    ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
    118    ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    119    ctx->mask.sampler.normalized_coords = 0;
    120 
    121    ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    122    ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    123    ctx->blend_sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    124    ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    125    ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
    126    ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    127    ctx->blend_sampler.normalized_coords = 0;
    128 
    129    vg_set_error(ctx, VG_NO_ERROR);
    130 
    131    ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create();
    132    ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create();
    133    ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create();
    134    ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create();
    135    ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create();
    136 
    137    ctx->renderer = renderer_create(ctx);
    138    ctx->sc = shaders_cache_create(ctx);
    139    ctx->shader = shader_create(ctx);
    140 
    141    ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context);
    142 
    143    return ctx;
    144 }
    145 
    146 void vg_destroy_context(struct vg_context *ctx)
    147 {
    148    struct pipe_resource **cbuf = &ctx->mask.cbuf;
    149 
    150    util_destroy_blit(ctx->blit);
    151    renderer_destroy(ctx->renderer);
    152    shaders_cache_destroy(ctx->sc);
    153    shader_destroy(ctx->shader);
    154    paint_destroy(ctx->default_paint);
    155 
    156    if (*cbuf)
    157       pipe_resource_reference(cbuf, NULL);
    158 
    159    if (ctx->mask.union_fs)
    160       vg_shader_destroy(ctx, ctx->mask.union_fs);
    161    if (ctx->mask.intersect_fs)
    162       vg_shader_destroy(ctx, ctx->mask.intersect_fs);
    163    if (ctx->mask.subtract_fs)
    164       vg_shader_destroy(ctx, ctx->mask.subtract_fs);
    165    if (ctx->mask.set_fs)
    166       vg_shader_destroy(ctx, ctx->mask.set_fs);
    167 
    168    cso_release_all(ctx->cso_context);
    169    cso_destroy_context(ctx->cso_context);
    170 
    171    cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]);
    172    cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]);
    173    cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]);
    174    cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]);
    175    cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]);
    176 
    177    api_destroy_dispatch(ctx->dispatch);
    178 
    179    FREE(ctx);
    180 }
    181 
    182 void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type)
    183 {
    184    obj->type = type;
    185    obj->ctx = ctx;
    186    obj->handle = create_handle(obj);
    187 }
    188 
    189 /** free object resources, but not the object itself */
    190 void vg_free_object(struct vg_object *obj)
    191 {
    192    obj->type = 0;
    193    obj->ctx = NULL;
    194    destroy_handle(obj->handle);
    195 }
    196 
    197 VGboolean vg_context_is_object_valid(struct vg_context *ctx,
    198                                 enum vg_object_type type,
    199                                 VGHandle handle)
    200 {
    201     if (ctx) {
    202        struct cso_hash *hash = ctx->owned_objects[type];
    203        if (!hash)
    204           return VG_FALSE;
    205        return cso_hash_contains(hash, (unsigned) handle);
    206     }
    207     return VG_FALSE;
    208 }
    209 
    210 void vg_context_add_object(struct vg_context *ctx,
    211                            struct vg_object *obj)
    212 {
    213     if (ctx) {
    214        struct cso_hash *hash = ctx->owned_objects[obj->type];
    215        if (!hash)
    216           return;
    217        cso_hash_insert(hash, (unsigned) obj->handle, obj);
    218     }
    219 }
    220 
    221 void vg_context_remove_object(struct vg_context *ctx,
    222                               struct vg_object *obj)
    223 {
    224    if (ctx) {
    225       struct cso_hash *hash = ctx->owned_objects[obj->type];
    226       if (!hash)
    227          return;
    228       cso_hash_take(hash, (unsigned) obj->handle);
    229    }
    230 }
    231 
    232 static struct pipe_resource *
    233 create_texture(struct pipe_context *pipe, enum pipe_format format,
    234                     VGint width, VGint height)
    235 {
    236    struct pipe_resource templ;
    237 
    238    memset(&templ, 0, sizeof(templ));
    239 
    240    if (format != PIPE_FORMAT_NONE) {
    241       templ.format = format;
    242    }
    243    else {
    244       templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
    245    }
    246 
    247    templ.target = PIPE_TEXTURE_2D;
    248    templ.width0 = width;
    249    templ.height0 = height;
    250    templ.depth0 = 1;
    251    templ.array_size = 1;
    252    templ.last_level = 0;
    253 
    254    if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
    255       templ.bind = PIPE_BIND_DEPTH_STENCIL;
    256    } else {
    257       templ.bind = (PIPE_BIND_DISPLAY_TARGET |
    258                     PIPE_BIND_RENDER_TARGET |
    259                     PIPE_BIND_SAMPLER_VIEW);
    260    }
    261 
    262    return pipe->screen->resource_create(pipe->screen, &templ);
    263 }
    264 
    265 static struct pipe_sampler_view *
    266 create_tex_and_view(struct pipe_context *pipe, enum pipe_format format,
    267                     VGint width, VGint height)
    268 {
    269    struct pipe_resource *texture;
    270    struct pipe_sampler_view view_templ;
    271    struct pipe_sampler_view *view;
    272 
    273    texture = create_texture(pipe, format, width, height);
    274 
    275    if (!texture)
    276       return NULL;
    277 
    278    u_sampler_view_default_template(&view_templ, texture, texture->format);
    279    view = pipe->create_sampler_view(pipe, texture, &view_templ);
    280    /* want the texture to go away if the view is freed */
    281    pipe_resource_reference(&texture, NULL);
    282 
    283    return view;
    284 }
    285 
    286 static void
    287 vg_context_update_surface_mask_view(struct vg_context *ctx,
    288                                     uint width, uint height)
    289 {
    290    struct st_framebuffer *stfb = ctx->draw_buffer;
    291    struct pipe_sampler_view *old_sampler_view = stfb->surface_mask_view;
    292    struct pipe_context *pipe = ctx->pipe;
    293 
    294    if (old_sampler_view &&
    295        old_sampler_view->texture->width0 == width &&
    296        old_sampler_view->texture->height0 == height)
    297       return;
    298 
    299    /*
    300      we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
    301      this texture and use it as a sampler, so while this wastes some
    302      space it makes both of those a lot simpler
    303    */
    304    stfb->surface_mask_view = create_tex_and_view(pipe,
    305          PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
    306 
    307    if (!stfb->surface_mask_view) {
    308       if (old_sampler_view)
    309          pipe_sampler_view_reference(&old_sampler_view, NULL);
    310       return;
    311    }
    312 
    313    /* XXX could this call be avoided? */
    314    vg_validate_state(ctx);
    315 
    316    /* alpha mask starts with 1.f alpha */
    317    mask_fill(0, 0, width, height, 1.f);
    318 
    319    /* if we had an old surface copy it over */
    320    if (old_sampler_view) {
    321       struct pipe_box src_box;
    322       u_box_origin_2d(MIN2(old_sampler_view->texture->width0,
    323                            stfb->surface_mask_view->texture->width0),
    324                       MIN2(old_sampler_view->texture->height0,
    325                            stfb->surface_mask_view->texture->height0),
    326                       &src_box);
    327 
    328       pipe->resource_copy_region(pipe,
    329                                  stfb->surface_mask_view->texture,
    330                                  0, 0, 0, 0,
    331                                  old_sampler_view->texture,
    332                                  0, &src_box);
    333    }
    334 
    335    /* Free the old texture
    336     */
    337    if (old_sampler_view)
    338       pipe_sampler_view_reference(&old_sampler_view, NULL);
    339 }
    340 
    341 static void
    342 vg_context_update_blend_texture_view(struct vg_context *ctx,
    343                                      uint width, uint height)
    344 {
    345    struct pipe_context *pipe = ctx->pipe;
    346    struct st_framebuffer *stfb = ctx->draw_buffer;
    347    struct pipe_sampler_view *old = stfb->blend_texture_view;
    348 
    349    if (old &&
    350        old->texture->width0 == width &&
    351        old->texture->height0 == height)
    352       return;
    353 
    354    stfb->blend_texture_view = create_tex_and_view(pipe,
    355          PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
    356 
    357    pipe_sampler_view_reference(&old, NULL);
    358 }
    359 
    360 static boolean
    361 vg_context_update_depth_stencil_rb(struct vg_context * ctx,
    362                                    uint width, uint height)
    363 {
    364    struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb;
    365    struct pipe_context *pipe = ctx->pipe;
    366    struct pipe_surface surf_tmpl;
    367 
    368    if ((dsrb->width == width && dsrb->height == height) && dsrb->texture)
    369       return FALSE;
    370 
    371    /* unreference existing ones */
    372    pipe_surface_reference(&dsrb->surface, NULL);
    373    pipe_resource_reference(&dsrb->texture, NULL);
    374    dsrb->width = dsrb->height = 0;
    375 
    376    dsrb->texture = create_texture(pipe, dsrb->format, width, height);
    377    if (!dsrb->texture)
    378       return TRUE;
    379 
    380    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
    381    u_surface_default_template(&surf_tmpl, dsrb->texture,
    382                               PIPE_BIND_DEPTH_STENCIL);
    383    dsrb->surface = pipe->create_surface(pipe,
    384                                         dsrb->texture,
    385                                         &surf_tmpl);
    386    if (!dsrb->surface) {
    387       pipe_resource_reference(&dsrb->texture, NULL);
    388       return TRUE;
    389    }
    390 
    391    dsrb->width = width;
    392    dsrb->height = height;
    393 
    394    assert(dsrb->surface->width == width);
    395    assert(dsrb->surface->height == height);
    396 
    397    return TRUE;
    398 }
    399 
    400 void vg_validate_state(struct vg_context *ctx)
    401 {
    402    struct st_framebuffer *stfb = ctx->draw_buffer;
    403 
    404    vg_manager_validate_framebuffer(ctx);
    405 
    406    if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height))
    407       ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
    408 
    409    /* blend state depends on fb format and paint color */
    410    if ((ctx->state.dirty & FRAMEBUFFER_DIRTY) ||
    411        (ctx->state.dirty & PAINT_DIRTY))
    412       ctx->state.dirty |= BLEND_DIRTY;
    413 
    414    renderer_validate(ctx->renderer, ctx->state.dirty,
    415          ctx->draw_buffer, &ctx->state.vg);
    416 
    417    ctx->state.dirty = 0;
    418 
    419    shader_set_masking(ctx->shader, ctx->state.vg.masking);
    420    shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
    421    shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform);
    422 }
    423 
    424 VGboolean vg_object_is_valid(VGHandle object, enum vg_object_type type)
    425 {
    426    struct vg_object *obj = handle_to_object(object);
    427    if (obj && is_aligned(obj) && obj->type == type)
    428       return VG_TRUE;
    429    else
    430       return VG_FALSE;
    431 }
    432 
    433 void vg_set_error(struct vg_context *ctx,
    434                   VGErrorCode code)
    435 {
    436    /*vgGetError returns the oldest error code provided by
    437     * an API call on the current context since the previous
    438     * call to vgGetError on that context (or since the creation
    439     of the context).*/
    440    if (ctx->_error == VG_NO_ERROR)
    441       ctx->_error = code;
    442 }
    443 
    444 static void vg_prepare_blend_texture(struct vg_context *ctx,
    445                                      struct pipe_sampler_view *src)
    446 {
    447    struct st_framebuffer *stfb = ctx->draw_buffer;
    448    struct pipe_surface *surf;
    449    struct pipe_surface surf_tmpl;
    450 
    451    vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height);
    452 
    453    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
    454    u_surface_default_template(&surf_tmpl, stfb->blend_texture_view->texture,
    455                               PIPE_BIND_RENDER_TARGET);
    456    surf = ctx->pipe->create_surface(ctx->pipe,
    457                                     stfb->blend_texture_view->texture,
    458                                     &surf_tmpl);
    459    if (surf) {
    460       util_blit_pixels_tex(ctx->blit,
    461                            src, 0, 0, stfb->width, stfb->height,
    462                            surf, 0, 0, stfb->width, stfb->height,
    463                            0.0, PIPE_TEX_MIPFILTER_NEAREST);
    464 
    465       pipe_surface_reference(&surf, NULL);
    466    }
    467 }
    468 
    469 struct pipe_sampler_view *vg_prepare_blend_surface(struct vg_context *ctx)
    470 {
    471    struct pipe_context *pipe = ctx->pipe;
    472    struct pipe_sampler_view *view;
    473    struct pipe_sampler_view view_templ;
    474    struct st_framebuffer *stfb = ctx->draw_buffer;
    475    struct st_renderbuffer *strb = stfb->strb;
    476 
    477    vg_validate_state(ctx);
    478 
    479    u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format);
    480    view = pipe->create_sampler_view(pipe, strb->texture, &view_templ);
    481 
    482    vg_prepare_blend_texture(ctx, view);
    483 
    484    pipe_sampler_view_reference(&view, NULL);
    485 
    486    return stfb->blend_texture_view;
    487 }
    488 
    489 
    490 struct pipe_sampler_view *vg_prepare_blend_surface_from_mask(struct vg_context *ctx)
    491 {
    492    struct st_framebuffer *stfb = ctx->draw_buffer;
    493 
    494    vg_validate_state(ctx);
    495 
    496    vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height);
    497    vg_prepare_blend_texture(ctx, stfb->surface_mask_view);
    498 
    499    return stfb->blend_texture_view;
    500 }
    501 
    502 struct pipe_sampler_view *vg_get_surface_mask(struct vg_context *ctx)
    503 {
    504    struct st_framebuffer *stfb = ctx->draw_buffer;
    505 
    506    vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height);
    507 
    508    return stfb->surface_mask_view;
    509 }
    510 
    511 /**
    512  * A transformation from window coordinates to paint coordinates.
    513  */
    514 VGboolean vg_get_paint_matrix(struct vg_context *ctx,
    515                               const struct matrix *paint_to_user,
    516                               const struct matrix *user_to_surface,
    517                               struct matrix *mat)
    518 {
    519    struct matrix tmp;
    520 
    521    /* get user-to-paint matrix */
    522    memcpy(mat, paint_to_user, sizeof(*paint_to_user));
    523    if (!matrix_invert(mat))
    524       return VG_FALSE;
    525 
    526    /* get surface-to-user matrix */
    527    memcpy(&tmp, user_to_surface, sizeof(*user_to_surface));
    528    if (!matrix_invert(&tmp))
    529       return VG_FALSE;
    530 
    531    matrix_mult(mat, &tmp);
    532 
    533    return VG_TRUE;
    534 }
    535