17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2008-2009 VMware, Inc. 47ec681f3Smrg * All Rights Reserved. 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the 87ec681f3Smrg * "Software"), to deal in the Software without restriction, including 97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to 117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 127ec681f3Smrg * the following conditions: 137ec681f3Smrg * 147ec681f3Smrg * The above copyright notice and this permission notice (including the 157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions 167ec681f3Smrg * of the Software. 177ec681f3Smrg * 187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257ec681f3Smrg * 267ec681f3Smrg **************************************************************************/ 277ec681f3Smrg 287ec681f3Smrg#include <windows.h> 297ec681f3Smrg 307ec681f3Smrg#include "pipe/p_screen.h" 317ec681f3Smrg#include "pipe/p_state.h" 327ec681f3Smrg#include "util/u_memory.h" 337ec681f3Smrg#include "hud/hud_context.h" 347ec681f3Smrg#include "util/os_time.h" 357ec681f3Smrg#include "frontend/api.h" 367ec681f3Smrg 377ec681f3Smrg#include <GL/gl.h> 387ec681f3Smrg#include "gldrv.h" 397ec681f3Smrg#include "stw_framebuffer.h" 407ec681f3Smrg#include "stw_device.h" 417ec681f3Smrg#include "stw_winsys.h" 427ec681f3Smrg#include "stw_tls.h" 437ec681f3Smrg#include "stw_context.h" 447ec681f3Smrg#include "stw_st.h" 457ec681f3Smrg 467ec681f3Smrg 477ec681f3Smrg/** 487ec681f3Smrg * Search the framebuffer with the matching HWND while holding the 497ec681f3Smrg * stw_dev::fb_mutex global lock. 507ec681f3Smrg * If a stw_framebuffer is found, lock it and return the pointer. 517ec681f3Smrg * Else, return NULL. 527ec681f3Smrg */ 537ec681f3Smrgstatic struct stw_framebuffer * 547ec681f3Smrgstw_framebuffer_from_hwnd_locked(HWND hwnd) 557ec681f3Smrg{ 567ec681f3Smrg struct stw_framebuffer *fb; 577ec681f3Smrg 587ec681f3Smrg for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next) 597ec681f3Smrg if (fb->hWnd == hwnd) { 607ec681f3Smrg stw_framebuffer_lock(fb); 617ec681f3Smrg assert(fb->mutex.RecursionCount == 1); 627ec681f3Smrg return fb; 637ec681f3Smrg } 647ec681f3Smrg 657ec681f3Smrg return NULL; 667ec681f3Smrg} 677ec681f3Smrg 687ec681f3Smrg 697ec681f3Smrg/** 707ec681f3Smrg * Decrement the reference count on the given stw_framebuffer object. 717ec681f3Smrg * If the reference count hits zero, destroy the object. 727ec681f3Smrg * 737ec681f3Smrg * Note: Both stw_dev::fb_mutex and stw_framebuffer::mutex must already be 747ec681f3Smrg * locked. After this function completes, the fb's mutex will be unlocked. 757ec681f3Smrg */ 767ec681f3Smrgvoid 777ec681f3Smrgstw_framebuffer_release_locked(struct stw_framebuffer *fb, 787ec681f3Smrg struct st_context_iface *stctx) 797ec681f3Smrg{ 807ec681f3Smrg struct stw_framebuffer **link; 817ec681f3Smrg 827ec681f3Smrg assert(fb); 837ec681f3Smrg assert(stw_own_mutex(&fb->mutex)); 847ec681f3Smrg assert(stw_own_mutex(&stw_dev->fb_mutex) || fb->owner == STW_FRAMEBUFFER_EGL_WINDOW); 857ec681f3Smrg 867ec681f3Smrg /* check the reference count */ 877ec681f3Smrg fb->refcnt--; 887ec681f3Smrg if (fb->refcnt) { 897ec681f3Smrg stw_framebuffer_unlock(fb); 907ec681f3Smrg return; 917ec681f3Smrg } 927ec681f3Smrg 937ec681f3Smrg if (fb->owner != STW_FRAMEBUFFER_EGL_WINDOW) { 947ec681f3Smrg /* remove this stw_framebuffer from the device's linked list */ 957ec681f3Smrg link = &stw_dev->fb_head; 967ec681f3Smrg while (*link != fb) 977ec681f3Smrg link = &(*link)->next; 987ec681f3Smrg assert(*link); 997ec681f3Smrg *link = fb->next; 1007ec681f3Smrg fb->next = NULL; 1017ec681f3Smrg } 1027ec681f3Smrg 1037ec681f3Smrg if (fb->shared_surface) 1047ec681f3Smrg stw_dev->stw_winsys->shared_surface_close(stw_dev->screen, 1057ec681f3Smrg fb->shared_surface); 1067ec681f3Smrg 1077ec681f3Smrg if (fb->winsys_framebuffer) 1087ec681f3Smrg fb->winsys_framebuffer->destroy(fb->winsys_framebuffer, stctx ? stctx->pipe : NULL); 1097ec681f3Smrg 1107ec681f3Smrg stw_st_destroy_framebuffer_locked(fb->stfb); 1117ec681f3Smrg 1127ec681f3Smrg stw_framebuffer_unlock(fb); 1137ec681f3Smrg 1147ec681f3Smrg DeleteCriticalSection(&fb->mutex); 1157ec681f3Smrg 1167ec681f3Smrg FREE( fb ); 1177ec681f3Smrg} 1187ec681f3Smrg 1197ec681f3Smrg 1207ec681f3Smrg/** 1217ec681f3Smrg * Query the size of the given framebuffer's on-screen window and update 1227ec681f3Smrg * the stw_framebuffer's width/height. 1237ec681f3Smrg */ 1247ec681f3Smrgstatic void 1257ec681f3Smrgstw_framebuffer_get_size(struct stw_framebuffer *fb) 1267ec681f3Smrg{ 1277ec681f3Smrg LONG width, height; 1287ec681f3Smrg RECT client_rect; 1297ec681f3Smrg RECT window_rect; 1307ec681f3Smrg POINT client_pos; 1317ec681f3Smrg 1327ec681f3Smrg /* 1337ec681f3Smrg * Sanity checking. 1347ec681f3Smrg */ 1357ec681f3Smrg assert(fb->hWnd); 1367ec681f3Smrg assert(fb->width && fb->height); 1377ec681f3Smrg assert(fb->client_rect.right == fb->client_rect.left + fb->width); 1387ec681f3Smrg assert(fb->client_rect.bottom == fb->client_rect.top + fb->height); 1397ec681f3Smrg 1407ec681f3Smrg /* 1417ec681f3Smrg * Get the client area size. 1427ec681f3Smrg */ 1437ec681f3Smrg if (!GetClientRect(fb->hWnd, &client_rect)) { 1447ec681f3Smrg return; 1457ec681f3Smrg } 1467ec681f3Smrg 1477ec681f3Smrg assert(client_rect.left == 0); 1487ec681f3Smrg assert(client_rect.top == 0); 1497ec681f3Smrg width = client_rect.right - client_rect.left; 1507ec681f3Smrg height = client_rect.bottom - client_rect.top; 1517ec681f3Smrg 1527ec681f3Smrg fb->minimized = width == 0 || height == 0; 1537ec681f3Smrg 1547ec681f3Smrg if (width <= 0 || height <= 0) { 1557ec681f3Smrg /* 1567ec681f3Smrg * When the window is minimized GetClientRect will return zeros. Simply 1577ec681f3Smrg * preserve the current window size, until the window is restored or 1587ec681f3Smrg * maximized again. 1597ec681f3Smrg */ 1607ec681f3Smrg return; 1617ec681f3Smrg } 1627ec681f3Smrg 1637ec681f3Smrg if (width != fb->width || height != fb->height) { 1647ec681f3Smrg fb->must_resize = TRUE; 1657ec681f3Smrg fb->width = width; 1667ec681f3Smrg fb->height = height; 1677ec681f3Smrg } 1687ec681f3Smrg 1697ec681f3Smrg client_pos.x = 0; 1707ec681f3Smrg client_pos.y = 0; 1717ec681f3Smrg if (ClientToScreen(fb->hWnd, &client_pos) && 1727ec681f3Smrg GetWindowRect(fb->hWnd, &window_rect)) { 1737ec681f3Smrg fb->client_rect.left = client_pos.x - window_rect.left; 1747ec681f3Smrg fb->client_rect.top = client_pos.y - window_rect.top; 1757ec681f3Smrg } 1767ec681f3Smrg 1777ec681f3Smrg fb->client_rect.right = fb->client_rect.left + fb->width; 1787ec681f3Smrg fb->client_rect.bottom = fb->client_rect.top + fb->height; 1797ec681f3Smrg 1807ec681f3Smrg#if 0 1817ec681f3Smrg debug_printf("\n"); 1827ec681f3Smrg debug_printf("%s: hwnd = %p\n", __FUNCTION__, fb->hWnd); 1837ec681f3Smrg debug_printf("%s: client_position = (%li, %li)\n", 1847ec681f3Smrg __FUNCTION__, client_pos.x, client_pos.y); 1857ec681f3Smrg debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n", 1867ec681f3Smrg __FUNCTION__, 1877ec681f3Smrg window_rect.left, window_rect.top, 1887ec681f3Smrg window_rect.right, window_rect.bottom); 1897ec681f3Smrg debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n", 1907ec681f3Smrg __FUNCTION__, 1917ec681f3Smrg fb->client_rect.left, fb->client_rect.top, 1927ec681f3Smrg fb->client_rect.right, fb->client_rect.bottom); 1937ec681f3Smrg#endif 1947ec681f3Smrg} 1957ec681f3Smrg 1967ec681f3Smrg 1977ec681f3Smrg/** 1987ec681f3Smrg * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx 1997ec681f3Smrg * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx 2007ec681f3Smrg */ 2017ec681f3SmrgLRESULT CALLBACK 2027ec681f3Smrgstw_call_window_proc(int nCode, WPARAM wParam, LPARAM lParam) 2037ec681f3Smrg{ 2047ec681f3Smrg struct stw_tls_data *tls_data; 2057ec681f3Smrg PCWPSTRUCT pParams = (PCWPSTRUCT)lParam; 2067ec681f3Smrg struct stw_framebuffer *fb; 2077ec681f3Smrg 2087ec681f3Smrg tls_data = stw_tls_get_data(); 2097ec681f3Smrg if (!tls_data) 2107ec681f3Smrg return 0; 2117ec681f3Smrg 2127ec681f3Smrg if (nCode < 0 || !stw_dev) 2137ec681f3Smrg return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); 2147ec681f3Smrg 2157ec681f3Smrg /* We check that the stw_dev object is initialized before we try to do 2167ec681f3Smrg * anything with it. Otherwise, in multi-threaded programs there's a 2177ec681f3Smrg * chance of executing this code before the stw_dev object is fully 2187ec681f3Smrg * initialized. 2197ec681f3Smrg */ 2207ec681f3Smrg if (stw_dev && stw_dev->initialized) { 2217ec681f3Smrg if (pParams->message == WM_WINDOWPOSCHANGED) { 2227ec681f3Smrg /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according 2237ec681f3Smrg * to http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx 2247ec681f3Smrg * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it 2257ec681f3Smrg * can be masked out by the application. 2267ec681f3Smrg */ 2277ec681f3Smrg LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam; 2287ec681f3Smrg if ((lpWindowPos->flags & SWP_SHOWWINDOW) || 2297ec681f3Smrg !(lpWindowPos->flags & SWP_NOMOVE) || 2307ec681f3Smrg !(lpWindowPos->flags & SWP_NOSIZE)) { 2317ec681f3Smrg fb = stw_framebuffer_from_hwnd( pParams->hwnd ); 2327ec681f3Smrg if (fb) { 2337ec681f3Smrg /* Size in WINDOWPOS includes the window frame, so get the size 2347ec681f3Smrg * of the client area via GetClientRect. 2357ec681f3Smrg */ 2367ec681f3Smrg stw_framebuffer_get_size(fb); 2377ec681f3Smrg stw_framebuffer_unlock(fb); 2387ec681f3Smrg } 2397ec681f3Smrg } 2407ec681f3Smrg } 2417ec681f3Smrg else if (pParams->message == WM_DESTROY) { 2427ec681f3Smrg stw_lock_framebuffers(stw_dev); 2437ec681f3Smrg fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd ); 2447ec681f3Smrg if (fb) { 2457ec681f3Smrg struct stw_context *current_context = stw_current_context(); 2467ec681f3Smrg struct st_context_iface *ctx_iface = current_context && 2477ec681f3Smrg current_context->current_framebuffer == fb ? current_context->st : NULL; 2487ec681f3Smrg stw_framebuffer_release_locked(fb, ctx_iface); 2497ec681f3Smrg } 2507ec681f3Smrg stw_unlock_framebuffers(stw_dev); 2517ec681f3Smrg } 2527ec681f3Smrg } 2537ec681f3Smrg 2547ec681f3Smrg return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); 2557ec681f3Smrg} 2567ec681f3Smrg 2577ec681f3Smrg 2587ec681f3Smrg/** 2597ec681f3Smrg * Create a new stw_framebuffer object which corresponds to the given 2607ec681f3Smrg * HDC/window. If successful, we return the new stw_framebuffer object 2617ec681f3Smrg * with its mutex locked. 2627ec681f3Smrg */ 2637ec681f3Smrgstruct stw_framebuffer * 2647ec681f3Smrgstw_framebuffer_create(HWND hWnd, int iPixelFormat, enum stw_framebuffer_owner owner) 2657ec681f3Smrg{ 2667ec681f3Smrg struct stw_framebuffer *fb; 2677ec681f3Smrg const struct stw_pixelformat_info *pfi; 2687ec681f3Smrg 2697ec681f3Smrg fb = CALLOC_STRUCT( stw_framebuffer ); 2707ec681f3Smrg if (fb == NULL) 2717ec681f3Smrg return NULL; 2727ec681f3Smrg 2737ec681f3Smrg fb->hWnd = hWnd; 2747ec681f3Smrg fb->iPixelFormat = iPixelFormat; 2757ec681f3Smrg 2767ec681f3Smrg if (stw_dev->stw_winsys->create_framebuffer) 2777ec681f3Smrg fb->winsys_framebuffer = 2787ec681f3Smrg stw_dev->stw_winsys->create_framebuffer(stw_dev->screen, hWnd, iPixelFormat); 2797ec681f3Smrg 2807ec681f3Smrg /* 2817ec681f3Smrg * We often need a displayable pixel format to make GDI happy. Set it 2827ec681f3Smrg * here (always 1, i.e., out first pixel format) where appropriate. 2837ec681f3Smrg */ 2847ec681f3Smrg fb->iDisplayablePixelFormat = iPixelFormat <= stw_dev->pixelformat_count 2857ec681f3Smrg ? iPixelFormat : 1; 2867ec681f3Smrg fb->owner = owner; 2877ec681f3Smrg 2887ec681f3Smrg fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat ); 2897ec681f3Smrg fb->stfb = stw_st_create_framebuffer( fb ); 2907ec681f3Smrg if (!fb->stfb) { 2917ec681f3Smrg FREE( fb ); 2927ec681f3Smrg return NULL; 2937ec681f3Smrg } 2947ec681f3Smrg 2957ec681f3Smrg fb->refcnt = 1; 2967ec681f3Smrg 2977ec681f3Smrg /* 2987ec681f3Smrg * Windows can be sometimes have zero width and or height, but we ensure 2997ec681f3Smrg * a non-zero framebuffer size at all times. 3007ec681f3Smrg */ 3017ec681f3Smrg 3027ec681f3Smrg fb->must_resize = TRUE; 3037ec681f3Smrg fb->width = 1; 3047ec681f3Smrg fb->height = 1; 3057ec681f3Smrg fb->client_rect.left = 0; 3067ec681f3Smrg fb->client_rect.top = 0; 3077ec681f3Smrg fb->client_rect.right = fb->client_rect.left + fb->width; 3087ec681f3Smrg fb->client_rect.bottom = fb->client_rect.top + fb->height; 3097ec681f3Smrg 3107ec681f3Smrg stw_framebuffer_get_size(fb); 3117ec681f3Smrg 3127ec681f3Smrg InitializeCriticalSection(&fb->mutex); 3137ec681f3Smrg 3147ec681f3Smrg /* This is the only case where we lock the stw_framebuffer::mutex before 3157ec681f3Smrg * stw_dev::fb_mutex, since no other thread can know about this framebuffer 3167ec681f3Smrg * and we must prevent any other thread from destroying it before we return. 3177ec681f3Smrg */ 3187ec681f3Smrg stw_framebuffer_lock(fb); 3197ec681f3Smrg 3207ec681f3Smrg if (owner != STW_FRAMEBUFFER_EGL_WINDOW) { 3217ec681f3Smrg stw_lock_framebuffers(stw_dev); 3227ec681f3Smrg fb->next = stw_dev->fb_head; 3237ec681f3Smrg stw_dev->fb_head = fb; 3247ec681f3Smrg stw_unlock_framebuffers(stw_dev); 3257ec681f3Smrg } 3267ec681f3Smrg 3277ec681f3Smrg return fb; 3287ec681f3Smrg} 3297ec681f3Smrg 3307ec681f3Smrg/** 3317ec681f3Smrg * Increase fb reference count. The referenced framebuffer should be locked. 3327ec681f3Smrg * 3337ec681f3Smrg * It's not necessary to hold stw_dev::fb_mutex global lock. 3347ec681f3Smrg */ 3357ec681f3Smrgvoid 3367ec681f3Smrgstw_framebuffer_reference_locked(struct stw_framebuffer *fb) 3377ec681f3Smrg{ 3387ec681f3Smrg if (fb) { 3397ec681f3Smrg assert(stw_own_mutex(&fb->mutex)); 3407ec681f3Smrg fb->refcnt++; 3417ec681f3Smrg } 3427ec681f3Smrg} 3437ec681f3Smrg 3447ec681f3Smrg/** 3457ec681f3Smrg * Release stw_framebuffer::mutex lock. This framebuffer must not be accessed 3467ec681f3Smrg * after calling this function, as it may have been deleted by another thread 3477ec681f3Smrg * in the meanwhile. 3487ec681f3Smrg */ 3497ec681f3Smrgvoid 3507ec681f3Smrgstw_framebuffer_unlock(struct stw_framebuffer *fb) 3517ec681f3Smrg{ 3527ec681f3Smrg assert(fb); 3537ec681f3Smrg assert(stw_own_mutex(&fb->mutex)); 3547ec681f3Smrg LeaveCriticalSection(&fb->mutex); 3557ec681f3Smrg} 3567ec681f3Smrg 3577ec681f3Smrg 3587ec681f3Smrg/** 3597ec681f3Smrg * Update the framebuffer's size if necessary. 3607ec681f3Smrg */ 3617ec681f3Smrgvoid 3627ec681f3Smrgstw_framebuffer_update(struct stw_framebuffer *fb) 3637ec681f3Smrg{ 3647ec681f3Smrg assert(fb->stfb); 3657ec681f3Smrg assert(fb->height); 3667ec681f3Smrg assert(fb->width); 3677ec681f3Smrg 3687ec681f3Smrg /* XXX: It would be nice to avoid checking the size again -- in theory 3697ec681f3Smrg * stw_call_window_proc would have cought the resize and stored the right 3707ec681f3Smrg * size already, but unfortunately threads created before the DllMain is 3717ec681f3Smrg * called don't get a DLL_THREAD_ATTACH notification, and there is no way 3727ec681f3Smrg * to know of their existing without using the not very portable PSAPI. 3737ec681f3Smrg */ 3747ec681f3Smrg stw_framebuffer_get_size(fb); 3757ec681f3Smrg} 3767ec681f3Smrg 3777ec681f3Smrg 3787ec681f3Smrg/** 3797ec681f3Smrg * Try to free all stw_framebuffer objects associated with the device. 3807ec681f3Smrg */ 3817ec681f3Smrgvoid 3827ec681f3Smrgstw_framebuffer_cleanup(void) 3837ec681f3Smrg{ 3847ec681f3Smrg struct stw_framebuffer *fb; 3857ec681f3Smrg struct stw_framebuffer *next; 3867ec681f3Smrg 3877ec681f3Smrg if (!stw_dev) 3887ec681f3Smrg return; 3897ec681f3Smrg 3907ec681f3Smrg stw_lock_framebuffers(stw_dev); 3917ec681f3Smrg 3927ec681f3Smrg fb = stw_dev->fb_head; 3937ec681f3Smrg while (fb) { 3947ec681f3Smrg next = fb->next; 3957ec681f3Smrg 3967ec681f3Smrg stw_framebuffer_lock(fb); 3977ec681f3Smrg stw_framebuffer_release_locked(fb, NULL); 3987ec681f3Smrg 3997ec681f3Smrg fb = next; 4007ec681f3Smrg } 4017ec681f3Smrg stw_dev->fb_head = NULL; 4027ec681f3Smrg 4037ec681f3Smrg stw_unlock_framebuffers(stw_dev); 4047ec681f3Smrg} 4057ec681f3Smrg 4067ec681f3Smrg 4077ec681f3Smrg/** 4087ec681f3Smrg * Given an hdc, return the corresponding stw_framebuffer. 4097ec681f3Smrg * The returned stw_framebuffer will have its mutex locked. 4107ec681f3Smrg */ 4117ec681f3Smrgstatic struct stw_framebuffer * 4127ec681f3Smrgstw_framebuffer_from_hdc_locked(HDC hdc) 4137ec681f3Smrg{ 4147ec681f3Smrg HWND hwnd; 4157ec681f3Smrg 4167ec681f3Smrg hwnd = WindowFromDC(hdc); 4177ec681f3Smrg if (!hwnd) { 4187ec681f3Smrg return NULL; 4197ec681f3Smrg } 4207ec681f3Smrg 4217ec681f3Smrg return stw_framebuffer_from_hwnd_locked(hwnd); 4227ec681f3Smrg} 4237ec681f3Smrg 4247ec681f3Smrg 4257ec681f3Smrg/** 4267ec681f3Smrg * Given an HDC, return the corresponding stw_framebuffer. 4277ec681f3Smrg * The returned stw_framebuffer will have its mutex locked. 4287ec681f3Smrg */ 4297ec681f3Smrgstruct stw_framebuffer * 4307ec681f3Smrgstw_framebuffer_from_hdc(HDC hdc) 4317ec681f3Smrg{ 4327ec681f3Smrg struct stw_framebuffer *fb; 4337ec681f3Smrg 4347ec681f3Smrg if (!stw_dev) 4357ec681f3Smrg return NULL; 4367ec681f3Smrg 4377ec681f3Smrg stw_lock_framebuffers(stw_dev); 4387ec681f3Smrg fb = stw_framebuffer_from_hdc_locked(hdc); 4397ec681f3Smrg stw_unlock_framebuffers(stw_dev); 4407ec681f3Smrg 4417ec681f3Smrg return fb; 4427ec681f3Smrg} 4437ec681f3Smrg 4447ec681f3Smrg 4457ec681f3Smrg/** 4467ec681f3Smrg * Given an HWND, return the corresponding stw_framebuffer. 4477ec681f3Smrg * The returned stw_framebuffer will have its mutex locked. 4487ec681f3Smrg */ 4497ec681f3Smrgstruct stw_framebuffer * 4507ec681f3Smrgstw_framebuffer_from_hwnd(HWND hwnd) 4517ec681f3Smrg{ 4527ec681f3Smrg struct stw_framebuffer *fb; 4537ec681f3Smrg 4547ec681f3Smrg stw_lock_framebuffers(stw_dev); 4557ec681f3Smrg fb = stw_framebuffer_from_hwnd_locked(hwnd); 4567ec681f3Smrg stw_unlock_framebuffers(stw_dev); 4577ec681f3Smrg 4587ec681f3Smrg return fb; 4597ec681f3Smrg} 4607ec681f3Smrg 4617ec681f3Smrg 4627ec681f3SmrgBOOL APIENTRY 4637ec681f3SmrgDrvSetPixelFormat(HDC hdc, LONG iPixelFormat) 4647ec681f3Smrg{ 4657ec681f3Smrg uint count; 4667ec681f3Smrg uint index; 4677ec681f3Smrg struct stw_framebuffer *fb; 4687ec681f3Smrg 4697ec681f3Smrg if (!stw_dev) 4707ec681f3Smrg return FALSE; 4717ec681f3Smrg 4727ec681f3Smrg index = (uint) iPixelFormat - 1; 4737ec681f3Smrg count = stw_pixelformat_get_count(hdc); 4747ec681f3Smrg if (index >= count) 4757ec681f3Smrg return FALSE; 4767ec681f3Smrg 4777ec681f3Smrg fb = stw_framebuffer_from_hdc_locked(hdc); 4787ec681f3Smrg if (fb) { 4797ec681f3Smrg /* 4807ec681f3Smrg * SetPixelFormat must be called only once. However ignore 4817ec681f3Smrg * pbuffers, for which the framebuffer object is created first. 4827ec681f3Smrg */ 4837ec681f3Smrg boolean bPbuffer = fb->owner == STW_FRAMEBUFFER_PBUFFER; 4847ec681f3Smrg 4857ec681f3Smrg stw_framebuffer_unlock( fb ); 4867ec681f3Smrg 4877ec681f3Smrg return bPbuffer; 4887ec681f3Smrg } 4897ec681f3Smrg 4907ec681f3Smrg fb = stw_framebuffer_create(WindowFromDC(hdc), iPixelFormat, STW_FRAMEBUFFER_WGL_WINDOW); 4917ec681f3Smrg if (!fb) { 4927ec681f3Smrg return FALSE; 4937ec681f3Smrg } 4947ec681f3Smrg 4957ec681f3Smrg stw_framebuffer_unlock( fb ); 4967ec681f3Smrg 4977ec681f3Smrg /* Some applications mistakenly use the undocumented wglSetPixelFormat 4987ec681f3Smrg * function instead of SetPixelFormat, so we call SetPixelFormat here to 4997ec681f3Smrg * avoid opengl32.dll's wglCreateContext to fail */ 5007ec681f3Smrg if (GetPixelFormat(hdc) == 0) { 5017ec681f3Smrg BOOL bRet = SetPixelFormat(hdc, iPixelFormat, NULL); 5027ec681f3Smrg if (!bRet) { 5037ec681f3Smrg debug_printf("SetPixelFormat failed\n"); 5047ec681f3Smrg } 5057ec681f3Smrg } 5067ec681f3Smrg 5077ec681f3Smrg return TRUE; 5087ec681f3Smrg} 5097ec681f3Smrg 5107ec681f3Smrg 5117ec681f3Smrgint 5127ec681f3Smrgstw_pixelformat_get(HDC hdc) 5137ec681f3Smrg{ 5147ec681f3Smrg int iPixelFormat = 0; 5157ec681f3Smrg struct stw_framebuffer *fb; 5167ec681f3Smrg 5177ec681f3Smrg fb = stw_framebuffer_from_hdc(hdc); 5187ec681f3Smrg if (fb) { 5197ec681f3Smrg iPixelFormat = fb->iPixelFormat; 5207ec681f3Smrg stw_framebuffer_unlock(fb); 5217ec681f3Smrg } 5227ec681f3Smrg 5237ec681f3Smrg return iPixelFormat; 5247ec681f3Smrg} 5257ec681f3Smrg 5267ec681f3Smrg 5277ec681f3SmrgBOOL APIENTRY 5287ec681f3SmrgDrvPresentBuffers(HDC hdc, LPPRESENTBUFFERS data) 5297ec681f3Smrg{ 5307ec681f3Smrg struct stw_framebuffer *fb; 5317ec681f3Smrg struct stw_context *ctx; 5327ec681f3Smrg struct pipe_screen *screen; 5337ec681f3Smrg struct pipe_context *pipe; 5347ec681f3Smrg struct pipe_resource *res; 5357ec681f3Smrg 5367ec681f3Smrg if (!stw_dev) 5377ec681f3Smrg return FALSE; 5387ec681f3Smrg 5397ec681f3Smrg fb = stw_framebuffer_from_hdc( hdc ); 5407ec681f3Smrg if (fb == NULL) 5417ec681f3Smrg return FALSE; 5427ec681f3Smrg 5437ec681f3Smrg screen = stw_dev->screen; 5447ec681f3Smrg ctx = stw_current_context(); 5457ec681f3Smrg pipe = ctx ? ctx->st->pipe : NULL; 5467ec681f3Smrg 5477ec681f3Smrg res = (struct pipe_resource *)data->pPrivData; 5487ec681f3Smrg 5497ec681f3Smrg if (data->hSurface != fb->hSharedSurface) { 5507ec681f3Smrg if (fb->shared_surface) { 5517ec681f3Smrg stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface); 5527ec681f3Smrg fb->shared_surface = NULL; 5537ec681f3Smrg } 5547ec681f3Smrg 5557ec681f3Smrg fb->hSharedSurface = data->hSurface; 5567ec681f3Smrg 5577ec681f3Smrg if (data->hSurface && 5587ec681f3Smrg stw_dev->stw_winsys->shared_surface_open) { 5597ec681f3Smrg fb->shared_surface = 5607ec681f3Smrg stw_dev->stw_winsys->shared_surface_open(screen, 5617ec681f3Smrg fb->hSharedSurface); 5627ec681f3Smrg } 5637ec681f3Smrg } 5647ec681f3Smrg 5657ec681f3Smrg if (!fb->minimized) { 5667ec681f3Smrg if (fb->shared_surface) { 5677ec681f3Smrg stw_dev->stw_winsys->compose(screen, 5687ec681f3Smrg res, 5697ec681f3Smrg fb->shared_surface, 5707ec681f3Smrg &fb->client_rect, 5717ec681f3Smrg data->ullPresentToken); 5727ec681f3Smrg } 5737ec681f3Smrg else { 5747ec681f3Smrg stw_dev->stw_winsys->present( screen, pipe, res, hdc ); 5757ec681f3Smrg } 5767ec681f3Smrg } 5777ec681f3Smrg 5787ec681f3Smrg stw_framebuffer_update(fb); 5797ec681f3Smrg stw_notify_current_locked(fb); 5807ec681f3Smrg 5817ec681f3Smrg stw_framebuffer_unlock(fb); 5827ec681f3Smrg 5837ec681f3Smrg return TRUE; 5847ec681f3Smrg} 5857ec681f3Smrg 5867ec681f3Smrg 5877ec681f3Smrg/** 5887ec681f3Smrg * Queue a composition. 5897ec681f3Smrg * 5907ec681f3Smrg * The stw_framebuffer object must have its mutex locked. The mutex will 5917ec681f3Smrg * be unlocked here before returning. 5927ec681f3Smrg */ 5937ec681f3SmrgBOOL 5947ec681f3Smrgstw_framebuffer_present_locked(HDC hdc, 5957ec681f3Smrg struct stw_framebuffer *fb, 5967ec681f3Smrg struct pipe_resource *res) 5977ec681f3Smrg{ 5987ec681f3Smrg if (fb->winsys_framebuffer) { 5997ec681f3Smrg BOOL result = fb->winsys_framebuffer->present(fb->winsys_framebuffer); 6007ec681f3Smrg 6017ec681f3Smrg stw_framebuffer_update(fb); 6027ec681f3Smrg stw_notify_current_locked(fb); 6037ec681f3Smrg stw_framebuffer_unlock(fb); 6047ec681f3Smrg 6057ec681f3Smrg return result; 6067ec681f3Smrg } 6077ec681f3Smrg else if (stw_dev->callbacks.pfnPresentBuffers && 6087ec681f3Smrg stw_dev->stw_winsys->compose) { 6097ec681f3Smrg PRESENTBUFFERSCB data; 6107ec681f3Smrg 6117ec681f3Smrg memset(&data, 0, sizeof data); 6127ec681f3Smrg data.nVersion = 2; 6137ec681f3Smrg data.syncType = PRESCB_SYNCTYPE_NONE; 6147ec681f3Smrg data.luidAdapter = stw_dev->AdapterLuid; 6157ec681f3Smrg data.updateRect = fb->client_rect; 6167ec681f3Smrg data.pPrivData = (void *)res; 6177ec681f3Smrg 6187ec681f3Smrg stw_notify_current_locked(fb); 6197ec681f3Smrg stw_framebuffer_unlock(fb); 6207ec681f3Smrg 6217ec681f3Smrg return stw_dev->callbacks.pfnPresentBuffers(hdc, &data); 6227ec681f3Smrg } 6237ec681f3Smrg else { 6247ec681f3Smrg struct pipe_screen *screen = stw_dev->screen; 6257ec681f3Smrg struct stw_context *ctx = stw_current_context(); 6267ec681f3Smrg struct pipe_context *pipe = ctx ? ctx->st->pipe : NULL; 6277ec681f3Smrg 6287ec681f3Smrg stw_dev->stw_winsys->present( screen, pipe, res, hdc ); 6297ec681f3Smrg 6307ec681f3Smrg stw_framebuffer_update(fb); 6317ec681f3Smrg stw_notify_current_locked(fb); 6327ec681f3Smrg stw_framebuffer_unlock(fb); 6337ec681f3Smrg 6347ec681f3Smrg return TRUE; 6357ec681f3Smrg } 6367ec681f3Smrg} 6377ec681f3Smrg 6387ec681f3Smrg 6397ec681f3Smrg/** 6407ec681f3Smrg * This is called just before issuing the buffer swap/present. 6417ec681f3Smrg * We query the current time and determine if we should sleep before 6427ec681f3Smrg * issuing the swap/present. 6437ec681f3Smrg * This is a bit of a hack and is certainly not very accurate but it 6447ec681f3Smrg * basically works. 6457ec681f3Smrg * This is for the WGL_ARB_swap_interval extension. 6467ec681f3Smrg */ 6477ec681f3Smrgstatic void 6487ec681f3Smrgwait_swap_interval(struct stw_framebuffer *fb) 6497ec681f3Smrg{ 6507ec681f3Smrg /* Note: all time variables here are in units of microseconds */ 6517ec681f3Smrg int64_t cur_time = os_time_get_nano() / 1000; 6527ec681f3Smrg 6537ec681f3Smrg if (fb->prev_swap_time != 0) { 6547ec681f3Smrg /* Compute time since previous swap */ 6557ec681f3Smrg int64_t delta = cur_time - fb->prev_swap_time; 6567ec681f3Smrg int64_t min_swap_period = 6577ec681f3Smrg 1.0e6 / stw_dev->refresh_rate * stw_dev->swap_interval; 6587ec681f3Smrg 6597ec681f3Smrg /* If time since last swap is less than wait period, wait. 6607ec681f3Smrg * Note that it's possible for the delta to be negative because of 6617ec681f3Smrg * rollover. See https://bugs.freedesktop.org/show_bug.cgi?id=102241 6627ec681f3Smrg */ 6637ec681f3Smrg if ((delta >= 0) && (delta < min_swap_period)) { 6647ec681f3Smrg float fudge = 1.75f; /* emperical fudge factor */ 6657ec681f3Smrg int64_t wait = (min_swap_period - delta) * fudge; 6667ec681f3Smrg os_time_sleep(wait); 6677ec681f3Smrg } 6687ec681f3Smrg } 6697ec681f3Smrg 6707ec681f3Smrg fb->prev_swap_time = cur_time; 6717ec681f3Smrg} 6727ec681f3Smrg 6737ec681f3SmrgBOOL 6747ec681f3Smrgstw_framebuffer_swap_locked(HDC hdc, struct stw_framebuffer *fb) 6757ec681f3Smrg{ 6767ec681f3Smrg struct stw_context *ctx; 6777ec681f3Smrg if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) { 6787ec681f3Smrg stw_framebuffer_unlock(fb); 6797ec681f3Smrg return TRUE; 6807ec681f3Smrg } 6817ec681f3Smrg 6827ec681f3Smrg ctx = stw_current_context(); 6837ec681f3Smrg if (ctx) { 6847ec681f3Smrg if (ctx->hud) { 6857ec681f3Smrg /* Display the HUD */ 6867ec681f3Smrg struct pipe_resource *back = 6877ec681f3Smrg stw_get_framebuffer_resource(fb->stfb, ST_ATTACHMENT_BACK_LEFT); 6887ec681f3Smrg if (back) { 6897ec681f3Smrg hud_run(ctx->hud, NULL, back); 6907ec681f3Smrg } 6917ec681f3Smrg } 6927ec681f3Smrg 6937ec681f3Smrg if (ctx->current_framebuffer == fb) { 6947ec681f3Smrg /* flush current context */ 6957ec681f3Smrg stw_st_flush(ctx->st, fb->stfb, ST_FLUSH_END_OF_FRAME); 6967ec681f3Smrg } 6977ec681f3Smrg } 6987ec681f3Smrg 6997ec681f3Smrg if (stw_dev->swap_interval != 0 && !fb->winsys_framebuffer) { 7007ec681f3Smrg wait_swap_interval(fb); 7017ec681f3Smrg } 7027ec681f3Smrg 7037ec681f3Smrg return stw_st_swap_framebuffer_locked(hdc, ctx->st, fb->stfb); 7047ec681f3Smrg} 7057ec681f3Smrg 7067ec681f3SmrgBOOL APIENTRY 7077ec681f3SmrgDrvSwapBuffers(HDC hdc) 7087ec681f3Smrg{ 7097ec681f3Smrg struct stw_framebuffer *fb; 7107ec681f3Smrg 7117ec681f3Smrg if (!stw_dev) 7127ec681f3Smrg return FALSE; 7137ec681f3Smrg 7147ec681f3Smrg fb = stw_framebuffer_from_hdc( hdc ); 7157ec681f3Smrg if (fb == NULL) 7167ec681f3Smrg return FALSE; 7177ec681f3Smrg 7187ec681f3Smrg return stw_framebuffer_swap_locked(hdc, fb); 7197ec681f3Smrg} 7207ec681f3Smrg 7217ec681f3Smrg 7227ec681f3SmrgBOOL APIENTRY 7237ec681f3SmrgDrvSwapLayerBuffers(HDC hdc, UINT fuPlanes) 7247ec681f3Smrg{ 7257ec681f3Smrg if (fuPlanes & WGL_SWAP_MAIN_PLANE) 7267ec681f3Smrg return DrvSwapBuffers(hdc); 7277ec681f3Smrg 7287ec681f3Smrg return FALSE; 7297ec681f3Smrg} 730