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