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 48PUBLIC 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 55static const uint __dri2NConfigOptions = 1; 56 57/*****************************************************************/ 58/** \name Screen handling functions */ 59/*****************************************************************/ 60/*@{*/ 61 62static void 63setupLoaderExtensions(__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 78static __DRIscreen * 79dri2CreateNewScreen(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 */ 128static 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 147static const __DRIextension **driGetExtensions(__DRIscreen *psp) 148{ 149 return psp->extensions; 150} 151 152/*@}*/ 153 154 155/*****************************************************************/ 156/** \name Context handling functions */ 157/*****************************************************************/ 158/*@{*/ 159 160static __DRIcontext * 161dri2CreateContextAttribs(__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 298static __DRIcontext * 299dri2CreateNewContextForAPI(__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 309static __DRIcontext * 310dri2CreateNewContext(__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 */ 324static void 325driDestroyContext(__DRIcontext *pcp) 326{ 327 if (pcp) { 328 driDriverAPI.DestroyContext(pcp); 329 free(pcp); 330 } 331} 332 333static int 334driCopyContext(__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 350static void dri_get_drawable(__DRIdrawable *pdp); 351static 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 */ 358static 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 */ 400static 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 452static void dri_get_drawable(__DRIdrawable *pdp) 453{ 454 pdp->refcount++; 455} 456 457static 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 469static __DRIdrawable * 470dri2CreateNewDrawable(__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 501static void 502driDestroyDrawable(__DRIdrawable *pdp) 503{ 504 dri_put_drawable(pdp); 505} 506 507static __DRIbuffer * 508dri2AllocateBuffer(__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 516static void 517dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer) 518{ 519 driDriverAPI.ReleaseBuffer(screen, buffer); 520} 521 522 523static int 524dri2ConfigQueryb(__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 534static int 535dri2ConfigQueryi(__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 546static int 547dri2ConfigQueryf(__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 557static unsigned int 558dri2GetAPIMask(__DRIscreen *screen) 559{ 560 return screen->api_mask; 561} 562 563 564/** Core interface */ 565const __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 */ 583const __DRIdri2Extension driDRI2Extension = { 584 { __DRI_DRI2, 3 }, 585 dri2CreateNewScreen, 586 dri2CreateNewDrawable, 587 dri2CreateNewContext, 588 dri2GetAPIMask, 589 dri2CreateNewContextForAPI, 590 dri2AllocateBuffer, 591 dri2ReleaseBuffer, 592 dri2CreateContextAttribs 593}; 594 595const __DRI2configQueryExtension dri2ConfigQueryExtension = { 596 { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION }, 597 dri2ConfigQueryb, 598 dri2ConfigQueryi, 599 dri2ConfigQueryf, 600}; 601 602void 603dri2InvalidateDrawable(__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 */ 614void 615driUpdateFramebufferSize(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