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