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
48static LRESULT CALLBACK
49WndProc(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
69HPBUFFERARB WINAPI
70wglCreatePbufferARB(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
271HDC WINAPI
272wglGetPbufferDCARB(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
290int WINAPI
291wglReleasePbufferDCARB(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
307BOOL WINAPI
308wglDestroyPbufferARB(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
324BOOL WINAPI
325wglQueryPbufferARB(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