Home | History | Annotate | Download | only in vega
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.9
      4  *
      5  * Copyright 2009 VMware, Inc.  All Rights Reserved.
      6  * Copyright (C) 2010 LunarG Inc.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the "Software"),
     10  * to deal in the Software without restriction, including without limitation
     11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     12  * and/or sell copies of the Software, and to permit persons to whom the
     13  * Software is furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included
     16  * in all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     24  * DEALINGS IN THE SOFTWARE.
     25  *
     26  * Authors:
     27  *    Chia-I Wu <olv (at) lunarg.com>
     28  */
     29 
     30 #include "state_tracker/st_api.h"
     31 
     32 #include "pipe/p_context.h"
     33 #include "pipe/p_screen.h"
     34 #include "util/u_memory.h"
     35 #include "util/u_inlines.h"
     36 #include "util/u_box.h"
     37 #include "util/u_surface.h"
     38 
     39 #include "vg_api.h"
     40 #include "vg_manager.h"
     41 #include "vg_context.h"
     42 #include "api.h"
     43 #include "handle.h"
     44 
     45 static boolean
     46 vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt)
     47 {
     48    struct st_renderbuffer *strb = ctx->draw_buffer->strb;
     49    struct pipe_context *pipe = ctx->pipe;
     50    struct pipe_surface surf_tmpl;
     51 
     52    if (strb->texture == pt) {
     53       pipe_resource_reference(&pt, NULL);
     54       return FALSE;
     55    }
     56 
     57    /* unreference existing ones */
     58    pipe_surface_reference(&strb->surface, NULL);
     59    pipe_resource_reference(&strb->texture, NULL);
     60    strb->width = strb->height = 0;
     61 
     62    strb->texture = pt;
     63 
     64    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
     65    u_surface_default_template(&surf_tmpl, strb->texture,
     66                               PIPE_BIND_RENDER_TARGET);
     67    strb->surface = pipe->create_surface(pipe, strb->texture, &surf_tmpl);
     68 
     69    if (!strb->surface) {
     70       pipe_resource_reference(&strb->texture, NULL);
     71       return TRUE;
     72    }
     73 
     74    strb->width = pt->width0;
     75    strb->height = pt->height0;
     76 
     77    return TRUE;
     78 }
     79 
     80 /**
     81  * Flush the front buffer if the current context renders to the front buffer.
     82  */
     83 void
     84 vg_manager_flush_frontbuffer(struct vg_context *ctx)
     85 {
     86    struct st_framebuffer *stfb = ctx->draw_buffer;
     87 
     88    if (!stfb)
     89       return;
     90 
     91    switch (stfb->strb_att) {
     92    case ST_ATTACHMENT_FRONT_LEFT:
     93    case ST_ATTACHMENT_FRONT_RIGHT:
     94       stfb->iface->flush_front(stfb->iface, stfb->strb_att);
     95       break;
     96    default:
     97       break;
     98    }
     99 }
    100 
    101 /**
    102  * Re-validate the framebuffer.
    103  */
    104 void
    105 vg_manager_validate_framebuffer(struct vg_context *ctx)
    106 {
    107    struct st_framebuffer *stfb = ctx->draw_buffer;
    108    struct pipe_resource *pt;
    109    int32_t new_stamp;
    110 
    111    /* no binding surface */
    112    if (!stfb)
    113       return;
    114 
    115    new_stamp = p_atomic_read(&stfb->iface->stamp);
    116    if (stfb->iface_stamp != new_stamp) {
    117       do {
    118 	 /* validate the fb */
    119 	 if (!stfb->iface->validate(stfb->iface, &stfb->strb_att,
    120 				    1, &pt) || !pt)
    121 	    return;
    122 
    123 	 stfb->iface_stamp = new_stamp;
    124 	 new_stamp = p_atomic_read(&stfb->iface->stamp);
    125 
    126       } while (stfb->iface_stamp != new_stamp);
    127 
    128       if (vg_context_update_color_rb(ctx, pt) ||
    129           stfb->width != pt->width0 ||
    130           stfb->height != pt->height0)
    131          ++stfb->stamp;
    132 
    133       stfb->width = pt->width0;
    134       stfb->height = pt->height0;
    135    }
    136 
    137    if (ctx->draw_stamp != stfb->stamp) {
    138       ctx->state.dirty |= FRAMEBUFFER_DIRTY;
    139       ctx->draw_stamp = stfb->stamp;
    140    }
    141 }
    142 
    143 static void
    144 vg_context_flush(struct st_context_iface *stctxi, unsigned flags,
    145                  struct pipe_fence_handle **fence)
    146 {
    147    struct vg_context *ctx = (struct vg_context *) stctxi;
    148    ctx->pipe->flush(ctx->pipe, fence);
    149    if (flags & ST_FLUSH_FRONT)
    150       vg_manager_flush_frontbuffer(ctx);
    151 }
    152 
    153 static void
    154 vg_context_destroy(struct st_context_iface *stctxi)
    155 {
    156    struct vg_context *ctx = (struct vg_context *) stctxi;
    157    struct pipe_context *pipe = ctx->pipe;
    158 
    159    vg_destroy_context(ctx);
    160    pipe->destroy(pipe);
    161 }
    162 
    163 static struct st_context_iface *
    164 vg_api_create_context(struct st_api *stapi, struct st_manager *smapi,
    165                       const struct st_context_attribs *attribs,
    166                       enum st_context_error *error,
    167                       struct st_context_iface *shared_stctxi)
    168 {
    169    struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi;
    170    struct vg_context *ctx;
    171    struct pipe_context *pipe;
    172 
    173    if (!(stapi->profile_mask & (1 << attribs->profile))) {
    174       *error = ST_CONTEXT_ERROR_BAD_API;
    175       return NULL;
    176    }
    177 
    178    /* only 1.0 is supported */
    179    if (attribs->major > 1 || (attribs->major == 1 && attribs->minor > 0)) {
    180       *error = ST_CONTEXT_ERROR_BAD_VERSION;
    181       return NULL;
    182    }
    183 
    184    /* for VGHandle / pointer lookups */
    185    init_handles();
    186 
    187    pipe = smapi->screen->context_create(smapi->screen, NULL);
    188    if (!pipe) {
    189       *error = ST_CONTEXT_ERROR_NO_MEMORY;
    190       return NULL;
    191    }
    192    ctx = vg_create_context(pipe, NULL, shared_ctx);
    193    if (!ctx) {
    194       pipe->destroy(pipe);
    195       *error = ST_CONTEXT_ERROR_NO_MEMORY;
    196       return NULL;
    197    }
    198 
    199    ctx->iface.destroy = vg_context_destroy;
    200 
    201    ctx->iface.flush = vg_context_flush;
    202 
    203    ctx->iface.teximage = NULL;
    204    ctx->iface.copy = NULL;
    205 
    206    ctx->iface.st_context_private = (void *) smapi;
    207 
    208    return &ctx->iface;
    209 }
    210 
    211 static struct st_renderbuffer *
    212 create_renderbuffer(enum pipe_format format)
    213 {
    214    struct st_renderbuffer *strb;
    215 
    216    strb = CALLOC_STRUCT(st_renderbuffer);
    217    if (strb)
    218       strb->format = format;
    219 
    220    return strb;
    221 }
    222 
    223 static void
    224 destroy_renderbuffer(struct st_renderbuffer *strb)
    225 {
    226    pipe_surface_reference(&strb->surface, NULL);
    227    pipe_resource_reference(&strb->texture, NULL);
    228    FREE(strb);
    229 }
    230 
    231 /**
    232  * Decide the buffer to render to.
    233  */
    234 static enum st_attachment_type
    235 choose_attachment(struct st_framebuffer_iface *stfbi)
    236 {
    237    enum st_attachment_type statt;
    238 
    239    statt = stfbi->visual->render_buffer;
    240    if (statt != ST_ATTACHMENT_INVALID) {
    241       /* use the buffer given by the visual, unless it is unavailable */
    242       if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) {
    243          switch (statt) {
    244          case ST_ATTACHMENT_BACK_LEFT:
    245             statt = ST_ATTACHMENT_FRONT_LEFT;
    246             break;
    247          case ST_ATTACHMENT_BACK_RIGHT:
    248             statt = ST_ATTACHMENT_FRONT_RIGHT;
    249             break;
    250          default:
    251             break;
    252          }
    253 
    254          if (!st_visual_have_buffers(stfbi->visual, 1 << statt))
    255             statt = ST_ATTACHMENT_INVALID;
    256       }
    257    }
    258 
    259    return statt;
    260 }
    261 
    262 /**
    263  * Bind the context to the given framebuffers.
    264  */
    265 static boolean
    266 vg_context_bind_framebuffers(struct st_context_iface *stctxi,
    267                              struct st_framebuffer_iface *stdrawi,
    268                              struct st_framebuffer_iface *streadi)
    269 {
    270    struct vg_context *ctx = (struct vg_context *) stctxi;
    271    struct st_framebuffer *stfb;
    272    enum st_attachment_type strb_att;
    273 
    274    /* the draw and read framebuffers must be the same */
    275    if (stdrawi != streadi)
    276       return FALSE;
    277 
    278    strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID;
    279 
    280    if (ctx->draw_buffer) {
    281       stfb = ctx->draw_buffer;
    282 
    283       /* free the existing fb */
    284       if (!stdrawi ||
    285           stfb->strb_att != strb_att ||
    286           stfb->strb->format != stdrawi->visual->color_format) {
    287          destroy_renderbuffer(stfb->strb);
    288          destroy_renderbuffer(stfb->dsrb);
    289          FREE(stfb);
    290 
    291          ctx->draw_buffer = NULL;
    292       }
    293    }
    294 
    295    if (!stdrawi)
    296       return TRUE;
    297 
    298    if (strb_att == ST_ATTACHMENT_INVALID)
    299       return FALSE;
    300 
    301    /* create a new fb */
    302    if (!ctx->draw_buffer) {
    303       stfb = CALLOC_STRUCT(st_framebuffer);
    304       if (!stfb)
    305          return FALSE;
    306 
    307       stfb->strb = create_renderbuffer(stdrawi->visual->color_format);
    308       if (!stfb->strb) {
    309          FREE(stfb);
    310          return FALSE;
    311       }
    312 
    313       stfb->dsrb = create_renderbuffer(ctx->ds_format);
    314       if (!stfb->dsrb) {
    315          FREE(stfb->strb);
    316          FREE(stfb);
    317          return FALSE;
    318       }
    319 
    320       stfb->width = 0;
    321       stfb->height = 0;
    322       stfb->strb_att = strb_att;
    323       stfb->stamp = 1;
    324       stfb->iface_stamp = p_atomic_read(&stdrawi->stamp) - 1;
    325 
    326       ctx->draw_buffer = stfb;
    327    }
    328 
    329    ctx->draw_buffer->iface = stdrawi;
    330    ctx->draw_stamp = ctx->draw_buffer->stamp - 1;
    331 
    332    return TRUE;
    333 }
    334 
    335 static boolean
    336 vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
    337                     struct st_framebuffer_iface *stdrawi,
    338                     struct st_framebuffer_iface *streadi)
    339 {
    340    struct vg_context *ctx = (struct vg_context *) stctxi;
    341 
    342    if (stctxi)
    343       vg_context_bind_framebuffers(stctxi, stdrawi, streadi);
    344    vg_set_current_context(ctx);
    345 
    346    return TRUE;
    347 }
    348 
    349 static struct st_context_iface *
    350 vg_api_get_current(struct st_api *stapi)
    351 {
    352    struct vg_context *ctx = vg_current_context();
    353 
    354    return (ctx) ? &ctx->iface : NULL;
    355 }
    356 
    357 static st_proc_t
    358 vg_api_get_proc_address(struct st_api *stapi, const char *procname)
    359 {
    360    return api_get_proc_address(procname);
    361 }
    362 
    363 static void
    364 vg_api_destroy(struct st_api *stapi)
    365 {
    366 }
    367 
    368 static const struct st_api vg_api = {
    369    "Vega " VEGA_VERSION_STRING,
    370    ST_API_OPENVG,
    371    ST_PROFILE_DEFAULT_MASK,
    372    0,
    373    vg_api_destroy,
    374    vg_api_get_proc_address,
    375    vg_api_create_context,
    376    vg_api_make_current,
    377    vg_api_get_current,
    378 };
    379 
    380 const struct st_api *
    381 vg_api_get(void)
    382 {
    383    return &vg_api;
    384 }
    385