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