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