1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Soft- 6 * ware"), to deal in the Software without restriction, including without 7 * limitation the rights to use, copy, modify, merge, publish, distribute, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, provided that the above copyright 10 * notice(s) and this permission notice appear in all copies of the Soft- 11 * ware and that both the above copyright notice(s) and this permission 12 * notice appear in supporting documentation. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22 * MANCE OF THIS SOFTWARE. 23 * 24 * Except as contained in this notice, the name of a copyright holder shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization of 27 * the copyright holder. 28 * 29 * Authors: 30 * Kristian Høgsberg (krh@redhat.com) 31 */ 32 33#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 34 35#include <X11/Xlib.h> 36#include <X11/extensions/Xfixes.h> 37#include <X11/Xlib-xcb.h> 38#include <xcb/xcb.h> 39#include <xcb/dri2.h> 40#include "glxclient.h" 41#include <X11/extensions/dri2proto.h> 42#include <dlfcn.h> 43#include <fcntl.h> 44#include <unistd.h> 45#include <sys/types.h> 46#include <sys/mman.h> 47#include <sys/time.h> 48#include "dri2.h" 49#include "dri_common.h" 50#include "dri2_priv.h" 51#include "loader.h" 52#include "loader_dri_helper.h" 53 54#undef DRI2_MINOR 55#define DRI2_MINOR 1 56 57struct dri2_display 58{ 59 __GLXDRIdisplay base; 60 61 __glxHashTable *dri2Hash; 62 63 const __DRIextension *loader_extensions[5]; 64}; 65 66struct dri2_drawable 67{ 68 __GLXDRIdrawable base; 69 __DRIdrawable *driDrawable; 70 __DRIbuffer buffers[5]; 71 int bufferCount; 72 int width, height; 73 int have_back; 74 int have_fake_front; 75 int swap_interval; 76 77 uint64_t previous_time; 78 unsigned frames; 79}; 80 81static const struct glx_context_vtable dri2_context_vtable; 82 83/* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and 84 * low halves separately. This helps you split them. 85 */ 86static void 87split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo) 88{ 89 *hi = (counter >> 32); 90 *lo = counter & 0xffffffff; 91} 92 93static uint64_t 94merge_counter(uint32_t hi, uint32_t lo) 95{ 96 return ((uint64_t)hi << 32) | lo; 97} 98 99static void 100dri2_destroy_context(struct glx_context *context) 101{ 102 struct dri2_context *pcp = (struct dri2_context *) context; 103 struct dri2_screen *psc = (struct dri2_screen *) context->psc; 104 105 driReleaseDrawables(&pcp->base); 106 107 free((char *) context->extensions); 108 109 (*psc->core->destroyContext) (pcp->driContext); 110 111 free(pcp); 112} 113 114static Bool 115dri2_bind_context(struct glx_context *context, struct glx_context *old, 116 GLXDrawable draw, GLXDrawable read) 117{ 118 struct dri2_context *pcp = (struct dri2_context *) context; 119 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; 120 struct dri2_drawable *pdraw, *pread; 121 __DRIdrawable *dri_draw = NULL, *dri_read = NULL; 122 123 pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw); 124 pread = (struct dri2_drawable *) driFetchDrawable(context, read); 125 126 driReleaseDrawables(old); 127 128 if (pdraw) 129 dri_draw = pdraw->driDrawable; 130 else if (draw != None) 131 return GLXBadDrawable; 132 133 if (pread) 134 dri_read = pread->driDrawable; 135 else if (read != None) 136 return GLXBadDrawable; 137 138 if (!(*psc->core->bindContext) (pcp->driContext, dri_draw, dri_read)) 139 return GLXBadContext; 140 141 return Success; 142} 143 144static void 145dri2_unbind_context(struct glx_context *context, struct glx_context *new) 146{ 147 struct dri2_context *pcp = (struct dri2_context *) context; 148 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; 149 150 (*psc->core->unbindContext) (pcp->driContext); 151} 152 153static struct glx_context * 154dri2_create_context_attribs(struct glx_screen *base, 155 struct glx_config *config_base, 156 struct glx_context *shareList, 157 unsigned num_attribs, 158 const uint32_t *attribs, 159 unsigned *error) 160{ 161 struct dri2_context *pcp = NULL; 162 struct dri2_context *pcp_shared = NULL; 163 struct dri2_screen *psc = (struct dri2_screen *) base; 164 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 165 __DRIcontext *shared = NULL; 166 167 struct dri_ctx_attribs dca; 168 uint32_t ctx_attribs[2 * 6]; 169 unsigned num_ctx_attribs = 0; 170 171 *error = dri_convert_glx_attribs(num_attribs, attribs, &dca); 172 if (*error != __DRI_CTX_ERROR_SUCCESS) 173 goto error_exit; 174 175 /* Check the renderType value */ 176 if (!validate_renderType_against_config(config_base, dca.render_type)) 177 goto error_exit; 178 179 if (shareList) { 180 /* We can't share with an indirect context */ 181 if (!shareList->isDirect) 182 return NULL; 183 184 /* The GLX_ARB_create_context_no_error specs say: 185 * 186 * BadMatch is generated if the value of GLX_CONTEXT_OPENGL_NO_ERROR_ARB 187 * used to create <share_context> does not match the value of 188 * GLX_CONTEXT_OPENGL_NO_ERROR_ARB for the context being created. 189 */ 190 if (!!shareList->noError != !!dca.no_error) { 191 *error = __DRI_CTX_ERROR_BAD_FLAG; 192 return NULL; 193 } 194 195 pcp_shared = (struct dri2_context *) shareList; 196 shared = pcp_shared->driContext; 197 } 198 199 pcp = calloc(1, sizeof *pcp); 200 if (pcp == NULL) { 201 *error = __DRI_CTX_ERROR_NO_MEMORY; 202 goto error_exit; 203 } 204 205 if (!glx_context_init(&pcp->base, &psc->base, config_base)) 206 goto error_exit; 207 208 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 209 ctx_attribs[num_ctx_attribs++] = dca.major_ver; 210 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 211 ctx_attribs[num_ctx_attribs++] = dca.minor_ver; 212 213 /* Only send a value when the non-default value is requested. By doing 214 * this we don't have to check the driver's DRI2 version before sending the 215 * default value. 216 */ 217 if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) { 218 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; 219 ctx_attribs[num_ctx_attribs++] = dca.reset; 220 } 221 222 if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) { 223 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR; 224 ctx_attribs[num_ctx_attribs++] = dca.release; 225 } 226 227 if (dca.no_error) { 228 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_NO_ERROR; 229 ctx_attribs[num_ctx_attribs++] = dca.no_error; 230 pcp->base.noError = GL_TRUE; 231 } 232 233 if (dca.flags != 0) { 234 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 235 ctx_attribs[num_ctx_attribs++] = dca.flags; 236 } 237 238 /* The renderType is retrieved from attribs, or set to default 239 * of GLX_RGBA_TYPE. 240 */ 241 pcp->base.renderType = dca.render_type; 242 243 pcp->driContext = 244 (*psc->dri2->createContextAttribs) (psc->driScreen, 245 dca.api, 246 config ? config->driConfig : NULL, 247 shared, 248 num_ctx_attribs / 2, 249 ctx_attribs, 250 error, 251 pcp); 252 253 if (pcp->driContext == NULL) 254 goto error_exit; 255 256 pcp->base.vtable = base->context_vtable; 257 258 return &pcp->base; 259 260error_exit: 261 free(pcp); 262 263 return NULL; 264} 265 266static void 267dri2DestroyDrawable(__GLXDRIdrawable *base) 268{ 269 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 270 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 271 struct glx_display *dpyPriv = psc->base.display; 272 struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; 273 274 __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable); 275 (*psc->core->destroyDrawable) (pdraw->driDrawable); 276 277 /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable 278 * now, as the application explicitly asked to destroy the GLX 279 * drawable. Otherwise, for legacy drawables, we let the DRI2 280 * drawable linger on the server, since there's no good way of 281 * knowing when the application is done with it. The server will 282 * destroy the DRI2 drawable when it destroys the X drawable or the 283 * client exits anyway. */ 284 if (pdraw->base.xDrawable != pdraw->base.drawable) 285 DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable); 286 287 free(pdraw); 288} 289 290static __GLXDRIdrawable * 291dri2CreateDrawable(struct glx_screen *base, XID xDrawable, 292 GLXDrawable drawable, int type, 293 struct glx_config *config_base) 294{ 295 struct dri2_drawable *pdraw; 296 struct dri2_screen *psc = (struct dri2_screen *) base; 297 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 298 struct glx_display *dpyPriv; 299 struct dri2_display *pdp; 300 301 dpyPriv = __glXInitialize(psc->base.dpy); 302 if (dpyPriv == NULL) 303 return NULL; 304 305 pdraw = calloc(1, sizeof(*pdraw)); 306 if (!pdraw) 307 return NULL; 308 309 pdraw->base.destroyDrawable = dri2DestroyDrawable; 310 pdraw->base.xDrawable = xDrawable; 311 pdraw->base.drawable = drawable; 312 pdraw->base.psc = &psc->base; 313 pdraw->bufferCount = 0; 314 pdraw->swap_interval = dri_get_initial_swap_interval(psc->driScreen, psc->config); 315 pdraw->have_back = 0; 316 317 DRI2CreateDrawable(psc->base.dpy, xDrawable); 318 pdp = (struct dri2_display *)dpyPriv->dri2Display; 319 /* Create a new drawable */ 320 pdraw->driDrawable = 321 (*psc->dri2->createNewDrawable) (psc->driScreen, 322 config->driConfig, pdraw); 323 324 if (!pdraw->driDrawable) { 325 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 326 free(pdraw); 327 return NULL; 328 } 329 330 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) { 331 (*psc->core->destroyDrawable) (pdraw->driDrawable); 332 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 333 free(pdraw); 334 return None; 335 } 336 337 /* 338 * Make sure server has the same swap interval we do for the new 339 * drawable. 340 */ 341 if (psc->vtable.setSwapInterval) 342 psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval); 343 344 return &pdraw->base; 345} 346 347static int 348dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw, 349 int64_t *ust, int64_t *msc, int64_t *sbc) 350{ 351 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 352 xcb_dri2_get_msc_cookie_t get_msc_cookie; 353 xcb_dri2_get_msc_reply_t *get_msc_reply; 354 355 get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable); 356 get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL); 357 358 if (!get_msc_reply) 359 return 0; 360 361 *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo); 362 *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo); 363 *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo); 364 free(get_msc_reply); 365 366 return 1; 367} 368 369static int 370dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 371 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 372{ 373 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 374 xcb_dri2_wait_msc_cookie_t wait_msc_cookie; 375 xcb_dri2_wait_msc_reply_t *wait_msc_reply; 376 uint32_t target_msc_hi, target_msc_lo; 377 uint32_t divisor_hi, divisor_lo; 378 uint32_t remainder_hi, remainder_lo; 379 380 split_counter(target_msc, &target_msc_hi, &target_msc_lo); 381 split_counter(divisor, &divisor_hi, &divisor_lo); 382 split_counter(remainder, &remainder_hi, &remainder_lo); 383 384 wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable, 385 target_msc_hi, target_msc_lo, 386 divisor_hi, divisor_lo, 387 remainder_hi, remainder_lo); 388 wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL); 389 390 if (!wait_msc_reply) 391 return 0; 392 393 *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo); 394 *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo); 395 *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo); 396 free(wait_msc_reply); 397 398 return 1; 399} 400 401static int 402dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 403 int64_t *msc, int64_t *sbc) 404{ 405 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 406 xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie; 407 xcb_dri2_wait_sbc_reply_t *wait_sbc_reply; 408 uint32_t target_sbc_hi, target_sbc_lo; 409 410 split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo); 411 412 wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable, 413 target_sbc_hi, target_sbc_lo); 414 wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL); 415 416 if (!wait_sbc_reply) 417 return 0; 418 419 *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo); 420 *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo); 421 *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo); 422 free(wait_sbc_reply); 423 424 return 1; 425} 426 427static __DRIcontext * 428dri2GetCurrentContext() 429{ 430 struct glx_context *gc = __glXGetCurrentContext(); 431 struct dri2_context *dri2Ctx = (struct dri2_context *)gc; 432 433 return (gc != &dummyContext) ? dri2Ctx->driContext : NULL; 434} 435 436/** 437 * dri2Throttle - Request driver throttling 438 * 439 * This function uses the DRI2 throttle extension to give the 440 * driver the opportunity to throttle on flush front, copysubbuffer 441 * and swapbuffers. 442 */ 443static void 444dri2Throttle(struct dri2_screen *psc, 445 struct dri2_drawable *draw, 446 enum __DRI2throttleReason reason) 447{ 448 if (psc->throttle) { 449 __DRIcontext *ctx = dri2GetCurrentContext(); 450 451 psc->throttle->throttle(ctx, draw->driDrawable, reason); 452 } 453} 454 455/** 456 * Asks the driver to flush any queued work necessary for serializing with the 457 * X command stream, and optionally the slightly more strict requirement of 458 * glFlush() equivalence (which would require flushing even if nothing had 459 * been drawn to a window system framebuffer, for example). 460 */ 461static void 462dri2Flush(struct dri2_screen *psc, 463 __DRIcontext *ctx, 464 struct dri2_drawable *draw, 465 unsigned flags, 466 enum __DRI2throttleReason throttle_reason) 467{ 468 if (ctx && psc->f && psc->f->base.version >= 4) { 469 psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason); 470 } else { 471 if (flags & __DRI2_FLUSH_CONTEXT) 472 glFlush(); 473 474 if (psc->f) 475 psc->f->flush(draw->driDrawable); 476 477 dri2Throttle(psc, draw, throttle_reason); 478 } 479} 480 481static void 482__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 483 int width, int height, 484 enum __DRI2throttleReason reason, Bool flush) 485{ 486 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 487 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 488 XRectangle xrect; 489 XserverRegion region; 490 __DRIcontext *ctx = dri2GetCurrentContext(); 491 unsigned flags; 492 493 /* Check we have the right attachments */ 494 if (!priv->have_back) 495 return; 496 497 xrect.x = x; 498 xrect.y = priv->height - y - height; 499 xrect.width = width; 500 xrect.height = height; 501 502 flags = __DRI2_FLUSH_DRAWABLE; 503 if (flush) 504 flags |= __DRI2_FLUSH_CONTEXT; 505 dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_COPYSUBBUFFER); 506 507 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 508 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 509 DRI2BufferFrontLeft, DRI2BufferBackLeft); 510 511 /* Refresh the fake front (if present) after we just damaged the real 512 * front. 513 */ 514 if (priv->have_fake_front) 515 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 516 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 517 518 XFixesDestroyRegion(psc->base.dpy, region); 519} 520 521static void 522dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 523 int width, int height, Bool flush) 524{ 525 __dri2CopySubBuffer(pdraw, x, y, width, height, 526 __DRI2_THROTTLE_COPYSUBBUFFER, flush); 527} 528 529 530static void 531dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) 532{ 533 XRectangle xrect; 534 XserverRegion region; 535 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 536 537 xrect.x = 0; 538 xrect.y = 0; 539 xrect.width = priv->width; 540 xrect.height = priv->height; 541 542 if (psc->f) 543 (*psc->f->flush) (priv->driDrawable); 544 545 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 546 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); 547 XFixesDestroyRegion(psc->base.dpy, region); 548 549} 550 551static void 552dri2_wait_x(struct glx_context *gc) 553{ 554 struct dri2_drawable *priv = (struct dri2_drawable *) 555 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 556 557 if (priv == NULL || !priv->have_fake_front) 558 return; 559 560 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 561} 562 563static void 564dri2_wait_gl(struct glx_context *gc) 565{ 566 struct dri2_drawable *priv = (struct dri2_drawable *) 567 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 568 569 if (priv == NULL || !priv->have_fake_front) 570 return; 571 572 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 573} 574 575/** 576 * Called by the driver when it needs to update the real front buffer with the 577 * contents of its fake front buffer. 578 */ 579static void 580dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 581{ 582 struct glx_display *priv; 583 struct glx_context *gc; 584 struct dri2_drawable *pdraw = loaderPrivate; 585 struct dri2_screen *psc; 586 587 if (!pdraw) 588 return; 589 590 if (!pdraw->base.psc) 591 return; 592 593 psc = (struct dri2_screen *) pdraw->base.psc; 594 595 priv = __glXInitialize(psc->base.dpy); 596 597 if (priv == NULL) 598 return; 599 600 gc = __glXGetCurrentContext(); 601 602 dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT); 603 604 dri2_wait_gl(gc); 605} 606 607 608static void 609dri2DestroyScreen(struct glx_screen *base) 610{ 611 struct dri2_screen *psc = (struct dri2_screen *) base; 612 613 /* Free the direct rendering per screen data */ 614 (*psc->core->destroyScreen) (psc->driScreen); 615 driDestroyConfigs(psc->driver_configs); 616 free(psc->driverName); 617 close(psc->fd); 618 free(psc); 619} 620 621/** 622 * Process list of buffer received from the server 623 * 624 * Processes the list of buffers received in a reply from the server to either 625 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 626 */ 627static void 628process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 629 unsigned count) 630{ 631 int i; 632 633 pdraw->bufferCount = count; 634 pdraw->have_fake_front = 0; 635 pdraw->have_back = 0; 636 637 /* This assumes the DRI2 buffer attachment tokens matches the 638 * __DRIbuffer tokens. */ 639 for (i = 0; i < count; i++) { 640 pdraw->buffers[i].attachment = buffers[i].attachment; 641 pdraw->buffers[i].name = buffers[i].name; 642 pdraw->buffers[i].pitch = buffers[i].pitch; 643 pdraw->buffers[i].cpp = buffers[i].cpp; 644 pdraw->buffers[i].flags = buffers[i].flags; 645 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 646 pdraw->have_fake_front = 1; 647 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 648 pdraw->have_back = 1; 649 } 650 651} 652 653unsigned dri2GetSwapEventType(Display* dpy, XID drawable) 654{ 655 struct glx_display *glx_dpy = __glXInitialize(dpy); 656 __GLXDRIdrawable *pdraw; 657 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 658 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 659 return 0; 660 return glx_dpy->codes.first_event + GLX_BufferSwapComplete; 661} 662 663static void show_fps(struct dri2_drawable *draw) 664{ 665 const int interval = 666 ((struct dri2_screen *) draw->base.psc)->show_fps_interval; 667 struct timeval tv; 668 uint64_t current_time; 669 670 gettimeofday(&tv, NULL); 671 current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec; 672 673 draw->frames++; 674 675 if (draw->previous_time + interval * 1000000 <= current_time) { 676 if (draw->previous_time) { 677 fprintf(stderr, "libGL: FPS = %.2f\n", 678 ((uint64_t)draw->frames * 1000000) / 679 (double)(current_time - draw->previous_time)); 680 } 681 draw->frames = 0; 682 draw->previous_time = current_time; 683 } 684} 685 686static int64_t 687dri2XcbSwapBuffers(Display *dpy, 688 __GLXDRIdrawable *pdraw, 689 int64_t target_msc, 690 int64_t divisor, 691 int64_t remainder) 692{ 693 xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie; 694 xcb_dri2_swap_buffers_reply_t *swap_buffers_reply; 695 uint32_t target_msc_hi, target_msc_lo; 696 uint32_t divisor_hi, divisor_lo; 697 uint32_t remainder_hi, remainder_lo; 698 int64_t ret = 0; 699 xcb_connection_t *c = XGetXCBConnection(dpy); 700 701 split_counter(target_msc, &target_msc_hi, &target_msc_lo); 702 split_counter(divisor, &divisor_hi, &divisor_lo); 703 split_counter(remainder, &remainder_hi, &remainder_lo); 704 705 swap_buffers_cookie = 706 xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable, 707 target_msc_hi, target_msc_lo, 708 divisor_hi, divisor_lo, 709 remainder_hi, remainder_lo); 710 711 /* Immediately wait on the swapbuffers reply. If we didn't, we'd have 712 * to do so some time before reusing a (non-pageflipped) backbuffer. 713 * Otherwise, the new rendering could get ahead of the X Server's 714 * dispatch of the swapbuffer and you'd display garbage. 715 * 716 * We use XSync() first to reap the invalidate events through the event 717 * filter, to ensure that the next drawing doesn't use an invalidated 718 * buffer. 719 */ 720 XSync(dpy, False); 721 722 swap_buffers_reply = 723 xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL); 724 if (swap_buffers_reply) { 725 ret = merge_counter(swap_buffers_reply->swap_hi, 726 swap_buffers_reply->swap_lo); 727 free(swap_buffers_reply); 728 } 729 return ret; 730} 731 732static int64_t 733dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 734 int64_t remainder, Bool flush) 735{ 736 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 737 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 738 int64_t ret = 0; 739 740 /* Check we have the right attachments */ 741 if (!priv->have_back) 742 return ret; 743 744 __DRIcontext *ctx = dri2GetCurrentContext(); 745 unsigned flags = __DRI2_FLUSH_DRAWABLE; 746 if (flush) 747 flags |= __DRI2_FLUSH_CONTEXT; 748 dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); 749 750 ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw, 751 target_msc, divisor, remainder); 752 753 if (psc->show_fps_interval) { 754 show_fps(priv); 755 } 756 757 return ret; 758} 759 760static __DRIbuffer * 761dri2GetBuffers(__DRIdrawable * driDrawable, 762 int *width, int *height, 763 unsigned int *attachments, int count, 764 int *out_count, void *loaderPrivate) 765{ 766 struct dri2_drawable *pdraw = loaderPrivate; 767 DRI2Buffer *buffers; 768 769 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 770 width, height, attachments, count, out_count); 771 if (buffers == NULL) 772 return NULL; 773 774 pdraw->width = *width; 775 pdraw->height = *height; 776 process_buffers(pdraw, buffers, *out_count); 777 778 free(buffers); 779 780 return pdraw->buffers; 781} 782 783static __DRIbuffer * 784dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 785 int *width, int *height, 786 unsigned int *attachments, int count, 787 int *out_count, void *loaderPrivate) 788{ 789 struct dri2_drawable *pdraw = loaderPrivate; 790 DRI2Buffer *buffers; 791 792 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 793 pdraw->base.xDrawable, 794 width, height, attachments, 795 count, out_count); 796 if (buffers == NULL) 797 return NULL; 798 799 pdraw->width = *width; 800 pdraw->height = *height; 801 process_buffers(pdraw, buffers, *out_count); 802 803 free(buffers); 804 805 return pdraw->buffers; 806} 807 808static int 809dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 810{ 811 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 812 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 813 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 814 815 if (!dri_valid_swap_interval(psc->driScreen, psc->config, interval)) 816 return GLX_BAD_VALUE; 817 818 xcb_dri2_swap_interval(c, priv->base.xDrawable, interval); 819 priv->swap_interval = interval; 820 821 return 0; 822} 823 824static int 825dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 826{ 827 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 828 829 return priv->swap_interval; 830} 831 832static void 833driSetBackgroundContext(void *loaderPrivate) 834{ 835 struct dri2_context *pcp = (struct dri2_context *) loaderPrivate; 836 __glXSetCurrentContext(&pcp->base); 837} 838 839static GLboolean 840driIsThreadSafe(void *loaderPrivate) 841{ 842 struct dri2_context *pcp = (struct dri2_context *) loaderPrivate; 843 /* Check Xlib is running in thread safe mode 844 * 845 * 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'. 846 * It wll be NULL if XInitThreads wasn't called. 847 */ 848 return pcp->base.psc->dpy->lock_fns != NULL; 849} 850 851static const __DRIdri2LoaderExtension dri2LoaderExtension = { 852 .base = { __DRI_DRI2_LOADER, 3 }, 853 854 .getBuffers = dri2GetBuffers, 855 .flushFrontBuffer = dri2FlushFrontBuffer, 856 .getBuffersWithFormat = dri2GetBuffersWithFormat, 857}; 858 859const __DRIuseInvalidateExtension dri2UseInvalidate = { 860 .base = { __DRI_USE_INVALIDATE, 1 } 861}; 862 863const __DRIbackgroundCallableExtension driBackgroundCallable = { 864 .base = { __DRI_BACKGROUND_CALLABLE, 2 }, 865 866 .setBackgroundContext = driSetBackgroundContext, 867 .isThreadSafe = driIsThreadSafe, 868}; 869 870_X_HIDDEN void 871dri2InvalidateBuffers(Display *dpy, XID drawable) 872{ 873 __GLXDRIdrawable *pdraw = 874 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 875 struct dri2_screen *psc; 876 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 877 878 if (!pdraw) 879 return; 880 881 psc = (struct dri2_screen *) pdraw->psc; 882 883 if (psc->f && psc->f->base.version >= 3 && psc->f->invalidate) 884 psc->f->invalidate(pdp->driDrawable); 885} 886 887static void 888dri2_bind_tex_image(__GLXDRIdrawable *base, 889 int buffer, const int *attrib_list) 890{ 891 struct glx_context *gc = __glXGetCurrentContext(); 892 struct dri2_context *pcp = (struct dri2_context *) gc; 893 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 894 struct dri2_screen *psc; 895 896 if (pdraw != NULL) { 897 psc = (struct dri2_screen *) base->psc; 898 899 if (psc->texBuffer->base.version >= 2 && 900 psc->texBuffer->setTexBuffer2 != NULL) { 901 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 902 pdraw->base.textureTarget, 903 pdraw->base.textureFormat, 904 pdraw->driDrawable); 905 } 906 else { 907 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 908 pdraw->base.textureTarget, 909 pdraw->driDrawable); 910 } 911 } 912} 913 914static void 915dri2_release_tex_image(__GLXDRIdrawable *base, int buffer) 916{ 917 struct glx_context *gc = __glXGetCurrentContext(); 918 struct dri2_context *pcp = (struct dri2_context *) gc; 919 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 920 struct dri2_screen *psc; 921 922 if (pdraw != NULL) { 923 psc = (struct dri2_screen *) base->psc; 924 925 if (psc->texBuffer->base.version >= 3 && 926 psc->texBuffer->releaseTexBuffer != NULL) { 927 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 928 pdraw->base.textureTarget, 929 pdraw->driDrawable); 930 } 931 } 932} 933 934static const struct glx_context_vtable dri2_context_vtable = { 935 .destroy = dri2_destroy_context, 936 .bind = dri2_bind_context, 937 .unbind = dri2_unbind_context, 938 .wait_gl = dri2_wait_gl, 939 .wait_x = dri2_wait_x, 940 .interop_query_device_info = dri2_interop_query_device_info, 941 .interop_export_object = dri2_interop_export_object 942}; 943 944static void 945dri2BindExtensions(struct dri2_screen *psc, struct glx_display * priv, 946 const char *driverName) 947{ 948 const unsigned mask = psc->dri2->getAPIMask(psc->driScreen); 949 const __DRIextension **extensions; 950 int i; 951 952 extensions = psc->core->getExtensions(psc->driScreen); 953 954 __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control"); 955 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 956 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 957 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 958 959 /* 960 * GLX_INTEL_swap_event is broken on the server side, where it's 961 * currently unconditionally enabled. This completely breaks 962 * systems running on drivers which don't support that extension. 963 * There's no way to test for its presence on this side, so instead 964 * of disabling it unconditionally, just disable it for drivers 965 * which are known to not support it. 966 * 967 * This was fixed in xserver 1.15.0 (190b03215), so now we only 968 * disable the broken driver. 969 */ 970 if (strcmp(driverName, "vmwgfx") != 0) { 971 __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event"); 972 } 973 974 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); 975 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); 976 __glXEnableDirectExtension(&psc->base, "GLX_EXT_no_config_context"); 977 978 if ((mask & ((1 << __DRI_API_GLES) | 979 (1 << __DRI_API_GLES2) | 980 (1 << __DRI_API_GLES3))) != 0) { 981 __glXEnableDirectExtension(&psc->base, 982 "GLX_EXT_create_context_es_profile"); 983 __glXEnableDirectExtension(&psc->base, 984 "GLX_EXT_create_context_es2_profile"); 985 } 986 987 for (i = 0; extensions[i]; i++) { 988 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 989 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 990 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 991 } 992 993 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 994 psc->f = (__DRI2flushExtension *) extensions[i]; 995 /* internal driver extension, no GL extension exposed */ 996 } 997 998 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 999 psc->config = (__DRI2configQueryExtension *) extensions[i]; 1000 1001 if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0))) 1002 psc->throttle = (__DRI2throttleExtension *) extensions[i]; 1003 1004 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) 1005 __glXEnableDirectExtension(&psc->base, 1006 "GLX_ARB_create_context_robustness"); 1007 1008 if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { 1009 psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; 1010 __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer"); 1011 unsigned int no_error = 0; 1012 if (psc->rendererQuery->queryInteger(psc->driScreen, 1013 __DRI2_RENDERER_HAS_NO_ERROR_CONTEXT, 1014 &no_error) == 0 && no_error) 1015 __glXEnableDirectExtension(&psc->base, 1016 "GLX_ARB_create_context_no_error"); 1017 } 1018 1019 if (strcmp(extensions[i]->name, __DRI2_INTEROP) == 0) 1020 psc->interop = (__DRI2interopExtension*)extensions[i]; 1021 1022 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) 1023 __glXEnableDirectExtension(&psc->base, 1024 "GLX_ARB_context_flush_control"); 1025 } 1026} 1027 1028static char * 1029dri2_get_driver_name(struct glx_screen *glx_screen) 1030{ 1031 struct dri2_screen *psc = (struct dri2_screen *)glx_screen; 1032 1033 return psc->driverName; 1034} 1035 1036static const struct glx_screen_vtable dri2_screen_vtable = { 1037 .create_context = dri_common_create_context, 1038 .create_context_attribs = dri2_create_context_attribs, 1039 .query_renderer_integer = dri2_query_renderer_integer, 1040 .query_renderer_string = dri2_query_renderer_string, 1041 .get_driver_name = dri2_get_driver_name, 1042}; 1043 1044static struct glx_screen * 1045dri2CreateScreen(int screen, struct glx_display * priv) 1046{ 1047 const __DRIconfig **driver_configs; 1048 const __DRIextension **extensions; 1049 const struct dri2_display *const pdp = (struct dri2_display *) 1050 priv->dri2Display; 1051 struct dri2_screen *psc; 1052 __GLXDRIscreen *psp; 1053 struct glx_config *configs = NULL, *visuals = NULL; 1054 char *driverName = NULL, *loader_driverName, *deviceName, *tmp; 1055 drm_magic_t magic; 1056 int i; 1057 1058 psc = calloc(1, sizeof *psc); 1059 if (psc == NULL) 1060 return NULL; 1061 1062 psc->fd = -1; 1063 1064 if (!glx_screen_init(&psc->base, screen, priv)) { 1065 free(psc); 1066 return NULL; 1067 } 1068 1069 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 1070 &driverName, &deviceName)) { 1071 glx_screen_cleanup(&psc->base); 1072 free(psc); 1073 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen); 1074 return NULL; 1075 } 1076 1077 psc->fd = loader_open_device(deviceName); 1078 if (psc->fd < 0) { 1079 ErrorMessageF("failed to open %s: %s\n", deviceName, strerror(errno)); 1080 goto handle_error; 1081 } 1082 1083 if (drmGetMagic(psc->fd, &magic)) { 1084 ErrorMessageF("failed to get magic\n"); 1085 goto handle_error; 1086 } 1087 1088 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 1089 ErrorMessageF("failed to authenticate magic %d\n", magic); 1090 goto handle_error; 1091 } 1092 1093 /* If Mesa knows about the appropriate driver for this fd, then trust it. 1094 * Otherwise, default to the server's value. 1095 */ 1096 loader_driverName = loader_get_driver_for_fd(psc->fd); 1097 if (loader_driverName) { 1098 free(driverName); 1099 driverName = loader_driverName; 1100 } 1101 psc->driverName = driverName; 1102 1103 extensions = driOpenDriver(driverName, &psc->driver); 1104 if (extensions == NULL) 1105 goto handle_error; 1106 1107 for (i = 0; extensions[i]; i++) { 1108 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 1109 psc->core = (__DRIcoreExtension *) extensions[i]; 1110 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 1111 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 1112 } 1113 1114 if (psc->core == NULL || psc->dri2 == NULL || psc->dri2->base.version < 3) { 1115 ErrorMessageF("core dri or dri2 extension not found\n"); 1116 goto handle_error; 1117 } 1118 1119 if (psc->dri2->base.version >= 4) { 1120 psc->driScreen = 1121 psc->dri2->createNewScreen2(screen, psc->fd, 1122 (const __DRIextension **) 1123 &pdp->loader_extensions[0], 1124 extensions, 1125 &driver_configs, psc); 1126 } else { 1127 psc->driScreen = 1128 psc->dri2->createNewScreen(screen, psc->fd, 1129 (const __DRIextension **) 1130 &pdp->loader_extensions[0], 1131 &driver_configs, psc); 1132 } 1133 1134 if (psc->driScreen == NULL) { 1135 ErrorMessageF("glx: failed to create dri2 screen\n"); 1136 goto handle_error; 1137 } 1138 1139 dri2BindExtensions(psc, priv, driverName); 1140 1141 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 1142 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 1143 1144 if (!configs || !visuals) { 1145 ErrorMessageF("No matching fbConfigs or visuals found\n"); 1146 goto handle_error; 1147 } 1148 1149 glx_config_destroy_list(psc->base.configs); 1150 psc->base.configs = configs; 1151 glx_config_destroy_list(psc->base.visuals); 1152 psc->base.visuals = visuals; 1153 1154 psc->driver_configs = driver_configs; 1155 1156 psc->base.vtable = &dri2_screen_vtable; 1157 psc->base.context_vtable = &dri2_context_vtable; 1158 psp = &psc->vtable; 1159 psc->base.driScreen = psp; 1160 psp->destroyScreen = dri2DestroyScreen; 1161 psp->createDrawable = dri2CreateDrawable; 1162 psp->swapBuffers = dri2SwapBuffers; 1163 psp->getDrawableMSC = NULL; 1164 psp->waitForMSC = NULL; 1165 psp->waitForSBC = NULL; 1166 psp->setSwapInterval = NULL; 1167 psp->getSwapInterval = NULL; 1168 psp->getBufferAge = NULL; 1169 psp->bindTexImage = dri2_bind_tex_image; 1170 psp->releaseTexImage = dri2_release_tex_image; 1171 1172 psp->getDrawableMSC = dri2DrawableGetMSC; 1173 psp->waitForMSC = dri2WaitForMSC; 1174 psp->waitForSBC = dri2WaitForSBC; 1175 psp->setSwapInterval = dri2SetSwapInterval; 1176 psp->getSwapInterval = dri2GetSwapInterval; 1177 psp->maxSwapInterval = INT_MAX; 1178 1179 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 1180 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 1181 1182 if (psc->config->base.version > 1 && 1183 psc->config->configQuerys(psc->driScreen, "glx_extension_override", 1184 &tmp) == 0) 1185 __glXParseExtensionOverride(&psc->base, tmp); 1186 1187 if (psc->config->base.version > 1 && 1188 psc->config->configQuerys(psc->driScreen, 1189 "indirect_gl_extension_override", 1190 &tmp) == 0) 1191 __IndirectGlParseExtensionOverride(&psc->base, tmp); 1192 1193 if (psc->config->base.version > 1) { 1194 uint8_t force = false; 1195 if (psc->config->configQueryb(psc->driScreen, "force_direct_glx_context", 1196 &force) == 0) { 1197 psc->base.force_direct_context = force; 1198 } 1199 1200 uint8_t invalid_glx_destroy_window = false; 1201 if (psc->config->configQueryb(psc->driScreen, 1202 "allow_invalid_glx_destroy_window", 1203 &invalid_glx_destroy_window) == 0) { 1204 psc->base.allow_invalid_glx_destroy_window = invalid_glx_destroy_window; 1205 } 1206 } 1207 1208 /* DRI2 supports SubBuffer through DRI2CopyRegion, so it's always 1209 * available.*/ 1210 psp->copySubBuffer = dri2CopySubBuffer; 1211 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 1212 1213 free(deviceName); 1214 1215 tmp = getenv("LIBGL_SHOW_FPS"); 1216 psc->show_fps_interval = (tmp) ? atoi(tmp) : 0; 1217 if (psc->show_fps_interval < 0) 1218 psc->show_fps_interval = 0; 1219 1220 InfoMessageF("Using DRI2 for screen %d\n", screen); 1221 1222 return &psc->base; 1223 1224handle_error: 1225 CriticalErrorMessageF("failed to load driver: %s\n", driverName); 1226 1227 if (configs) 1228 glx_config_destroy_list(configs); 1229 if (visuals) 1230 glx_config_destroy_list(visuals); 1231 if (psc->driScreen) 1232 psc->core->destroyScreen(psc->driScreen); 1233 psc->driScreen = NULL; 1234 if (psc->fd >= 0) 1235 close(psc->fd); 1236 if (psc->driver) 1237 dlclose(psc->driver); 1238 1239 free(deviceName); 1240 glx_screen_cleanup(&psc->base); 1241 free(psc); 1242 1243 return NULL; 1244} 1245 1246/* Called from __glXFreeDisplayPrivate. 1247 */ 1248static void 1249dri2DestroyDisplay(__GLXDRIdisplay * dpy) 1250{ 1251 struct dri2_display *pdp = (struct dri2_display *) dpy; 1252 1253 __glxHashDestroy(pdp->dri2Hash); 1254 free(dpy); 1255} 1256 1257_X_HIDDEN __GLXDRIdrawable * 1258dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 1259{ 1260 struct glx_display *d = __glXInitialize(dpy); 1261 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 1262 __GLXDRIdrawable *pdraw; 1263 1264 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 1265 return pdraw; 1266 1267 return NULL; 1268} 1269 1270/* 1271 * Allocate, initialize and return a __DRIdisplayPrivate object. 1272 * This is called from __glXInitialize() when we are given a new 1273 * display pointer. 1274 */ 1275_X_HIDDEN __GLXDRIdisplay * 1276dri2CreateDisplay(Display * dpy) 1277{ 1278 struct dri2_display *pdp; 1279 int eventBase, errorBase, i; 1280 int driMajor, driMinor; 1281 1282 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 1283 return NULL; 1284 1285 pdp = malloc(sizeof *pdp); 1286 if (pdp == NULL) 1287 return NULL; 1288 1289 if (!DRI2QueryVersion(dpy, &driMajor, &driMinor) || 1290 driMinor < 3) { 1291 free(pdp); 1292 return NULL; 1293 } 1294 1295 pdp->base.destroyDisplay = dri2DestroyDisplay; 1296 pdp->base.createScreen = dri2CreateScreen; 1297 1298 i = 0; 1299 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 1300 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 1301 pdp->loader_extensions[i++] = &driBackgroundCallable.base; 1302 pdp->loader_extensions[i++] = NULL; 1303 1304 pdp->dri2Hash = __glxHashCreate(); 1305 if (pdp->dri2Hash == NULL) { 1306 free(pdp); 1307 return NULL; 1308 } 1309 1310 return &pdp->base; 1311} 1312 1313#endif /* GLX_DIRECT_RENDERING */ 1314