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 
43 static EGLBoolean
wgl_match_config(const _EGLConfig * conf,const _EGLConfig * criteria)44 wgl_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 
55 static struct wgl_egl_config *
wgl_add_config(_EGLDisplay * disp,const struct stw_pixelformat_info * stw_config,int id,EGLint surface_type)56 wgl_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 
173 static EGLBoolean
wgl_add_configs(_EGLDisplay * disp,HDC hdc)174 wgl_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 
195 static void
wgl_display_destroy(_EGLDisplay * disp)196 wgl_display_destroy(_EGLDisplay *disp)
197 {
198    free(disp);
199 }
200 
201 static EGLBoolean
wgl_initialize_impl(_EGLDisplay * disp,HDC hdc)202 wgl_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 
266 cleanup:
267    wgl_display_destroy(disp);
268    return _eglError(EGL_NOT_INITIALIZED, err);
269 }
270 
271 static EGLBoolean
wgl_initialize(_EGLDisplay * disp)272 wgl_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  */
318 static void
wgl_display_release(_EGLDisplay * disp)319 wgl_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  */
344 static EGLBoolean
wgl_terminate(_EGLDisplay * disp)345 wgl_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  */
358 static _EGLContext *
wgl_create_context(_EGLDisplay * disp,_EGLConfig * conf,_EGLContext * share_list,const EGLint * attrib_list)359 wgl_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 
460 cleanup:
461    free(wgl_ctx);
462    return NULL;
463 }
464 
465 /**
466  * Called via eglDestroyContext(), drv->DestroyContext().
467  */
468 static EGLBoolean
wgl_destroy_context(_EGLDisplay * disp,_EGLContext * ctx)469 wgl_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 
482 static EGLBoolean
wgl_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)483 wgl_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 
496 static void
wgl_gl_flush()497 wgl_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  */
519 static EGLBoolean
wgl_make_current(_EGLDisplay * disp,_EGLSurface * dsurf,_EGLSurface * rsurf,_EGLContext * ctx)520 wgl_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 
659 static _EGLSurface*
wgl_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)660 wgl_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 
687 static EGLBoolean
wgl_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)688 wgl_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 
701 struct _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