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