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