• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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