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