Home | History | Annotate | Download | only in dri
      1 /**************************************************************************
      2  *
      3  * Copyright 2009, VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 /*
     28  * Author: Keith Whitwell <keithw (at) vmware.com>
     29  * Author: Jakob Bornecrantz <wallbraker (at) gmail.com>
     30  */
     31 
     32 #include "utils.h"
     33 
     34 #include "dri_screen.h"
     35 #include "dri_drawable.h"
     36 #include "dri_context.h"
     37 #include "state_tracker/drm_driver.h"
     38 
     39 #include "pipe/p_context.h"
     40 #include "pipe-loader/pipe_loader.h"
     41 #include "state_tracker/st_context.h"
     42 
     43 GLboolean
     44 dri_create_context(gl_api api, const struct gl_config * visual,
     45                    __DRIcontext * cPriv,
     46                    const struct __DriverContextConfig *ctx_config,
     47                    unsigned *error,
     48                    void *sharedContextPrivate)
     49 {
     50    __DRIscreen *sPriv = cPriv->driScreenPriv;
     51    struct dri_screen *screen = dri_screen(sPriv);
     52    struct st_api *stapi = screen->st_api;
     53    struct dri_context *ctx = NULL;
     54    struct st_context_iface *st_share = NULL;
     55    struct st_context_attribs attribs;
     56    enum st_context_error ctx_err = 0;
     57    unsigned allowed_flags = __DRI_CTX_FLAG_DEBUG |
     58                             __DRI_CTX_FLAG_FORWARD_COMPATIBLE |
     59                             __DRI_CTX_FLAG_NO_ERROR;
     60    unsigned allowed_attribs =
     61       __DRIVER_CONTEXT_ATTRIB_PRIORITY |
     62       __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR;
     63    const __DRIbackgroundCallableExtension *backgroundCallable =
     64       screen->sPriv->dri2.backgroundCallable;
     65 
     66    if (screen->has_reset_status_query) {
     67       allowed_flags |= __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS;
     68       allowed_attribs |= __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY;
     69    }
     70 
     71    if (ctx_config->flags & ~allowed_flags) {
     72       *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
     73       goto fail;
     74    }
     75 
     76    if (ctx_config->attribute_mask & ~allowed_attribs) {
     77       *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
     78       goto fail;
     79    }
     80 
     81    memset(&attribs, 0, sizeof(attribs));
     82    switch (api) {
     83    case API_OPENGLES:
     84       attribs.profile = ST_PROFILE_OPENGL_ES1;
     85       break;
     86    case API_OPENGLES2:
     87       attribs.profile = ST_PROFILE_OPENGL_ES2;
     88       break;
     89    case API_OPENGL_COMPAT:
     90    case API_OPENGL_CORE:
     91       attribs.profile = api == API_OPENGL_COMPAT ? ST_PROFILE_DEFAULT
     92                                                  : ST_PROFILE_OPENGL_CORE;
     93       attribs.major = ctx_config->major_version;
     94       attribs.minor = ctx_config->minor_version;
     95 
     96       if ((ctx_config->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
     97 	 attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
     98       break;
     99    default:
    100       *error = __DRI_CTX_ERROR_BAD_API;
    101       goto fail;
    102    }
    103 
    104    if ((ctx_config->flags & __DRI_CTX_FLAG_DEBUG) != 0)
    105       attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
    106 
    107    if (ctx_config->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)
    108       attribs.flags |= ST_CONTEXT_FLAG_ROBUST_ACCESS;
    109 
    110    if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY)
    111       if (ctx_config->reset_strategy != __DRI_CTX_RESET_NO_NOTIFICATION)
    112          attribs.flags |= ST_CONTEXT_FLAG_RESET_NOTIFICATION_ENABLED;
    113 
    114    if (ctx_config->flags & __DRI_CTX_FLAG_NO_ERROR)
    115       attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
    116 
    117    if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_PRIORITY) {
    118       switch (ctx_config->priority) {
    119       case __DRI_CTX_PRIORITY_LOW:
    120          attribs.flags |= ST_CONTEXT_FLAG_LOW_PRIORITY;
    121          break;
    122       case __DRI_CTX_PRIORITY_HIGH:
    123          attribs.flags |= ST_CONTEXT_FLAG_HIGH_PRIORITY;
    124          break;
    125       default:
    126          break;
    127       }
    128    }
    129 
    130    if ((ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR)
    131        && (ctx_config->release_behavior == __DRI_CTX_RELEASE_BEHAVIOR_NONE))
    132       attribs.flags |= ST_CONTEXT_FLAG_RELEASE_NONE;
    133 
    134    struct dri_context *share_ctx = NULL;
    135    if (sharedContextPrivate) {
    136       share_ctx = (struct dri_context *)sharedContextPrivate;
    137       st_share = share_ctx->st;
    138    }
    139 
    140    ctx = CALLOC_STRUCT(dri_context);
    141    if (ctx == NULL) {
    142       *error = __DRI_CTX_ERROR_NO_MEMORY;
    143       goto fail;
    144    }
    145 
    146    cPriv->driverPrivate = ctx;
    147    ctx->cPriv = cPriv;
    148    ctx->sPriv = sPriv;
    149 
    150    if (driQueryOptionb(&screen->dev->option_cache, "mesa_no_error"))
    151       attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
    152 
    153    attribs.options = screen->options;
    154    dri_fill_st_visual(&attribs.visual, screen, visual);
    155    ctx->st = stapi->create_context(stapi, &screen->base, &attribs, &ctx_err,
    156 				   st_share);
    157    if (ctx->st == NULL) {
    158       switch (ctx_err) {
    159       case ST_CONTEXT_SUCCESS:
    160 	 *error = __DRI_CTX_ERROR_SUCCESS;
    161 	 break;
    162       case ST_CONTEXT_ERROR_NO_MEMORY:
    163 	 *error = __DRI_CTX_ERROR_NO_MEMORY;
    164 	 break;
    165       case ST_CONTEXT_ERROR_BAD_API:
    166 	 *error = __DRI_CTX_ERROR_BAD_API;
    167 	 break;
    168       case ST_CONTEXT_ERROR_BAD_VERSION:
    169 	 *error = __DRI_CTX_ERROR_BAD_VERSION;
    170 	 break;
    171       case ST_CONTEXT_ERROR_BAD_FLAG:
    172 	 *error = __DRI_CTX_ERROR_BAD_FLAG;
    173 	 break;
    174       case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
    175 	 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
    176 	 break;
    177       case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
    178 	 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
    179 	 break;
    180       }
    181       goto fail;
    182    }
    183    ctx->st->st_manager_private = (void *) ctx;
    184    ctx->stapi = stapi;
    185 
    186    if (ctx->st->cso_context) {
    187       ctx->pp = pp_init(ctx->st->pipe, screen->pp_enabled, ctx->st->cso_context);
    188       ctx->hud = hud_create(ctx->st->cso_context,
    189                             share_ctx ? share_ctx->hud : NULL);
    190    }
    191 
    192    /* Do this last. */
    193    if (ctx->st->start_thread &&
    194          driQueryOptionb(&screen->dev->option_cache, "mesa_glthread")) {
    195 
    196       if (backgroundCallable && backgroundCallable->base.version >= 2 &&
    197             backgroundCallable->isThreadSafe) {
    198 
    199          if (backgroundCallable->isThreadSafe(cPriv->loaderPrivate))
    200             ctx->st->start_thread(ctx->st);
    201          else
    202             fprintf(stderr, "dri_create_context: glthread isn't thread safe "
    203                   "- missing call XInitThreads\n");
    204       } else {
    205          fprintf(stderr, "dri_create_context: requested glthread but driver "
    206                "is missing backgroundCallable V2 extension\n");
    207       }
    208    }
    209 
    210    *error = __DRI_CTX_ERROR_SUCCESS;
    211    return GL_TRUE;
    212 
    213  fail:
    214    if (ctx && ctx->st)
    215       ctx->st->destroy(ctx->st);
    216 
    217    free(ctx);
    218    return GL_FALSE;
    219 }
    220 
    221 void
    222 dri_destroy_context(__DRIcontext * cPriv)
    223 {
    224    struct dri_context *ctx = dri_context(cPriv);
    225 
    226    if (ctx->hud) {
    227       hud_destroy(ctx->hud, ctx->st->cso_context);
    228    }
    229 
    230    if (ctx->pp)
    231       pp_free(ctx->pp);
    232 
    233    /* No particular reason to wait for command completion before
    234     * destroying a context, but we flush the context here
    235     * to avoid having to add code elsewhere to cope with flushing a
    236     * partially destroyed context.
    237     */
    238    ctx->st->flush(ctx->st, 0, NULL);
    239    ctx->st->destroy(ctx->st);
    240    free(ctx);
    241 }
    242 
    243 /* This is called inside MakeCurrent to unbind the context. */
    244 GLboolean
    245 dri_unbind_context(__DRIcontext * cPriv)
    246 {
    247    /* dri_util.c ensures cPriv is not null */
    248    struct dri_screen *screen = dri_screen(cPriv->driScreenPriv);
    249    struct dri_context *ctx = dri_context(cPriv);
    250    struct st_context_iface *st = ctx->st;
    251    struct st_api *stapi = screen->st_api;
    252 
    253    if (--ctx->bind_count == 0) {
    254       if (st == stapi->get_current(stapi)) {
    255          if (st->thread_finish)
    256             st->thread_finish(st);
    257 
    258          /* Record HUD queries for the duration the context was "current". */
    259          if (ctx->hud)
    260             hud_record_only(ctx->hud, st->pipe);
    261 
    262          stapi->make_current(stapi, NULL, NULL, NULL);
    263       }
    264    }
    265 
    266    return GL_TRUE;
    267 }
    268 
    269 GLboolean
    270 dri_make_current(__DRIcontext * cPriv,
    271 		 __DRIdrawable * driDrawPriv,
    272 		 __DRIdrawable * driReadPriv)
    273 {
    274    /* dri_util.c ensures cPriv is not null */
    275    struct dri_context *ctx = dri_context(cPriv);
    276    struct dri_drawable *draw = dri_drawable(driDrawPriv);
    277    struct dri_drawable *read = dri_drawable(driReadPriv);
    278 
    279    ++ctx->bind_count;
    280 
    281    if (!draw && !read)
    282       return ctx->stapi->make_current(ctx->stapi, ctx->st, NULL, NULL);
    283    else if (!draw || !read)
    284       return GL_FALSE;
    285 
    286    if (ctx->dPriv != driDrawPriv) {
    287       ctx->dPriv = driDrawPriv;
    288       draw->texture_stamp = driDrawPriv->lastStamp - 1;
    289    }
    290    if (ctx->rPriv != driReadPriv) {
    291       ctx->rPriv = driReadPriv;
    292       read->texture_stamp = driReadPriv->lastStamp - 1;
    293    }
    294 
    295    ctx->stapi->make_current(ctx->stapi, ctx->st, &draw->base, &read->base);
    296 
    297    /* This is ok to call here. If they are already init, it's a no-op. */
    298    if (ctx->pp && draw->textures[ST_ATTACHMENT_BACK_LEFT])
    299       pp_init_fbos(ctx->pp, draw->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
    300                    draw->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
    301 
    302    return GL_TRUE;
    303 }
    304 
    305 struct dri_context *
    306 dri_get_current(__DRIscreen *sPriv)
    307 {
    308    struct dri_screen *screen = dri_screen(sPriv);
    309    struct st_api *stapi = screen->st_api;
    310    struct st_context_iface *st;
    311 
    312    st = stapi->get_current(stapi);
    313 
    314    return (struct dri_context *) st ? st->st_manager_private : NULL;
    315 }
    316 
    317 /* vim: set sw=3 ts=8 sts=3 expandtab: */
    318