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 "state_tracker/st_api.h"
37 #include "stw_framebuffer.h"
38 #include "stw_device.h"
39 #include "stw_winsys.h"
41 #include "stw_context.h"
46 * Search the framebuffer with the matching HWND while holding the
47 * stw_dev::fb_mutex global lock.
49 static INLINE
struct stw_framebuffer
*
50 stw_framebuffer_from_hwnd_locked(
53 struct stw_framebuffer
*fb
;
55 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
56 if (fb
->hWnd
== hwnd
) {
57 pipe_mutex_lock(fb
->mutex
);
66 * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
67 * must be held, by this order. If there are still references to the
68 * framebuffer, nothing will happen.
71 stw_framebuffer_destroy_locked(
72 struct stw_framebuffer
*fb
)
74 struct stw_framebuffer
**link
;
76 /* check the reference count */
79 pipe_mutex_unlock( fb
->mutex
);
83 link
= &stw_dev
->fb_head
;
85 link
= &(*link
)->next
;
90 if(fb
->shared_surface
)
91 stw_dev
->stw_winsys
->shared_surface_close(stw_dev
->screen
, fb
->shared_surface
);
93 stw_st_destroy_framebuffer_locked(fb
->stfb
);
95 pipe_mutex_unlock( fb
->mutex
);
97 pipe_mutex_destroy( fb
->mutex
);
104 stw_framebuffer_release(
105 struct stw_framebuffer
*fb
)
108 pipe_mutex_unlock( fb
->mutex
);
113 stw_framebuffer_get_size( struct stw_framebuffer
*fb
)
115 unsigned width
, height
;
122 /* Get the client area size. */
123 GetClientRect( fb
->hWnd
, &client_rect
);
124 assert(client_rect
.left
== 0);
125 assert(client_rect
.top
== 0);
126 width
= client_rect
.right
- client_rect
.left
;
127 height
= client_rect
.bottom
- client_rect
.top
;
134 if(width
!= fb
->width
|| height
!= fb
->height
) {
135 fb
->must_resize
= TRUE
;
142 ClientToScreen(fb
->hWnd
, &client_pos
);
144 GetWindowRect(fb
->hWnd
, &window_rect
);
146 fb
->client_rect
.left
= client_pos
.x
- window_rect
.left
;
147 fb
->client_rect
.top
= client_pos
.y
- window_rect
.top
;
148 fb
->client_rect
.right
= fb
->client_rect
.left
+ fb
->width
;
149 fb
->client_rect
.bottom
= fb
->client_rect
.top
+ fb
->height
;
153 debug_printf("%s: client_position = (%i, %i)\n",
154 __FUNCTION__
, client_pos
.x
, client_pos
.y
);
155 debug_printf("%s: window_rect = (%i, %i) - (%i, %i)\n",
157 window_rect
.left
, window_rect
.top
,
158 window_rect
.right
, window_rect
.bottom
);
159 debug_printf("%s: client_rect = (%i, %i) - (%i, %i)\n",
161 fb
->client_rect
.left
, fb
->client_rect
.top
,
162 fb
->client_rect
.right
, fb
->client_rect
.bottom
);
168 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
169 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
172 stw_call_window_proc(
177 struct stw_tls_data
*tls_data
;
178 PCWPSTRUCT pParams
= (PCWPSTRUCT
)lParam
;
179 struct stw_framebuffer
*fb
;
181 tls_data
= stw_tls_get_data();
185 if (nCode
< 0 || !stw_dev
)
186 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
188 if (pParams
->message
== WM_WINDOWPOSCHANGED
) {
189 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
190 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
191 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
192 * can be masked out by the application. */
193 LPWINDOWPOS lpWindowPos
= (LPWINDOWPOS
)pParams
->lParam
;
194 if((lpWindowPos
->flags
& SWP_SHOWWINDOW
) ||
195 !(lpWindowPos
->flags
& SWP_NOMOVE
) ||
196 !(lpWindowPos
->flags
& SWP_NOSIZE
)) {
197 fb
= stw_framebuffer_from_hwnd( pParams
->hwnd
);
199 /* Size in WINDOWPOS includes the window frame, so get the size
200 * of the client area via GetClientRect. */
201 stw_framebuffer_get_size(fb
);
202 stw_framebuffer_release(fb
);
206 else if (pParams
->message
== WM_DESTROY
) {
207 pipe_mutex_lock( stw_dev
->fb_mutex
);
208 fb
= stw_framebuffer_from_hwnd_locked( pParams
->hwnd
);
210 stw_framebuffer_destroy_locked(fb
);
211 pipe_mutex_unlock( stw_dev
->fb_mutex
);
214 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
218 struct stw_framebuffer
*
219 stw_framebuffer_create(
224 struct stw_framebuffer
*fb
;
225 const struct stw_pixelformat_info
*pfi
;
227 /* We only support drawing to a window. */
228 hWnd
= WindowFromDC( hdc
);
232 fb
= CALLOC_STRUCT( stw_framebuffer
);
238 fb
->iPixelFormat
= iPixelFormat
;
240 fb
->pfi
= pfi
= stw_pixelformat_get_info( iPixelFormat
- 1 );
241 fb
->stfb
= stw_st_create_framebuffer( fb
);
249 stw_framebuffer_get_size(fb
);
251 pipe_mutex_init( fb
->mutex
);
253 /* This is the only case where we lock the stw_framebuffer::mutex before
254 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
255 * and we must prevent any other thread from destroying it before we return.
257 pipe_mutex_lock( fb
->mutex
);
259 pipe_mutex_lock( stw_dev
->fb_mutex
);
260 fb
->next
= stw_dev
->fb_head
;
261 stw_dev
->fb_head
= fb
;
262 pipe_mutex_unlock( stw_dev
->fb_mutex
);
268 * Have ptr reference fb. The referenced framebuffer should be locked.
271 stw_framebuffer_reference(
272 struct stw_framebuffer
**ptr
,
273 struct stw_framebuffer
*fb
)
275 struct stw_framebuffer
*old_fb
= *ptr
;
283 pipe_mutex_lock(stw_dev
->fb_mutex
);
285 pipe_mutex_lock(old_fb
->mutex
);
286 stw_framebuffer_destroy_locked(old_fb
);
288 pipe_mutex_unlock(stw_dev
->fb_mutex
);
296 * Update the framebuffer's size if necessary.
299 stw_framebuffer_update(
300 struct stw_framebuffer
*fb
)
306 /* XXX: It would be nice to avoid checking the size again -- in theory
307 * stw_call_window_proc would have cought the resize and stored the right
308 * size already, but unfortunately threads created before the DllMain is
309 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
310 * to know of their existing without using the not very portable PSAPI.
312 stw_framebuffer_get_size(fb
);
317 stw_framebuffer_cleanup( void )
319 struct stw_framebuffer
*fb
;
320 struct stw_framebuffer
*next
;
325 pipe_mutex_lock( stw_dev
->fb_mutex
);
327 fb
= stw_dev
->fb_head
;
331 pipe_mutex_lock(fb
->mutex
);
332 stw_framebuffer_destroy_locked(fb
);
336 stw_dev
->fb_head
= NULL
;
338 pipe_mutex_unlock( stw_dev
->fb_mutex
);
343 * Given an hdc, return the corresponding stw_framebuffer.
345 static INLINE
struct stw_framebuffer
*
346 stw_framebuffer_from_hdc_locked(
350 struct stw_framebuffer
*fb
;
353 * Some applications create and use several HDCs for the same window, so
354 * looking up the framebuffer by the HDC is not reliable. Use HWND whenever
357 hwnd
= WindowFromDC(hdc
);
359 return stw_framebuffer_from_hwnd_locked(hwnd
);
361 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
362 if (fb
->hDC
== hdc
) {
363 pipe_mutex_lock(fb
->mutex
);
372 * Given an hdc, return the corresponding stw_framebuffer.
374 struct stw_framebuffer
*
375 stw_framebuffer_from_hdc(
378 struct stw_framebuffer
*fb
;
383 pipe_mutex_lock( stw_dev
->fb_mutex
);
384 fb
= stw_framebuffer_from_hdc_locked(hdc
);
385 pipe_mutex_unlock( stw_dev
->fb_mutex
);
392 * Given an hdc, return the corresponding stw_framebuffer.
394 struct stw_framebuffer
*
395 stw_framebuffer_from_hwnd(
398 struct stw_framebuffer
*fb
;
400 pipe_mutex_lock( stw_dev
->fb_mutex
);
401 fb
= stw_framebuffer_from_hwnd_locked(hwnd
);
402 pipe_mutex_unlock( stw_dev
->fb_mutex
);
415 struct stw_framebuffer
*fb
;
420 index
= (uint
) iPixelFormat
- 1;
421 count
= stw_pixelformat_get_extended_count();
425 fb
= stw_framebuffer_from_hdc_locked(hdc
);
427 /* SetPixelFormat must be called only once */
428 stw_framebuffer_release( fb
);
432 fb
= stw_framebuffer_create(hdc
, iPixelFormat
);
437 stw_framebuffer_release( fb
);
439 /* Some applications mistakenly use the undocumented wglSetPixelFormat
440 * function instead of SetPixelFormat, so we call SetPixelFormat here to
441 * avoid opengl32.dll's wglCreateContext to fail */
442 if (GetPixelFormat(hdc
) == 0) {
443 SetPixelFormat(hdc
, iPixelFormat
, NULL
);
454 int iPixelFormat
= 0;
455 struct stw_framebuffer
*fb
;
457 fb
= stw_framebuffer_from_hdc(hdc
);
459 iPixelFormat
= fb
->iPixelFormat
;
460 stw_framebuffer_release(fb
);
468 DrvPresentBuffers(HDC hdc
, PGLPRESENTBUFFERSDATA data
)
470 struct stw_framebuffer
*fb
;
471 struct pipe_screen
*screen
;
472 struct pipe_surface
*surface
;
477 fb
= stw_framebuffer_from_hdc( hdc
);
481 screen
= stw_dev
->screen
;
483 surface
= (struct pipe_surface
*)data
->pPrivateData
;
485 if(data
->hSharedSurface
!= fb
->hSharedSurface
) {
486 if(fb
->shared_surface
) {
487 stw_dev
->stw_winsys
->shared_surface_close(screen
, fb
->shared_surface
);
488 fb
->shared_surface
= NULL
;
491 fb
->hSharedSurface
= data
->hSharedSurface
;
493 if(data
->hSharedSurface
&&
494 stw_dev
->stw_winsys
->shared_surface_open
) {
495 fb
->shared_surface
= stw_dev
->stw_winsys
->shared_surface_open(screen
, fb
->hSharedSurface
);
499 if(fb
->shared_surface
) {
500 stw_dev
->stw_winsys
->compose(screen
,
504 data
->PresentHistoryToken
);
507 stw_dev
->stw_winsys
->present( screen
, surface
, hdc
);
510 stw_framebuffer_update(fb
);
511 stw_notify_current_locked(fb
);
513 stw_framebuffer_release(fb
);
520 * Queue a composition.
522 * It will drop the lock on success.
525 stw_framebuffer_present_locked(HDC hdc
,
526 struct stw_framebuffer
*fb
,
527 struct pipe_surface
*surface
)
529 if(stw_dev
->callbacks
.wglCbPresentBuffers
&&
530 stw_dev
->stw_winsys
->compose
) {
531 GLCBPRESENTBUFFERSDATA data
;
533 memset(&data
, 0, sizeof data
);
536 data
.AdapterLuid
= stw_dev
->AdapterLuid
;
537 data
.rect
= fb
->client_rect
;
538 data
.pPrivateData
= (void *)surface
;
540 stw_notify_current_locked(fb
);
541 stw_framebuffer_release(fb
);
543 return stw_dev
->callbacks
.wglCbPresentBuffers(hdc
, &data
);
546 struct pipe_screen
*screen
= stw_dev
->screen
;
548 stw_dev
->stw_winsys
->present( screen
, surface
, hdc
);
550 stw_framebuffer_update(fb
);
551 stw_notify_current_locked(fb
);
552 stw_framebuffer_release(fb
);
563 struct stw_framebuffer
*fb
;
568 fb
= stw_framebuffer_from_hdc( hdc
);
572 if (!(fb
->pfi
->pfd
.dwFlags
& PFD_DOUBLEBUFFER
)) {
573 stw_framebuffer_release(fb
);
577 stw_flush_current_locked(fb
);
579 return stw_st_swap_framebuffer_locked(fb
->stfb
);
588 if(fuPlanes
& WGL_SWAP_MAIN_PLANE
)
589 return DrvSwapBuffers(hdc
);