1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2008-2009 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include <windows.h> 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include "pipe/p_screen.h" 31bf215546Sopenharmony_ci#include "pipe/p_state.h" 32bf215546Sopenharmony_ci#include "util/u_memory.h" 33bf215546Sopenharmony_ci#include "hud/hud_context.h" 34bf215546Sopenharmony_ci#include "util/os_time.h" 35bf215546Sopenharmony_ci#include "frontend/api.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#include <GL/gl.h> 38bf215546Sopenharmony_ci#include "gldrv.h" 39bf215546Sopenharmony_ci#include "stw_framebuffer.h" 40bf215546Sopenharmony_ci#include "stw_device.h" 41bf215546Sopenharmony_ci#include "stw_winsys.h" 42bf215546Sopenharmony_ci#include "stw_tls.h" 43bf215546Sopenharmony_ci#include "stw_context.h" 44bf215546Sopenharmony_ci#include "stw_st.h" 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci/** 48bf215546Sopenharmony_ci * Search the framebuffer with the matching HWND while holding the 49bf215546Sopenharmony_ci * stw_dev::fb_mutex global lock. 50bf215546Sopenharmony_ci * If a stw_framebuffer is found, lock it and return the pointer. 51bf215546Sopenharmony_ci * Else, return NULL. 52bf215546Sopenharmony_ci */ 53bf215546Sopenharmony_cistatic struct stw_framebuffer * 54bf215546Sopenharmony_cistw_framebuffer_from_hwnd_locked(HWND hwnd) 55bf215546Sopenharmony_ci{ 56bf215546Sopenharmony_ci struct stw_framebuffer *fb; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next) 59bf215546Sopenharmony_ci if (fb->hWnd == hwnd) { 60bf215546Sopenharmony_ci stw_framebuffer_lock(fb); 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci /* When running with Zink, during the Vulkan surface creation 63bf215546Sopenharmony_ci * it's possible that the underlying Vulkan driver will try to 64bf215546Sopenharmony_ci * access the HWND/HDC we passed in (see stw_st_fill_private_loader_data()). 65bf215546Sopenharmony_ci * Because we create the Vulkan surface while holding the framebuffer 66bf215546Sopenharmony_ci * lock, when the driver starts to look up properties, 67bf215546Sopenharmony_ci * we'd end up double locking when looking up the framebuffer. 68bf215546Sopenharmony_ci */ 69bf215546Sopenharmony_ci assert(stw_dev->zink || fb->mutex.RecursionCount == 1); 70bf215546Sopenharmony_ci return fb; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci return NULL; 74bf215546Sopenharmony_ci} 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci/** 78bf215546Sopenharmony_ci * Decrement the reference count on the given stw_framebuffer object. 79bf215546Sopenharmony_ci * If the reference count hits zero, destroy the object. 80bf215546Sopenharmony_ci * 81bf215546Sopenharmony_ci * Note: Both stw_dev::fb_mutex and stw_framebuffer::mutex must already be 82bf215546Sopenharmony_ci * locked. After this function completes, the fb's mutex will be unlocked. 83bf215546Sopenharmony_ci */ 84bf215546Sopenharmony_civoid 85bf215546Sopenharmony_cistw_framebuffer_release_locked(struct stw_framebuffer *fb, 86bf215546Sopenharmony_ci struct st_context_iface *stctx) 87bf215546Sopenharmony_ci{ 88bf215546Sopenharmony_ci struct stw_framebuffer **link; 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci assert(fb); 91bf215546Sopenharmony_ci assert(stw_own_mutex(&fb->mutex)); 92bf215546Sopenharmony_ci assert(stw_own_mutex(&stw_dev->fb_mutex) || fb->owner == STW_FRAMEBUFFER_EGL_WINDOW); 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci /* check the reference count */ 95bf215546Sopenharmony_ci fb->refcnt--; 96bf215546Sopenharmony_ci if (fb->refcnt) { 97bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 98bf215546Sopenharmony_ci return; 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci if (fb->owner != STW_FRAMEBUFFER_EGL_WINDOW) { 102bf215546Sopenharmony_ci /* remove this stw_framebuffer from the device's linked list */ 103bf215546Sopenharmony_ci link = &stw_dev->fb_head; 104bf215546Sopenharmony_ci while (*link != fb) 105bf215546Sopenharmony_ci link = &(*link)->next; 106bf215546Sopenharmony_ci assert(*link); 107bf215546Sopenharmony_ci *link = fb->next; 108bf215546Sopenharmony_ci fb->next = NULL; 109bf215546Sopenharmony_ci } 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci if (fb->shared_surface) 112bf215546Sopenharmony_ci stw_dev->stw_winsys->shared_surface_close(stw_dev->screen, 113bf215546Sopenharmony_ci fb->shared_surface); 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci if (fb->winsys_framebuffer) 116bf215546Sopenharmony_ci fb->winsys_framebuffer->destroy(fb->winsys_framebuffer, stctx ? stctx->pipe : NULL); 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci stw_st_destroy_framebuffer_locked(fb->stfb); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci DeleteCriticalSection(&fb->mutex); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci FREE( fb ); 125bf215546Sopenharmony_ci} 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci/** 129bf215546Sopenharmony_ci * Query the size of the given framebuffer's on-screen window and update 130bf215546Sopenharmony_ci * the stw_framebuffer's width/height. 131bf215546Sopenharmony_ci */ 132bf215546Sopenharmony_cistatic void 133bf215546Sopenharmony_cistw_framebuffer_get_size(struct stw_framebuffer *fb) 134bf215546Sopenharmony_ci{ 135bf215546Sopenharmony_ci LONG width, height; 136bf215546Sopenharmony_ci RECT client_rect; 137bf215546Sopenharmony_ci RECT window_rect; 138bf215546Sopenharmony_ci POINT client_pos; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci /* 141bf215546Sopenharmony_ci * Sanity checking. 142bf215546Sopenharmony_ci */ 143bf215546Sopenharmony_ci assert(fb->hWnd); 144bf215546Sopenharmony_ci assert(fb->width && fb->height); 145bf215546Sopenharmony_ci assert(fb->client_rect.right == fb->client_rect.left + fb->width); 146bf215546Sopenharmony_ci assert(fb->client_rect.bottom == fb->client_rect.top + fb->height); 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci /* 149bf215546Sopenharmony_ci * Get the client area size. 150bf215546Sopenharmony_ci */ 151bf215546Sopenharmony_ci if (!GetClientRect(fb->hWnd, &client_rect)) { 152bf215546Sopenharmony_ci return; 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci assert(client_rect.left == 0); 156bf215546Sopenharmony_ci assert(client_rect.top == 0); 157bf215546Sopenharmony_ci width = client_rect.right - client_rect.left; 158bf215546Sopenharmony_ci height = client_rect.bottom - client_rect.top; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci fb->minimized = width == 0 || height == 0; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci if (width <= 0 || height <= 0) { 163bf215546Sopenharmony_ci /* 164bf215546Sopenharmony_ci * When the window is minimized GetClientRect will return zeros. Simply 165bf215546Sopenharmony_ci * preserve the current window size, until the window is restored or 166bf215546Sopenharmony_ci * maximized again. 167bf215546Sopenharmony_ci */ 168bf215546Sopenharmony_ci return; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci if (width != fb->width || height != fb->height) { 172bf215546Sopenharmony_ci fb->must_resize = TRUE; 173bf215546Sopenharmony_ci fb->width = width; 174bf215546Sopenharmony_ci fb->height = height; 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci client_pos.x = 0; 178bf215546Sopenharmony_ci client_pos.y = 0; 179bf215546Sopenharmony_ci if (ClientToScreen(fb->hWnd, &client_pos) && 180bf215546Sopenharmony_ci GetWindowRect(fb->hWnd, &window_rect)) { 181bf215546Sopenharmony_ci fb->client_rect.left = client_pos.x - window_rect.left; 182bf215546Sopenharmony_ci fb->client_rect.top = client_pos.y - window_rect.top; 183bf215546Sopenharmony_ci } 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci fb->client_rect.right = fb->client_rect.left + fb->width; 186bf215546Sopenharmony_ci fb->client_rect.bottom = fb->client_rect.top + fb->height; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci#if 0 189bf215546Sopenharmony_ci debug_printf("\n"); 190bf215546Sopenharmony_ci debug_printf("%s: hwnd = %p\n", __FUNCTION__, fb->hWnd); 191bf215546Sopenharmony_ci debug_printf("%s: client_position = (%li, %li)\n", 192bf215546Sopenharmony_ci __FUNCTION__, client_pos.x, client_pos.y); 193bf215546Sopenharmony_ci debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n", 194bf215546Sopenharmony_ci __FUNCTION__, 195bf215546Sopenharmony_ci window_rect.left, window_rect.top, 196bf215546Sopenharmony_ci window_rect.right, window_rect.bottom); 197bf215546Sopenharmony_ci debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n", 198bf215546Sopenharmony_ci __FUNCTION__, 199bf215546Sopenharmony_ci fb->client_rect.left, fb->client_rect.top, 200bf215546Sopenharmony_ci fb->client_rect.right, fb->client_rect.bottom); 201bf215546Sopenharmony_ci#endif 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci/** 206bf215546Sopenharmony_ci * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx 207bf215546Sopenharmony_ci * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx 208bf215546Sopenharmony_ci */ 209bf215546Sopenharmony_ciLRESULT CALLBACK 210bf215546Sopenharmony_cistw_call_window_proc(int nCode, WPARAM wParam, LPARAM lParam) 211bf215546Sopenharmony_ci{ 212bf215546Sopenharmony_ci struct stw_tls_data *tls_data; 213bf215546Sopenharmony_ci PCWPSTRUCT pParams = (PCWPSTRUCT)lParam; 214bf215546Sopenharmony_ci struct stw_framebuffer *fb; 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci tls_data = stw_tls_get_data(); 217bf215546Sopenharmony_ci if (!tls_data) 218bf215546Sopenharmony_ci return 0; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci if (nCode < 0 || !stw_dev) 221bf215546Sopenharmony_ci return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* We check that the stw_dev object is initialized before we try to do 224bf215546Sopenharmony_ci * anything with it. Otherwise, in multi-threaded programs there's a 225bf215546Sopenharmony_ci * chance of executing this code before the stw_dev object is fully 226bf215546Sopenharmony_ci * initialized. 227bf215546Sopenharmony_ci */ 228bf215546Sopenharmony_ci if (stw_dev && stw_dev->initialized) { 229bf215546Sopenharmony_ci if (pParams->message == WM_WINDOWPOSCHANGED) { 230bf215546Sopenharmony_ci /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according 231bf215546Sopenharmony_ci * to http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx 232bf215546Sopenharmony_ci * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it 233bf215546Sopenharmony_ci * can be masked out by the application. 234bf215546Sopenharmony_ci */ 235bf215546Sopenharmony_ci LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam; 236bf215546Sopenharmony_ci if ((lpWindowPos->flags & SWP_SHOWWINDOW) || 237bf215546Sopenharmony_ci !(lpWindowPos->flags & SWP_NOMOVE) || 238bf215546Sopenharmony_ci !(lpWindowPos->flags & SWP_NOSIZE)) { 239bf215546Sopenharmony_ci fb = stw_framebuffer_from_hwnd( pParams->hwnd ); 240bf215546Sopenharmony_ci if (fb) { 241bf215546Sopenharmony_ci /* Size in WINDOWPOS includes the window frame, so get the size 242bf215546Sopenharmony_ci * of the client area via GetClientRect. 243bf215546Sopenharmony_ci */ 244bf215546Sopenharmony_ci stw_framebuffer_get_size(fb); 245bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 246bf215546Sopenharmony_ci } 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci } 249bf215546Sopenharmony_ci else if (pParams->message == WM_DESTROY) { 250bf215546Sopenharmony_ci stw_lock_framebuffers(stw_dev); 251bf215546Sopenharmony_ci fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd ); 252bf215546Sopenharmony_ci if (fb) { 253bf215546Sopenharmony_ci struct stw_context *current_context = stw_current_context(); 254bf215546Sopenharmony_ci struct st_context_iface *ctx_iface = current_context && 255bf215546Sopenharmony_ci current_context->current_framebuffer == fb ? current_context->st : NULL; 256bf215546Sopenharmony_ci stw_framebuffer_release_locked(fb, ctx_iface); 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci stw_unlock_framebuffers(stw_dev); 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci } 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); 263bf215546Sopenharmony_ci} 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci/** 267bf215546Sopenharmony_ci * Create a new stw_framebuffer object which corresponds to the given 268bf215546Sopenharmony_ci * HDC/window. If successful, we return the new stw_framebuffer object 269bf215546Sopenharmony_ci * with its mutex locked. 270bf215546Sopenharmony_ci */ 271bf215546Sopenharmony_cistruct stw_framebuffer * 272bf215546Sopenharmony_cistw_framebuffer_create(HWND hWnd, int iPixelFormat, enum stw_framebuffer_owner owner) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci struct stw_framebuffer *fb; 275bf215546Sopenharmony_ci const struct stw_pixelformat_info *pfi; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci fb = CALLOC_STRUCT( stw_framebuffer ); 278bf215546Sopenharmony_ci if (fb == NULL) 279bf215546Sopenharmony_ci return NULL; 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci fb->hWnd = hWnd; 282bf215546Sopenharmony_ci fb->iPixelFormat = iPixelFormat; 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci if (stw_dev->stw_winsys->create_framebuffer) 285bf215546Sopenharmony_ci fb->winsys_framebuffer = 286bf215546Sopenharmony_ci stw_dev->stw_winsys->create_framebuffer(stw_dev->screen, hWnd, iPixelFormat); 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci /* 289bf215546Sopenharmony_ci * We often need a displayable pixel format to make GDI happy. Set it 290bf215546Sopenharmony_ci * here (always 1, i.e., out first pixel format) where appropriate. 291bf215546Sopenharmony_ci */ 292bf215546Sopenharmony_ci fb->iDisplayablePixelFormat = iPixelFormat <= stw_dev->pixelformat_count 293bf215546Sopenharmony_ci ? iPixelFormat : 1; 294bf215546Sopenharmony_ci fb->owner = owner; 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat ); 297bf215546Sopenharmony_ci fb->stfb = stw_st_create_framebuffer( fb ); 298bf215546Sopenharmony_ci if (!fb->stfb) { 299bf215546Sopenharmony_ci FREE( fb ); 300bf215546Sopenharmony_ci return NULL; 301bf215546Sopenharmony_ci } 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci fb->refcnt = 1; 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci /* 306bf215546Sopenharmony_ci * Windows can be sometimes have zero width and or height, but we ensure 307bf215546Sopenharmony_ci * a non-zero framebuffer size at all times. 308bf215546Sopenharmony_ci */ 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci fb->must_resize = TRUE; 311bf215546Sopenharmony_ci fb->width = 1; 312bf215546Sopenharmony_ci fb->height = 1; 313bf215546Sopenharmony_ci fb->client_rect.left = 0; 314bf215546Sopenharmony_ci fb->client_rect.top = 0; 315bf215546Sopenharmony_ci fb->client_rect.right = fb->client_rect.left + fb->width; 316bf215546Sopenharmony_ci fb->client_rect.bottom = fb->client_rect.top + fb->height; 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci stw_framebuffer_get_size(fb); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci InitializeCriticalSection(&fb->mutex); 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci /* This is the only case where we lock the stw_framebuffer::mutex before 323bf215546Sopenharmony_ci * stw_dev::fb_mutex, since no other thread can know about this framebuffer 324bf215546Sopenharmony_ci * and we must prevent any other thread from destroying it before we return. 325bf215546Sopenharmony_ci */ 326bf215546Sopenharmony_ci stw_framebuffer_lock(fb); 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci if (owner != STW_FRAMEBUFFER_EGL_WINDOW) { 329bf215546Sopenharmony_ci stw_lock_framebuffers(stw_dev); 330bf215546Sopenharmony_ci fb->next = stw_dev->fb_head; 331bf215546Sopenharmony_ci stw_dev->fb_head = fb; 332bf215546Sopenharmony_ci stw_unlock_framebuffers(stw_dev); 333bf215546Sopenharmony_ci } 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci return fb; 336bf215546Sopenharmony_ci} 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci/** 339bf215546Sopenharmony_ci * Increase fb reference count. The referenced framebuffer should be locked. 340bf215546Sopenharmony_ci * 341bf215546Sopenharmony_ci * It's not necessary to hold stw_dev::fb_mutex global lock. 342bf215546Sopenharmony_ci */ 343bf215546Sopenharmony_civoid 344bf215546Sopenharmony_cistw_framebuffer_reference_locked(struct stw_framebuffer *fb) 345bf215546Sopenharmony_ci{ 346bf215546Sopenharmony_ci if (fb) { 347bf215546Sopenharmony_ci assert(stw_own_mutex(&fb->mutex)); 348bf215546Sopenharmony_ci fb->refcnt++; 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci} 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci/** 353bf215546Sopenharmony_ci * Release stw_framebuffer::mutex lock. This framebuffer must not be accessed 354bf215546Sopenharmony_ci * after calling this function, as it may have been deleted by another thread 355bf215546Sopenharmony_ci * in the meanwhile. 356bf215546Sopenharmony_ci */ 357bf215546Sopenharmony_civoid 358bf215546Sopenharmony_cistw_framebuffer_unlock(struct stw_framebuffer *fb) 359bf215546Sopenharmony_ci{ 360bf215546Sopenharmony_ci assert(fb); 361bf215546Sopenharmony_ci assert(stw_own_mutex(&fb->mutex)); 362bf215546Sopenharmony_ci LeaveCriticalSection(&fb->mutex); 363bf215546Sopenharmony_ci} 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci/** 367bf215546Sopenharmony_ci * Update the framebuffer's size if necessary. 368bf215546Sopenharmony_ci */ 369bf215546Sopenharmony_civoid 370bf215546Sopenharmony_cistw_framebuffer_update(struct stw_framebuffer *fb) 371bf215546Sopenharmony_ci{ 372bf215546Sopenharmony_ci assert(fb->stfb); 373bf215546Sopenharmony_ci assert(fb->height); 374bf215546Sopenharmony_ci assert(fb->width); 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci /* XXX: It would be nice to avoid checking the size again -- in theory 377bf215546Sopenharmony_ci * stw_call_window_proc would have cought the resize and stored the right 378bf215546Sopenharmony_ci * size already, but unfortunately threads created before the DllMain is 379bf215546Sopenharmony_ci * called don't get a DLL_THREAD_ATTACH notification, and there is no way 380bf215546Sopenharmony_ci * to know of their existing without using the not very portable PSAPI. 381bf215546Sopenharmony_ci */ 382bf215546Sopenharmony_ci stw_framebuffer_get_size(fb); 383bf215546Sopenharmony_ci} 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci/** 387bf215546Sopenharmony_ci * Try to free all stw_framebuffer objects associated with the device. 388bf215546Sopenharmony_ci */ 389bf215546Sopenharmony_civoid 390bf215546Sopenharmony_cistw_framebuffer_cleanup(void) 391bf215546Sopenharmony_ci{ 392bf215546Sopenharmony_ci struct stw_framebuffer *fb; 393bf215546Sopenharmony_ci struct stw_framebuffer *next; 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci if (!stw_dev) 396bf215546Sopenharmony_ci return; 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci stw_lock_framebuffers(stw_dev); 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci fb = stw_dev->fb_head; 401bf215546Sopenharmony_ci while (fb) { 402bf215546Sopenharmony_ci next = fb->next; 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci stw_framebuffer_lock(fb); 405bf215546Sopenharmony_ci stw_framebuffer_release_locked(fb, NULL); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci fb = next; 408bf215546Sopenharmony_ci } 409bf215546Sopenharmony_ci stw_dev->fb_head = NULL; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci stw_unlock_framebuffers(stw_dev); 412bf215546Sopenharmony_ci} 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci/** 416bf215546Sopenharmony_ci * Given an hdc, return the corresponding stw_framebuffer. 417bf215546Sopenharmony_ci * The returned stw_framebuffer will have its mutex locked. 418bf215546Sopenharmony_ci */ 419bf215546Sopenharmony_cistatic struct stw_framebuffer * 420bf215546Sopenharmony_cistw_framebuffer_from_hdc_locked(HDC hdc) 421bf215546Sopenharmony_ci{ 422bf215546Sopenharmony_ci HWND hwnd; 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci hwnd = WindowFromDC(hdc); 425bf215546Sopenharmony_ci if (!hwnd) { 426bf215546Sopenharmony_ci return NULL; 427bf215546Sopenharmony_ci } 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci return stw_framebuffer_from_hwnd_locked(hwnd); 430bf215546Sopenharmony_ci} 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci/** 434bf215546Sopenharmony_ci * Given an HDC, return the corresponding stw_framebuffer. 435bf215546Sopenharmony_ci * The returned stw_framebuffer will have its mutex locked. 436bf215546Sopenharmony_ci */ 437bf215546Sopenharmony_cistruct stw_framebuffer * 438bf215546Sopenharmony_cistw_framebuffer_from_hdc(HDC hdc) 439bf215546Sopenharmony_ci{ 440bf215546Sopenharmony_ci struct stw_framebuffer *fb; 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci if (!stw_dev) 443bf215546Sopenharmony_ci return NULL; 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci stw_lock_framebuffers(stw_dev); 446bf215546Sopenharmony_ci fb = stw_framebuffer_from_hdc_locked(hdc); 447bf215546Sopenharmony_ci stw_unlock_framebuffers(stw_dev); 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci return fb; 450bf215546Sopenharmony_ci} 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci/** 454bf215546Sopenharmony_ci * Given an HWND, return the corresponding stw_framebuffer. 455bf215546Sopenharmony_ci * The returned stw_framebuffer will have its mutex locked. 456bf215546Sopenharmony_ci */ 457bf215546Sopenharmony_cistruct stw_framebuffer * 458bf215546Sopenharmony_cistw_framebuffer_from_hwnd(HWND hwnd) 459bf215546Sopenharmony_ci{ 460bf215546Sopenharmony_ci struct stw_framebuffer *fb; 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci stw_lock_framebuffers(stw_dev); 463bf215546Sopenharmony_ci fb = stw_framebuffer_from_hwnd_locked(hwnd); 464bf215546Sopenharmony_ci stw_unlock_framebuffers(stw_dev); 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci return fb; 467bf215546Sopenharmony_ci} 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ciBOOL APIENTRY 471bf215546Sopenharmony_ciDrvSetPixelFormat(HDC hdc, LONG iPixelFormat) 472bf215546Sopenharmony_ci{ 473bf215546Sopenharmony_ci uint count; 474bf215546Sopenharmony_ci uint index; 475bf215546Sopenharmony_ci struct stw_framebuffer *fb; 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci if (!stw_dev) 478bf215546Sopenharmony_ci return FALSE; 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_ci index = (uint) iPixelFormat - 1; 481bf215546Sopenharmony_ci count = stw_pixelformat_get_count(hdc); 482bf215546Sopenharmony_ci if (index >= count) 483bf215546Sopenharmony_ci return FALSE; 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_ci fb = stw_framebuffer_from_hdc_locked(hdc); 486bf215546Sopenharmony_ci if (fb) { 487bf215546Sopenharmony_ci /* 488bf215546Sopenharmony_ci * SetPixelFormat must be called only once. However ignore 489bf215546Sopenharmony_ci * pbuffers, for which the framebuffer object is created first. 490bf215546Sopenharmony_ci */ 491bf215546Sopenharmony_ci boolean bPbuffer = fb->owner == STW_FRAMEBUFFER_PBUFFER; 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci stw_framebuffer_unlock( fb ); 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci return bPbuffer; 496bf215546Sopenharmony_ci } 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci fb = stw_framebuffer_create(WindowFromDC(hdc), iPixelFormat, STW_FRAMEBUFFER_WGL_WINDOW); 499bf215546Sopenharmony_ci if (!fb) { 500bf215546Sopenharmony_ci return FALSE; 501bf215546Sopenharmony_ci } 502bf215546Sopenharmony_ci 503bf215546Sopenharmony_ci stw_framebuffer_unlock( fb ); 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci /* Some applications mistakenly use the undocumented wglSetPixelFormat 506bf215546Sopenharmony_ci * function instead of SetPixelFormat, so we call SetPixelFormat here to 507bf215546Sopenharmony_ci * avoid opengl32.dll's wglCreateContext to fail */ 508bf215546Sopenharmony_ci if (GetPixelFormat(hdc) == 0) { 509bf215546Sopenharmony_ci BOOL bRet = SetPixelFormat(hdc, iPixelFormat, NULL); 510bf215546Sopenharmony_ci if (!bRet) { 511bf215546Sopenharmony_ci debug_printf("SetPixelFormat failed\n"); 512bf215546Sopenharmony_ci } 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci return TRUE; 516bf215546Sopenharmony_ci} 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_ciint 520bf215546Sopenharmony_cistw_pixelformat_get(HDC hdc) 521bf215546Sopenharmony_ci{ 522bf215546Sopenharmony_ci int iPixelFormat = 0; 523bf215546Sopenharmony_ci struct stw_framebuffer *fb; 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci fb = stw_framebuffer_from_hdc(hdc); 526bf215546Sopenharmony_ci if (fb) { 527bf215546Sopenharmony_ci iPixelFormat = fb->iPixelFormat; 528bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 529bf215546Sopenharmony_ci } 530bf215546Sopenharmony_ci 531bf215546Sopenharmony_ci return iPixelFormat; 532bf215546Sopenharmony_ci} 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_ciBOOL APIENTRY 536bf215546Sopenharmony_ciDrvPresentBuffers(HDC hdc, LPPRESENTBUFFERS data) 537bf215546Sopenharmony_ci{ 538bf215546Sopenharmony_ci struct stw_framebuffer *fb; 539bf215546Sopenharmony_ci struct stw_context *ctx; 540bf215546Sopenharmony_ci struct pipe_screen *screen; 541bf215546Sopenharmony_ci struct pipe_context *pipe; 542bf215546Sopenharmony_ci struct pipe_resource *res; 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci if (!stw_dev) 545bf215546Sopenharmony_ci return FALSE; 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci fb = stw_framebuffer_from_hdc( hdc ); 548bf215546Sopenharmony_ci if (fb == NULL) 549bf215546Sopenharmony_ci return FALSE; 550bf215546Sopenharmony_ci 551bf215546Sopenharmony_ci screen = stw_dev->screen; 552bf215546Sopenharmony_ci ctx = stw_current_context(); 553bf215546Sopenharmony_ci pipe = ctx ? ctx->st->pipe : NULL; 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci res = (struct pipe_resource *)data->pPrivData; 556bf215546Sopenharmony_ci 557bf215546Sopenharmony_ci if (data->hSurface != fb->hSharedSurface) { 558bf215546Sopenharmony_ci if (fb->shared_surface) { 559bf215546Sopenharmony_ci stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface); 560bf215546Sopenharmony_ci fb->shared_surface = NULL; 561bf215546Sopenharmony_ci } 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci fb->hSharedSurface = data->hSurface; 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci if (data->hSurface && 566bf215546Sopenharmony_ci stw_dev->stw_winsys->shared_surface_open) { 567bf215546Sopenharmony_ci fb->shared_surface = 568bf215546Sopenharmony_ci stw_dev->stw_winsys->shared_surface_open(screen, 569bf215546Sopenharmony_ci fb->hSharedSurface); 570bf215546Sopenharmony_ci } 571bf215546Sopenharmony_ci } 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci if (!fb->minimized) { 574bf215546Sopenharmony_ci if (fb->shared_surface) { 575bf215546Sopenharmony_ci stw_dev->stw_winsys->compose(screen, 576bf215546Sopenharmony_ci res, 577bf215546Sopenharmony_ci fb->shared_surface, 578bf215546Sopenharmony_ci &fb->client_rect, 579bf215546Sopenharmony_ci data->ullPresentToken); 580bf215546Sopenharmony_ci } 581bf215546Sopenharmony_ci else { 582bf215546Sopenharmony_ci stw_dev->stw_winsys->present( screen, pipe, res, hdc ); 583bf215546Sopenharmony_ci } 584bf215546Sopenharmony_ci } 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci stw_framebuffer_update(fb); 587bf215546Sopenharmony_ci stw_notify_current_locked(fb); 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 590bf215546Sopenharmony_ci 591bf215546Sopenharmony_ci return TRUE; 592bf215546Sopenharmony_ci} 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci 595bf215546Sopenharmony_ci/** 596bf215546Sopenharmony_ci * Queue a composition. 597bf215546Sopenharmony_ci * 598bf215546Sopenharmony_ci * The stw_framebuffer object must have its mutex locked. The mutex will 599bf215546Sopenharmony_ci * be unlocked here before returning. 600bf215546Sopenharmony_ci */ 601bf215546Sopenharmony_ciBOOL 602bf215546Sopenharmony_cistw_framebuffer_present_locked(HDC hdc, 603bf215546Sopenharmony_ci struct stw_framebuffer *fb, 604bf215546Sopenharmony_ci struct pipe_resource *res) 605bf215546Sopenharmony_ci{ 606bf215546Sopenharmony_ci if (fb->winsys_framebuffer) { 607bf215546Sopenharmony_ci BOOL result = fb->winsys_framebuffer->present(fb->winsys_framebuffer); 608bf215546Sopenharmony_ci 609bf215546Sopenharmony_ci stw_framebuffer_update(fb); 610bf215546Sopenharmony_ci stw_notify_current_locked(fb); 611bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_ci return result; 614bf215546Sopenharmony_ci } 615bf215546Sopenharmony_ci else if (stw_dev->callbacks.pfnPresentBuffers && 616bf215546Sopenharmony_ci stw_dev->stw_winsys->compose) { 617bf215546Sopenharmony_ci PRESENTBUFFERSCB data; 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_ci memset(&data, 0, sizeof data); 620bf215546Sopenharmony_ci data.nVersion = 2; 621bf215546Sopenharmony_ci data.syncType = PRESCB_SYNCTYPE_NONE; 622bf215546Sopenharmony_ci data.luidAdapter = stw_dev->AdapterLuid; 623bf215546Sopenharmony_ci data.updateRect = fb->client_rect; 624bf215546Sopenharmony_ci data.pPrivData = (void *)res; 625bf215546Sopenharmony_ci 626bf215546Sopenharmony_ci stw_notify_current_locked(fb); 627bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 628bf215546Sopenharmony_ci 629bf215546Sopenharmony_ci return stw_dev->callbacks.pfnPresentBuffers(hdc, &data); 630bf215546Sopenharmony_ci } 631bf215546Sopenharmony_ci else { 632bf215546Sopenharmony_ci struct pipe_screen *screen = stw_dev->screen; 633bf215546Sopenharmony_ci struct stw_context *ctx = stw_current_context(); 634bf215546Sopenharmony_ci struct pipe_context *pipe = ctx ? ctx->st->pipe : NULL; 635bf215546Sopenharmony_ci 636bf215546Sopenharmony_ci stw_dev->stw_winsys->present( screen, pipe, res, hdc ); 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci stw_framebuffer_update(fb); 639bf215546Sopenharmony_ci stw_notify_current_locked(fb); 640bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_ci return TRUE; 643bf215546Sopenharmony_ci } 644bf215546Sopenharmony_ci} 645bf215546Sopenharmony_ci 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci/** 648bf215546Sopenharmony_ci * This is called just before issuing the buffer swap/present. 649bf215546Sopenharmony_ci * We query the current time and determine if we should sleep before 650bf215546Sopenharmony_ci * issuing the swap/present. 651bf215546Sopenharmony_ci * This is a bit of a hack and is certainly not very accurate but it 652bf215546Sopenharmony_ci * basically works. 653bf215546Sopenharmony_ci * This is for the WGL_ARB_swap_interval extension. 654bf215546Sopenharmony_ci */ 655bf215546Sopenharmony_cistatic void 656bf215546Sopenharmony_ciwait_swap_interval(struct stw_framebuffer *fb) 657bf215546Sopenharmony_ci{ 658bf215546Sopenharmony_ci /* Note: all time variables here are in units of microseconds */ 659bf215546Sopenharmony_ci int64_t cur_time = os_time_get_nano() / 1000; 660bf215546Sopenharmony_ci 661bf215546Sopenharmony_ci if (fb->prev_swap_time != 0) { 662bf215546Sopenharmony_ci /* Compute time since previous swap */ 663bf215546Sopenharmony_ci int64_t delta = cur_time - fb->prev_swap_time; 664bf215546Sopenharmony_ci int64_t min_swap_period = 665bf215546Sopenharmony_ci 1.0e6 / stw_dev->refresh_rate * stw_dev->swap_interval; 666bf215546Sopenharmony_ci 667bf215546Sopenharmony_ci /* If time since last swap is less than wait period, wait. 668bf215546Sopenharmony_ci * Note that it's possible for the delta to be negative because of 669bf215546Sopenharmony_ci * rollover. See https://bugs.freedesktop.org/show_bug.cgi?id=102241 670bf215546Sopenharmony_ci */ 671bf215546Sopenharmony_ci if ((delta >= 0) && (delta < min_swap_period)) { 672bf215546Sopenharmony_ci float fudge = 1.75f; /* emperical fudge factor */ 673bf215546Sopenharmony_ci int64_t wait = (min_swap_period - delta) * fudge; 674bf215546Sopenharmony_ci os_time_sleep(wait); 675bf215546Sopenharmony_ci } 676bf215546Sopenharmony_ci } 677bf215546Sopenharmony_ci 678bf215546Sopenharmony_ci fb->prev_swap_time = cur_time; 679bf215546Sopenharmony_ci} 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ciBOOL 682bf215546Sopenharmony_cistw_framebuffer_swap_locked(HDC hdc, struct stw_framebuffer *fb) 683bf215546Sopenharmony_ci{ 684bf215546Sopenharmony_ci struct stw_context *ctx; 685bf215546Sopenharmony_ci if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) { 686bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 687bf215546Sopenharmony_ci return TRUE; 688bf215546Sopenharmony_ci } 689bf215546Sopenharmony_ci 690bf215546Sopenharmony_ci ctx = stw_current_context(); 691bf215546Sopenharmony_ci if (ctx) { 692bf215546Sopenharmony_ci if (ctx->hud) { 693bf215546Sopenharmony_ci /* Display the HUD */ 694bf215546Sopenharmony_ci struct pipe_resource *back = 695bf215546Sopenharmony_ci stw_get_framebuffer_resource(fb->stfb, ST_ATTACHMENT_BACK_LEFT); 696bf215546Sopenharmony_ci if (back) { 697bf215546Sopenharmony_ci hud_run(ctx->hud, NULL, back); 698bf215546Sopenharmony_ci } 699bf215546Sopenharmony_ci } 700bf215546Sopenharmony_ci 701bf215546Sopenharmony_ci if (ctx->current_framebuffer == fb) { 702bf215546Sopenharmony_ci /* flush current context */ 703bf215546Sopenharmony_ci stw_st_flush(ctx->st, fb->stfb, ST_FLUSH_END_OF_FRAME); 704bf215546Sopenharmony_ci } 705bf215546Sopenharmony_ci } 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_ci if (stw_dev->swap_interval != 0 && !fb->winsys_framebuffer) { 708bf215546Sopenharmony_ci wait_swap_interval(fb); 709bf215546Sopenharmony_ci } 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci return stw_st_swap_framebuffer_locked(hdc, ctx->st, fb->stfb); 712bf215546Sopenharmony_ci} 713bf215546Sopenharmony_ci 714bf215546Sopenharmony_ciBOOL APIENTRY 715bf215546Sopenharmony_ciDrvSwapBuffers(HDC hdc) 716bf215546Sopenharmony_ci{ 717bf215546Sopenharmony_ci struct stw_framebuffer *fb; 718bf215546Sopenharmony_ci 719bf215546Sopenharmony_ci if (!stw_dev) 720bf215546Sopenharmony_ci return FALSE; 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci fb = stw_framebuffer_from_hdc( hdc ); 723bf215546Sopenharmony_ci if (fb == NULL) 724bf215546Sopenharmony_ci return FALSE; 725bf215546Sopenharmony_ci 726bf215546Sopenharmony_ci return stw_framebuffer_swap_locked(hdc, fb); 727bf215546Sopenharmony_ci} 728bf215546Sopenharmony_ci 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_ciBOOL APIENTRY 731bf215546Sopenharmony_ciDrvSwapLayerBuffers(HDC hdc, UINT fuPlanes) 732bf215546Sopenharmony_ci{ 733bf215546Sopenharmony_ci if (fuPlanes & WGL_SWAP_MAIN_PLANE) 734bf215546Sopenharmony_ci return DrvSwapBuffers(hdc); 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_ci return FALSE; 737bf215546Sopenharmony_ci} 738