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