1 /* 2 * Copyright 2014 Jon Turney 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 #include "glxclient.h" 25 #include "glx_error.h" 26 #include "dri_common.h" 27 #include "util/macros.h" 28 #include "windows/xwindowsdri.h" 29 #include "windows/windowsgl.h" 30 31 struct driwindows_display 32 { 33 __GLXDRIdisplay base; 34 int event_base; 35 }; 36 37 struct driwindows_context 38 { 39 struct glx_context base; 40 windowsContext *windowsContext; 41 }; 42 43 struct driwindows_config 44 { 45 struct glx_config base; 46 int pxfi; 47 }; 48 49 struct driwindows_screen 50 { 51 struct glx_screen base; 52 __DRIscreen *driScreen; 53 __GLXDRIscreen vtable; 54 Bool copySubBuffer; 55 }; 56 57 struct driwindows_drawable 58 { 59 __GLXDRIdrawable base; 60 windowsDrawable *windowsDrawable; 61 }; 62 63 /** 64 * GLXDRI functions 65 */ 66 67 static void 68 driwindows_destroy_context(struct glx_context *context) 69 { 70 struct driwindows_context *pcp = (struct driwindows_context *) context; 71 72 driReleaseDrawables(&pcp->base); 73 74 free((char *) context->extensions); 75 76 windows_destroy_context(pcp->windowsContext); 77 78 free(pcp); 79 } 80 81 static int 82 driwindows_bind_context(struct glx_context *context, struct glx_context *old, 83 GLXDrawable draw, GLXDrawable read) 84 { 85 struct driwindows_context *pcp = (struct driwindows_context *) context; 86 struct driwindows_drawable *pdraw, *pread; 87 88 pdraw = (struct driwindows_drawable *) driFetchDrawable(context, draw); 89 pread = (struct driwindows_drawable *) driFetchDrawable(context, read); 90 91 driReleaseDrawables(&pcp->base); 92 93 if (pdraw == NULL || pread == NULL) 94 return GLXBadDrawable; 95 96 if (windows_bind_context(pcp->windowsContext, 97 pdraw->windowsDrawable, pread->windowsDrawable)) 98 return Success; 99 100 return GLXBadContext; 101 } 102 103 static void 104 driwindows_unbind_context(struct glx_context *context, struct glx_context *new) 105 { 106 struct driwindows_context *pcp = (struct driwindows_context *) context; 107 108 windows_unbind_context(pcp->windowsContext); 109 } 110 111 static void 112 driwindows_bind_tex_image(Display * dpy, 113 GLXDrawable drawable, 114 int buffer, const int *attrib_list) 115 { 116 struct glx_context *gc = __glXGetCurrentContext(); 117 struct driwindows_context *pcp = (struct driwindows_context *) gc; 118 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 119 struct driwindows_drawable *pdraw = (struct driwindows_drawable *) base; 120 121 __glXInitialize(dpy); 122 123 if (pdraw != NULL) { 124 windows_setTexBuffer(pcp->windowsContext, 125 pdraw->base.textureTarget, 126 pdraw->base.textureFormat, 127 pdraw->windowsDrawable); 128 } 129 } 130 131 static void 132 driwindows_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 133 { 134 struct glx_context *gc = __glXGetCurrentContext(); 135 struct driwindows_context *pcp = (struct driwindows_context *) gc; 136 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 137 struct glx_display *dpyPriv = __glXInitialize(dpy); 138 struct driwindows_drawable *pdraw = (struct driwindows_drawable *) base; 139 140 if (dpyPriv != NULL && pdraw != NULL) { 141 windows_releaseTexBuffer(pcp->windowsContext, 142 pdraw->base.textureTarget, 143 pdraw->windowsDrawable); 144 } 145 } 146 147 static const struct glx_context_vtable driwindows_context_vtable = { 148 .destroy = driwindows_destroy_context, 149 .bind = driwindows_bind_context, 150 .unbind = driwindows_unbind_context, 151 .wait_gl = NULL, 152 .wait_x = NULL, 153 .use_x_font = DRI_glXUseXFont, 154 .bind_tex_image = driwindows_bind_tex_image, 155 .release_tex_image = driwindows_release_tex_image, 156 .get_proc_address = NULL, 157 }; 158 159 static struct glx_context * 160 driwindows_create_context(struct glx_screen *base, 161 struct glx_config *config_base, 162 struct glx_context *shareList, int renderType) 163 { 164 struct driwindows_context *pcp, *pcp_shared; 165 struct driwindows_config *config = (struct driwindows_config *) config_base; 166 struct driwindows_screen *psc = (struct driwindows_screen *) base; 167 windowsContext *shared = NULL; 168 169 if (!psc->base.driScreen) 170 return NULL; 171 172 /* Check the renderType value */ 173 if (!validate_renderType_against_config(config_base, renderType)) 174 return NULL; 175 176 if (shareList) { 177 /* If the shareList context is not on this renderer, we cannot possibly 178 * create a context that shares with it. 179 */ 180 if (shareList->vtable->destroy != driwindows_destroy_context) { 181 return NULL; 182 } 183 184 pcp_shared = (struct driwindows_context *) shareList; 185 shared = pcp_shared->windowsContext; 186 } 187 188 pcp = calloc(1, sizeof *pcp); 189 if (pcp == NULL) 190 return NULL; 191 192 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 193 free(pcp); 194 return NULL; 195 } 196 197 pcp->base.renderType = renderType; 198 199 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi); 200 201 pcp->windowsContext = windows_create_context(config->pxfi, shared); 202 203 if (!pcp->windowsContext) { 204 free(pcp); 205 return NULL; 206 } 207 208 pcp->base.vtable = &driwindows_context_vtable; 209 210 return &pcp->base; 211 } 212 213 static struct glx_context * 214 driwindows_create_context_attribs(struct glx_screen *base, 215 struct glx_config *config_base, 216 struct glx_context *shareList, 217 unsigned num_attribs, 218 const uint32_t *attribs, 219 unsigned *error) 220 { 221 struct driwindows_context *pcp, *pcp_shared; 222 struct driwindows_config *config = (struct driwindows_config *) config_base; 223 struct driwindows_screen *psc = (struct driwindows_screen *) base; 224 windowsContext *shared = NULL; 225 226 int i; 227 uint32_t renderType = GLX_RGBA_TYPE; 228 229 /* Extract renderType from attribs */ 230 for (i = 0; i < num_attribs; i++) { 231 switch (attribs[i * 2]) { 232 case GLX_RENDER_TYPE: 233 renderType = attribs[i * 2 + 1]; 234 break; 235 } 236 } 237 238 /* 239 Perhaps we should map GLX tokens to WGL tokens, but they appear to have 240 identical values, so far 241 */ 242 243 if (!psc->base.driScreen) 244 return NULL; 245 246 /* Check the renderType value */ 247 if (!validate_renderType_against_config(config_base, renderType)) { 248 return NULL; 249 } 250 251 if (shareList) { 252 /* If the shareList context is not on this renderer, we cannot possibly 253 * create a context that shares with it. 254 */ 255 if (shareList->vtable->destroy != driwindows_destroy_context) { 256 return NULL; 257 } 258 259 pcp_shared = (struct driwindows_context *) shareList; 260 shared = pcp_shared->windowsContext; 261 } 262 263 pcp = calloc(1, sizeof *pcp); 264 if (pcp == NULL) 265 return NULL; 266 267 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 268 free(pcp); 269 return NULL; 270 } 271 272 pcp->base.renderType = renderType; 273 274 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi); 275 276 pcp->windowsContext = windows_create_context_attribs(config->pxfi, 277 shared, 278 (const int *)attribs); 279 if (pcp->windowsContext == NULL) { 280 free(pcp); 281 return NULL; 282 } 283 284 pcp->base.vtable = &driwindows_context_vtable; 285 286 return &pcp->base; 287 } 288 289 static void 290 driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw) 291 { 292 struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw; 293 294 windows_destroy_drawable(pdp->windowsDrawable); 295 296 free(pdp); 297 } 298 299 static __GLXDRIdrawable * 300 driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable, 301 GLXDrawable drawable, struct glx_config *modes) 302 { 303 struct driwindows_drawable *pdp; 304 struct driwindows_screen *psc = (struct driwindows_screen *) base; 305 306 pdp = calloc(1, sizeof(*pdp)); 307 if (!pdp) 308 return NULL; 309 310 pdp->base.xDrawable = xDrawable; 311 pdp->base.drawable = drawable; 312 pdp->base.psc = &psc->base; 313 314 /* 315 By this stage, the X drawable already exists, but the GLX drawable may 316 not. 317 318 Query the server with the XID to find the correct HWND, HPBUFFERARB or 319 HBITMAP 320 */ 321 322 unsigned int type; 323 void *handle; 324 325 if (!XWindowsDRIQueryDrawable(psc->base.dpy, base->scr, drawable, &type, &handle)) 326 { 327 free(pdp); 328 return NULL; 329 } 330 331 /* No handle found is a failure */ 332 if (!handle) { 333 free(pdp); 334 return NULL; 335 } 336 337 /* Create a new drawable */ 338 pdp->windowsDrawable = windows_create_drawable(type, handle); 339 340 if (!pdp->windowsDrawable) { 341 free(pdp); 342 return NULL; 343 } 344 345 pdp->base.destroyDrawable = driwindowsDestroyDrawable; 346 347 return &pdp->base; 348 } 349 350 static int64_t 351 driwindowsSwapBuffers(__GLXDRIdrawable * pdraw, 352 int64_t target_msc, int64_t divisor, int64_t remainder, 353 Bool flush) 354 { 355 struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw; 356 357 (void) target_msc; 358 (void) divisor; 359 (void) remainder; 360 361 if (flush) { 362 glFlush(); 363 } 364 365 windows_swap_buffers(pdp->windowsDrawable); 366 367 return 0; 368 } 369 370 static void 371 driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw, 372 int x, int y, int width, int height, Bool flush) 373 { 374 struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw; 375 376 if (flush) { 377 glFlush(); 378 } 379 380 windows_copy_subbuffer(pdp->windowsDrawable, x, y, width, height); 381 } 382 383 static void 384 driwindowsDestroyScreen(struct glx_screen *base) 385 { 386 struct driwindows_screen *psc = (struct driwindows_screen *) base; 387 388 /* Free the direct rendering per screen data */ 389 psc->driScreen = NULL; 390 free(psc); 391 } 392 393 static const struct glx_screen_vtable driwindows_screen_vtable = { 394 .create_context = driwindows_create_context, 395 .create_context_attribs = driwindows_create_context_attribs, 396 .query_renderer_integer = NULL, 397 .query_renderer_string = NULL, 398 }; 399 400 static Bool 401 driwindowsBindExtensions(struct driwindows_screen *psc) 402 { 403 Bool result = 1; 404 405 const struct 406 { 407 char *wglext; 408 char *glxext; 409 Bool mandatory; 410 } extensionMap[] = { 411 { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 }, 412 { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 }, 413 { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 }, 414 // { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 }, 415 // Not exactly equivalent, needs some more glue to be written 416 { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 }, 417 { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 }, 418 { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 }, 419 { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 }, 420 { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 }, 421 { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 }, 422 { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 }, 423 }; 424 425 char *wgl_extensions; 426 char *gl_extensions; 427 int i; 428 429 windows_extensions(&gl_extensions, &wgl_extensions); 430 431 for (i = 0; i < ARRAY_SIZE(extensionMap); i++) { 432 if (strstr(wgl_extensions, extensionMap[i].wglext)) { 433 __glXEnableDirectExtension(&psc->base, extensionMap[i].glxext); 434 InfoMessageF("enabled %s\n", extensionMap[i].glxext); 435 } 436 else if (extensionMap[i].mandatory) { 437 ErrorMessageF("required WGL extension %s is missing\n", extensionMap[i].wglext); 438 result = 0; 439 } 440 } 441 442 /* 443 Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might 444 only be in GL_EXTENSIONS 445 */ 446 if (strstr(gl_extensions, "GL_WIN_swap_hint")) { 447 psc->copySubBuffer = 1; 448 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 449 InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n"); 450 } 451 452 free(gl_extensions); 453 free(wgl_extensions); 454 455 return result; 456 } 457 458 static struct glx_config * 459 driwindowsMapConfigs(struct glx_display *priv, int screen, struct glx_config *configs, struct glx_config *fbconfigs) 460 { 461 struct glx_config head, *tail, *m; 462 463 tail = &head; 464 head.next = NULL; 465 466 for (m = configs; m; m = m->next) { 467 int fbconfigID = GLX_DONT_CARE; 468 if (fbconfigs) { 469 /* 470 visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig 471 with matching visualID and get the fbconfigID from there 472 */ 473 struct glx_config *f; 474 for (f = fbconfigs; f; f = f->next) { 475 if (f->visualID == m->visualID) 476 fbconfigID = f->fbconfigID; 477 } 478 } 479 else { 480 fbconfigID = m->fbconfigID; 481 } 482 483 int pxfi; 484 XWindowsDRIFBConfigToPixelFormat(priv->dpy, screen, fbconfigID, &pxfi); 485 if (pxfi == 0) 486 continue; 487 488 struct driwindows_config *config = malloc(sizeof(*config)); 489 490 tail->next = &config->base; 491 if (tail->next == NULL) 492 continue; 493 494 config->base = *m; 495 config->pxfi = pxfi; 496 497 tail = tail->next; 498 } 499 500 return head.next; 501 } 502 503 static struct glx_screen * 504 driwindowsCreateScreen(int screen, struct glx_display *priv) 505 { 506 __GLXDRIscreen *psp; 507 struct driwindows_screen *psc; 508 struct glx_config *configs = NULL, *visuals = NULL; 509 int directCapable; 510 511 psc = calloc(1, sizeof *psc); 512 if (psc == NULL) 513 return NULL; 514 515 if (!glx_screen_init(&psc->base, screen, priv)) { 516 free(psc); 517 return NULL; 518 } 519 520 if (!XWindowsDRIQueryDirectRenderingCapable(psc->base.dpy, screen, &directCapable) || 521 !directCapable) { 522 ErrorMessageF("Screen is not Windows-DRI capable\n"); 523 goto handle_error; 524 } 525 526 /* discover native supported extensions */ 527 if (!driwindowsBindExtensions(psc)) { 528 goto handle_error; 529 } 530 531 /* Augment configs with pxfi information */ 532 configs = driwindowsMapConfigs(priv, screen, psc->base.configs, NULL); 533 visuals = driwindowsMapConfigs(priv, screen, psc->base.visuals, configs); 534 535 if (!configs || !visuals) { 536 ErrorMessageF("No fbConfigs or visuals found\n"); 537 goto handle_error; 538 } 539 540 glx_config_destroy_list(psc->base.configs); 541 psc->base.configs = configs; 542 glx_config_destroy_list(psc->base.visuals); 543 psc->base.visuals = visuals; 544 545 psc->base.vtable = &driwindows_screen_vtable; 546 psp = &psc->vtable; 547 psc->base.driScreen = psp; 548 psp->destroyScreen = driwindowsDestroyScreen; 549 psp->createDrawable = driwindowsCreateDrawable; 550 psp->swapBuffers = driwindowsSwapBuffers; 551 552 if (psc->copySubBuffer) 553 psp->copySubBuffer = driwindowsCopySubBuffer; 554 555 return &psc->base; 556 557 handle_error: 558 glx_screen_cleanup(&psc->base); 559 560 return NULL; 561 } 562 563 /* Called from __glXFreeDisplayPrivate. 564 */ 565 static void 566 driwindowsDestroyDisplay(__GLXDRIdisplay * dpy) 567 { 568 free(dpy); 569 } 570 571 /* 572 * Allocate, initialize and return a __GLXDRIdisplay object. 573 * This is called from __glXInitialize() when we are given a new 574 * display pointer. 575 */ 576 _X_HIDDEN __GLXDRIdisplay * 577 driwindowsCreateDisplay(Display * dpy) 578 { 579 struct driwindows_display *pdpyp; 580 581 int eventBase, errorBase; 582 int major, minor, patch; 583 584 /* Verify server has Windows-DRI extension */ 585 if (!XWindowsDRIQueryExtension(dpy, &eventBase, &errorBase)) { 586 ErrorMessageF("Windows-DRI extension not available\n"); 587 return NULL; 588 } 589 590 if (!XWindowsDRIQueryVersion(dpy, &major, &minor, &patch)) { 591 ErrorMessageF("Fetching Windows-DRI extension version failed\n"); 592 return NULL; 593 } 594 595 if (!windows_check_renderer()) { 596 ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n"); 597 return NULL; 598 } 599 600 pdpyp = malloc(sizeof *pdpyp); 601 if (pdpyp == NULL) 602 return NULL; 603 604 pdpyp->base.destroyDisplay = driwindowsDestroyDisplay; 605 pdpyp->base.createScreen = driwindowsCreateScreen; 606 607 pdpyp->event_base = eventBase; 608 609 return &pdpyp->base; 610 } 611