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