1 /**************************************************************************
2 *
3 * Copyright 2008-2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <windows.h>
29
30 #include "pipe/p_screen.h"
31 #include "pipe/p_state.h"
32 #include "util/u_memory.h"
33 #include "hud/hud_context.h"
34 #include "util/os_time.h"
35 #include "frontend/api.h"
36
37 #include <GL/gl.h>
38 #include "gldrv.h"
39 #include "stw_framebuffer.h"
40 #include "stw_device.h"
41 #include "stw_winsys.h"
42 #include "stw_tls.h"
43 #include "stw_context.h"
44 #include "stw_st.h"
45
46
47 /**
48 * Search the framebuffer with the matching HWND while holding the
49 * stw_dev::fb_mutex global lock.
50 * If a stw_framebuffer is found, lock it and return the pointer.
51 * Else, return NULL.
52 */
53 static struct stw_framebuffer *
stw_framebuffer_from_hwnd_locked(HWND hwnd)54 stw_framebuffer_from_hwnd_locked(HWND hwnd)
55 {
56 struct stw_framebuffer *fb;
57
58 for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next)
59 if (fb->hWnd == hwnd) {
60 stw_framebuffer_lock(fb);
61
62 /* When running with Zink, during the Vulkan surface creation
63 * it's possible that the underlying Vulkan driver will try to
64 * access the HWND/HDC we passed in (see stw_st_fill_private_loader_data()).
65 * Because we create the Vulkan surface while holding the framebuffer
66 * lock, when the driver starts to look up properties,
67 * we'd end up double locking when looking up the framebuffer.
68 */
69 assert(stw_dev->zink || fb->mutex.RecursionCount == 1);
70 return fb;
71 }
72
73 return NULL;
74 }
75
76
77 /**
78 * Decrement the reference count on the given stw_framebuffer object.
79 * If the reference count hits zero, destroy the object.
80 *
81 * Note: Both stw_dev::fb_mutex and stw_framebuffer::mutex must already be
82 * locked. After this function completes, the fb's mutex will be unlocked.
83 */
84 void
stw_framebuffer_release_locked(struct stw_framebuffer * fb,struct st_context_iface * stctx)85 stw_framebuffer_release_locked(struct stw_framebuffer *fb,
86 struct st_context_iface *stctx)
87 {
88 struct stw_framebuffer **link;
89
90 assert(fb);
91 assert(stw_own_mutex(&fb->mutex));
92 assert(stw_own_mutex(&stw_dev->fb_mutex) || fb->owner == STW_FRAMEBUFFER_EGL_WINDOW);
93
94 /* check the reference count */
95 fb->refcnt--;
96 if (fb->refcnt) {
97 stw_framebuffer_unlock(fb);
98 return;
99 }
100
101 if (fb->owner != STW_FRAMEBUFFER_EGL_WINDOW) {
102 /* remove this stw_framebuffer from the device's linked list */
103 link = &stw_dev->fb_head;
104 while (*link != fb)
105 link = &(*link)->next;
106 assert(*link);
107 *link = fb->next;
108 fb->next = NULL;
109 }
110
111 if (fb->shared_surface)
112 stw_dev->stw_winsys->shared_surface_close(stw_dev->screen,
113 fb->shared_surface);
114
115 if (fb->winsys_framebuffer)
116 fb->winsys_framebuffer->destroy(fb->winsys_framebuffer, stctx ? stctx->pipe : NULL);
117
118 stw_st_destroy_framebuffer_locked(fb->stfb);
119
120 stw_framebuffer_unlock(fb);
121
122 DeleteCriticalSection(&fb->mutex);
123
124 FREE( fb );
125 }
126
127
128 /**
129 * Query the size of the given framebuffer's on-screen window and update
130 * the stw_framebuffer's width/height.
131 */
132 static void
stw_framebuffer_get_size(struct stw_framebuffer * fb)133 stw_framebuffer_get_size(struct stw_framebuffer *fb)
134 {
135 LONG width, height;
136 RECT client_rect;
137 RECT window_rect;
138 POINT client_pos;
139
140 /*
141 * Sanity checking.
142 */
143 assert(fb->hWnd);
144 assert(fb->width && fb->height);
145 assert(fb->client_rect.right == fb->client_rect.left + fb->width);
146 assert(fb->client_rect.bottom == fb->client_rect.top + fb->height);
147
148 /*
149 * Get the client area size.
150 */
151 if (!GetClientRect(fb->hWnd, &client_rect)) {
152 return;
153 }
154
155 assert(client_rect.left == 0);
156 assert(client_rect.top == 0);
157 width = client_rect.right - client_rect.left;
158 height = client_rect.bottom - client_rect.top;
159
160 fb->minimized = width == 0 || height == 0;
161
162 if (width <= 0 || height <= 0) {
163 /*
164 * When the window is minimized GetClientRect will return zeros. Simply
165 * preserve the current window size, until the window is restored or
166 * maximized again.
167 */
168 return;
169 }
170
171 if (width != fb->width || height != fb->height) {
172 fb->must_resize = TRUE;
173 fb->width = width;
174 fb->height = height;
175 }
176
177 client_pos.x = 0;
178 client_pos.y = 0;
179 if (ClientToScreen(fb->hWnd, &client_pos) &&
180 GetWindowRect(fb->hWnd, &window_rect)) {
181 fb->client_rect.left = client_pos.x - window_rect.left;
182 fb->client_rect.top = client_pos.y - window_rect.top;
183 }
184
185 fb->client_rect.right = fb->client_rect.left + fb->width;
186 fb->client_rect.bottom = fb->client_rect.top + fb->height;
187
188 #if 0
189 debug_printf("\n");
190 debug_printf("%s: hwnd = %p\n", __FUNCTION__, fb->hWnd);
191 debug_printf("%s: client_position = (%li, %li)\n",
192 __FUNCTION__, client_pos.x, client_pos.y);
193 debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n",
194 __FUNCTION__,
195 window_rect.left, window_rect.top,
196 window_rect.right, window_rect.bottom);
197 debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n",
198 __FUNCTION__,
199 fb->client_rect.left, fb->client_rect.top,
200 fb->client_rect.right, fb->client_rect.bottom);
201 #endif
202 }
203
204
205 /**
206 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
207 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
208 */
209 LRESULT CALLBACK
stw_call_window_proc(int nCode,WPARAM wParam,LPARAM lParam)210 stw_call_window_proc(int nCode, WPARAM wParam, LPARAM lParam)
211 {
212 struct stw_tls_data *tls_data;
213 PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
214 struct stw_framebuffer *fb;
215
216 tls_data = stw_tls_get_data();
217 if (!tls_data)
218 return 0;
219
220 if (nCode < 0 || !stw_dev)
221 return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
222
223 /* We check that the stw_dev object is initialized before we try to do
224 * anything with it. Otherwise, in multi-threaded programs there's a
225 * chance of executing this code before the stw_dev object is fully
226 * initialized.
227 */
228 if (stw_dev && stw_dev->initialized) {
229 if (pParams->message == WM_WINDOWPOSCHANGED) {
230 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according
231 * to http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
232 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
233 * can be masked out by the application.
234 */
235 LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
236 if ((lpWindowPos->flags & SWP_SHOWWINDOW) ||
237 !(lpWindowPos->flags & SWP_NOMOVE) ||
238 !(lpWindowPos->flags & SWP_NOSIZE)) {
239 fb = stw_framebuffer_from_hwnd( pParams->hwnd );
240 if (fb) {
241 /* Size in WINDOWPOS includes the window frame, so get the size
242 * of the client area via GetClientRect.
243 */
244 stw_framebuffer_get_size(fb);
245 stw_framebuffer_unlock(fb);
246 }
247 }
248 }
249 else if (pParams->message == WM_DESTROY) {
250 stw_lock_framebuffers(stw_dev);
251 fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd );
252 if (fb) {
253 struct stw_context *current_context = stw_current_context();
254 struct st_context_iface *ctx_iface = current_context &&
255 current_context->current_framebuffer == fb ? current_context->st : NULL;
256 stw_framebuffer_release_locked(fb, ctx_iface);
257 }
258 stw_unlock_framebuffers(stw_dev);
259 }
260 }
261
262 return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
263 }
264
265
266 /**
267 * Create a new stw_framebuffer object which corresponds to the given
268 * HDC/window. If successful, we return the new stw_framebuffer object
269 * with its mutex locked.
270 */
271 struct stw_framebuffer *
stw_framebuffer_create(HWND hWnd,int iPixelFormat,enum stw_framebuffer_owner owner)272 stw_framebuffer_create(HWND hWnd, int iPixelFormat, enum stw_framebuffer_owner owner)
273 {
274 struct stw_framebuffer *fb;
275 const struct stw_pixelformat_info *pfi;
276
277 fb = CALLOC_STRUCT( stw_framebuffer );
278 if (fb == NULL)
279 return NULL;
280
281 fb->hWnd = hWnd;
282 fb->iPixelFormat = iPixelFormat;
283
284 if (stw_dev->stw_winsys->create_framebuffer)
285 fb->winsys_framebuffer =
286 stw_dev->stw_winsys->create_framebuffer(stw_dev->screen, hWnd, iPixelFormat);
287
288 /*
289 * We often need a displayable pixel format to make GDI happy. Set it
290 * here (always 1, i.e., out first pixel format) where appropriate.
291 */
292 fb->iDisplayablePixelFormat = iPixelFormat <= stw_dev->pixelformat_count
293 ? iPixelFormat : 1;
294 fb->owner = owner;
295
296 fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat );
297 fb->stfb = stw_st_create_framebuffer( fb );
298 if (!fb->stfb) {
299 FREE( fb );
300 return NULL;
301 }
302
303 fb->refcnt = 1;
304
305 /*
306 * Windows can be sometimes have zero width and or height, but we ensure
307 * a non-zero framebuffer size at all times.
308 */
309
310 fb->must_resize = TRUE;
311 fb->width = 1;
312 fb->height = 1;
313 fb->client_rect.left = 0;
314 fb->client_rect.top = 0;
315 fb->client_rect.right = fb->client_rect.left + fb->width;
316 fb->client_rect.bottom = fb->client_rect.top + fb->height;
317
318 stw_framebuffer_get_size(fb);
319
320 InitializeCriticalSection(&fb->mutex);
321
322 /* This is the only case where we lock the stw_framebuffer::mutex before
323 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
324 * and we must prevent any other thread from destroying it before we return.
325 */
326 stw_framebuffer_lock(fb);
327
328 if (owner != STW_FRAMEBUFFER_EGL_WINDOW) {
329 stw_lock_framebuffers(stw_dev);
330 fb->next = stw_dev->fb_head;
331 stw_dev->fb_head = fb;
332 stw_unlock_framebuffers(stw_dev);
333 }
334
335 return fb;
336 }
337
338 /**
339 * Increase fb reference count. The referenced framebuffer should be locked.
340 *
341 * It's not necessary to hold stw_dev::fb_mutex global lock.
342 */
343 void
stw_framebuffer_reference_locked(struct stw_framebuffer * fb)344 stw_framebuffer_reference_locked(struct stw_framebuffer *fb)
345 {
346 if (fb) {
347 assert(stw_own_mutex(&fb->mutex));
348 fb->refcnt++;
349 }
350 }
351
352 /**
353 * Release stw_framebuffer::mutex lock. This framebuffer must not be accessed
354 * after calling this function, as it may have been deleted by another thread
355 * in the meanwhile.
356 */
357 void
stw_framebuffer_unlock(struct stw_framebuffer * fb)358 stw_framebuffer_unlock(struct stw_framebuffer *fb)
359 {
360 assert(fb);
361 assert(stw_own_mutex(&fb->mutex));
362 LeaveCriticalSection(&fb->mutex);
363 }
364
365
366 /**
367 * Update the framebuffer's size if necessary.
368 */
369 void
stw_framebuffer_update(struct stw_framebuffer * fb)370 stw_framebuffer_update(struct stw_framebuffer *fb)
371 {
372 assert(fb->stfb);
373 assert(fb->height);
374 assert(fb->width);
375
376 /* XXX: It would be nice to avoid checking the size again -- in theory
377 * stw_call_window_proc would have cought the resize and stored the right
378 * size already, but unfortunately threads created before the DllMain is
379 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
380 * to know of their existing without using the not very portable PSAPI.
381 */
382 stw_framebuffer_get_size(fb);
383 }
384
385
386 /**
387 * Try to free all stw_framebuffer objects associated with the device.
388 */
389 void
stw_framebuffer_cleanup(void)390 stw_framebuffer_cleanup(void)
391 {
392 struct stw_framebuffer *fb;
393 struct stw_framebuffer *next;
394
395 if (!stw_dev)
396 return;
397
398 stw_lock_framebuffers(stw_dev);
399
400 fb = stw_dev->fb_head;
401 while (fb) {
402 next = fb->next;
403
404 stw_framebuffer_lock(fb);
405 stw_framebuffer_release_locked(fb, NULL);
406
407 fb = next;
408 }
409 stw_dev->fb_head = NULL;
410
411 stw_unlock_framebuffers(stw_dev);
412 }
413
414
415 /**
416 * Given an hdc, return the corresponding stw_framebuffer.
417 * The returned stw_framebuffer will have its mutex locked.
418 */
419 static struct stw_framebuffer *
stw_framebuffer_from_hdc_locked(HDC hdc)420 stw_framebuffer_from_hdc_locked(HDC hdc)
421 {
422 HWND hwnd;
423
424 hwnd = WindowFromDC(hdc);
425 if (!hwnd) {
426 return NULL;
427 }
428
429 return stw_framebuffer_from_hwnd_locked(hwnd);
430 }
431
432
433 /**
434 * Given an HDC, return the corresponding stw_framebuffer.
435 * The returned stw_framebuffer will have its mutex locked.
436 */
437 struct stw_framebuffer *
stw_framebuffer_from_hdc(HDC hdc)438 stw_framebuffer_from_hdc(HDC hdc)
439 {
440 struct stw_framebuffer *fb;
441
442 if (!stw_dev)
443 return NULL;
444
445 stw_lock_framebuffers(stw_dev);
446 fb = stw_framebuffer_from_hdc_locked(hdc);
447 stw_unlock_framebuffers(stw_dev);
448
449 return fb;
450 }
451
452
453 /**
454 * Given an HWND, return the corresponding stw_framebuffer.
455 * The returned stw_framebuffer will have its mutex locked.
456 */
457 struct stw_framebuffer *
stw_framebuffer_from_hwnd(HWND hwnd)458 stw_framebuffer_from_hwnd(HWND hwnd)
459 {
460 struct stw_framebuffer *fb;
461
462 stw_lock_framebuffers(stw_dev);
463 fb = stw_framebuffer_from_hwnd_locked(hwnd);
464 stw_unlock_framebuffers(stw_dev);
465
466 return fb;
467 }
468
469
470 BOOL APIENTRY
DrvSetPixelFormat(HDC hdc,LONG iPixelFormat)471 DrvSetPixelFormat(HDC hdc, LONG iPixelFormat)
472 {
473 uint count;
474 uint index;
475 struct stw_framebuffer *fb;
476
477 if (!stw_dev)
478 return FALSE;
479
480 index = (uint) iPixelFormat - 1;
481 count = stw_pixelformat_get_count(hdc);
482 if (index >= count)
483 return FALSE;
484
485 fb = stw_framebuffer_from_hdc_locked(hdc);
486 if (fb) {
487 /*
488 * SetPixelFormat must be called only once. However ignore
489 * pbuffers, for which the framebuffer object is created first.
490 */
491 boolean bPbuffer = fb->owner == STW_FRAMEBUFFER_PBUFFER;
492
493 stw_framebuffer_unlock( fb );
494
495 return bPbuffer;
496 }
497
498 fb = stw_framebuffer_create(WindowFromDC(hdc), iPixelFormat, STW_FRAMEBUFFER_WGL_WINDOW);
499 if (!fb) {
500 return FALSE;
501 }
502
503 stw_framebuffer_unlock( fb );
504
505 /* Some applications mistakenly use the undocumented wglSetPixelFormat
506 * function instead of SetPixelFormat, so we call SetPixelFormat here to
507 * avoid opengl32.dll's wglCreateContext to fail */
508 if (GetPixelFormat(hdc) == 0) {
509 BOOL bRet = SetPixelFormat(hdc, iPixelFormat, NULL);
510 if (!bRet) {
511 debug_printf("SetPixelFormat failed\n");
512 }
513 }
514
515 return TRUE;
516 }
517
518
519 int
stw_pixelformat_get(HDC hdc)520 stw_pixelformat_get(HDC hdc)
521 {
522 int iPixelFormat = 0;
523 struct stw_framebuffer *fb;
524
525 fb = stw_framebuffer_from_hdc(hdc);
526 if (fb) {
527 iPixelFormat = fb->iPixelFormat;
528 stw_framebuffer_unlock(fb);
529 }
530
531 return iPixelFormat;
532 }
533
534
535 BOOL APIENTRY
DrvPresentBuffers(HDC hdc,LPPRESENTBUFFERS data)536 DrvPresentBuffers(HDC hdc, LPPRESENTBUFFERS data)
537 {
538 struct stw_framebuffer *fb;
539 struct stw_context *ctx;
540 struct pipe_screen *screen;
541 struct pipe_context *pipe;
542 struct pipe_resource *res;
543
544 if (!stw_dev)
545 return FALSE;
546
547 fb = stw_framebuffer_from_hdc( hdc );
548 if (fb == NULL)
549 return FALSE;
550
551 screen = stw_dev->screen;
552 ctx = stw_current_context();
553 pipe = ctx ? ctx->st->pipe : NULL;
554
555 res = (struct pipe_resource *)data->pPrivData;
556
557 if (data->hSurface != fb->hSharedSurface) {
558 if (fb->shared_surface) {
559 stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface);
560 fb->shared_surface = NULL;
561 }
562
563 fb->hSharedSurface = data->hSurface;
564
565 if (data->hSurface &&
566 stw_dev->stw_winsys->shared_surface_open) {
567 fb->shared_surface =
568 stw_dev->stw_winsys->shared_surface_open(screen,
569 fb->hSharedSurface);
570 }
571 }
572
573 if (!fb->minimized) {
574 if (fb->shared_surface) {
575 stw_dev->stw_winsys->compose(screen,
576 res,
577 fb->shared_surface,
578 &fb->client_rect,
579 data->ullPresentToken);
580 }
581 else {
582 stw_dev->stw_winsys->present( screen, pipe, res, hdc );
583 }
584 }
585
586 stw_framebuffer_update(fb);
587 stw_notify_current_locked(fb);
588
589 stw_framebuffer_unlock(fb);
590
591 return TRUE;
592 }
593
594
595 /**
596 * Queue a composition.
597 *
598 * The stw_framebuffer object must have its mutex locked. The mutex will
599 * be unlocked here before returning.
600 */
601 BOOL
stw_framebuffer_present_locked(HDC hdc,struct stw_framebuffer * fb,struct pipe_resource * res)602 stw_framebuffer_present_locked(HDC hdc,
603 struct stw_framebuffer *fb,
604 struct pipe_resource *res)
605 {
606 if (fb->winsys_framebuffer) {
607 BOOL result = fb->winsys_framebuffer->present(fb->winsys_framebuffer);
608
609 stw_framebuffer_update(fb);
610 stw_notify_current_locked(fb);
611 stw_framebuffer_unlock(fb);
612
613 return result;
614 }
615 else if (stw_dev->callbacks.pfnPresentBuffers &&
616 stw_dev->stw_winsys->compose) {
617 PRESENTBUFFERSCB data;
618
619 memset(&data, 0, sizeof data);
620 data.nVersion = 2;
621 data.syncType = PRESCB_SYNCTYPE_NONE;
622 data.luidAdapter = stw_dev->AdapterLuid;
623 data.updateRect = fb->client_rect;
624 data.pPrivData = (void *)res;
625
626 stw_notify_current_locked(fb);
627 stw_framebuffer_unlock(fb);
628
629 return stw_dev->callbacks.pfnPresentBuffers(hdc, &data);
630 }
631 else {
632 struct pipe_screen *screen = stw_dev->screen;
633 struct stw_context *ctx = stw_current_context();
634 struct pipe_context *pipe = ctx ? ctx->st->pipe : NULL;
635
636 stw_dev->stw_winsys->present( screen, pipe, res, hdc );
637
638 stw_framebuffer_update(fb);
639 stw_notify_current_locked(fb);
640 stw_framebuffer_unlock(fb);
641
642 return TRUE;
643 }
644 }
645
646
647 /**
648 * This is called just before issuing the buffer swap/present.
649 * We query the current time and determine if we should sleep before
650 * issuing the swap/present.
651 * This is a bit of a hack and is certainly not very accurate but it
652 * basically works.
653 * This is for the WGL_ARB_swap_interval extension.
654 */
655 static void
wait_swap_interval(struct stw_framebuffer * fb)656 wait_swap_interval(struct stw_framebuffer *fb)
657 {
658 /* Note: all time variables here are in units of microseconds */
659 int64_t cur_time = os_time_get_nano() / 1000;
660
661 if (fb->prev_swap_time != 0) {
662 /* Compute time since previous swap */
663 int64_t delta = cur_time - fb->prev_swap_time;
664 int64_t min_swap_period =
665 1.0e6 / stw_dev->refresh_rate * stw_dev->swap_interval;
666
667 /* If time since last swap is less than wait period, wait.
668 * Note that it's possible for the delta to be negative because of
669 * rollover. See https://bugs.freedesktop.org/show_bug.cgi?id=102241
670 */
671 if ((delta >= 0) && (delta < min_swap_period)) {
672 float fudge = 1.75f; /* emperical fudge factor */
673 int64_t wait = (min_swap_period - delta) * fudge;
674 os_time_sleep(wait);
675 }
676 }
677
678 fb->prev_swap_time = cur_time;
679 }
680
681 BOOL
stw_framebuffer_swap_locked(HDC hdc,struct stw_framebuffer * fb)682 stw_framebuffer_swap_locked(HDC hdc, struct stw_framebuffer *fb)
683 {
684 struct stw_context *ctx;
685 if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) {
686 stw_framebuffer_unlock(fb);
687 return TRUE;
688 }
689
690 ctx = stw_current_context();
691 if (ctx) {
692 if (ctx->hud) {
693 /* Display the HUD */
694 struct pipe_resource *back =
695 stw_get_framebuffer_resource(fb->stfb, ST_ATTACHMENT_BACK_LEFT);
696 if (back) {
697 hud_run(ctx->hud, NULL, back);
698 }
699 }
700
701 if (ctx->current_framebuffer == fb) {
702 /* flush current context */
703 stw_st_flush(ctx->st, fb->stfb, ST_FLUSH_END_OF_FRAME);
704 }
705 }
706
707 if (stw_dev->swap_interval != 0 && !fb->winsys_framebuffer) {
708 wait_swap_interval(fb);
709 }
710
711 return stw_st_swap_framebuffer_locked(hdc, ctx->st, fb->stfb);
712 }
713
714 BOOL APIENTRY
DrvSwapBuffers(HDC hdc)715 DrvSwapBuffers(HDC hdc)
716 {
717 struct stw_framebuffer *fb;
718
719 if (!stw_dev)
720 return FALSE;
721
722 fb = stw_framebuffer_from_hdc( hdc );
723 if (fb == NULL)
724 return FALSE;
725
726 return stw_framebuffer_swap_locked(hdc, fb);
727 }
728
729
730 BOOL APIENTRY
DrvSwapLayerBuffers(HDC hdc,UINT fuPlanes)731 DrvSwapLayerBuffers(HDC hdc, UINT fuPlanes)
732 {
733 if (fuPlanes & WGL_SWAP_MAIN_PLANE)
734 return DrvSwapBuffers(hdc);
735
736 return FALSE;
737 }
738