1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 "state_tracker/st_context.h"
34 #include "state_tracker/st_public.h"
37 #include "trace/tr_screen.h"
38 #include "trace/tr_texture.h"
41 #include "stw_framebuffer.h"
42 #include "stw_device.h"
43 #include "stw_public.h"
44 #include "stw_winsys.h"
49 * Search the framebuffer with the matching HWND while holding the
50 * stw_dev::fb_mutex global lock.
52 static INLINE
struct stw_framebuffer
*
53 stw_framebuffer_from_hwnd_locked(
56 struct stw_framebuffer
*fb
;
58 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
59 if (fb
->hWnd
== hwnd
) {
60 pipe_mutex_lock(fb
->mutex
);
69 * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
70 * must be held, by this order. Obviously no further access to fb can be done
74 stw_framebuffer_destroy_locked(
75 struct stw_framebuffer
*fb
)
77 struct stw_framebuffer
**link
;
79 link
= &stw_dev
->fb_head
;
81 link
= &(*link
)->next
;
86 st_unreference_framebuffer(fb
->stfb
);
88 pipe_mutex_unlock( fb
->mutex
);
90 pipe_mutex_destroy( fb
->mutex
);
97 stw_framebuffer_release(
98 struct stw_framebuffer
*fb
)
101 pipe_mutex_unlock( fb
->mutex
);
106 stw_framebuffer_get_size( struct stw_framebuffer
*fb
)
108 unsigned width
, height
;
113 GetClientRect( fb
->hWnd
, &rect
);
114 width
= rect
.right
- rect
.left
;
115 height
= rect
.bottom
- rect
.top
;
122 if(width
!= fb
->width
|| height
!= fb
->height
) {
123 fb
->must_resize
= TRUE
;
131 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
132 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
135 stw_call_window_proc(
140 struct stw_tls_data
*tls_data
;
141 PCWPSTRUCT pParams
= (PCWPSTRUCT
)lParam
;
142 struct stw_framebuffer
*fb
;
144 tls_data
= stw_tls_get_data();
149 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
151 if (pParams
->message
== WM_WINDOWPOSCHANGED
) {
152 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
153 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
154 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
155 * can be masked out by the application. */
156 LPWINDOWPOS lpWindowPos
= (LPWINDOWPOS
)pParams
->lParam
;
157 if((lpWindowPos
->flags
& SWP_SHOWWINDOW
) ||
158 !(lpWindowPos
->flags
& SWP_NOSIZE
)) {
159 fb
= stw_framebuffer_from_hwnd( pParams
->hwnd
);
161 /* Size in WINDOWPOS includes the window frame, so get the size
162 * of the client area via GetClientRect. */
163 stw_framebuffer_get_size(fb
);
164 stw_framebuffer_release(fb
);
168 else if (pParams
->message
== WM_DESTROY
) {
169 pipe_mutex_lock( stw_dev
->fb_mutex
);
170 fb
= stw_framebuffer_from_hwnd_locked( pParams
->hwnd
);
172 stw_framebuffer_destroy_locked(fb
);
173 pipe_mutex_unlock( stw_dev
->fb_mutex
);
176 return CallNextHookEx(tls_data
->hCallWndProcHook
, nCode
, wParam
, lParam
);
180 struct stw_framebuffer
*
181 stw_framebuffer_create(
186 struct stw_framebuffer
*fb
;
187 const struct stw_pixelformat_info
*pfi
;
189 /* We only support drawing to a window. */
190 hWnd
= WindowFromDC( hdc
);
194 fb
= CALLOC_STRUCT( stw_framebuffer
);
200 fb
->iPixelFormat
= iPixelFormat
;
202 fb
->pfi
= pfi
= stw_pixelformat_get_info( iPixelFormat
- 1 );
204 stw_pixelformat_visual(&fb
->visual
, pfi
);
206 stw_framebuffer_get_size(fb
);
208 pipe_mutex_init( fb
->mutex
);
210 /* This is the only case where we lock the stw_framebuffer::mutex before
211 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
212 * and we must prevent any other thread from destroying it before we return.
214 pipe_mutex_lock( fb
->mutex
);
216 pipe_mutex_lock( stw_dev
->fb_mutex
);
217 fb
->next
= stw_dev
->fb_head
;
218 stw_dev
->fb_head
= fb
;
219 pipe_mutex_unlock( stw_dev
->fb_mutex
);
226 stw_framebuffer_allocate(
227 struct stw_framebuffer
*fb
)
232 const struct stw_pixelformat_info
*pfi
= fb
->pfi
;
233 enum pipe_format colorFormat
, depthFormat
, stencilFormat
;
235 colorFormat
= pfi
->color_format
;
237 assert(pf_layout( pfi
->depth_stencil_format
) == PIPE_FORMAT_LAYOUT_RGBAZS
);
239 if(pf_get_component_bits( pfi
->depth_stencil_format
, PIPE_FORMAT_COMP_Z
))
240 depthFormat
= pfi
->depth_stencil_format
;
242 depthFormat
= PIPE_FORMAT_NONE
;
244 if(pf_get_component_bits( pfi
->depth_stencil_format
, PIPE_FORMAT_COMP_S
))
245 stencilFormat
= pfi
->depth_stencil_format
;
247 stencilFormat
= PIPE_FORMAT_NONE
;
249 assert(fb
->must_resize
);
253 fb
->stfb
= st_create_framebuffer(
262 // to notify the context
263 fb
->must_resize
= TRUE
;
266 return fb
->stfb
? TRUE
: FALSE
;
271 * Update the framebuffer's size if necessary.
274 stw_framebuffer_update(
275 struct stw_framebuffer
*fb
)
281 /* XXX: It would be nice to avoid checking the size again -- in theory
282 * stw_call_window_proc would have cought the resize and stored the right
283 * size already, but unfortunately threads created before the DllMain is
284 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
285 * to know of their existing without using the not very portable PSAPI.
287 stw_framebuffer_get_size(fb
);
289 if(fb
->must_resize
) {
290 st_resize_framebuffer(fb
->stfb
, fb
->width
, fb
->height
);
291 fb
->must_resize
= FALSE
;
297 stw_framebuffer_cleanup( void )
299 struct stw_framebuffer
*fb
;
300 struct stw_framebuffer
*next
;
302 pipe_mutex_lock( stw_dev
->fb_mutex
);
304 fb
= stw_dev
->fb_head
;
308 pipe_mutex_lock(fb
->mutex
);
309 stw_framebuffer_destroy_locked(fb
);
313 stw_dev
->fb_head
= NULL
;
315 pipe_mutex_unlock( stw_dev
->fb_mutex
);
320 * Given an hdc, return the corresponding stw_framebuffer.
322 static INLINE
struct stw_framebuffer
*
323 stw_framebuffer_from_hdc_locked(
327 struct stw_framebuffer
*fb
;
330 * Some applications create and use several HDCs for the same window, so
331 * looking up the framebuffer by the HDC is not reliable. Use HWND whenever
334 hwnd
= WindowFromDC(hdc
);
336 return stw_framebuffer_from_hwnd_locked(hwnd
);
338 for (fb
= stw_dev
->fb_head
; fb
!= NULL
; fb
= fb
->next
)
339 if (fb
->hDC
== hdc
) {
340 pipe_mutex_lock(fb
->mutex
);
349 * Given an hdc, return the corresponding stw_framebuffer.
351 struct stw_framebuffer
*
352 stw_framebuffer_from_hdc(
355 struct stw_framebuffer
*fb
;
357 pipe_mutex_lock( stw_dev
->fb_mutex
);
358 fb
= stw_framebuffer_from_hdc_locked(hdc
);
359 pipe_mutex_unlock( stw_dev
->fb_mutex
);
366 * Given an hdc, return the corresponding stw_framebuffer.
368 struct stw_framebuffer
*
369 stw_framebuffer_from_hwnd(
372 struct stw_framebuffer
*fb
;
374 pipe_mutex_lock( stw_dev
->fb_mutex
);
375 fb
= stw_framebuffer_from_hwnd_locked(hwnd
);
376 pipe_mutex_unlock( stw_dev
->fb_mutex
);
389 struct stw_framebuffer
*fb
;
391 index
= (uint
) iPixelFormat
- 1;
392 count
= stw_pixelformat_get_extended_count();
396 fb
= stw_framebuffer_from_hdc_locked(hdc
);
398 /* SetPixelFormat must be called only once */
399 stw_framebuffer_release( fb
);
403 fb
= stw_framebuffer_create(hdc
, iPixelFormat
);
408 stw_framebuffer_release( fb
);
410 /* Some applications mistakenly use the undocumented wglSetPixelFormat
411 * function instead of SetPixelFormat, so we call SetPixelFormat here to
412 * avoid opengl32.dll's wglCreateContext to fail */
413 if (GetPixelFormat(hdc
) == 0) {
414 SetPixelFormat(hdc
, iPixelFormat
, NULL
);
425 int iPixelFormat
= 0;
426 struct stw_framebuffer
*fb
;
428 fb
= stw_framebuffer_from_hdc(hdc
);
430 iPixelFormat
= fb
->iPixelFormat
;
431 stw_framebuffer_release(fb
);
442 struct stw_framebuffer
*fb
;
443 struct pipe_screen
*screen
;
444 struct pipe_surface
*surface
;
446 fb
= stw_framebuffer_from_hdc( hdc
);
450 if (!(fb
->pfi
->pfd
.dwFlags
& PFD_DOUBLEBUFFER
)) {
451 stw_framebuffer_release(fb
);
455 /* If we're swapping the buffer associated with the current context
456 * we have to flush any pending rendering commands first.
458 st_notify_swapbuffers( fb
->stfb
);
460 screen
= stw_dev
->screen
;
462 if(!st_get_framebuffer_surface( fb
->stfb
, ST_SURFACE_BACK_LEFT
, &surface
)) {
463 /* FIXME: this shouldn't happen, but does on glean */
464 stw_framebuffer_release(fb
);
469 if(stw_dev
->trace_running
) {
470 screen
= trace_screen(screen
)->screen
;
471 surface
= trace_surface(surface
)->surface
;
475 stw_dev
->stw_winsys
->flush_frontbuffer( screen
, surface
, hdc
);
477 stw_framebuffer_update(fb
);
478 stw_framebuffer_release(fb
);
485 stw_swap_layer_buffers(
489 if(fuPlanes
& WGL_SWAP_MAIN_PLANE
)
490 return stw_swap_buffers(hdc
);