17ec681f3Smrg/*
27ec681f3Smrg * Copyright © Microsoft Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#include <egldriver.h>
257ec681f3Smrg#include <egllog.h>
267ec681f3Smrg#include <eglcurrent.h>
277ec681f3Smrg#include <eglcontext.h>
287ec681f3Smrg#include <eglsurface.h>
297ec681f3Smrg
307ec681f3Smrg#include "egl_wgl.h"
317ec681f3Smrg
327ec681f3Smrg#include <stw_device.h>
337ec681f3Smrg#include <stw_pixelformat.h>
347ec681f3Smrg#include <stw_context.h>
357ec681f3Smrg#include <stw_framebuffer.h>
367ec681f3Smrg
377ec681f3Smrg#include <GL/wglext.h>
387ec681f3Smrg
397ec681f3Smrg#include <pipe/p_screen.h>
407ec681f3Smrg
417ec681f3Smrg#include <mapi/glapi/glapi.h>
427ec681f3Smrg
437ec681f3Smrgstatic EGLBoolean
447ec681f3Smrgwgl_match_config(const _EGLConfig *conf, const _EGLConfig *criteria)
457ec681f3Smrg{
467ec681f3Smrg   if (_eglCompareConfigs(conf, criteria, NULL, EGL_FALSE) != 0)
477ec681f3Smrg      return EGL_FALSE;
487ec681f3Smrg
497ec681f3Smrg   if (!_eglMatchConfig(conf, criteria))
507ec681f3Smrg      return EGL_FALSE;
517ec681f3Smrg
527ec681f3Smrg   return EGL_TRUE;
537ec681f3Smrg}
547ec681f3Smrg
557ec681f3Smrgstatic struct wgl_egl_config *
567ec681f3Smrgwgl_add_config(_EGLDisplay *disp, const struct stw_pixelformat_info *stw_config, int id, EGLint surface_type)
577ec681f3Smrg{
587ec681f3Smrg   struct wgl_egl_config *conf;
597ec681f3Smrg   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
607ec681f3Smrg   _EGLConfig base;
617ec681f3Smrg   unsigned int double_buffer;
627ec681f3Smrg   int wgl_shifts[4] = { -1, -1, -1, -1 };
637ec681f3Smrg   unsigned int wgl_sizes[4] = { 0, 0, 0, 0 };
647ec681f3Smrg   _EGLConfig *matching_config;
657ec681f3Smrg   EGLint num_configs = 0;
667ec681f3Smrg   EGLint config_id;
677ec681f3Smrg
687ec681f3Smrg   _eglInitConfig(&base, disp, id);
697ec681f3Smrg
707ec681f3Smrg   double_buffer = (stw_config->pfd.dwFlags & PFD_DOUBLEBUFFER) != 0;
717ec681f3Smrg
727ec681f3Smrg   if (stw_config->pfd.iPixelType != PFD_TYPE_RGBA)
737ec681f3Smrg      return NULL;
747ec681f3Smrg
757ec681f3Smrg   wgl_sizes[0] = stw_config->pfd.cRedBits;
767ec681f3Smrg   wgl_sizes[1] = stw_config->pfd.cGreenBits;
777ec681f3Smrg   wgl_sizes[2] = stw_config->pfd.cBlueBits;
787ec681f3Smrg   wgl_sizes[3] = stw_config->pfd.cAlphaBits;
797ec681f3Smrg
807ec681f3Smrg   base.RedSize = stw_config->pfd.cRedBits;
817ec681f3Smrg   base.GreenSize = stw_config->pfd.cGreenBits;
827ec681f3Smrg   base.BlueSize = stw_config->pfd.cBlueBits;
837ec681f3Smrg   base.AlphaSize = stw_config->pfd.cAlphaBits;
847ec681f3Smrg   base.BufferSize = stw_config->pfd.cColorBits;
857ec681f3Smrg
867ec681f3Smrg   wgl_shifts[0] = stw_config->pfd.cRedShift;
877ec681f3Smrg   wgl_shifts[1] = stw_config->pfd.cGreenShift;
887ec681f3Smrg   wgl_shifts[2] = stw_config->pfd.cBlueShift;
897ec681f3Smrg   wgl_shifts[3] = stw_config->pfd.cAlphaShift;
907ec681f3Smrg
917ec681f3Smrg   if (stw_config->pfd.cAccumBits) {
927ec681f3Smrg      /* Don't expose visuals with the accumulation buffer. */
937ec681f3Smrg      return NULL;
947ec681f3Smrg   }
957ec681f3Smrg
967ec681f3Smrg   base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH;
977ec681f3Smrg   base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT;
987ec681f3Smrg
997ec681f3Smrg   base.DepthSize = stw_config->pfd.cDepthBits;
1007ec681f3Smrg   base.StencilSize = stw_config->pfd.cStencilBits;
1017ec681f3Smrg   base.Samples = stw_config->stvis.samples;
1027ec681f3Smrg   base.SampleBuffers = base.Samples > 1;
1037ec681f3Smrg
1047ec681f3Smrg   base.NativeRenderable = EGL_TRUE;
1057ec681f3Smrg
1067ec681f3Smrg   if (surface_type & EGL_PBUFFER_BIT) {
1077ec681f3Smrg      base.BindToTextureRGB = stw_config->bindToTextureRGB;
1087ec681f3Smrg      if (base.AlphaSize > 0)
1097ec681f3Smrg         base.BindToTextureRGBA = stw_config->bindToTextureRGBA;
1107ec681f3Smrg   }
1117ec681f3Smrg
1127ec681f3Smrg   if (double_buffer) {
1137ec681f3Smrg      surface_type &= ~EGL_PIXMAP_BIT;
1147ec681f3Smrg   }
1157ec681f3Smrg
1167ec681f3Smrg   if (!(stw_config->pfd.dwFlags & PFD_DRAW_TO_WINDOW)) {
1177ec681f3Smrg      surface_type &= ~EGL_WINDOW_BIT;
1187ec681f3Smrg   }
1197ec681f3Smrg
1207ec681f3Smrg   if (!surface_type)
1217ec681f3Smrg      return NULL;
1227ec681f3Smrg
1237ec681f3Smrg   base.SurfaceType = surface_type;
1247ec681f3Smrg   base.RenderableType = disp->ClientAPIs;
1257ec681f3Smrg   base.Conformant = disp->ClientAPIs;
1267ec681f3Smrg
1277ec681f3Smrg   base.MinSwapInterval = 0;
1287ec681f3Smrg   base.MaxSwapInterval = 1;
1297ec681f3Smrg
1307ec681f3Smrg   if (!_eglValidateConfig(&base, EGL_FALSE)) {
1317ec681f3Smrg      _eglLog(_EGL_DEBUG, "wgl: failed to validate config %d", id);
1327ec681f3Smrg      return NULL;
1337ec681f3Smrg   }
1347ec681f3Smrg
1357ec681f3Smrg   config_id = base.ConfigID;
1367ec681f3Smrg   base.ConfigID = EGL_DONT_CARE;
1377ec681f3Smrg   base.SurfaceType = EGL_DONT_CARE;
1387ec681f3Smrg   num_configs = _eglFilterArray(disp->Configs, (void **)&matching_config, 1,
1397ec681f3Smrg      (_EGLArrayForEach)wgl_match_config, &base);
1407ec681f3Smrg
1417ec681f3Smrg   if (num_configs == 1) {
1427ec681f3Smrg      conf = (struct wgl_egl_config *)matching_config;
1437ec681f3Smrg
1447ec681f3Smrg      if (!conf->stw_config[double_buffer])
1457ec681f3Smrg         conf->stw_config[double_buffer] = stw_config;
1467ec681f3Smrg      else
1477ec681f3Smrg         /* a similar config type is already added (unlikely) => discard */
1487ec681f3Smrg         return NULL;
1497ec681f3Smrg   }
1507ec681f3Smrg   else if (num_configs == 0) {
1517ec681f3Smrg      conf = calloc(1, sizeof * conf);
1527ec681f3Smrg      if (conf == NULL)
1537ec681f3Smrg         return NULL;
1547ec681f3Smrg
1557ec681f3Smrg      conf->stw_config[double_buffer] = stw_config;
1567ec681f3Smrg
1577ec681f3Smrg      memcpy(&conf->base, &base, sizeof base);
1587ec681f3Smrg      conf->base.SurfaceType = 0;
1597ec681f3Smrg      conf->base.ConfigID = config_id;
1607ec681f3Smrg
1617ec681f3Smrg      _eglLinkConfig(&conf->base);
1627ec681f3Smrg   }
1637ec681f3Smrg   else {
1647ec681f3Smrg      unreachable("duplicates should not be possible");
1657ec681f3Smrg      return NULL;
1667ec681f3Smrg   }
1677ec681f3Smrg
1687ec681f3Smrg   conf->base.SurfaceType |= surface_type;
1697ec681f3Smrg
1707ec681f3Smrg   return conf;
1717ec681f3Smrg}
1727ec681f3Smrg
1737ec681f3Smrgstatic EGLBoolean
1747ec681f3Smrgwgl_add_configs(_EGLDisplay *disp, HDC hdc)
1757ec681f3Smrg{
1767ec681f3Smrg   unsigned int config_count = 0;
1777ec681f3Smrg   unsigned surface_type = EGL_PBUFFER_BIT | (hdc ? EGL_WINDOW_BIT : 0);
1787ec681f3Smrg
1797ec681f3Smrg   // This is already a filtered set of what the driver supports,
1807ec681f3Smrg   // and there's no further filtering needed per-visual
1817ec681f3Smrg   for (unsigned i = 1; stw_pixelformat_get_info(i) != NULL; i++) {
1827ec681f3Smrg
1837ec681f3Smrg      struct wgl_egl_config *wgl_conf = wgl_add_config(disp, stw_pixelformat_get_info(i),
1847ec681f3Smrg         config_count + 1, surface_type);
1857ec681f3Smrg
1867ec681f3Smrg      if (wgl_conf) {
1877ec681f3Smrg         if (wgl_conf->base.ConfigID == config_count + 1)
1887ec681f3Smrg            config_count++;
1897ec681f3Smrg      }
1907ec681f3Smrg   }
1917ec681f3Smrg
1927ec681f3Smrg   return (config_count != 0);
1937ec681f3Smrg}
1947ec681f3Smrg
1957ec681f3Smrgstatic void
1967ec681f3Smrgwgl_display_destroy(_EGLDisplay *disp)
1977ec681f3Smrg{
1987ec681f3Smrg   free(disp);
1997ec681f3Smrg}
2007ec681f3Smrg
2017ec681f3Smrgstatic EGLBoolean
2027ec681f3Smrgwgl_initialize_impl(_EGLDisplay *disp, HDC hdc)
2037ec681f3Smrg{
2047ec681f3Smrg   struct wgl_egl_display *wgl_dpy;
2057ec681f3Smrg   const char* err;
2067ec681f3Smrg
2077ec681f3Smrg   wgl_dpy = calloc(1, sizeof * wgl_dpy);
2087ec681f3Smrg   if (!wgl_dpy)
2097ec681f3Smrg      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
2107ec681f3Smrg
2117ec681f3Smrg   disp->DriverData = (void *)wgl_dpy;
2127ec681f3Smrg
2137ec681f3Smrg   if (!stw_init_screen(hdc)) {
2147ec681f3Smrg      err = "wgl: failed to initialize screen";
2157ec681f3Smrg      goto cleanup;
2167ec681f3Smrg   }
2177ec681f3Smrg
2187ec681f3Smrg   wgl_dpy->screen = stw_get_device()->screen;
2197ec681f3Smrg
2207ec681f3Smrg   disp->ClientAPIs = 0;
2217ec681f3Smrg   if (_eglIsApiValid(EGL_OPENGL_API))
2227ec681f3Smrg      disp->ClientAPIs |= EGL_OPENGL_BIT;
2237ec681f3Smrg   if (_eglIsApiValid(EGL_OPENGL_ES_API))
2247ec681f3Smrg      disp->ClientAPIs |= EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
2257ec681f3Smrg
2267ec681f3Smrg   disp->Extensions.KHR_no_config_context = EGL_TRUE;
2277ec681f3Smrg   disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
2287ec681f3Smrg   disp->Extensions.MESA_query_driver = EGL_TRUE;
2297ec681f3Smrg
2307ec681f3Smrg   /* Report back to EGL the bitmask of priorities supported */
2317ec681f3Smrg   disp->Extensions.IMG_context_priority =
2327ec681f3Smrg      wgl_dpy->screen->get_param(wgl_dpy->screen, PIPE_CAP_CONTEXT_PRIORITY_MASK);
2337ec681f3Smrg
2347ec681f3Smrg   disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
2357ec681f3Smrg
2367ec681f3Smrg   if (wgl_dpy->screen->is_format_supported(wgl_dpy->screen,
2377ec681f3Smrg         PIPE_FORMAT_B8G8R8A8_SRGB,
2387ec681f3Smrg         PIPE_TEXTURE_2D, 0, 0,
2397ec681f3Smrg         PIPE_BIND_RENDER_TARGET))
2407ec681f3Smrg      disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
2417ec681f3Smrg
2427ec681f3Smrg   disp->Extensions.KHR_create_context = EGL_TRUE;
2437ec681f3Smrg   disp->Extensions.KHR_reusable_sync = EGL_TRUE;
2447ec681f3Smrg
2457ec681f3Smrg#if 0
2467ec681f3Smrg   disp->Extensions.KHR_image_base = EGL_TRUE;
2477ec681f3Smrg   disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
2487ec681f3Smrg   if (wgl_dpy->image->base.version >= 5 &&
2497ec681f3Smrg      wgl_dpy->image->createImageFromTexture) {
2507ec681f3Smrg      disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
2517ec681f3Smrg      disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE;
2527ec681f3Smrg
2537ec681f3Smrg      if (wgl_renderer_query_integer(wgl_dpy,
2547ec681f3Smrg         __wgl_RENDERER_HAS_TEXTURE_3D))
2557ec681f3Smrg         disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE;
2567ec681f3Smrg   }
2577ec681f3Smrg#endif
2587ec681f3Smrg
2597ec681f3Smrg   if (!wgl_add_configs(disp, hdc)) {
2607ec681f3Smrg      err = "wgl: failed to add configs";
2617ec681f3Smrg      goto cleanup;
2627ec681f3Smrg   }
2637ec681f3Smrg
2647ec681f3Smrg   return EGL_TRUE;
2657ec681f3Smrg
2667ec681f3Smrgcleanup:
2677ec681f3Smrg   wgl_display_destroy(disp);
2687ec681f3Smrg   return _eglError(EGL_NOT_INITIALIZED, err);
2697ec681f3Smrg}
2707ec681f3Smrg
2717ec681f3Smrgstatic EGLBoolean
2727ec681f3Smrgwgl_initialize(_EGLDisplay *disp)
2737ec681f3Smrg{
2747ec681f3Smrg   EGLBoolean ret = EGL_FALSE;
2757ec681f3Smrg   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
2767ec681f3Smrg
2777ec681f3Smrg   /* In the case where the application calls eglMakeCurrent(context1),
2787ec681f3Smrg    * eglTerminate, then eglInitialize again (without a call to eglReleaseThread
2797ec681f3Smrg    * or eglMakeCurrent(NULL) before that), wgl_dpy structure is still
2807ec681f3Smrg    * initialized, as we need it to be able to free context1 correctly.
2817ec681f3Smrg    *
2827ec681f3Smrg    * It would probably be safest to forcibly release the display with
2837ec681f3Smrg    * wgl_display_release, to make sure the display is reinitialized correctly.
2847ec681f3Smrg    * However, the EGL spec states that we need to keep a reference to the
2857ec681f3Smrg    * current context (so we cannot call wgl_make_current(NULL)), and therefore
2867ec681f3Smrg    * we would leak context1 as we would be missing the old display connection
2877ec681f3Smrg    * to free it up correctly.
2887ec681f3Smrg    */
2897ec681f3Smrg   if (wgl_dpy) {
2907ec681f3Smrg      wgl_dpy->ref_count++;
2917ec681f3Smrg      return EGL_TRUE;
2927ec681f3Smrg   }
2937ec681f3Smrg
2947ec681f3Smrg   switch (disp->Platform) {
2957ec681f3Smrg   case _EGL_PLATFORM_SURFACELESS:
2967ec681f3Smrg      ret = wgl_initialize_impl(disp, NULL);
2977ec681f3Smrg      break;
2987ec681f3Smrg   case _EGL_PLATFORM_WINDOWS:
2997ec681f3Smrg      ret = wgl_initialize_impl(disp, disp->PlatformDisplay);
3007ec681f3Smrg      break;
3017ec681f3Smrg   default:
3027ec681f3Smrg      unreachable("Callers ensure we cannot get here.");
3037ec681f3Smrg      return EGL_FALSE;
3047ec681f3Smrg   }
3057ec681f3Smrg
3067ec681f3Smrg   if (!ret)
3077ec681f3Smrg      return EGL_FALSE;
3087ec681f3Smrg
3097ec681f3Smrg   wgl_dpy = wgl_egl_display(disp);
3107ec681f3Smrg   wgl_dpy->ref_count++;
3117ec681f3Smrg
3127ec681f3Smrg   return EGL_TRUE;
3137ec681f3Smrg}
3147ec681f3Smrg
3157ec681f3Smrg/**
3167ec681f3Smrg * Decrement display reference count, and free up display if necessary.
3177ec681f3Smrg */
3187ec681f3Smrgstatic void
3197ec681f3Smrgwgl_display_release(_EGLDisplay *disp)
3207ec681f3Smrg{
3217ec681f3Smrg   struct wgl_egl_display *wgl_dpy;
3227ec681f3Smrg
3237ec681f3Smrg   if (!disp)
3247ec681f3Smrg      return;
3257ec681f3Smrg
3267ec681f3Smrg   wgl_dpy = wgl_egl_display(disp);
3277ec681f3Smrg
3287ec681f3Smrg   assert(wgl_dpy->ref_count > 0);
3297ec681f3Smrg   wgl_dpy->ref_count--;
3307ec681f3Smrg
3317ec681f3Smrg   if (wgl_dpy->ref_count > 0)
3327ec681f3Smrg      return;
3337ec681f3Smrg
3347ec681f3Smrg   _eglCleanupDisplay(disp);
3357ec681f3Smrg   wgl_display_destroy(disp);
3367ec681f3Smrg}
3377ec681f3Smrg
3387ec681f3Smrg/**
3397ec681f3Smrg * Called via eglTerminate(), drv->Terminate().
3407ec681f3Smrg *
3417ec681f3Smrg * This must be guaranteed to be called exactly once, even if eglTerminate is
3427ec681f3Smrg * called many times (without a eglInitialize in between).
3437ec681f3Smrg */
3447ec681f3Smrgstatic EGLBoolean
3457ec681f3Smrgwgl_terminate(_EGLDisplay *disp)
3467ec681f3Smrg{
3477ec681f3Smrg   /* Release all non-current Context/Surfaces. */
3487ec681f3Smrg   _eglReleaseDisplayResources(disp);
3497ec681f3Smrg
3507ec681f3Smrg   wgl_display_release(disp);
3517ec681f3Smrg
3527ec681f3Smrg   return EGL_TRUE;
3537ec681f3Smrg}
3547ec681f3Smrg
3557ec681f3Smrg/**
3567ec681f3Smrg * Called via eglCreateContext(), drv->CreateContext().
3577ec681f3Smrg */
3587ec681f3Smrgstatic _EGLContext *
3597ec681f3Smrgwgl_create_context(_EGLDisplay *disp, _EGLConfig *conf,
3607ec681f3Smrg   _EGLContext *share_list, const EGLint *attrib_list)
3617ec681f3Smrg{
3627ec681f3Smrg   struct wgl_egl_context *wgl_ctx;
3637ec681f3Smrg   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
3647ec681f3Smrg   struct wgl_egl_context *wgl_ctx_shared = wgl_egl_context(share_list);
3657ec681f3Smrg   struct stw_context *shared =
3667ec681f3Smrg      wgl_ctx_shared ? wgl_ctx_shared->ctx : NULL;
3677ec681f3Smrg   struct wgl_egl_config *wgl_config = wgl_egl_config(conf);
3687ec681f3Smrg   const struct stw_pixelformat_info *stw_config;
3697ec681f3Smrg
3707ec681f3Smrg   wgl_ctx = malloc(sizeof * wgl_ctx);
3717ec681f3Smrg   if (!wgl_ctx) {
3727ec681f3Smrg      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
3737ec681f3Smrg      return NULL;
3747ec681f3Smrg   }
3757ec681f3Smrg
3767ec681f3Smrg   if (!_eglInitContext(&wgl_ctx->base, disp, conf, attrib_list))
3777ec681f3Smrg      goto cleanup;
3787ec681f3Smrg
3797ec681f3Smrg   /* The EGL_EXT_create_context_robustness spec says:
3807ec681f3Smrg    *
3817ec681f3Smrg    *    "Add to the eglCreateContext context creation errors: [...]
3827ec681f3Smrg    *
3837ec681f3Smrg    *     * If the reset notification behavior of <share_context> and the
3847ec681f3Smrg    *       newly created context are different then an EGL_BAD_MATCH error is
3857ec681f3Smrg    *       generated."
3867ec681f3Smrg    */
3877ec681f3Smrg   if (share_list && share_list->ResetNotificationStrategy !=
3887ec681f3Smrg      wgl_ctx->base.ResetNotificationStrategy) {
3897ec681f3Smrg      _eglError(EGL_BAD_MATCH, "eglCreateContext");
3907ec681f3Smrg      goto cleanup;
3917ec681f3Smrg   }
3927ec681f3Smrg
3937ec681f3Smrg   /* The EGL_KHR_create_context_no_error spec says:
3947ec681f3Smrg    *
3957ec681f3Smrg    *    "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
3967ec681f3Smrg    *    used to create <share_context> does not match the value of
3977ec681f3Smrg    *    EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created."
3987ec681f3Smrg    */
3997ec681f3Smrg   if (share_list && share_list->NoError != wgl_ctx->base.NoError) {
4007ec681f3Smrg      _eglError(EGL_BAD_MATCH, "eglCreateContext");
4017ec681f3Smrg      goto cleanup;
4027ec681f3Smrg   }
4037ec681f3Smrg
4047ec681f3Smrg   unsigned profile_mask = 0;
4057ec681f3Smrg   switch (wgl_ctx->base.ClientAPI) {
4067ec681f3Smrg   case EGL_OPENGL_ES_API:
4077ec681f3Smrg      profile_mask = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
4087ec681f3Smrg      break;
4097ec681f3Smrg   case EGL_OPENGL_API:
4107ec681f3Smrg      if ((wgl_ctx->base.ClientMajorVersion >= 4
4117ec681f3Smrg         || (wgl_ctx->base.ClientMajorVersion == 3
4127ec681f3Smrg            && wgl_ctx->base.ClientMinorVersion >= 2))
4137ec681f3Smrg         && wgl_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR)
4147ec681f3Smrg         profile_mask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
4157ec681f3Smrg      else if (wgl_ctx->base.ClientMajorVersion == 3 &&
4167ec681f3Smrg         wgl_ctx->base.ClientMinorVersion == 1)
4177ec681f3Smrg         profile_mask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
4187ec681f3Smrg      else
4197ec681f3Smrg         profile_mask = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
4207ec681f3Smrg      break;
4217ec681f3Smrg   default:
4227ec681f3Smrg      _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
4237ec681f3Smrg      free(wgl_ctx);
4247ec681f3Smrg      return NULL;
4257ec681f3Smrg   }
4267ec681f3Smrg
4277ec681f3Smrg   if (conf != NULL) {
4287ec681f3Smrg      /* The config chosen here isn't necessarily
4297ec681f3Smrg       * used for surfaces later.
4307ec681f3Smrg       * A pixmap surface will use the single config.
4317ec681f3Smrg       * This opportunity depends on disabling the
4327ec681f3Smrg       * doubleBufferMode check in
4337ec681f3Smrg       * src/mesa/main/context.c:check_compatible()
4347ec681f3Smrg       */
4357ec681f3Smrg      if (wgl_config->stw_config[1])
4367ec681f3Smrg         stw_config = wgl_config->stw_config[1];
4377ec681f3Smrg      else
4387ec681f3Smrg         stw_config = wgl_config->stw_config[0];
4397ec681f3Smrg   }
4407ec681f3Smrg   else
4417ec681f3Smrg      stw_config = NULL;
4427ec681f3Smrg
4437ec681f3Smrg   unsigned flags = 0;
4447ec681f3Smrg   if (wgl_ctx->base.Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR)
4457ec681f3Smrg      flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
4467ec681f3Smrg   if (wgl_ctx->base.Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR)
4477ec681f3Smrg      flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
4487ec681f3Smrg   wgl_ctx->ctx = stw_create_context_attribs(disp->PlatformDisplay, 0, shared,
4497ec681f3Smrg      wgl_ctx->base.ClientMajorVersion,
4507ec681f3Smrg      wgl_ctx->base.ClientMinorVersion,
4517ec681f3Smrg      flags,
4527ec681f3Smrg      profile_mask,
4537ec681f3Smrg      stw_config->iPixelFormat);
4547ec681f3Smrg
4557ec681f3Smrg   if (!wgl_ctx->ctx)
4567ec681f3Smrg      goto cleanup;
4577ec681f3Smrg
4587ec681f3Smrg   return &wgl_ctx->base;
4597ec681f3Smrg
4607ec681f3Smrgcleanup:
4617ec681f3Smrg   free(wgl_ctx);
4627ec681f3Smrg   return NULL;
4637ec681f3Smrg}
4647ec681f3Smrg
4657ec681f3Smrg/**
4667ec681f3Smrg * Called via eglDestroyContext(), drv->DestroyContext().
4677ec681f3Smrg */
4687ec681f3Smrgstatic EGLBoolean
4697ec681f3Smrgwgl_destroy_context(_EGLDisplay *disp, _EGLContext *ctx)
4707ec681f3Smrg{
4717ec681f3Smrg   struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
4727ec681f3Smrg   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
4737ec681f3Smrg
4747ec681f3Smrg   if (_eglPutContext(ctx)) {
4757ec681f3Smrg      stw_destroy_context(wgl_ctx->ctx);
4767ec681f3Smrg      free(wgl_ctx);
4777ec681f3Smrg   }
4787ec681f3Smrg
4797ec681f3Smrg   return EGL_TRUE;
4807ec681f3Smrg}
4817ec681f3Smrg
4827ec681f3Smrgstatic EGLBoolean
4837ec681f3Smrgwgl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
4847ec681f3Smrg{
4857ec681f3Smrg   struct wgl_egl_surface *wgl_surf = wgl_egl_surface(surf);
4867ec681f3Smrg
4877ec681f3Smrg   if (!_eglPutSurface(surf))
4887ec681f3Smrg      return EGL_TRUE;
4897ec681f3Smrg
4907ec681f3Smrg   struct stw_context *ctx = stw_current_context();
4917ec681f3Smrg   stw_framebuffer_lock(wgl_surf->fb);
4927ec681f3Smrg   stw_framebuffer_release_locked(wgl_surf->fb, ctx ? ctx->st : NULL);
4937ec681f3Smrg   return EGL_TRUE;
4947ec681f3Smrg}
4957ec681f3Smrg
4967ec681f3Smrgstatic void
4977ec681f3Smrgwgl_gl_flush()
4987ec681f3Smrg{
4997ec681f3Smrg   static void (*glFlush)(void);
5007ec681f3Smrg   static mtx_t glFlushMutex = _MTX_INITIALIZER_NP;
5017ec681f3Smrg
5027ec681f3Smrg   mtx_lock(&glFlushMutex);
5037ec681f3Smrg   if (!glFlush)
5047ec681f3Smrg      glFlush = _glapi_get_proc_address("glFlush");
5057ec681f3Smrg   mtx_unlock(&glFlushMutex);
5067ec681f3Smrg
5077ec681f3Smrg   /* if glFlush is not available things are horribly broken */
5087ec681f3Smrg   if (!glFlush) {
5097ec681f3Smrg      _eglLog(_EGL_WARNING, "wgl: failed to find glFlush entry point");
5107ec681f3Smrg      return;
5117ec681f3Smrg   }
5127ec681f3Smrg
5137ec681f3Smrg   glFlush();
5147ec681f3Smrg}
5157ec681f3Smrg
5167ec681f3Smrg/**
5177ec681f3Smrg * Called via eglMakeCurrent(), drv->MakeCurrent().
5187ec681f3Smrg */
5197ec681f3Smrgstatic EGLBoolean
5207ec681f3Smrgwgl_make_current(_EGLDisplay *disp, _EGLSurface *dsurf,
5217ec681f3Smrg   _EGLSurface *rsurf, _EGLContext *ctx)
5227ec681f3Smrg{
5237ec681f3Smrg   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
5247ec681f3Smrg   struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
5257ec681f3Smrg   _EGLDisplay *old_disp = NULL;
5267ec681f3Smrg   struct wgl_egl_display *old_wgl_dpy = NULL;
5277ec681f3Smrg   _EGLContext *old_ctx;
5287ec681f3Smrg   _EGLSurface *old_dsurf, *old_rsurf;
5297ec681f3Smrg   _EGLSurface *tmp_dsurf, *tmp_rsurf;
5307ec681f3Smrg   struct stw_framebuffer *ddraw, *rdraw;
5317ec681f3Smrg   struct stw_context *cctx;
5327ec681f3Smrg   EGLint egl_error = EGL_SUCCESS;
5337ec681f3Smrg
5347ec681f3Smrg   if (!wgl_dpy)
5357ec681f3Smrg      return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent");
5367ec681f3Smrg
5377ec681f3Smrg   /* make new bindings, set the EGL error otherwise */
5387ec681f3Smrg   if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
5397ec681f3Smrg      return EGL_FALSE;
5407ec681f3Smrg
5417ec681f3Smrg   if (old_ctx) {
5427ec681f3Smrg      struct stw_context *old_cctx = wgl_egl_context(old_ctx)->ctx;
5437ec681f3Smrg      old_disp = old_ctx->Resource.Display;
5447ec681f3Smrg      old_wgl_dpy = wgl_egl_display(old_disp);
5457ec681f3Smrg
5467ec681f3Smrg      /* flush before context switch */
5477ec681f3Smrg      wgl_gl_flush();
5487ec681f3Smrg
5497ec681f3Smrg#if 0
5507ec681f3Smrg      if (old_dsurf)
5517ec681f3Smrg         wgl_surf_update_fence_fd(old_ctx, disp, old_dsurf);
5527ec681f3Smrg
5537ec681f3Smrg      /* Disable shared buffer mode */
5547ec681f3Smrg      if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
5557ec681f3Smrg         old_wgl_dpy->vtbl->set_shared_buffer_mode) {
5567ec681f3Smrg         old_wgl_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false);
5577ec681f3Smrg      }
5587ec681f3Smrg#endif
5597ec681f3Smrg
5607ec681f3Smrg      stw_unbind_context(old_cctx);
5617ec681f3Smrg   }
5627ec681f3Smrg
5637ec681f3Smrg   ddraw = (dsurf) ? wgl_egl_surface(dsurf)->fb : NULL;
5647ec681f3Smrg   rdraw = (rsurf) ? wgl_egl_surface(rsurf)->fb : NULL;
5657ec681f3Smrg   cctx = (wgl_ctx) ? wgl_ctx->ctx : NULL;
5667ec681f3Smrg
5677ec681f3Smrg   if (cctx || ddraw || rdraw) {
5687ec681f3Smrg      if (!stw_make_current(ddraw, rdraw, cctx)) {
5697ec681f3Smrg         _EGLContext *tmp_ctx;
5707ec681f3Smrg
5717ec681f3Smrg         /* stw_make_current failed. We cannot tell for sure why, but
5727ec681f3Smrg          * setting the error to EGL_BAD_MATCH is surely better than leaving it
5737ec681f3Smrg          * as EGL_SUCCESS.
5747ec681f3Smrg          */
5757ec681f3Smrg         egl_error = EGL_BAD_MATCH;
5767ec681f3Smrg
5777ec681f3Smrg         /* undo the previous _eglBindContext */
5787ec681f3Smrg         _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf);
5797ec681f3Smrg         assert(&wgl_ctx->base == ctx &&
5807ec681f3Smrg            tmp_dsurf == dsurf &&
5817ec681f3Smrg            tmp_rsurf == rsurf);
5827ec681f3Smrg
5837ec681f3Smrg         _eglPutSurface(dsurf);
5847ec681f3Smrg         _eglPutSurface(rsurf);
5857ec681f3Smrg         _eglPutContext(ctx);
5867ec681f3Smrg
5877ec681f3Smrg         _eglPutSurface(old_dsurf);
5887ec681f3Smrg         _eglPutSurface(old_rsurf);
5897ec681f3Smrg         _eglPutContext(old_ctx);
5907ec681f3Smrg
5917ec681f3Smrg         ddraw = (old_dsurf) ? wgl_egl_surface(old_dsurf)->fb : NULL;
5927ec681f3Smrg         rdraw = (old_rsurf) ? wgl_egl_surface(old_rsurf)->fb : NULL;
5937ec681f3Smrg         cctx = (old_ctx) ? wgl_egl_context(old_ctx)->ctx : NULL;
5947ec681f3Smrg
5957ec681f3Smrg         /* undo the previous wgl_dpy->core->unbindContext */
5967ec681f3Smrg         if (stw_make_current(ddraw, rdraw, cctx)) {
5977ec681f3Smrg#if 0
5987ec681f3Smrg            if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
5997ec681f3Smrg               old_wgl_dpy->vtbl->set_shared_buffer_mode) {
6007ec681f3Smrg               old_wgl_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true);
6017ec681f3Smrg            }
6027ec681f3Smrg#endif
6037ec681f3Smrg
6047ec681f3Smrg            return _eglError(egl_error, "eglMakeCurrent");
6057ec681f3Smrg         }
6067ec681f3Smrg
6077ec681f3Smrg         /* We cannot restore the same state as it was before calling
6087ec681f3Smrg          * eglMakeCurrent() and the spec isn't clear about what to do. We
6097ec681f3Smrg          * can prevent EGL from calling into the DRI driver with no DRI
6107ec681f3Smrg          * context bound.
6117ec681f3Smrg          */
6127ec681f3Smrg         dsurf = rsurf = NULL;
6137ec681f3Smrg         ctx = NULL;
6147ec681f3Smrg
6157ec681f3Smrg         _eglBindContext(ctx, dsurf, rsurf, &tmp_ctx, &tmp_dsurf, &tmp_rsurf);
6167ec681f3Smrg         assert(tmp_ctx == old_ctx && tmp_dsurf == old_dsurf &&
6177ec681f3Smrg            tmp_rsurf == old_rsurf);
6187ec681f3Smrg
6197ec681f3Smrg         _eglLog(_EGL_WARNING, "wgl: failed to rebind the previous context");
6207ec681f3Smrg      }
6217ec681f3Smrg      else {
6227ec681f3Smrg         /* wgl_dpy->core->bindContext succeeded, so take a reference on the
6237ec681f3Smrg          * wgl_dpy. This prevents wgl_dpy from being reinitialized when a
6247ec681f3Smrg          * EGLDisplay is terminated and then initialized again while a
6257ec681f3Smrg          * context is still bound. See wgl_intitialize() for a more in depth
6267ec681f3Smrg          * explanation. */
6277ec681f3Smrg         wgl_dpy->ref_count++;
6287ec681f3Smrg      }
6297ec681f3Smrg   }
6307ec681f3Smrg
6317ec681f3Smrg   wgl_destroy_surface(disp, old_dsurf);
6327ec681f3Smrg   wgl_destroy_surface(disp, old_rsurf);
6337ec681f3Smrg
6347ec681f3Smrg   if (old_ctx) {
6357ec681f3Smrg      wgl_destroy_context(disp, old_ctx);
6367ec681f3Smrg      wgl_display_release(old_disp);
6377ec681f3Smrg   }
6387ec681f3Smrg
6397ec681f3Smrg   if (egl_error != EGL_SUCCESS)
6407ec681f3Smrg      return _eglError(egl_error, "eglMakeCurrent");
6417ec681f3Smrg
6427ec681f3Smrg#if 0
6437ec681f3Smrg   if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) &&
6447ec681f3Smrg      wgl_dpy->vtbl->set_shared_buffer_mode) {
6457ec681f3Smrg      /* Always update the shared buffer mode. This is obviously needed when
6467ec681f3Smrg       * the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When
6477ec681f3Smrg       * EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the
6487ec681f3Smrg       * case where external non-EGL API may have changed window's shared
6497ec681f3Smrg       * buffer mode since we last saw it.
6507ec681f3Smrg       */
6517ec681f3Smrg      bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER);
6527ec681f3Smrg      wgl_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode);
6537ec681f3Smrg   }
6547ec681f3Smrg#endif
6557ec681f3Smrg
6567ec681f3Smrg   return EGL_TRUE;
6577ec681f3Smrg}
6587ec681f3Smrg
6597ec681f3Smrgstatic _EGLSurface*
6607ec681f3Smrgwgl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
6617ec681f3Smrg                          void *native_window, const EGLint *attrib_list)
6627ec681f3Smrg{
6637ec681f3Smrg   struct wgl_egl_config *wgl_conf = wgl_egl_config(conf);
6647ec681f3Smrg
6657ec681f3Smrg   struct wgl_egl_surface *wgl_surf = calloc(1, sizeof(*wgl_surf));
6667ec681f3Smrg   if (!wgl_surf)
6677ec681f3Smrg      return NULL;
6687ec681f3Smrg
6697ec681f3Smrg   if (!_eglInitSurface(&wgl_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, native_window)) {
6707ec681f3Smrg      free(wgl_surf);
6717ec681f3Smrg      return NULL;
6727ec681f3Smrg   }
6737ec681f3Smrg
6747ec681f3Smrg   const struct stw_pixelformat_info *stw_conf = wgl_conf->stw_config[1] ?
6757ec681f3Smrg      wgl_conf->stw_config[1] : wgl_conf->stw_config[0];
6767ec681f3Smrg   wgl_surf->fb = stw_framebuffer_create(native_window, stw_conf->iPixelFormat, STW_FRAMEBUFFER_EGL_WINDOW);
6777ec681f3Smrg   if (!wgl_surf->fb) {
6787ec681f3Smrg      free(wgl_surf);
6797ec681f3Smrg      return NULL;
6807ec681f3Smrg   }
6817ec681f3Smrg
6827ec681f3Smrg   stw_framebuffer_unlock(wgl_surf->fb);
6837ec681f3Smrg
6847ec681f3Smrg   return &wgl_surf->base;
6857ec681f3Smrg}
6867ec681f3Smrg
6877ec681f3Smrgstatic EGLBoolean
6887ec681f3Smrgwgl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
6897ec681f3Smrg{
6907ec681f3Smrg   struct wgl_egl_display *wgl_disp = wgl_egl_display(disp);
6917ec681f3Smrg   struct wgl_egl_surface *wgl_surf = wgl_egl_surface(draw);
6927ec681f3Smrg
6937ec681f3Smrg   stw_framebuffer_lock(wgl_surf->fb);
6947ec681f3Smrg   HDC hdc = GetDC(wgl_surf->fb->hWnd);
6957ec681f3Smrg   BOOL ret = stw_framebuffer_swap_locked(hdc, wgl_surf->fb);
6967ec681f3Smrg   ReleaseDC(wgl_surf->fb->hWnd, hdc);
6977ec681f3Smrg
6987ec681f3Smrg   return ret;
6997ec681f3Smrg}
7007ec681f3Smrg
7017ec681f3Smrgstruct _egl_driver _eglDriver = {
7027ec681f3Smrg   .Initialize = wgl_initialize,
7037ec681f3Smrg   .Terminate = wgl_terminate,
7047ec681f3Smrg   .CreateContext = wgl_create_context,
7057ec681f3Smrg   .DestroyContext = wgl_destroy_context,
7067ec681f3Smrg   .MakeCurrent = wgl_make_current,
7077ec681f3Smrg   .CreateWindowSurface = wgl_create_window_surface,
7087ec681f3Smrg   .DestroySurface = wgl_destroy_surface,
7097ec681f3Smrg   .GetProcAddress = _glapi_get_proc_address,
7107ec681f3Smrg   .SwapBuffers = wgl_swap_buffers,
7117ec681f3Smrg};
7127ec681f3Smrg
713