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