1/************************************************************************** 2 * 3 * Copyright 2010 VMware, Inc. 4 * All Rights Reserved. 5 * 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: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 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. 25 * 26 **************************************************************************/ 27 28#include <windows.h> 29 30#define WGL_WGLEXT_PROTOTYPES 31 32#include <GL/gl.h> 33#include <GL/wglext.h> 34 35#include "pipe/p_defines.h" 36#include "pipe/p_screen.h" 37 38#include "stw_device.h" 39#include "stw_pixelformat.h" 40#include "stw_framebuffer.h" 41 42 43#define LARGE_WINDOW_SIZE 60000 44 45 46static LRESULT CALLBACK 47WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 48{ 49 MINMAXINFO *pMMI; 50 switch (uMsg) { 51 case WM_GETMINMAXINFO: 52 // Allow to create a window bigger than the desktop 53 pMMI = (MINMAXINFO *)lParam; 54 pMMI->ptMaxSize.x = LARGE_WINDOW_SIZE; 55 pMMI->ptMaxSize.y = LARGE_WINDOW_SIZE; 56 pMMI->ptMaxTrackSize.x = LARGE_WINDOW_SIZE; 57 pMMI->ptMaxTrackSize.y = LARGE_WINDOW_SIZE; 58 break; 59 default: 60 break; 61 } 62 63 return DefWindowProc(hWnd, uMsg, wParam, lParam); 64} 65 66 67HPBUFFERARB WINAPI 68wglCreatePbufferARB(HDC hCurrentDC, 69 int iPixelFormat, 70 int iWidth, 71 int iHeight, 72 const int *piAttribList) 73{ 74 static boolean first = TRUE; 75 const int *piAttrib; 76 int useLargest = 0; 77 const struct stw_pixelformat_info *info; 78 struct stw_framebuffer *fb; 79 DWORD dwExStyle; 80 DWORD dwStyle; 81 RECT rect; 82 HWND hWnd; 83 HDC hDC; 84 int iDisplayablePixelFormat; 85 PIXELFORMATDESCRIPTOR pfd; 86 BOOL bRet; 87 88 info = stw_pixelformat_get_info(iPixelFormat - 1); 89 if (!info) { 90 SetLastError(ERROR_INVALID_PIXEL_FORMAT); 91 return 0; 92 } 93 94 if (iWidth <= 0 || iHeight <= 0) { 95 SetLastError(ERROR_INVALID_DATA); 96 return 0; 97 } 98 99 for (piAttrib = piAttribList; *piAttrib; piAttrib++) { 100 switch (*piAttrib) { 101 case WGL_PBUFFER_LARGEST_ARB: 102 piAttrib++; 103 useLargest = *piAttrib; 104 break; 105 default: 106 SetLastError(ERROR_INVALID_DATA); 107 return 0; 108 } 109 } 110 111 if (iWidth > stw_dev->max_2d_length) { 112 if (useLargest) { 113 iWidth = stw_dev->max_2d_length; 114 } else { 115 SetLastError(ERROR_NO_SYSTEM_RESOURCES); 116 return 0; 117 } 118 } 119 120 if (iHeight > stw_dev->max_2d_length) { 121 if (useLargest) { 122 iHeight = stw_dev->max_2d_length; 123 } else { 124 SetLastError(ERROR_NO_SYSTEM_RESOURCES); 125 return 0; 126 } 127 } 128 129 /* 130 * Implement pbuffers through invisible windows 131 */ 132 133 if (first) { 134 WNDCLASS wc; 135 memset(&wc, 0, sizeof wc); 136 wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); 137 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 138 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 139 wc.lpfnWndProc = WndProc; 140 wc.lpszClassName = "wglpbuffer"; 141 wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 142 RegisterClass(&wc); 143 first = FALSE; 144 } 145 146 dwExStyle = 0; 147 dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 148 149 if (0) { 150 /* 151 * Don't hide the window -- useful for debugging what the application is 152 * drawing 153 */ 154 155 dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW; 156 } else { 157 dwStyle |= WS_POPUPWINDOW; 158 } 159 160 rect.left = 0; 161 rect.top = 0; 162 rect.right = rect.left + iWidth; 163 rect.bottom = rect.top + iHeight; 164 165 /* 166 * The CreateWindowEx parameters are the total (outside) dimensions of the 167 * window, which can vary with Windows version and user settings. Use 168 * AdjustWindowRect to get the required total area for the given client area. 169 * 170 * AdjustWindowRectEx does not accept WS_OVERLAPPED style (which is defined 171 * as 0), which means we need to use some other style instead, e.g., 172 * WS_OVERLAPPEDWINDOW or WS_POPUPWINDOW as above. 173 */ 174 175 AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle); 176 177 hWnd = CreateWindowEx(dwExStyle, 178 "wglpbuffer", /* wc.lpszClassName */ 179 NULL, 180 dwStyle, 181 CW_USEDEFAULT, /* x */ 182 CW_USEDEFAULT, /* y */ 183 rect.right - rect.left, /* width */ 184 rect.bottom - rect.top, /* height */ 185 NULL, 186 NULL, 187 NULL, 188 NULL); 189 if (!hWnd) { 190 return 0; 191 } 192 193#ifdef DEBUG 194 /* 195 * Verify the client area size matches the specified size. 196 */ 197 198 GetClientRect(hWnd, &rect); 199 assert(rect.left == 0); 200 assert(rect.top == 0); 201 assert(rect.right - rect.left == iWidth); 202 assert(rect.bottom - rect.top == iHeight); 203#endif 204 205 hDC = GetDC(hWnd); 206 if (!hDC) { 207 return 0; 208 } 209 210 /* 211 * We can't pass non-displayable pixel formats to GDI, which is why we 212 * create the framebuffer object before calling SetPixelFormat(). 213 */ 214 fb = stw_framebuffer_create(hDC, iPixelFormat); 215 if (!fb) { 216 SetLastError(ERROR_NO_SYSTEM_RESOURCES); 217 return NULL; 218 } 219 220 fb->bPbuffer = TRUE; 221 iDisplayablePixelFormat = fb->iDisplayablePixelFormat; 222 223 stw_framebuffer_release(fb); 224 225 /* 226 * We need to set a displayable pixel format on the hidden window DC 227 * so that wglCreateContext and wglMakeCurrent are not overruled by GDI. 228 */ 229 bRet = SetPixelFormat(hDC, iDisplayablePixelFormat, &pfd); 230 assert(bRet); 231 232 return (HPBUFFERARB)fb; 233} 234 235 236HDC WINAPI 237wglGetPbufferDCARB(HPBUFFERARB hPbuffer) 238{ 239 struct stw_framebuffer *fb; 240 HDC hDC; 241 242 if (!hPbuffer) { 243 SetLastError(ERROR_INVALID_HANDLE); 244 return NULL; 245 } 246 247 fb = (struct stw_framebuffer *)hPbuffer; 248 249 hDC = GetDC(fb->hWnd); 250 251 assert(hDC == fb->hDC); 252 253 return hDC; 254} 255 256 257int WINAPI 258wglReleasePbufferDCARB(HPBUFFERARB hPbuffer, 259 HDC hDC) 260{ 261 struct stw_framebuffer *fb; 262 263 if (!hPbuffer) { 264 SetLastError(ERROR_INVALID_HANDLE); 265 return 0; 266 } 267 268 fb = (struct stw_framebuffer *)hPbuffer; 269 270 return ReleaseDC(fb->hWnd, hDC); 271} 272 273 274BOOL WINAPI 275wglDestroyPbufferARB(HPBUFFERARB hPbuffer) 276{ 277 struct stw_framebuffer *fb; 278 279 if (!hPbuffer) { 280 SetLastError(ERROR_INVALID_HANDLE); 281 return FALSE; 282 } 283 284 fb = (struct stw_framebuffer *)hPbuffer; 285 286 /* This will destroy all our data */ 287 return DestroyWindow(fb->hWnd); 288} 289 290 291BOOL WINAPI 292wglQueryPbufferARB(HPBUFFERARB hPbuffer, 293 int iAttribute, 294 int *piValue) 295{ 296 struct stw_framebuffer *fb; 297 298 if (!hPbuffer) { 299 SetLastError(ERROR_INVALID_HANDLE); 300 return FALSE; 301 } 302 303 fb = (struct stw_framebuffer *)hPbuffer; 304 305 switch (iAttribute) { 306 case WGL_PBUFFER_WIDTH_ARB: 307 *piValue = fb->width; 308 return TRUE; 309 case WGL_PBUFFER_HEIGHT_ARB: 310 *piValue = fb->height; 311 return TRUE; 312 case WGL_PBUFFER_LOST_ARB: 313 /* We assume that no content is ever lost due to display mode change */ 314 *piValue = FALSE; 315 return TRUE; 316 default: 317 SetLastError(ERROR_INVALID_DATA); 318 return FALSE; 319 } 320} 321