Home | History | Annotate | Download | only in common
      1 /*
      2  * (C) Copyright IBM Corporation 2002, 2004
      3  * 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 "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * on the rights to use, copy, modify, merge, publish, distribute, sub
      9  * license, and/or sell copies of the Software, and to permit persons to whom
     10  * the Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
     20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     22  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 /**
     26  * \file dri_util.c
     27  * DRI utility functions.
     28  *
     29  * This module acts as glue between GLX and the actual hardware driver.  A DRI
     30  * driver doesn't really \e have to use any of this - it's optional.  But, some
     31  * useful stuff is done here that otherwise would have to be duplicated in most
     32  * drivers.
     33  *
     34  * Basically, these utility functions take care of some of the dirty details of
     35  * screen initialization, context creation, context binding, DRM setup, etc.
     36  *
     37  * These functions are compiled into each DRI driver so libGL.so knows nothing
     38  * about them.
     39  */
     40 
     41 
     42 #include <xf86drm.h>
     43 #include "dri_util.h"
     44 #include "utils.h"
     45 #include "xmlpool.h"
     46 #include "../glsl/glsl_parser_extras.h"
     47 
     48 PUBLIC const char __dri2ConfigOptions[] =
     49    DRI_CONF_BEGIN
     50       DRI_CONF_SECTION_PERFORMANCE
     51          DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
     52       DRI_CONF_SECTION_END
     53    DRI_CONF_END;
     54 
     55 static const uint __dri2NConfigOptions = 1;
     56 
     57 /*****************************************************************/
     58 /** \name Screen handling functions                              */
     59 /*****************************************************************/
     60 /*@{*/
     61 
     62 static void
     63 setupLoaderExtensions(__DRIscreen *psp,
     64 		      const __DRIextension **extensions)
     65 {
     66     int i;
     67 
     68     for (i = 0; extensions[i]; i++) {
     69 	if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
     70 	    psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
     71 	if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
     72 	    psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
     73 	if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
     74 	    psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
     75     }
     76 }
     77 
     78 static __DRIscreen *
     79 dri2CreateNewScreen(int scrn, int fd,
     80 		    const __DRIextension **extensions,
     81 		    const __DRIconfig ***driver_configs, void *data)
     82 {
     83     static const __DRIextension *emptyExtensionList[] = { NULL };
     84     __DRIscreen *psp;
     85     drmVersionPtr version;
     86 
     87     psp = calloc(1, sizeof(*psp));
     88     if (!psp)
     89 	return NULL;
     90 
     91     setupLoaderExtensions(psp, extensions);
     92 
     93     version = drmGetVersion(fd);
     94     if (version) {
     95 	psp->drm_version.major = version->version_major;
     96 	psp->drm_version.minor = version->version_minor;
     97 	psp->drm_version.patch = version->version_patchlevel;
     98 	drmFreeVersion(version);
     99     }
    100 
    101     psp->loaderPrivate = data;
    102 
    103     psp->extensions = emptyExtensionList;
    104     psp->fd = fd;
    105     psp->myNum = scrn;
    106 
    107     psp->api_mask = (1 << __DRI_API_OPENGL);
    108 
    109     *driver_configs = driDriverAPI.InitScreen(psp);
    110     if (*driver_configs == NULL) {
    111 	free(psp);
    112 	return NULL;
    113     }
    114 
    115     driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, __dri2NConfigOptions);
    116     driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri2");
    117 
    118     return psp;
    119 }
    120 
    121 /**
    122  * Destroy the per-screen private information.
    123  *
    124  * \internal
    125  * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
    126  * drmClose(), and finally frees \p screenPrivate.
    127  */
    128 static void driDestroyScreen(__DRIscreen *psp)
    129 {
    130     if (psp) {
    131 	/* No interaction with the X-server is possible at this point.  This
    132 	 * routine is called after XCloseDisplay, so there is no protocol
    133 	 * stream open to the X-server anymore.
    134 	 */
    135 
    136        _mesa_destroy_shader_compiler();
    137 
    138 	driDriverAPI.DestroyScreen(psp);
    139 
    140 	driDestroyOptionCache(&psp->optionCache);
    141 	driDestroyOptionInfo(&psp->optionInfo);
    142 
    143 	free(psp);
    144     }
    145 }
    146 
    147 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
    148 {
    149     return psp->extensions;
    150 }
    151 
    152 /*@}*/
    153 
    154 
    155 /*****************************************************************/
    156 /** \name Context handling functions                             */
    157 /*****************************************************************/
    158 /*@{*/
    159 
    160 static __DRIcontext *
    161 dri2CreateContextAttribs(__DRIscreen *screen, int api,
    162 			 const __DRIconfig *config,
    163 			 __DRIcontext *shared,
    164 			 unsigned num_attribs,
    165 			 const uint32_t *attribs,
    166 			 unsigned *error,
    167 			 void *data)
    168 {
    169     __DRIcontext *context;
    170     const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
    171     void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
    172     gl_api mesa_api;
    173     unsigned major_version = 1;
    174     unsigned minor_version = 0;
    175     uint32_t flags = 0;
    176 
    177     assert((num_attribs == 0) || (attribs != NULL));
    178 
    179     if (!(screen->api_mask & (1 << api))) {
    180 	*error = __DRI_CTX_ERROR_BAD_API;
    181 	return NULL;
    182     }
    183 
    184     switch (api) {
    185     case __DRI_API_OPENGL:
    186 	mesa_api = API_OPENGL;
    187 	break;
    188     case __DRI_API_GLES:
    189 	mesa_api = API_OPENGLES;
    190 	break;
    191     case __DRI_API_GLES2:
    192 	mesa_api = API_OPENGLES2;
    193 	break;
    194     case __DRI_API_OPENGL_CORE:
    195         mesa_api = API_OPENGL_CORE;
    196         break;
    197     default:
    198 	*error = __DRI_CTX_ERROR_BAD_API;
    199 	return NULL;
    200     }
    201 
    202     for (unsigned i = 0; i < num_attribs; i++) {
    203 	switch (attribs[i * 2]) {
    204 	case __DRI_CTX_ATTRIB_MAJOR_VERSION:
    205 	    major_version = attribs[i * 2 + 1];
    206 	    break;
    207 	case __DRI_CTX_ATTRIB_MINOR_VERSION:
    208 	    minor_version = attribs[i * 2 + 1];
    209 	    break;
    210 	case __DRI_CTX_ATTRIB_FLAGS:
    211 	    flags = attribs[i * 2 + 1];
    212 	    break;
    213 	default:
    214 	    /* We can't create a context that satisfies the requirements of an
    215 	     * attribute that we don't understand.  Return failure.
    216 	     */
    217 	    assert(!"Should not get here.");
    218 	    *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
    219 	    return NULL;
    220 	}
    221     }
    222 
    223     /* Mesa does not support the GL_ARB_compatibilty extension or the
    224      * compatibility profile.  This means that we treat a API_OPENGL 3.1 as
    225      * API_OPENGL_CORE and reject API_OPENGL 3.2+.
    226      */
    227     if (mesa_api == API_OPENGL && major_version == 3 && minor_version == 1)
    228        mesa_api = API_OPENGL_CORE;
    229 
    230     if (mesa_api == API_OPENGL
    231         && ((major_version > 3)
    232             || (major_version == 3 && minor_version >= 2))) {
    233        *error = __DRI_CTX_ERROR_BAD_API;
    234        return NULL;
    235     }
    236 
    237     /* The EGL_KHR_create_context spec says:
    238      *
    239      *     "Flags are only defined for OpenGL context creation, and specifying
    240      *     a flags value other than zero for other types of contexts,
    241      *     including OpenGL ES contexts, will generate an error."
    242      *
    243      * The GLX_EXT_create_context_es2_profile specification doesn't say
    244      * anything specific about this case.  However, none of the known flags
    245      * have any meaning in an ES context, so this seems safe.
    246      */
    247     if (mesa_api != API_OPENGL
    248         && mesa_api != API_OPENGL_CORE
    249         && flags != 0) {
    250 	*error = __DRI_CTX_ERROR_BAD_FLAG;
    251 	return NULL;
    252     }
    253 
    254     /* There are no forward-compatible contexts before OpenGL 3.0.  The
    255      * GLX_ARB_create_context spec says:
    256      *
    257      *     "Forward-compatible contexts are defined only for OpenGL versions
    258      *     3.0 and later."
    259      *
    260      * Forward-looking contexts are supported by silently converting the
    261      * requested API to API_OPENGL_CORE.
    262      *
    263      * In Mesa, a debug context is the same as a regular context.
    264      */
    265     if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
    266        mesa_api = API_OPENGL_CORE;
    267     }
    268 
    269     if ((flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE))
    270         != 0) {
    271 	*error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
    272 	return NULL;
    273     }
    274 
    275     context = calloc(1, sizeof *context);
    276     if (!context) {
    277 	*error = __DRI_CTX_ERROR_NO_MEMORY;
    278 	return NULL;
    279     }
    280 
    281     context->loaderPrivate = data;
    282 
    283     context->driScreenPriv = screen;
    284     context->driDrawablePriv = NULL;
    285     context->driReadablePriv = NULL;
    286 
    287     if (!driDriverAPI.CreateContext(mesa_api, modes, context,
    288 				    major_version, minor_version,
    289 				    flags, error, shareCtx) ) {
    290         free(context);
    291         return NULL;
    292     }
    293 
    294     *error = __DRI_CTX_ERROR_SUCCESS;
    295     return context;
    296 }
    297 
    298 static __DRIcontext *
    299 dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
    300 			   const __DRIconfig *config,
    301 			   __DRIcontext *shared, void *data)
    302 {
    303     unsigned error;
    304 
    305     return dri2CreateContextAttribs(screen, api, config, shared, 0, NULL,
    306 				    &error, data);
    307 }
    308 
    309 static __DRIcontext *
    310 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
    311 		      __DRIcontext *shared, void *data)
    312 {
    313     return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
    314 				      config, shared, data);
    315 }
    316 
    317 /**
    318  * Destroy the per-context private information.
    319  *
    320  * \internal
    321  * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
    322  * drmDestroyContext(), and finally frees \p contextPrivate.
    323  */
    324 static void
    325 driDestroyContext(__DRIcontext *pcp)
    326 {
    327     if (pcp) {
    328 	driDriverAPI.DestroyContext(pcp);
    329 	free(pcp);
    330     }
    331 }
    332 
    333 static int
    334 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
    335 {
    336     (void) dest;
    337     (void) src;
    338     (void) mask;
    339     return GL_FALSE;
    340 }
    341 
    342 /*@}*/
    343 
    344 
    345 /*****************************************************************/
    346 /** \name Context (un)binding functions                          */
    347 /*****************************************************************/
    348 /*@{*/
    349 
    350 static void dri_get_drawable(__DRIdrawable *pdp);
    351 static void dri_put_drawable(__DRIdrawable *pdp);
    352 
    353 /**
    354  * This function takes both a read buffer and a draw buffer.  This is needed
    355  * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
    356  * function.
    357  */
    358 static int driBindContext(__DRIcontext *pcp,
    359 			  __DRIdrawable *pdp,
    360 			  __DRIdrawable *prp)
    361 {
    362     /*
    363     ** Assume error checking is done properly in glXMakeCurrent before
    364     ** calling driUnbindContext.
    365     */
    366 
    367     if (!pcp)
    368 	return GL_FALSE;
    369 
    370     /* Bind the drawable to the context */
    371     pcp->driDrawablePriv = pdp;
    372     pcp->driReadablePriv = prp;
    373     if (pdp) {
    374 	pdp->driContextPriv = pcp;
    375 	dri_get_drawable(pdp);
    376     }
    377     if (prp && pdp != prp) {
    378 	dri_get_drawable(prp);
    379     }
    380 
    381     return driDriverAPI.MakeCurrent(pcp, pdp, prp);
    382 }
    383 
    384 /**
    385  * Unbind context.
    386  *
    387  * \param scrn the screen.
    388  * \param gc context.
    389  *
    390  * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
    391  *
    392  * \internal
    393  * This function calls __DriverAPIRec::UnbindContext, and then decrements
    394  * __DRIdrawableRec::refcount which must be non-zero for a successful
    395  * return.
    396  *
    397  * While casting the opaque private pointers associated with the parameters
    398  * into their respective real types it also assures they are not \c NULL.
    399  */
    400 static int driUnbindContext(__DRIcontext *pcp)
    401 {
    402     __DRIdrawable *pdp;
    403     __DRIdrawable *prp;
    404 
    405     /*
    406     ** Assume error checking is done properly in glXMakeCurrent before
    407     ** calling driUnbindContext.
    408     */
    409 
    410     if (pcp == NULL)
    411 	return GL_FALSE;
    412 
    413     pdp = pcp->driDrawablePriv;
    414     prp = pcp->driReadablePriv;
    415 
    416     /* already unbound */
    417     if (!pdp && !prp)
    418 	return GL_TRUE;
    419 
    420     driDriverAPI.UnbindContext(pcp);
    421 
    422     assert(pdp);
    423     if (pdp->refcount == 0) {
    424 	/* ERROR!!! */
    425 	return GL_FALSE;
    426     }
    427 
    428     dri_put_drawable(pdp);
    429 
    430     if (prp != pdp) {
    431 	if (prp->refcount == 0) {
    432 	    /* ERROR!!! */
    433 	    return GL_FALSE;
    434 	}
    435 
    436 	dri_put_drawable(prp);
    437     }
    438 
    439     /* XXX this is disabled so that if we call SwapBuffers on an unbound
    440      * window we can determine the last context bound to the window and
    441      * use that context's lock. (BrianP, 2-Dec-2000)
    442      */
    443     pcp->driDrawablePriv = NULL;
    444     pcp->driReadablePriv = NULL;
    445 
    446     return GL_TRUE;
    447 }
    448 
    449 /*@}*/
    450 
    451 
    452 static void dri_get_drawable(__DRIdrawable *pdp)
    453 {
    454     pdp->refcount++;
    455 }
    456 
    457 static void dri_put_drawable(__DRIdrawable *pdp)
    458 {
    459     if (pdp) {
    460 	pdp->refcount--;
    461 	if (pdp->refcount)
    462 	    return;
    463 
    464 	driDriverAPI.DestroyBuffer(pdp);
    465 	free(pdp);
    466     }
    467 }
    468 
    469 static __DRIdrawable *
    470 dri2CreateNewDrawable(__DRIscreen *screen,
    471 		      const __DRIconfig *config,
    472 		      void *data)
    473 {
    474     __DRIdrawable *pdraw;
    475 
    476     pdraw = malloc(sizeof *pdraw);
    477     if (!pdraw)
    478 	return NULL;
    479 
    480     pdraw->loaderPrivate = data;
    481 
    482     pdraw->driScreenPriv = screen;
    483     pdraw->driContextPriv = NULL;
    484     pdraw->refcount = 0;
    485     pdraw->lastStamp = 0;
    486     pdraw->w = 0;
    487     pdraw->h = 0;
    488 
    489     dri_get_drawable(pdraw);
    490 
    491     if (!driDriverAPI.CreateBuffer(screen, pdraw, &config->modes, GL_FALSE)) {
    492        free(pdraw);
    493        return NULL;
    494     }
    495 
    496     pdraw->dri2.stamp = pdraw->lastStamp + 1;
    497 
    498     return pdraw;
    499 }
    500 
    501 static void
    502 driDestroyDrawable(__DRIdrawable *pdp)
    503 {
    504     dri_put_drawable(pdp);
    505 }
    506 
    507 static __DRIbuffer *
    508 dri2AllocateBuffer(__DRIscreen *screen,
    509 		   unsigned int attachment, unsigned int format,
    510 		   int width, int height)
    511 {
    512     return driDriverAPI.AllocateBuffer(screen, attachment, format,
    513 				       width, height);
    514 }
    515 
    516 static void
    517 dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
    518 {
    519     driDriverAPI.ReleaseBuffer(screen, buffer);
    520 }
    521 
    522 
    523 static int
    524 dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
    525 {
    526    if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
    527       return -1;
    528 
    529    *val = driQueryOptionb(&screen->optionCache, var);
    530 
    531    return 0;
    532 }
    533 
    534 static int
    535 dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
    536 {
    537    if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
    538        !driCheckOption(&screen->optionCache, var, DRI_ENUM))
    539       return -1;
    540 
    541     *val = driQueryOptioni(&screen->optionCache, var);
    542 
    543     return 0;
    544 }
    545 
    546 static int
    547 dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
    548 {
    549    if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
    550       return -1;
    551 
    552     *val = driQueryOptionf(&screen->optionCache, var);
    553 
    554     return 0;
    555 }
    556 
    557 static unsigned int
    558 dri2GetAPIMask(__DRIscreen *screen)
    559 {
    560     return screen->api_mask;
    561 }
    562 
    563 
    564 /** Core interface */
    565 const __DRIcoreExtension driCoreExtension = {
    566     { __DRI_CORE, __DRI_CORE_VERSION },
    567     NULL,
    568     driDestroyScreen,
    569     driGetExtensions,
    570     driGetConfigAttrib,
    571     driIndexConfigAttrib,
    572     NULL,
    573     driDestroyDrawable,
    574     NULL,
    575     NULL,
    576     driCopyContext,
    577     driDestroyContext,
    578     driBindContext,
    579     driUnbindContext
    580 };
    581 
    582 /** DRI2 interface */
    583 const __DRIdri2Extension driDRI2Extension = {
    584     { __DRI_DRI2, 3 },
    585     dri2CreateNewScreen,
    586     dri2CreateNewDrawable,
    587     dri2CreateNewContext,
    588     dri2GetAPIMask,
    589     dri2CreateNewContextForAPI,
    590     dri2AllocateBuffer,
    591     dri2ReleaseBuffer,
    592     dri2CreateContextAttribs
    593 };
    594 
    595 const __DRI2configQueryExtension dri2ConfigQueryExtension = {
    596    { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
    597    dri2ConfigQueryb,
    598    dri2ConfigQueryi,
    599    dri2ConfigQueryf,
    600 };
    601 
    602 void
    603 dri2InvalidateDrawable(__DRIdrawable *drawable)
    604 {
    605     drawable->dri2.stamp++;
    606 }
    607 
    608 /**
    609  * Check that the gl_framebuffer associated with dPriv is the right size.
    610  * Resize the gl_framebuffer if needed.
    611  * It's expected that the dPriv->driverPrivate member points to a
    612  * gl_framebuffer object.
    613  */
    614 void
    615 driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv)
    616 {
    617    struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate;
    618    if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) {
    619       ctx->Driver.ResizeBuffers(ctx, fb, dPriv->w, dPriv->h);
    620       /* if the driver needs the hw lock for ResizeBuffers, the drawable
    621          might have changed again by now */
    622       assert(fb->Width == dPriv->w);
    623       assert(fb->Height == dPriv->h);
    624    }
    625 }
    626