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 ReleaseDC(fb->hWnd, fb->hDC);
97 pipe_mutex_unlock( fb->mutex );
99 pipe_mutex_destroy( fb->mutex );
106 stw_framebuffer_release(
107 struct stw_framebuffer *fb)
110 pipe_mutex_unlock( fb->mutex );
115 stw_framebuffer_get_size( struct stw_framebuffer *fb )
127 assert(fb->width && fb->height);
128 assert(fb->client_rect.right == fb->client_rect.left + fb->width);
129 assert(fb->client_rect.bottom == fb->client_rect.top + fb->height);
132 * Get the client area size.
135 if (!GetClientRect(fb->hWnd, &client_rect)) {
139 assert(client_rect.left == 0);
140 assert(client_rect.top == 0);
141 width = client_rect.right - client_rect.left;
142 height = client_rect.bottom - client_rect.top;
144 if (width <= 0 || height <= 0) {
146 * When the window is minimized GetClientRect will return zeros. Simply
147 * preserve the current window size, until the window is restored or
154 if (width != fb->width || height != fb->height) {
155 fb->must_resize = TRUE;
162 if (ClientToScreen(fb->hWnd, &client_pos) &&
163 GetWindowRect(fb->hWnd, &window_rect)) {
164 fb->client_rect.left = client_pos.x - window_rect.left;
165 fb->client_rect.top = client_pos.y - window_rect.top;
168 fb->client_rect.right = fb->client_rect.left + fb->width;
169 fb->client_rect.bottom = fb->client_rect.top + fb->height;
173 debug_printf("%s: hwnd = %p\n", __FUNCTION__, fb->hWnd);
174 debug_printf("%s: client_position = (%li, %li)\n",
175 __FUNCTION__, client_pos.x, client_pos.y);
176 debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n",
178 window_rect.left, window_rect.top,
179 window_rect.right, window_rect.bottom);
180 debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n",
182 fb->client_rect.left, fb->client_rect.top,
183 fb->client_rect.right, fb->client_rect.bottom);
189 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
190 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
193 stw_call_window_proc(
198 struct stw_tls_data *tls_data;
199 PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
200 struct stw_framebuffer *fb;
202 tls_data = stw_tls_get_data();
206 if (nCode < 0 || !stw_dev)
207 return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
209 if (pParams->message == WM_WINDOWPOSCHANGED) {
210 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
211 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
212 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
213 * can be masked out by the application. */
214 LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
215 if((lpWindowPos->flags & SWP_SHOWWINDOW) ||
216 !(lpWindowPos->flags & SWP_NOMOVE) ||
217 !(lpWindowPos->flags & SWP_NOSIZE)) {
218 fb = stw_framebuffer_from_hwnd( pParams->hwnd );
220 /* Size in WINDOWPOS includes the window frame, so get the size
221 * of the client area via GetClientRect. */
222 stw_framebuffer_get_size(fb);
223 stw_framebuffer_release(fb);
227 else if (pParams->message == WM_DESTROY) {
228 pipe_mutex_lock( stw_dev->fb_mutex );
229 fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd );
231 stw_framebuffer_destroy_locked(fb);
232 pipe_mutex_unlock( stw_dev->fb_mutex );
235 return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
239 struct stw_framebuffer *
240 stw_framebuffer_create(
245 struct stw_framebuffer *fb;
246 const struct stw_pixelformat_info *pfi;
248 /* We only support drawing to a window. */
249 hWnd = WindowFromDC( hdc );
253 fb = CALLOC_STRUCT( stw_framebuffer );
257 /* Applications use, create, destroy device contexts, so the hdc passed is. We create our own DC
258 * because we need one for single buffered visuals.
260 fb->hDC = GetDC(hWnd);
263 fb->iPixelFormat = iPixelFormat;
265 fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat - 1 );
266 fb->stfb = stw_st_create_framebuffer( fb );
275 * Windows can be sometimes have zero width and or height, but we ensure
276 * a non-zero framebuffer size at all times.
279 fb->must_resize = TRUE;
282 fb->client_rect.left = 0;
283 fb->client_rect.top = 0;
284 fb->client_rect.right = fb->client_rect.left + fb->width;
285 fb->client_rect.bottom = fb->client_rect.top + fb->height;
287 stw_framebuffer_get_size(fb);
289 pipe_mutex_init( fb->mutex );
291 /* This is the only case where we lock the stw_framebuffer::mutex before
292 * stw_dev::fb_mutex, since no other thread can know about this framebuffer
293 * and we must prevent any other thread from destroying it before we return.
295 pipe_mutex_lock( fb->mutex );
297 pipe_mutex_lock( stw_dev->fb_mutex );
298 fb->next = stw_dev->fb_head;
299 stw_dev->fb_head = fb;
300 pipe_mutex_unlock( stw_dev->fb_mutex );
306 * Have ptr reference fb. The referenced framebuffer should be locked.
309 stw_framebuffer_reference(
310 struct stw_framebuffer **ptr,
311 struct stw_framebuffer *fb)
313 struct stw_framebuffer *old_fb = *ptr;
321 pipe_mutex_lock(stw_dev->fb_mutex);
323 pipe_mutex_lock(old_fb->mutex);
324 stw_framebuffer_destroy_locked(old_fb);
326 pipe_mutex_unlock(stw_dev->fb_mutex);
334 * Update the framebuffer's size if necessary.
337 stw_framebuffer_update(
338 struct stw_framebuffer *fb)
344 /* XXX: It would be nice to avoid checking the size again -- in theory
345 * stw_call_window_proc would have cought the resize and stored the right
346 * size already, but unfortunately threads created before the DllMain is
347 * called don't get a DLL_THREAD_ATTACH notification, and there is no way
348 * to know of their existing without using the not very portable PSAPI.
350 stw_framebuffer_get_size(fb);
355 stw_framebuffer_cleanup( void )
357 struct stw_framebuffer *fb;
358 struct stw_framebuffer *next;
363 pipe_mutex_lock( stw_dev->fb_mutex );
365 fb = stw_dev->fb_head;
369 pipe_mutex_lock(fb->mutex);
370 stw_framebuffer_destroy_locked(fb);
374 stw_dev->fb_head = NULL;
376 pipe_mutex_unlock( stw_dev->fb_mutex );
381 * Given an hdc, return the corresponding stw_framebuffer.
383 static INLINE struct stw_framebuffer *
384 stw_framebuffer_from_hdc_locked(
389 hwnd = WindowFromDC(hdc);
394 return stw_framebuffer_from_hwnd_locked(hwnd);
399 * Given an hdc, return the corresponding stw_framebuffer.
401 struct stw_framebuffer *
402 stw_framebuffer_from_hdc(
405 struct stw_framebuffer *fb;
410 pipe_mutex_lock( stw_dev->fb_mutex );
411 fb = stw_framebuffer_from_hdc_locked(hdc);
412 pipe_mutex_unlock( stw_dev->fb_mutex );
419 * Given an hdc, return the corresponding stw_framebuffer.
421 struct stw_framebuffer *
422 stw_framebuffer_from_hwnd(
425 struct stw_framebuffer *fb;
427 pipe_mutex_lock( stw_dev->fb_mutex );
428 fb = stw_framebuffer_from_hwnd_locked(hwnd);
429 pipe_mutex_unlock( stw_dev->fb_mutex );
442 struct stw_framebuffer *fb;
447 index = (uint) iPixelFormat - 1;
448 count = stw_pixelformat_get_extended_count();
452 fb = stw_framebuffer_from_hdc_locked(hdc);
454 /* SetPixelFormat must be called only once */
455 stw_framebuffer_release( fb );
459 fb = stw_framebuffer_create(hdc, iPixelFormat);
464 stw_framebuffer_release( fb );
466 /* Some applications mistakenly use the undocumented wglSetPixelFormat
467 * function instead of SetPixelFormat, so we call SetPixelFormat here to
468 * avoid opengl32.dll's wglCreateContext to fail */
469 if (GetPixelFormat(hdc) == 0) {
470 SetPixelFormat(hdc, iPixelFormat, NULL);
481 int iPixelFormat = 0;
482 struct stw_framebuffer *fb;
484 fb = stw_framebuffer_from_hdc(hdc);
486 iPixelFormat = fb->iPixelFormat;
487 stw_framebuffer_release(fb);
495 DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data)
497 struct stw_framebuffer *fb;
498 struct pipe_screen *screen;
499 struct pipe_resource *res;
504 fb = stw_framebuffer_from_hdc( hdc );
508 screen = stw_dev->screen;
510 res = (struct pipe_resource *)data->pPrivateData;
512 if(data->hSharedSurface != fb->hSharedSurface) {
513 if(fb->shared_surface) {
514 stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface);
515 fb->shared_surface = NULL;
518 fb->hSharedSurface = data->hSharedSurface;
520 if(data->hSharedSurface &&
521 stw_dev->stw_winsys->shared_surface_open) {
522 fb->shared_surface = stw_dev->stw_winsys->shared_surface_open(screen, fb->hSharedSurface);
526 if(fb->shared_surface) {
527 stw_dev->stw_winsys->compose(screen,
531 data->PresentHistoryToken);
534 stw_dev->stw_winsys->present( screen, res, hdc );
537 stw_framebuffer_update(fb);
538 stw_notify_current_locked(fb);
540 stw_framebuffer_release(fb);
547 * Queue a composition.
549 * It will drop the lock on success.
552 stw_framebuffer_present_locked(HDC hdc,
553 struct stw_framebuffer *fb,
554 struct pipe_resource *res)
556 if(stw_dev->callbacks.wglCbPresentBuffers &&
557 stw_dev->stw_winsys->compose) {
558 GLCBPRESENTBUFFERSDATA data;
560 memset(&data, 0, sizeof data);
563 data.AdapterLuid = stw_dev->AdapterLuid;
564 data.rect = fb->client_rect;
565 data.pPrivateData = (void *)res;
567 stw_notify_current_locked(fb);
568 stw_framebuffer_release(fb);
570 return stw_dev->callbacks.wglCbPresentBuffers(hdc, &data);
573 struct pipe_screen *screen = stw_dev->screen;
575 stw_dev->stw_winsys->present( screen, res, hdc );
577 stw_framebuffer_update(fb);
578 stw_notify_current_locked(fb);
579 stw_framebuffer_release(fb);
590 struct stw_framebuffer *fb;
595 fb = stw_framebuffer_from_hdc( hdc );
599 if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) {
600 stw_framebuffer_release(fb);
604 stw_flush_current_locked(fb);
606 return stw_st_swap_framebuffer_locked(hdc, fb->stfb);
615 if(fuPlanes & WGL_SWAP_MAIN_PLANE)
616 return DrvSwapBuffers(hdc);