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