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 "main/context.h"
31 #include "pipe/p_format.h"
32 #include "pipe/p_screen.h"
33 #include "util/u_format.h"
34 #include "state_tracker/st_context.h"
35 #include "state_tracker/st_public.h"
38 #include "trace/tr_screen.h"
39 #include "trace/tr_texture.h"
43 #include "stw_framebuffer.h"
44 #include "stw_device.h"
45 #include "stw_winsys.h"
50 * Search the framebuffer with the matching HWND while holding the
51 * stw_dev::fb_mutex global lock.
53 static INLINE
struct stw_framebuffer
*
54 stw_framebuffer_from_hwnd_locked(
57 struct stw_framebuffer
*fb
;
59 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
60 if (fb
->hWnd
== hwnd
) {
61 pipe_mutex_lock(fb
->mutex
);
70 * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
71 * must be held, by this order. Obviously no further access to fb can be done
75 stw_framebuffer_destroy_locked(
76 struct stw_framebuffer
*fb
)
78 struct stw_framebuffer
**link
;
80 link
= &stw_dev
->fb_head
;
82 link
= &(*link
)->next
;
87 if(fb
->shared_surface
)
88 stw_dev
->stw_winsys
->shared_surface_close(stw_dev
->screen
, fb
->shared_surface
);
90 st_unreference_framebuffer(fb
->stfb
);
92 pipe_mutex_unlock( fb
->mutex
);
94 pipe_mutex_destroy( fb
->mutex
);
101 stw_framebuffer_release(
102 struct stw_framebuffer
*fb
)
105 pipe_mutex_unlock( fb
->mutex
);
110 stw_framebuffer_get_size( struct stw_framebuffer
*fb
)
112 unsigned width
, height
;
119 /* Get the client area size. */
120 GetClientRect( fb
->hWnd
, &client_rect
);
121 assert(client_rect
.left
== 0);
122 assert(client_rect
.top
== 0);
123 width
= client_rect
.right
- client_rect
.left
;
124 height
= client_rect
.bottom
- client_rect
.top
;
131 if(width
!= fb
->width
|| height
!= fb
->height
) {
132 fb
->must_resize
= TRUE
;
139 ClientToScreen(fb
->hWnd
, &client_pos
);
141 GetWindowRect(fb
->hWnd
, &window_rect
);
143 fb
->client_rect
.left
= client_pos
.x
- window_rect
.left
;
144 fb
->client_rect
.top
= client_pos
.y
- window_rect
.top
;
145 fb
->client_rect
.right
= fb
->client_rect
.left
+ fb
->width
;
146 fb
->client_rect
.bottom
= fb
->client_rect
.top
+ fb
->height
;
150 debug_printf("%s: client_position = (%i, %i)\n",
151 __FUNCTION__
, client_pos
.x
, client_pos
.y
);
152 debug_printf("%s: window_rect = (%i, %i) - (%i, %i)\n",
154 window_rect
.left
, window_rect
.top
,
155 window_rect
.right
, window_rect
.bottom
);
156 debug_printf("%s: client_rect = (%i, %i) - (%i, %i)\n",
158 fb
->client_rect
.left
, fb
->client_rect
.top
,
159 fb
->client_rect
.right
, fb
->client_rect
.bottom
);
165 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
166 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
169 stw_call_window_proc(
174 struct stw_tls_data
*tls_data
;
175 PCWPSTRUCT pParams
= (PCWPSTRUCT
)lParam
;
176 struct stw_framebuffer
*fb
;
178 tls_data
= stw_tls_get_data();
183 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
185 if (pParams
->message
== WM_WINDOWPOSCHANGED
) {
186 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
187 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
188 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
189 * can be masked out by the application. */
190 LPWINDOWPOS lpWindowPos
= (LPWINDOWPOS
)pParams
->lParam
;
191 if((lpWindowPos
->flags
& SWP_SHOWWINDOW
) ||
192 !(lpWindowPos
->flags
& SWP_NOMOVE
) ||
193 !(lpWindowPos
->flags
& SWP_NOSIZE
)) {
194 fb
= stw_framebuffer_from_hwnd( pParams
->hwnd
);
196 /* Size in WINDOWPOS includes the window frame, so get the size
197 * of the client area via GetClientRect. */
198 stw_framebuffer_get_size(fb
);
199 stw_framebuffer_release(fb
);
203 else if (pParams
->message
== WM_DESTROY
) {
204 pipe_mutex_lock( stw_dev
->fb_mutex
);
205 fb
= stw_framebuffer_from_hwnd_locked( pParams
->hwnd
);
207 stw_framebuffer_destroy_locked(fb
);
208 pipe_mutex_unlock( stw_dev
->fb_mutex
);
211 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
215 struct stw_framebuffer
*
216 stw_framebuffer_create(
221 struct stw_framebuffer
*fb
;
222 const struct stw_pixelformat_info
*pfi
;
224 /* We only support drawing to a window. */
225 hWnd
= WindowFromDC( hdc
);
229 fb
= CALLOC_STRUCT( stw_framebuffer
);
235 fb
->iPixelFormat
= iPixelFormat
;
237 fb
->pfi
= pfi
= stw_pixelformat_get_info( iPixelFormat
- 1 );
239 stw_pixelformat_visual(&fb
->visual
, pfi
);
241 stw_framebuffer_get_size(fb
);
243 pipe_mutex_init( fb
->mutex
);
245 /* This is the only case where we lock the stw_framebuffer::mutex before
246 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
247 * and we must prevent any other thread from destroying it before we return.
249 pipe_mutex_lock( fb
->mutex
);
251 pipe_mutex_lock( stw_dev
->fb_mutex
);
252 fb
->next
= stw_dev
->fb_head
;
253 stw_dev
->fb_head
= fb
;
254 pipe_mutex_unlock( stw_dev
->fb_mutex
);
261 stw_framebuffer_allocate(
262 struct stw_framebuffer
*fb
)
267 const struct stw_pixelformat_info
*pfi
= fb
->pfi
;
268 enum pipe_format colorFormat
, depthFormat
, stencilFormat
;
270 colorFormat
= pfi
->color_format
;
272 if(util_format_get_component_bits(pfi
->depth_stencil_format
, UTIL_FORMAT_COLORSPACE_ZS
, 0))
273 depthFormat
= pfi
->depth_stencil_format
;
275 depthFormat
= PIPE_FORMAT_NONE
;
277 if(util_format_get_component_bits(pfi
->depth_stencil_format
, UTIL_FORMAT_COLORSPACE_ZS
, 1))
278 stencilFormat
= pfi
->depth_stencil_format
;
280 stencilFormat
= PIPE_FORMAT_NONE
;
282 assert(fb
->must_resize
);
286 fb
->stfb
= st_create_framebuffer(
295 // to notify the context
296 fb
->must_resize
= TRUE
;
299 return fb
->stfb
? TRUE
: FALSE
;
304 * Update the framebuffer's size if necessary.
307 stw_framebuffer_update(
308 struct stw_framebuffer
*fb
)
314 /* XXX: It would be nice to avoid checking the size again -- in theory
315 * stw_call_window_proc would have cought the resize and stored the right
316 * size already, but unfortunately threads created before the DllMain is
317 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
318 * to know of their existing without using the not very portable PSAPI.
320 stw_framebuffer_get_size(fb
);
322 if(fb
->must_resize
) {
323 st_resize_framebuffer(fb
->stfb
, fb
->width
, fb
->height
);
324 fb
->must_resize
= FALSE
;
330 stw_framebuffer_cleanup( void )
332 struct stw_framebuffer
*fb
;
333 struct stw_framebuffer
*next
;
335 pipe_mutex_lock( stw_dev
->fb_mutex
);
337 fb
= stw_dev
->fb_head
;
341 pipe_mutex_lock(fb
->mutex
);
342 stw_framebuffer_destroy_locked(fb
);
346 stw_dev
->fb_head
= NULL
;
348 pipe_mutex_unlock( stw_dev
->fb_mutex
);
353 * Given an hdc, return the corresponding stw_framebuffer.
355 static INLINE
struct stw_framebuffer
*
356 stw_framebuffer_from_hdc_locked(
360 struct stw_framebuffer
*fb
;
363 * Some applications create and use several HDCs for the same window, so
364 * looking up the framebuffer by the HDC is not reliable. Use HWND whenever
367 hwnd
= WindowFromDC(hdc
);
369 return stw_framebuffer_from_hwnd_locked(hwnd
);
371 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
372 if (fb
->hDC
== hdc
) {
373 pipe_mutex_lock(fb
->mutex
);
382 * Given an hdc, return the corresponding stw_framebuffer.
384 struct stw_framebuffer
*
385 stw_framebuffer_from_hdc(
388 struct stw_framebuffer
*fb
;
390 pipe_mutex_lock( stw_dev
->fb_mutex
);
391 fb
= stw_framebuffer_from_hdc_locked(hdc
);
392 pipe_mutex_unlock( stw_dev
->fb_mutex
);
399 * Given an hdc, return the corresponding stw_framebuffer.
401 struct stw_framebuffer
*
402 stw_framebuffer_from_hwnd(
405 struct stw_framebuffer
*fb
;
407 pipe_mutex_lock( stw_dev
->fb_mutex
);
408 fb
= stw_framebuffer_from_hwnd_locked(hwnd
);
409 pipe_mutex_unlock( stw_dev
->fb_mutex
);
422 struct stw_framebuffer
*fb
;
424 index
= (uint
) iPixelFormat
- 1;
425 count
= stw_pixelformat_get_extended_count();
429 fb
= stw_framebuffer_from_hdc_locked(hdc
);
431 /* SetPixelFormat must be called only once */
432 stw_framebuffer_release( fb
);
436 fb
= stw_framebuffer_create(hdc
, iPixelFormat
);
441 stw_framebuffer_release( fb
);
443 /* Some applications mistakenly use the undocumented wglSetPixelFormat
444 * function instead of SetPixelFormat, so we call SetPixelFormat here to
445 * avoid opengl32.dll's wglCreateContext to fail */
446 if (GetPixelFormat(hdc
) == 0) {
447 SetPixelFormat(hdc
, iPixelFormat
, NULL
);
458 int iPixelFormat
= 0;
459 struct stw_framebuffer
*fb
;
461 fb
= stw_framebuffer_from_hdc(hdc
);
463 iPixelFormat
= fb
->iPixelFormat
;
464 stw_framebuffer_release(fb
);
472 DrvPresentBuffers(HDC hdc
, PGLPRESENTBUFFERSDATA data
)
474 struct stw_framebuffer
*fb
;
475 struct pipe_screen
*screen
;
476 struct pipe_surface
*surface
;
478 fb
= stw_framebuffer_from_hdc( hdc
);
482 screen
= stw_dev
->screen
;
484 surface
= (struct pipe_surface
*)data
->pPrivateData
;
487 if(stw_dev
->trace_running
) {
488 screen
= trace_screen(screen
)->screen
;
489 surface
= trace_surface(surface
)->surface
;
493 if(data
->hSharedSurface
!= fb
->hSharedSurface
) {
494 if(fb
->shared_surface
) {
495 stw_dev
->stw_winsys
->shared_surface_close(screen
, fb
->shared_surface
);
496 fb
->shared_surface
= NULL
;
499 fb
->hSharedSurface
= data
->hSharedSurface
;
501 if(data
->hSharedSurface
&&
502 stw_dev
->stw_winsys
->shared_surface_open
) {
503 fb
->shared_surface
= stw_dev
->stw_winsys
->shared_surface_open(screen
, fb
->hSharedSurface
);
507 if(fb
->shared_surface
) {
508 stw_dev
->stw_winsys
->compose(screen
,
512 data
->PresentHistoryToken
);
515 stw_dev
->stw_winsys
->present( screen
, surface
, hdc
);
518 stw_framebuffer_update(fb
);
520 stw_framebuffer_release(fb
);
527 * Queue a composition.
529 * It will drop the lock on success.
532 stw_framebuffer_present_locked(HDC hdc
,
533 struct stw_framebuffer
*fb
,
534 struct pipe_surface
*surface
)
536 if(stw_dev
->callbacks
.wglCbPresentBuffers
&&
537 stw_dev
->stw_winsys
->compose
) {
538 GLCBPRESENTBUFFERSDATA data
;
540 memset(&data
, 0, sizeof data
);
543 data
.AdapterLuid
= stw_dev
->AdapterLuid
;
544 data
.rect
= fb
->client_rect
;
545 data
.pPrivateData
= (void *)surface
;
547 stw_framebuffer_release(fb
);
549 return stw_dev
->callbacks
.wglCbPresentBuffers(hdc
, &data
);
552 struct pipe_screen
*screen
= stw_dev
->screen
;
555 if(stw_dev
->trace_running
) {
556 screen
= trace_screen(screen
)->screen
;
557 surface
= trace_surface(surface
)->surface
;
561 stw_dev
->stw_winsys
->present( screen
, surface
, hdc
);
563 stw_framebuffer_update(fb
);
565 stw_framebuffer_release(fb
);
576 struct stw_framebuffer
*fb
;
577 struct pipe_surface
*surface
= NULL
;
579 fb
= stw_framebuffer_from_hdc( hdc
);
583 if (!(fb
->pfi
->pfd
.dwFlags
& PFD_DOUBLEBUFFER
)) {
584 stw_framebuffer_release(fb
);
588 st_swapbuffers(fb
->stfb
, &surface
, NULL
);
590 return stw_framebuffer_present_locked(hdc
, fb
, surface
);
599 if(fuPlanes
& WGL_SWAP_MAIN_PLANE
)
600 return DrvSwapBuffers(hdc
);