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