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 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
271 HDC WINAPI
wglGetPbufferDCARB(HPBUFFERARB hPbuffer)272 wglGetPbufferDCARB(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
290 int WINAPI
wglReleasePbufferDCARB(HPBUFFERARB hPbuffer,HDC hDC)291 wglReleasePbufferDCARB(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
307 BOOL WINAPI
wglDestroyPbufferARB(HPBUFFERARB hPbuffer)308 wglDestroyPbufferARB(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
324 BOOL WINAPI
wglQueryPbufferARB(HPBUFFERARB hPbuffer,int iAttribute,int * piValue)325 wglQueryPbufferARB(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