1 /**************************************************************************
3 * Copyright 2008-2009 Vmware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 #include "pipe/p_format.h"
31 #include "pipe/p_screen.h"
32 #include "util/u_format.h"
33 #include "util/u_memory.h"
34 #include "hud/hud_context.h"
35 #include "state_tracker/st_api.h"
38 #include "stw_framebuffer.h"
39 #include "stw_device.h"
40 #include "stw_winsys.h"
42 #include "stw_context.h"
47 * Search the framebuffer with the matching HWND while holding the
48 * stw_dev::fb_mutex global lock.
50 static INLINE
struct stw_framebuffer
*
51 stw_framebuffer_from_hwnd_locked(
54 struct stw_framebuffer
*fb
;
56 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
57 if (fb
->hWnd
== hwnd
) {
58 pipe_mutex_lock(fb
->mutex
);
67 * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
68 * must be held, by this order. If there are still references to the
69 * framebuffer, nothing will happen.
72 stw_framebuffer_destroy_locked(
73 struct stw_framebuffer
*fb
)
75 struct stw_framebuffer
**link
;
77 /* check the reference count */
80 pipe_mutex_unlock( fb
->mutex
);
84 link
= &stw_dev
->fb_head
;
86 link
= &(*link
)->next
;
91 if(fb
->shared_surface
)
92 stw_dev
->stw_winsys
->shared_surface_close(stw_dev
->screen
, fb
->shared_surface
);
94 stw_st_destroy_framebuffer_locked(fb
->stfb
);
96 pipe_mutex_unlock( fb
->mutex
);
98 pipe_mutex_destroy( fb
->mutex
);
105 stw_framebuffer_release(
106 struct stw_framebuffer
*fb
)
109 pipe_mutex_unlock( fb
->mutex
);
114 stw_framebuffer_get_size( struct stw_framebuffer
*fb
)
126 assert(fb
->width
&& fb
->height
);
127 assert(fb
->client_rect
.right
== fb
->client_rect
.left
+ fb
->width
);
128 assert(fb
->client_rect
.bottom
== fb
->client_rect
.top
+ fb
->height
);
131 * Get the client area size.
134 if (!GetClientRect(fb
->hWnd
, &client_rect
)) {
138 assert(client_rect
.left
== 0);
139 assert(client_rect
.top
== 0);
140 width
= client_rect
.right
- client_rect
.left
;
141 height
= client_rect
.bottom
- client_rect
.top
;
143 fb
->minimized
= width
== 0 || height
== 0;
145 if (width
<= 0 || height
<= 0) {
147 * When the window is minimized GetClientRect will return zeros. Simply
148 * preserve the current window size, until the window is restored or
155 if (width
!= fb
->width
|| height
!= fb
->height
) {
156 fb
->must_resize
= TRUE
;
163 if (ClientToScreen(fb
->hWnd
, &client_pos
) &&
164 GetWindowRect(fb
->hWnd
, &window_rect
)) {
165 fb
->client_rect
.left
= client_pos
.x
- window_rect
.left
;
166 fb
->client_rect
.top
= client_pos
.y
- window_rect
.top
;
169 fb
->client_rect
.right
= fb
->client_rect
.left
+ fb
->width
;
170 fb
->client_rect
.bottom
= fb
->client_rect
.top
+ fb
->height
;
174 debug_printf("%s: hwnd = %p\n", __FUNCTION__
, fb
->hWnd
);
175 debug_printf("%s: client_position = (%li, %li)\n",
176 __FUNCTION__
, client_pos
.x
, client_pos
.y
);
177 debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n",
179 window_rect
.left
, window_rect
.top
,
180 window_rect
.right
, window_rect
.bottom
);
181 debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n",
183 fb
->client_rect
.left
, fb
->client_rect
.top
,
184 fb
->client_rect
.right
, fb
->client_rect
.bottom
);
190 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
191 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
194 stw_call_window_proc(
199 struct stw_tls_data
*tls_data
;
200 PCWPSTRUCT pParams
= (PCWPSTRUCT
)lParam
;
201 struct stw_framebuffer
*fb
;
203 tls_data
= stw_tls_get_data();
207 if (nCode
< 0 || !stw_dev
)
208 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
210 if (pParams
->message
== WM_WINDOWPOSCHANGED
) {
211 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
212 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
213 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
214 * can be masked out by the application. */
215 LPWINDOWPOS lpWindowPos
= (LPWINDOWPOS
)pParams
->lParam
;
216 if((lpWindowPos
->flags
& SWP_SHOWWINDOW
) ||
217 !(lpWindowPos
->flags
& SWP_NOMOVE
) ||
218 !(lpWindowPos
->flags
& SWP_NOSIZE
)) {
219 fb
= stw_framebuffer_from_hwnd( pParams
->hwnd
);
221 /* Size in WINDOWPOS includes the window frame, so get the size
222 * of the client area via GetClientRect. */
223 stw_framebuffer_get_size(fb
);
224 stw_framebuffer_release(fb
);
228 else if (pParams
->message
== WM_DESTROY
) {
229 pipe_mutex_lock( stw_dev
->fb_mutex
);
230 fb
= stw_framebuffer_from_hwnd_locked( pParams
->hwnd
);
232 stw_framebuffer_destroy_locked(fb
);
233 pipe_mutex_unlock( stw_dev
->fb_mutex
);
236 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
240 struct stw_framebuffer
*
241 stw_framebuffer_create(
246 struct stw_framebuffer
*fb
;
247 const struct stw_pixelformat_info
*pfi
;
249 /* We only support drawing to a window. */
250 hWnd
= WindowFromDC( hdc
);
254 fb
= CALLOC_STRUCT( stw_framebuffer
);
259 fb
->iPixelFormat
= iPixelFormat
;
262 * We often need a displayable pixel format to make GDI happy. Set it here (always 1, i.e.,
263 * out first pixel format) where appropriat.
265 fb
->iDisplayablePixelFormat
= iPixelFormat
<= stw_dev
->pixelformat_count
? iPixelFormat
: 1;
267 fb
->pfi
= pfi
= stw_pixelformat_get_info( iPixelFormat
);
268 fb
->stfb
= stw_st_create_framebuffer( fb
);
277 * Windows can be sometimes have zero width and or height, but we ensure
278 * a non-zero framebuffer size at all times.
281 fb
->must_resize
= TRUE
;
284 fb
->client_rect
.left
= 0;
285 fb
->client_rect
.top
= 0;
286 fb
->client_rect
.right
= fb
->client_rect
.left
+ fb
->width
;
287 fb
->client_rect
.bottom
= fb
->client_rect
.top
+ fb
->height
;
289 stw_framebuffer_get_size(fb
);
291 pipe_mutex_init( fb
->mutex
);
293 /* This is the only case where we lock the stw_framebuffer::mutex before
294 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
295 * and we must prevent any other thread from destroying it before we return.
297 pipe_mutex_lock( fb
->mutex
);
299 pipe_mutex_lock( stw_dev
->fb_mutex
);
300 fb
->next
= stw_dev
->fb_head
;
301 stw_dev
->fb_head
= fb
;
302 pipe_mutex_unlock( stw_dev
->fb_mutex
);
308 * Have ptr reference fb. The referenced framebuffer should be locked.
311 stw_framebuffer_reference(
312 struct stw_framebuffer
**ptr
,
313 struct stw_framebuffer
*fb
)
315 struct stw_framebuffer
*old_fb
= *ptr
;
323 pipe_mutex_lock(stw_dev
->fb_mutex
);
325 pipe_mutex_lock(old_fb
->mutex
);
326 stw_framebuffer_destroy_locked(old_fb
);
328 pipe_mutex_unlock(stw_dev
->fb_mutex
);
336 * Update the framebuffer's size if necessary.
339 stw_framebuffer_update(
340 struct stw_framebuffer
*fb
)
346 /* XXX: It would be nice to avoid checking the size again -- in theory
347 * stw_call_window_proc would have cought the resize and stored the right
348 * size already, but unfortunately threads created before the DllMain is
349 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
350 * to know of their existing without using the not very portable PSAPI.
352 stw_framebuffer_get_size(fb
);
357 stw_framebuffer_cleanup( void )
359 struct stw_framebuffer
*fb
;
360 struct stw_framebuffer
*next
;
365 pipe_mutex_lock( stw_dev
->fb_mutex
);
367 fb
= stw_dev
->fb_head
;
371 pipe_mutex_lock(fb
->mutex
);
372 stw_framebuffer_destroy_locked(fb
);
376 stw_dev
->fb_head
= NULL
;
378 pipe_mutex_unlock( stw_dev
->fb_mutex
);
383 * Given an hdc, return the corresponding stw_framebuffer.
385 static INLINE
struct stw_framebuffer
*
386 stw_framebuffer_from_hdc_locked(
391 hwnd
= WindowFromDC(hdc
);
396 return stw_framebuffer_from_hwnd_locked(hwnd
);
401 * Given an hdc, return the corresponding stw_framebuffer.
403 struct stw_framebuffer
*
404 stw_framebuffer_from_hdc(
407 struct stw_framebuffer
*fb
;
412 pipe_mutex_lock( stw_dev
->fb_mutex
);
413 fb
= stw_framebuffer_from_hdc_locked(hdc
);
414 pipe_mutex_unlock( stw_dev
->fb_mutex
);
421 * Given an hdc, return the corresponding stw_framebuffer.
423 struct stw_framebuffer
*
424 stw_framebuffer_from_hwnd(
427 struct stw_framebuffer
*fb
;
429 pipe_mutex_lock( stw_dev
->fb_mutex
);
430 fb
= stw_framebuffer_from_hwnd_locked(hwnd
);
431 pipe_mutex_unlock( stw_dev
->fb_mutex
);
444 struct stw_framebuffer
*fb
;
449 index
= (uint
) iPixelFormat
- 1;
450 count
= stw_pixelformat_get_count();
454 fb
= stw_framebuffer_from_hdc_locked(hdc
);
457 * SetPixelFormat must be called only once. However ignore
458 * pbuffers, for which the framebuffer object is created first.
460 boolean bPbuffer
= fb
->bPbuffer
;
462 stw_framebuffer_release( fb
);
467 fb
= stw_framebuffer_create(hdc
, iPixelFormat
);
472 stw_framebuffer_release( fb
);
474 /* Some applications mistakenly use the undocumented wglSetPixelFormat
475 * function instead of SetPixelFormat, so we call SetPixelFormat here to
476 * avoid opengl32.dll's wglCreateContext to fail */
477 if (GetPixelFormat(hdc
) == 0) {
478 BOOL bRet
= SetPixelFormat(hdc
, iPixelFormat
, NULL
);
490 int iPixelFormat
= 0;
491 struct stw_framebuffer
*fb
;
493 fb
= stw_framebuffer_from_hdc(hdc
);
495 iPixelFormat
= fb
->iPixelFormat
;
496 stw_framebuffer_release(fb
);
504 DrvPresentBuffers(HDC hdc
, PGLPRESENTBUFFERSDATA data
)
506 struct stw_framebuffer
*fb
;
507 struct pipe_screen
*screen
;
508 struct pipe_resource
*res
;
513 fb
= stw_framebuffer_from_hdc( hdc
);
517 screen
= stw_dev
->screen
;
519 res
= (struct pipe_resource
*)data
->pPrivateData
;
521 if(data
->hSharedSurface
!= fb
->hSharedSurface
) {
522 if(fb
->shared_surface
) {
523 stw_dev
->stw_winsys
->shared_surface_close(screen
, fb
->shared_surface
);
524 fb
->shared_surface
= NULL
;
527 fb
->hSharedSurface
= data
->hSharedSurface
;
529 if(data
->hSharedSurface
&&
530 stw_dev
->stw_winsys
->shared_surface_open
) {
531 fb
->shared_surface
= stw_dev
->stw_winsys
->shared_surface_open(screen
, fb
->hSharedSurface
);
535 if (!fb
->minimized
) {
536 if (fb
->shared_surface
) {
537 stw_dev
->stw_winsys
->compose(screen
,
541 data
->PresentHistoryToken
);
544 stw_dev
->stw_winsys
->present( screen
, res
, hdc
);
548 stw_framebuffer_update(fb
);
549 stw_notify_current_locked(fb
);
551 stw_framebuffer_release(fb
);
558 * Queue a composition.
560 * It will drop the lock on success.
563 stw_framebuffer_present_locked(HDC hdc
,
564 struct stw_framebuffer
*fb
,
565 struct pipe_resource
*res
)
567 if(stw_dev
->callbacks
.wglCbPresentBuffers
&&
568 stw_dev
->stw_winsys
->compose
) {
569 GLCBPRESENTBUFFERSDATA data
;
571 memset(&data
, 0, sizeof data
);
574 data
.AdapterLuid
= stw_dev
->AdapterLuid
;
575 data
.rect
= fb
->client_rect
;
576 data
.pPrivateData
= (void *)res
;
578 stw_notify_current_locked(fb
);
579 stw_framebuffer_release(fb
);
581 return stw_dev
->callbacks
.wglCbPresentBuffers(hdc
, &data
);
584 struct pipe_screen
*screen
= stw_dev
->screen
;
586 stw_dev
->stw_winsys
->present( screen
, res
, hdc
);
588 stw_framebuffer_update(fb
);
589 stw_notify_current_locked(fb
);
590 stw_framebuffer_release(fb
);
601 struct stw_context
*ctx
;
602 struct stw_framebuffer
*fb
;
607 fb
= stw_framebuffer_from_hdc( hdc
);
611 if (!(fb
->pfi
->pfd
.dwFlags
& PFD_DOUBLEBUFFER
)) {
612 stw_framebuffer_release(fb
);
616 /* Display the HUD */
617 ctx
= stw_current_context();
618 if (ctx
&& ctx
->hud
) {
619 struct pipe_resource
*back
=
620 stw_get_framebuffer_resource(fb
->stfb
, ST_ATTACHMENT_BACK_LEFT
);
621 hud_draw(ctx
->hud
, back
);
624 stw_flush_current_locked(fb
);
626 return stw_st_swap_framebuffer_locked(hdc
, fb
->stfb
);
635 if(fuPlanes
& WGL_SWAP_MAIN_PLANE
)
636 return DrvSwapBuffers(hdc
);