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_screen.h"
31 #include "util/u_memory.h"
32 #include "hud/hud_context.h"
33 #include "state_tracker/st_api.h"
36 #include "stw_framebuffer.h"
37 #include "stw_device.h"
38 #include "stw_winsys.h"
40 #include "stw_context.h"
45 * Search the framebuffer with the matching HWND while holding the
46 * stw_dev::fb_mutex global lock.
48 static INLINE
struct stw_framebuffer
*
49 stw_framebuffer_from_hwnd_locked(
52 struct stw_framebuffer
*fb
;
54 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
55 if (fb
->hWnd
== hwnd
) {
56 pipe_mutex_lock(fb
->mutex
);
65 * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
66 * must be held, by this order. If there are still references to the
67 * framebuffer, nothing will happen.
70 stw_framebuffer_destroy_locked(struct stw_framebuffer
*fb
)
72 struct stw_framebuffer
**link
;
74 /* check the reference count */
77 pipe_mutex_unlock( fb
->mutex
);
81 link
= &stw_dev
->fb_head
;
83 link
= &(*link
)->next
;
88 if (fb
->shared_surface
)
89 stw_dev
->stw_winsys
->shared_surface_close(stw_dev
->screen
,
92 stw_st_destroy_framebuffer_locked(fb
->stfb
);
94 pipe_mutex_unlock( fb
->mutex
);
96 pipe_mutex_destroy( fb
->mutex
);
103 stw_framebuffer_release(struct stw_framebuffer
*fb
)
106 pipe_mutex_unlock( fb
->mutex
);
111 stw_framebuffer_get_size(struct stw_framebuffer
*fb
)
123 assert(fb
->width
&& fb
->height
);
124 assert(fb
->client_rect
.right
== fb
->client_rect
.left
+ fb
->width
);
125 assert(fb
->client_rect
.bottom
== fb
->client_rect
.top
+ fb
->height
);
128 * Get the client area size.
131 if (!GetClientRect(fb
->hWnd
, &client_rect
)) {
135 assert(client_rect
.left
== 0);
136 assert(client_rect
.top
== 0);
137 width
= client_rect
.right
- client_rect
.left
;
138 height
= client_rect
.bottom
- client_rect
.top
;
140 fb
->minimized
= width
== 0 || height
== 0;
142 if (width
<= 0 || height
<= 0) {
144 * When the window is minimized GetClientRect will return zeros. Simply
145 * preserve the current window size, until the window is restored or
152 if (width
!= fb
->width
|| height
!= fb
->height
) {
153 fb
->must_resize
= TRUE
;
160 if (ClientToScreen(fb
->hWnd
, &client_pos
) &&
161 GetWindowRect(fb
->hWnd
, &window_rect
)) {
162 fb
->client_rect
.left
= client_pos
.x
- window_rect
.left
;
163 fb
->client_rect
.top
= client_pos
.y
- window_rect
.top
;
166 fb
->client_rect
.right
= fb
->client_rect
.left
+ fb
->width
;
167 fb
->client_rect
.bottom
= fb
->client_rect
.top
+ fb
->height
;
171 debug_printf("%s: hwnd = %p\n", __FUNCTION__
, fb
->hWnd
);
172 debug_printf("%s: client_position = (%li, %li)\n",
173 __FUNCTION__
, client_pos
.x
, client_pos
.y
);
174 debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n",
176 window_rect
.left
, window_rect
.top
,
177 window_rect
.right
, window_rect
.bottom
);
178 debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n",
180 fb
->client_rect
.left
, fb
->client_rect
.top
,
181 fb
->client_rect
.right
, fb
->client_rect
.bottom
);
187 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
188 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
191 stw_call_window_proc(int nCode
, WPARAM wParam
, LPARAM lParam
)
193 struct stw_tls_data
*tls_data
;
194 PCWPSTRUCT pParams
= (PCWPSTRUCT
)lParam
;
195 struct stw_framebuffer
*fb
;
197 tls_data
= stw_tls_get_data();
201 if (nCode
< 0 || !stw_dev
)
202 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
204 if (pParams
->message
== WM_WINDOWPOSCHANGED
) {
205 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
206 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
207 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
208 * can be masked out by the application.
210 LPWINDOWPOS lpWindowPos
= (LPWINDOWPOS
)pParams
->lParam
;
211 if ((lpWindowPos
->flags
& SWP_SHOWWINDOW
) ||
212 !(lpWindowPos
->flags
& SWP_NOMOVE
) ||
213 !(lpWindowPos
->flags
& SWP_NOSIZE
)) {
214 fb
= stw_framebuffer_from_hwnd( pParams
->hwnd
);
216 /* Size in WINDOWPOS includes the window frame, so get the size
217 * of the client area via GetClientRect.
219 stw_framebuffer_get_size(fb
);
220 stw_framebuffer_release(fb
);
224 else if (pParams
->message
== WM_DESTROY
) {
225 pipe_mutex_lock( stw_dev
->fb_mutex
);
226 fb
= stw_framebuffer_from_hwnd_locked( pParams
->hwnd
);
228 stw_framebuffer_destroy_locked(fb
);
229 pipe_mutex_unlock( stw_dev
->fb_mutex
);
232 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
236 struct stw_framebuffer
*
237 stw_framebuffer_create(HDC hdc
, int iPixelFormat
)
240 struct stw_framebuffer
*fb
;
241 const struct stw_pixelformat_info
*pfi
;
243 /* We only support drawing to a window. */
244 hWnd
= WindowFromDC( hdc
);
248 fb
= CALLOC_STRUCT( stw_framebuffer
);
253 fb
->iPixelFormat
= iPixelFormat
;
256 * We often need a displayable pixel format to make GDI happy. Set it
257 * here (always 1, i.e., out first pixel format) where appropriate.
259 fb
->iDisplayablePixelFormat
= iPixelFormat
<= stw_dev
->pixelformat_count
262 fb
->pfi
= pfi
= stw_pixelformat_get_info( iPixelFormat
);
263 fb
->stfb
= stw_st_create_framebuffer( fb
);
272 * Windows can be sometimes have zero width and or height, but we ensure
273 * a non-zero framebuffer size at all times.
276 fb
->must_resize
= TRUE
;
279 fb
->client_rect
.left
= 0;
280 fb
->client_rect
.top
= 0;
281 fb
->client_rect
.right
= fb
->client_rect
.left
+ fb
->width
;
282 fb
->client_rect
.bottom
= fb
->client_rect
.top
+ fb
->height
;
284 stw_framebuffer_get_size(fb
);
286 pipe_mutex_init( fb
->mutex
);
288 /* This is the only case where we lock the stw_framebuffer::mutex before
289 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
290 * and we must prevent any other thread from destroying it before we return.
292 pipe_mutex_lock( fb
->mutex
);
294 pipe_mutex_lock( stw_dev
->fb_mutex
);
295 fb
->next
= stw_dev
->fb_head
;
296 stw_dev
->fb_head
= fb
;
297 pipe_mutex_unlock( stw_dev
->fb_mutex
);
304 * Have ptr reference fb. The referenced framebuffer should be locked.
307 stw_framebuffer_reference(struct stw_framebuffer
**ptr
,
308 struct stw_framebuffer
*fb
)
310 struct stw_framebuffer
*old_fb
= *ptr
;
318 pipe_mutex_lock(stw_dev
->fb_mutex
);
320 pipe_mutex_lock(old_fb
->mutex
);
321 stw_framebuffer_destroy_locked(old_fb
);
323 pipe_mutex_unlock(stw_dev
->fb_mutex
);
331 * Update the framebuffer's size if necessary.
334 stw_framebuffer_update(struct stw_framebuffer
*fb
)
340 /* XXX: It would be nice to avoid checking the size again -- in theory
341 * stw_call_window_proc would have cought the resize and stored the right
342 * size already, but unfortunately threads created before the DllMain is
343 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
344 * to know of their existing without using the not very portable PSAPI.
346 stw_framebuffer_get_size(fb
);
351 stw_framebuffer_cleanup(void)
353 struct stw_framebuffer
*fb
;
354 struct stw_framebuffer
*next
;
359 pipe_mutex_lock( stw_dev
->fb_mutex
);
361 fb
= stw_dev
->fb_head
;
365 pipe_mutex_lock(fb
->mutex
);
366 stw_framebuffer_destroy_locked(fb
);
370 stw_dev
->fb_head
= NULL
;
372 pipe_mutex_unlock( stw_dev
->fb_mutex
);
377 * Given an hdc, return the corresponding stw_framebuffer.
379 static INLINE
struct stw_framebuffer
*
380 stw_framebuffer_from_hdc_locked(
385 hwnd
= WindowFromDC(hdc
);
390 return stw_framebuffer_from_hwnd_locked(hwnd
);
395 * Given an hdc, return the corresponding stw_framebuffer.
397 struct stw_framebuffer
*
398 stw_framebuffer_from_hdc(HDC hdc
)
400 struct stw_framebuffer
*fb
;
405 pipe_mutex_lock( stw_dev
->fb_mutex
);
406 fb
= stw_framebuffer_from_hdc_locked(hdc
);
407 pipe_mutex_unlock( stw_dev
->fb_mutex
);
414 * Given an hdc, return the corresponding stw_framebuffer.
416 struct stw_framebuffer
*
417 stw_framebuffer_from_hwnd(HWND hwnd
)
419 struct stw_framebuffer
*fb
;
421 pipe_mutex_lock( stw_dev
->fb_mutex
);
422 fb
= stw_framebuffer_from_hwnd_locked(hwnd
);
423 pipe_mutex_unlock( stw_dev
->fb_mutex
);
430 DrvSetPixelFormat(HDC hdc
, LONG iPixelFormat
)
434 struct stw_framebuffer
*fb
;
439 index
= (uint
) iPixelFormat
- 1;
440 count
= stw_pixelformat_get_count();
444 fb
= stw_framebuffer_from_hdc_locked(hdc
);
447 * SetPixelFormat must be called only once. However ignore
448 * pbuffers, for which the framebuffer object is created first.
450 boolean bPbuffer
= fb
->bPbuffer
;
452 stw_framebuffer_release( fb
);
457 fb
= stw_framebuffer_create(hdc
, iPixelFormat
);
462 stw_framebuffer_release( fb
);
464 /* Some applications mistakenly use the undocumented wglSetPixelFormat
465 * function instead of SetPixelFormat, so we call SetPixelFormat here to
466 * avoid opengl32.dll's wglCreateContext to fail */
467 if (GetPixelFormat(hdc
) == 0) {
468 BOOL bRet
= SetPixelFormat(hdc
, iPixelFormat
, NULL
);
477 stw_pixelformat_get(HDC hdc
)
479 int iPixelFormat
= 0;
480 struct stw_framebuffer
*fb
;
482 fb
= stw_framebuffer_from_hdc(hdc
);
484 iPixelFormat
= fb
->iPixelFormat
;
485 stw_framebuffer_release(fb
);
493 DrvPresentBuffers(HDC hdc
, PGLPRESENTBUFFERSDATA data
)
495 struct stw_framebuffer
*fb
;
496 struct pipe_screen
*screen
;
497 struct pipe_resource
*res
;
502 fb
= stw_framebuffer_from_hdc( hdc
);
506 screen
= stw_dev
->screen
;
508 res
= (struct pipe_resource
*)data
->pPrivateData
;
510 if (data
->hSharedSurface
!= fb
->hSharedSurface
) {
511 if (fb
->shared_surface
) {
512 stw_dev
->stw_winsys
->shared_surface_close(screen
, fb
->shared_surface
);
513 fb
->shared_surface
= NULL
;
516 fb
->hSharedSurface
= data
->hSharedSurface
;
518 if (data
->hSharedSurface
&&
519 stw_dev
->stw_winsys
->shared_surface_open
) {
521 stw_dev
->stw_winsys
->shared_surface_open(screen
,
526 if (!fb
->minimized
) {
527 if (fb
->shared_surface
) {
528 stw_dev
->stw_winsys
->compose(screen
,
532 data
->PresentHistoryToken
);
535 stw_dev
->stw_winsys
->present( screen
, res
, hdc
);
539 stw_framebuffer_update(fb
);
540 stw_notify_current_locked(fb
);
542 stw_framebuffer_release(fb
);
549 * Queue a composition.
551 * It will drop the lock on success.
554 stw_framebuffer_present_locked(HDC hdc
,
555 struct stw_framebuffer
*fb
,
556 struct pipe_resource
*res
)
558 if (stw_dev
->callbacks
.wglCbPresentBuffers
&&
559 stw_dev
->stw_winsys
->compose
) {
560 GLCBPRESENTBUFFERSDATA data
;
562 memset(&data
, 0, sizeof data
);
565 data
.AdapterLuid
= stw_dev
->AdapterLuid
;
566 data
.rect
= fb
->client_rect
;
567 data
.pPrivateData
= (void *)res
;
569 stw_notify_current_locked(fb
);
570 stw_framebuffer_release(fb
);
572 return stw_dev
->callbacks
.wglCbPresentBuffers(hdc
, &data
);
575 struct pipe_screen
*screen
= stw_dev
->screen
;
577 stw_dev
->stw_winsys
->present( screen
, res
, hdc
);
579 stw_framebuffer_update(fb
);
580 stw_notify_current_locked(fb
);
581 stw_framebuffer_release(fb
);
589 DrvSwapBuffers(HDC hdc
)
591 struct stw_context
*ctx
;
592 struct stw_framebuffer
*fb
;
597 fb
= stw_framebuffer_from_hdc( hdc
);
601 if (!(fb
->pfi
->pfd
.dwFlags
& PFD_DOUBLEBUFFER
)) {
602 stw_framebuffer_release(fb
);
606 /* Display the HUD */
607 ctx
= stw_current_context();
608 if (ctx
&& ctx
->hud
) {
609 struct pipe_resource
*back
=
610 stw_get_framebuffer_resource(fb
->stfb
, ST_ATTACHMENT_BACK_LEFT
);
611 hud_draw(ctx
->hud
, back
);
614 stw_flush_current_locked(fb
);
616 return stw_st_swap_framebuffer_locked(hdc
, fb
->stfb
);
621 DrvSwapLayerBuffers(HDC hdc
, UINT fuPlanes
)
623 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
)
624 return DrvSwapBuffers(hdc
);