stw_ext_pbuffer.c revision 9ffc8ea8f4cfa15115a93039cc7099f0fd597fe3
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 fb = (struct stw_framebuffer *)hPbuffer; 243 244 hDC = GetDC(fb->hWnd); 245 246 assert(hDC == fb->hDC); 247 248 return hDC; 249} 250 251 252int WINAPI 253wglReleasePbufferDCARB(HPBUFFERARB hPbuffer, 254 HDC hDC) 255{ 256 struct stw_framebuffer *fb; 257 258 fb = (struct stw_framebuffer *)hPbuffer; 259 260 return ReleaseDC(fb->hWnd, hDC); 261} 262 263 264BOOL WINAPI 265wglDestroyPbufferARB(HPBUFFERARB hPbuffer) 266{ 267 struct stw_framebuffer *fb; 268 269 fb = (struct stw_framebuffer *)hPbuffer; 270 271 /* This will destroy all our data */ 272 return DestroyWindow(fb->hWnd); 273} 274 275 276BOOL WINAPI 277wglQueryPbufferARB(HPBUFFERARB hPbuffer, 278 int iAttribute, 279 int *piValue) 280{ 281 struct stw_framebuffer *fb; 282 283 fb = (struct stw_framebuffer *)hPbuffer; 284 285 switch (iAttribute) { 286 case WGL_PBUFFER_WIDTH_ARB: 287 *piValue = fb->width; 288 return TRUE; 289 case WGL_PBUFFER_HEIGHT_ARB: 290 *piValue = fb->height; 291 return TRUE; 292 case WGL_PBUFFER_LOST_ARB: 293 /* We assume that no content is ever lost due to display mode change */ 294 *piValue = FALSE; 295 return TRUE; 296 default: 297 SetLastError(ERROR_INVALID_DATA); 298 return FALSE; 299 } 300} 301