1/* 2 * Copyright © Microsoft Corporation 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 <egldriver.h> 25#include <egllog.h> 26#include <eglcurrent.h> 27#include <eglcontext.h> 28#include <eglsurface.h> 29 30#include "egl_wgl.h" 31 32#include <stw_device.h> 33#include <stw_pixelformat.h> 34#include <stw_context.h> 35#include <stw_framebuffer.h> 36 37#include <GL/wglext.h> 38 39#include <pipe/p_screen.h> 40 41#include <mapi/glapi/glapi.h> 42 43static EGLBoolean 44wgl_match_config(const _EGLConfig *conf, const _EGLConfig *criteria) 45{ 46 if (_eglCompareConfigs(conf, criteria, NULL, EGL_FALSE) != 0) 47 return EGL_FALSE; 48 49 if (!_eglMatchConfig(conf, criteria)) 50 return EGL_FALSE; 51 52 return EGL_TRUE; 53} 54 55static struct wgl_egl_config * 56wgl_add_config(_EGLDisplay *disp, const struct stw_pixelformat_info *stw_config, int id, EGLint surface_type) 57{ 58 struct wgl_egl_config *conf; 59 struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp); 60 _EGLConfig base; 61 unsigned int double_buffer; 62 int wgl_shifts[4] = { -1, -1, -1, -1 }; 63 unsigned int wgl_sizes[4] = { 0, 0, 0, 0 }; 64 _EGLConfig *matching_config; 65 EGLint num_configs = 0; 66 EGLint config_id; 67 68 _eglInitConfig(&base, disp, id); 69 70 double_buffer = (stw_config->pfd.dwFlags & PFD_DOUBLEBUFFER) != 0; 71 72 if (stw_config->pfd.iPixelType != PFD_TYPE_RGBA) 73 return NULL; 74 75 wgl_sizes[0] = stw_config->pfd.cRedBits; 76 wgl_sizes[1] = stw_config->pfd.cGreenBits; 77 wgl_sizes[2] = stw_config->pfd.cBlueBits; 78 wgl_sizes[3] = stw_config->pfd.cAlphaBits; 79 80 base.RedSize = stw_config->pfd.cRedBits; 81 base.GreenSize = stw_config->pfd.cGreenBits; 82 base.BlueSize = stw_config->pfd.cBlueBits; 83 base.AlphaSize = stw_config->pfd.cAlphaBits; 84 base.BufferSize = stw_config->pfd.cColorBits; 85 86 wgl_shifts[0] = stw_config->pfd.cRedShift; 87 wgl_shifts[1] = stw_config->pfd.cGreenShift; 88 wgl_shifts[2] = stw_config->pfd.cBlueShift; 89 wgl_shifts[3] = stw_config->pfd.cAlphaShift; 90 91 if (stw_config->pfd.cAccumBits) { 92 /* Don't expose visuals with the accumulation buffer. */ 93 return NULL; 94 } 95 96 base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH; 97 base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT; 98 99 base.DepthSize = stw_config->pfd.cDepthBits; 100 base.StencilSize = stw_config->pfd.cStencilBits; 101 base.Samples = stw_config->stvis.samples; 102 base.SampleBuffers = base.Samples > 1; 103 104 base.NativeRenderable = EGL_TRUE; 105 106 if (surface_type & EGL_PBUFFER_BIT) { 107 base.BindToTextureRGB = stw_config->bindToTextureRGB; 108 if (base.AlphaSize > 0) 109 base.BindToTextureRGBA = stw_config->bindToTextureRGBA; 110 } 111 112 if (double_buffer) { 113 surface_type &= ~EGL_PIXMAP_BIT; 114 } 115 116 if (!(stw_config->pfd.dwFlags & PFD_DRAW_TO_WINDOW)) { 117 surface_type &= ~EGL_WINDOW_BIT; 118 } 119 120 if (!surface_type) 121 return NULL; 122 123 base.SurfaceType = surface_type; 124 base.RenderableType = disp->ClientAPIs; 125 base.Conformant = disp->ClientAPIs; 126 127 base.MinSwapInterval = 0; 128 base.MaxSwapInterval = 1; 129 130 if (!_eglValidateConfig(&base, EGL_FALSE)) { 131 _eglLog(_EGL_DEBUG, "wgl: failed to validate config %d", id); 132 return NULL; 133 } 134 135 config_id = base.ConfigID; 136 base.ConfigID = EGL_DONT_CARE; 137 base.SurfaceType = EGL_DONT_CARE; 138 num_configs = _eglFilterArray(disp->Configs, (void **)&matching_config, 1, 139 (_EGLArrayForEach)wgl_match_config, &base); 140 141 if (num_configs == 1) { 142 conf = (struct wgl_egl_config *)matching_config; 143 144 if (!conf->stw_config[double_buffer]) 145 conf->stw_config[double_buffer] = stw_config; 146 else 147 /* a similar config type is already added (unlikely) => discard */ 148 return NULL; 149 } 150 else if (num_configs == 0) { 151 conf = calloc(1, sizeof * conf); 152 if (conf == NULL) 153 return NULL; 154 155 conf->stw_config[double_buffer] = stw_config; 156 157 memcpy(&conf->base, &base, sizeof base); 158 conf->base.SurfaceType = 0; 159 conf->base.ConfigID = config_id; 160 161 _eglLinkConfig(&conf->base); 162 } 163 else { 164 unreachable("duplicates should not be possible"); 165 return NULL; 166 } 167 168 conf->base.SurfaceType |= surface_type; 169 170 return conf; 171} 172 173static EGLBoolean 174wgl_add_configs(_EGLDisplay *disp, HDC hdc) 175{ 176 unsigned int config_count = 0; 177 unsigned surface_type = EGL_PBUFFER_BIT | (hdc ? EGL_WINDOW_BIT : 0); 178 179 // This is already a filtered set of what the driver supports, 180 // and there's no further filtering needed per-visual 181 for (unsigned i = 1; stw_pixelformat_get_info(i) != NULL; i++) { 182 183 struct wgl_egl_config *wgl_conf = wgl_add_config(disp, stw_pixelformat_get_info(i), 184 config_count + 1, surface_type); 185 186 if (wgl_conf) { 187 if (wgl_conf->base.ConfigID == config_count + 1) 188 config_count++; 189 } 190 } 191 192 return (config_count != 0); 193} 194 195static void 196wgl_display_destroy(_EGLDisplay *disp) 197{ 198 free(disp); 199} 200 201static EGLBoolean 202wgl_initialize_impl(_EGLDisplay *disp, HDC hdc) 203{ 204 struct wgl_egl_display *wgl_dpy; 205 const char* err; 206 207 wgl_dpy = calloc(1, sizeof * wgl_dpy); 208 if (!wgl_dpy) 209 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 210 211 disp->DriverData = (void *)wgl_dpy; 212 213 if (!stw_init_screen(hdc)) { 214 err = "wgl: failed to initialize screen"; 215 goto cleanup; 216 } 217 218 wgl_dpy->screen = stw_get_device()->screen; 219 220 disp->ClientAPIs = 0; 221 if (_eglIsApiValid(EGL_OPENGL_API)) 222 disp->ClientAPIs |= EGL_OPENGL_BIT; 223 if (_eglIsApiValid(EGL_OPENGL_ES_API)) 224 disp->ClientAPIs |= EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR; 225 226 disp->Extensions.KHR_no_config_context = EGL_TRUE; 227 disp->Extensions.KHR_surfaceless_context = EGL_TRUE; 228 disp->Extensions.MESA_query_driver = EGL_TRUE; 229 230 /* Report back to EGL the bitmask of priorities supported */ 231 disp->Extensions.IMG_context_priority = 232 wgl_dpy->screen->get_param(wgl_dpy->screen, PIPE_CAP_CONTEXT_PRIORITY_MASK); 233 234 disp->Extensions.EXT_pixel_format_float = EGL_TRUE; 235 236 if (wgl_dpy->screen->is_format_supported(wgl_dpy->screen, 237 PIPE_FORMAT_B8G8R8A8_SRGB, 238 PIPE_TEXTURE_2D, 0, 0, 239 PIPE_BIND_RENDER_TARGET)) 240 disp->Extensions.KHR_gl_colorspace = EGL_TRUE; 241 242 disp->Extensions.KHR_create_context = EGL_TRUE; 243 disp->Extensions.KHR_reusable_sync = EGL_TRUE; 244 245#if 0 246 disp->Extensions.KHR_image_base = EGL_TRUE; 247 disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; 248 if (wgl_dpy->image->base.version >= 5 && 249 wgl_dpy->image->createImageFromTexture) { 250 disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; 251 disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE; 252 253 if (wgl_renderer_query_integer(wgl_dpy, 254 __wgl_RENDERER_HAS_TEXTURE_3D)) 255 disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE; 256 } 257#endif 258 259 if (!wgl_add_configs(disp, hdc)) { 260 err = "wgl: failed to add configs"; 261 goto cleanup; 262 } 263 264 return EGL_TRUE; 265 266cleanup: 267 wgl_display_destroy(disp); 268 return _eglError(EGL_NOT_INITIALIZED, err); 269} 270 271static EGLBoolean 272wgl_initialize(_EGLDisplay *disp) 273{ 274 EGLBoolean ret = EGL_FALSE; 275 struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp); 276 277 /* In the case where the application calls eglMakeCurrent(context1), 278 * eglTerminate, then eglInitialize again (without a call to eglReleaseThread 279 * or eglMakeCurrent(NULL) before that), wgl_dpy structure is still 280 * initialized, as we need it to be able to free context1 correctly. 281 * 282 * It would probably be safest to forcibly release the display with 283 * wgl_display_release, to make sure the display is reinitialized correctly. 284 * However, the EGL spec states that we need to keep a reference to the 285 * current context (so we cannot call wgl_make_current(NULL)), and therefore 286 * we would leak context1 as we would be missing the old display connection 287 * to free it up correctly. 288 */ 289 if (wgl_dpy) { 290 wgl_dpy->ref_count++; 291 return EGL_TRUE; 292 } 293 294 switch (disp->Platform) { 295 case _EGL_PLATFORM_SURFACELESS: 296 ret = wgl_initialize_impl(disp, NULL); 297 break; 298 case _EGL_PLATFORM_WINDOWS: 299 ret = wgl_initialize_impl(disp, disp->PlatformDisplay); 300 break; 301 default: 302 unreachable("Callers ensure we cannot get here."); 303 return EGL_FALSE; 304 } 305 306 if (!ret) 307 return EGL_FALSE; 308 309 wgl_dpy = wgl_egl_display(disp); 310 wgl_dpy->ref_count++; 311 312 return EGL_TRUE; 313} 314 315/** 316 * Decrement display reference count, and free up display if necessary. 317 */ 318static void 319wgl_display_release(_EGLDisplay *disp) 320{ 321 struct wgl_egl_display *wgl_dpy; 322 323 if (!disp) 324 return; 325 326 wgl_dpy = wgl_egl_display(disp); 327 328 assert(wgl_dpy->ref_count > 0); 329 wgl_dpy->ref_count--; 330 331 if (wgl_dpy->ref_count > 0) 332 return; 333 334 _eglCleanupDisplay(disp); 335 wgl_display_destroy(disp); 336} 337 338/** 339 * Called via eglTerminate(), drv->Terminate(). 340 * 341 * This must be guaranteed to be called exactly once, even if eglTerminate is 342 * called many times (without a eglInitialize in between). 343 */ 344static EGLBoolean 345wgl_terminate(_EGLDisplay *disp) 346{ 347 /* Release all non-current Context/Surfaces. */ 348 _eglReleaseDisplayResources(disp); 349 350 wgl_display_release(disp); 351 352 return EGL_TRUE; 353} 354 355/** 356 * Called via eglCreateContext(), drv->CreateContext(). 357 */ 358static _EGLContext * 359wgl_create_context(_EGLDisplay *disp, _EGLConfig *conf, 360 _EGLContext *share_list, const EGLint *attrib_list) 361{ 362 struct wgl_egl_context *wgl_ctx; 363 struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp); 364 struct wgl_egl_context *wgl_ctx_shared = wgl_egl_context(share_list); 365 struct stw_context *shared = 366 wgl_ctx_shared ? wgl_ctx_shared->ctx : NULL; 367 struct wgl_egl_config *wgl_config = wgl_egl_config(conf); 368 const struct stw_pixelformat_info *stw_config; 369 370 wgl_ctx = malloc(sizeof * wgl_ctx); 371 if (!wgl_ctx) { 372 _eglError(EGL_BAD_ALLOC, "eglCreateContext"); 373 return NULL; 374 } 375 376 if (!_eglInitContext(&wgl_ctx->base, disp, conf, attrib_list)) 377 goto cleanup; 378 379 /* The EGL_EXT_create_context_robustness spec says: 380 * 381 * "Add to the eglCreateContext context creation errors: [...] 382 * 383 * * If the reset notification behavior of <share_context> and the 384 * newly created context are different then an EGL_BAD_MATCH error is 385 * generated." 386 */ 387 if (share_list && share_list->ResetNotificationStrategy != 388 wgl_ctx->base.ResetNotificationStrategy) { 389 _eglError(EGL_BAD_MATCH, "eglCreateContext"); 390 goto cleanup; 391 } 392 393 /* The EGL_KHR_create_context_no_error spec says: 394 * 395 * "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR 396 * used to create <share_context> does not match the value of 397 * EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created." 398 */ 399 if (share_list && share_list->NoError != wgl_ctx->base.NoError) { 400 _eglError(EGL_BAD_MATCH, "eglCreateContext"); 401 goto cleanup; 402 } 403 404 unsigned profile_mask = 0; 405 switch (wgl_ctx->base.ClientAPI) { 406 case EGL_OPENGL_ES_API: 407 profile_mask = WGL_CONTEXT_ES_PROFILE_BIT_EXT; 408 break; 409 case EGL_OPENGL_API: 410 if ((wgl_ctx->base.ClientMajorVersion >= 4 411 || (wgl_ctx->base.ClientMajorVersion == 3 412 && wgl_ctx->base.ClientMinorVersion >= 2)) 413 && wgl_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR) 414 profile_mask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; 415 else if (wgl_ctx->base.ClientMajorVersion == 3 && 416 wgl_ctx->base.ClientMinorVersion == 1) 417 profile_mask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; 418 else 419 profile_mask = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; 420 break; 421 default: 422 _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); 423 free(wgl_ctx); 424 return NULL; 425 } 426 427 if (conf != NULL) { 428 /* The config chosen here isn't necessarily 429 * used for surfaces later. 430 * A pixmap surface will use the single config. 431 * This opportunity depends on disabling the 432 * doubleBufferMode check in 433 * src/mesa/main/context.c:check_compatible() 434 */ 435 if (wgl_config->stw_config[1]) 436 stw_config = wgl_config->stw_config[1]; 437 else 438 stw_config = wgl_config->stw_config[0]; 439 } 440 else 441 stw_config = NULL; 442 443 unsigned flags = 0; 444 if (wgl_ctx->base.Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) 445 flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; 446 if (wgl_ctx->base.Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) 447 flags |= WGL_CONTEXT_DEBUG_BIT_ARB; 448 wgl_ctx->ctx = stw_create_context_attribs(disp->PlatformDisplay, 0, shared, 449 wgl_ctx->base.ClientMajorVersion, 450 wgl_ctx->base.ClientMinorVersion, 451 flags, 452 profile_mask, 453 stw_config->iPixelFormat); 454 455 if (!wgl_ctx->ctx) 456 goto cleanup; 457 458 return &wgl_ctx->base; 459 460cleanup: 461 free(wgl_ctx); 462 return NULL; 463} 464 465/** 466 * Called via eglDestroyContext(), drv->DestroyContext(). 467 */ 468static EGLBoolean 469wgl_destroy_context(_EGLDisplay *disp, _EGLContext *ctx) 470{ 471 struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx); 472 struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp); 473 474 if (_eglPutContext(ctx)) { 475 stw_destroy_context(wgl_ctx->ctx); 476 free(wgl_ctx); 477 } 478 479 return EGL_TRUE; 480} 481 482static EGLBoolean 483wgl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) 484{ 485 struct wgl_egl_surface *wgl_surf = wgl_egl_surface(surf); 486 487 if (!_eglPutSurface(surf)) 488 return EGL_TRUE; 489 490 struct stw_context *ctx = stw_current_context(); 491 stw_framebuffer_lock(wgl_surf->fb); 492 stw_framebuffer_release_locked(wgl_surf->fb, ctx ? ctx->st : NULL); 493 return EGL_TRUE; 494} 495 496static void 497wgl_gl_flush() 498{ 499 static void (*glFlush)(void); 500 static mtx_t glFlushMutex = _MTX_INITIALIZER_NP; 501 502 mtx_lock(&glFlushMutex); 503 if (!glFlush) 504 glFlush = _glapi_get_proc_address("glFlush"); 505 mtx_unlock(&glFlushMutex); 506 507 /* if glFlush is not available things are horribly broken */ 508 if (!glFlush) { 509 _eglLog(_EGL_WARNING, "wgl: failed to find glFlush entry point"); 510 return; 511 } 512 513 glFlush(); 514} 515 516/** 517 * Called via eglMakeCurrent(), drv->MakeCurrent(). 518 */ 519static EGLBoolean 520wgl_make_current(_EGLDisplay *disp, _EGLSurface *dsurf, 521 _EGLSurface *rsurf, _EGLContext *ctx) 522{ 523 struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp); 524 struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx); 525 _EGLDisplay *old_disp = NULL; 526 struct wgl_egl_display *old_wgl_dpy = NULL; 527 _EGLContext *old_ctx; 528 _EGLSurface *old_dsurf, *old_rsurf; 529 _EGLSurface *tmp_dsurf, *tmp_rsurf; 530 struct stw_framebuffer *ddraw, *rdraw; 531 struct stw_context *cctx; 532 EGLint egl_error = EGL_SUCCESS; 533 534 if (!wgl_dpy) 535 return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent"); 536 537 /* make new bindings, set the EGL error otherwise */ 538 if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) 539 return EGL_FALSE; 540 541 if (old_ctx) { 542 struct stw_context *old_cctx = wgl_egl_context(old_ctx)->ctx; 543 old_disp = old_ctx->Resource.Display; 544 old_wgl_dpy = wgl_egl_display(old_disp); 545 546 /* flush before context switch */ 547 wgl_gl_flush(); 548 549#if 0 550 if (old_dsurf) 551 wgl_surf_update_fence_fd(old_ctx, disp, old_dsurf); 552 553 /* Disable shared buffer mode */ 554 if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) && 555 old_wgl_dpy->vtbl->set_shared_buffer_mode) { 556 old_wgl_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false); 557 } 558#endif 559 560 stw_unbind_context(old_cctx); 561 } 562 563 ddraw = (dsurf) ? wgl_egl_surface(dsurf)->fb : NULL; 564 rdraw = (rsurf) ? wgl_egl_surface(rsurf)->fb : NULL; 565 cctx = (wgl_ctx) ? wgl_ctx->ctx : NULL; 566 567 if (cctx || ddraw || rdraw) { 568 if (!stw_make_current(ddraw, rdraw, cctx)) { 569 _EGLContext *tmp_ctx; 570 571 /* stw_make_current failed. We cannot tell for sure why, but 572 * setting the error to EGL_BAD_MATCH is surely better than leaving it 573 * as EGL_SUCCESS. 574 */ 575 egl_error = EGL_BAD_MATCH; 576 577 /* undo the previous _eglBindContext */ 578 _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf); 579 assert(&wgl_ctx->base == ctx && 580 tmp_dsurf == dsurf && 581 tmp_rsurf == rsurf); 582 583 _eglPutSurface(dsurf); 584 _eglPutSurface(rsurf); 585 _eglPutContext(ctx); 586 587 _eglPutSurface(old_dsurf); 588 _eglPutSurface(old_rsurf); 589 _eglPutContext(old_ctx); 590 591 ddraw = (old_dsurf) ? wgl_egl_surface(old_dsurf)->fb : NULL; 592 rdraw = (old_rsurf) ? wgl_egl_surface(old_rsurf)->fb : NULL; 593 cctx = (old_ctx) ? wgl_egl_context(old_ctx)->ctx : NULL; 594 595 /* undo the previous wgl_dpy->core->unbindContext */ 596 if (stw_make_current(ddraw, rdraw, cctx)) { 597#if 0 598 if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) && 599 old_wgl_dpy->vtbl->set_shared_buffer_mode) { 600 old_wgl_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true); 601 } 602#endif 603 604 return _eglError(egl_error, "eglMakeCurrent"); 605 } 606 607 /* We cannot restore the same state as it was before calling 608 * eglMakeCurrent() and the spec isn't clear about what to do. We 609 * can prevent EGL from calling into the DRI driver with no DRI 610 * context bound. 611 */ 612 dsurf = rsurf = NULL; 613 ctx = NULL; 614 615 _eglBindContext(ctx, dsurf, rsurf, &tmp_ctx, &tmp_dsurf, &tmp_rsurf); 616 assert(tmp_ctx == old_ctx && tmp_dsurf == old_dsurf && 617 tmp_rsurf == old_rsurf); 618 619 _eglLog(_EGL_WARNING, "wgl: failed to rebind the previous context"); 620 } 621 else { 622 /* wgl_dpy->core->bindContext succeeded, so take a reference on the 623 * wgl_dpy. This prevents wgl_dpy from being reinitialized when a 624 * EGLDisplay is terminated and then initialized again while a 625 * context is still bound. See wgl_intitialize() for a more in depth 626 * explanation. */ 627 wgl_dpy->ref_count++; 628 } 629 } 630 631 wgl_destroy_surface(disp, old_dsurf); 632 wgl_destroy_surface(disp, old_rsurf); 633 634 if (old_ctx) { 635 wgl_destroy_context(disp, old_ctx); 636 wgl_display_release(old_disp); 637 } 638 639 if (egl_error != EGL_SUCCESS) 640 return _eglError(egl_error, "eglMakeCurrent"); 641 642#if 0 643 if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) && 644 wgl_dpy->vtbl->set_shared_buffer_mode) { 645 /* Always update the shared buffer mode. This is obviously needed when 646 * the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When 647 * EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the 648 * case where external non-EGL API may have changed window's shared 649 * buffer mode since we last saw it. 650 */ 651 bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER); 652 wgl_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode); 653 } 654#endif 655 656 return EGL_TRUE; 657} 658 659static _EGLSurface* 660wgl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, 661 void *native_window, const EGLint *attrib_list) 662{ 663 struct wgl_egl_config *wgl_conf = wgl_egl_config(conf); 664 665 struct wgl_egl_surface *wgl_surf = calloc(1, sizeof(*wgl_surf)); 666 if (!wgl_surf) 667 return NULL; 668 669 if (!_eglInitSurface(&wgl_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, native_window)) { 670 free(wgl_surf); 671 return NULL; 672 } 673 674 const struct stw_pixelformat_info *stw_conf = wgl_conf->stw_config[1] ? 675 wgl_conf->stw_config[1] : wgl_conf->stw_config[0]; 676 wgl_surf->fb = stw_framebuffer_create(native_window, stw_conf->iPixelFormat, STW_FRAMEBUFFER_EGL_WINDOW); 677 if (!wgl_surf->fb) { 678 free(wgl_surf); 679 return NULL; 680 } 681 682 stw_framebuffer_unlock(wgl_surf->fb); 683 684 return &wgl_surf->base; 685} 686 687static EGLBoolean 688wgl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) 689{ 690 struct wgl_egl_display *wgl_disp = wgl_egl_display(disp); 691 struct wgl_egl_surface *wgl_surf = wgl_egl_surface(draw); 692 693 stw_framebuffer_lock(wgl_surf->fb); 694 HDC hdc = GetDC(wgl_surf->fb->hWnd); 695 BOOL ret = stw_framebuffer_swap_locked(hdc, wgl_surf->fb); 696 ReleaseDC(wgl_surf->fb->hWnd, hdc); 697 698 return ret; 699} 700 701struct _egl_driver _eglDriver = { 702 .Initialize = wgl_initialize, 703 .Terminate = wgl_terminate, 704 .CreateContext = wgl_create_context, 705 .DestroyContext = wgl_destroy_context, 706 .MakeCurrent = wgl_make_current, 707 .CreateWindowSurface = wgl_create_window_surface, 708 .DestroySurface = wgl_destroy_surface, 709 .GetProcAddress = _glapi_get_proc_address, 710 .SwapBuffers = wgl_swap_buffers, 711}; 712 713