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 "stw_device.h"
39#include "stw_pixelformat.h"
40#include "stw_framebuffer.h"
41
42
43#define LARGE_WINDOW_SIZE 60000
44
45
46static LRESULT CALLBACK
47WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
48{
49    MINMAXINFO *pMMI;
50    switch (uMsg) {
51    case WM_GETMINMAXINFO:
52        // Allow to create a window bigger than the desktop
53        pMMI = (MINMAXINFO *)lParam;
54        pMMI->ptMaxSize.x = LARGE_WINDOW_SIZE;
55        pMMI->ptMaxSize.y = LARGE_WINDOW_SIZE;
56        pMMI->ptMaxTrackSize.x = LARGE_WINDOW_SIZE;
57        pMMI->ptMaxTrackSize.y = LARGE_WINDOW_SIZE;
58        break;
59    default:
60        break;
61    }
62
63    return DefWindowProc(hWnd, uMsg, wParam, lParam);
64}
65
66
67HPBUFFERARB WINAPI
68wglCreatePbufferARB(HDC hCurrentDC,
69                    int iPixelFormat,
70                    int iWidth,
71                    int iHeight,
72                    const int *piAttribList)
73{
74   static boolean first = TRUE;
75   const int *piAttrib;
76   int useLargest = 0;
77   const struct stw_pixelformat_info *info;
78   struct stw_framebuffer *fb;
79   DWORD dwExStyle;
80   DWORD dwStyle;
81   RECT rect;
82   HWND hWnd;
83   HDC hDC;
84   int iDisplayablePixelFormat;
85   PIXELFORMATDESCRIPTOR pfd;
86   BOOL bRet;
87
88   info = stw_pixelformat_get_info(iPixelFormat - 1);
89   if (!info) {
90      SetLastError(ERROR_INVALID_PIXEL_FORMAT);
91      return 0;
92   }
93
94   if (iWidth <= 0 || iHeight <= 0) {
95      SetLastError(ERROR_INVALID_DATA);
96      return 0;
97   }
98
99   for (piAttrib = piAttribList; *piAttrib; piAttrib++) {
100      switch (*piAttrib) {
101      case WGL_PBUFFER_LARGEST_ARB:
102         piAttrib++;
103         useLargest = *piAttrib;
104         break;
105      default:
106         SetLastError(ERROR_INVALID_DATA);
107         return 0;
108      }
109   }
110
111   if (iWidth > stw_dev->max_2d_length) {
112      if (useLargest) {
113         iWidth = stw_dev->max_2d_length;
114      } else {
115         SetLastError(ERROR_NO_SYSTEM_RESOURCES);
116         return 0;
117      }
118   }
119
120   if (iHeight > stw_dev->max_2d_length) {
121      if (useLargest) {
122         iHeight = stw_dev->max_2d_length;
123      } else {
124         SetLastError(ERROR_NO_SYSTEM_RESOURCES);
125         return 0;
126      }
127   }
128
129   /*
130    * Implement pbuffers through invisible windows
131    */
132
133   if (first) {
134      WNDCLASS wc;
135      memset(&wc, 0, sizeof wc);
136      wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
137      wc.hCursor = LoadCursor(NULL, IDC_ARROW);
138      wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
139      wc.lpfnWndProc = WndProc;
140      wc.lpszClassName = "wglpbuffer";
141      wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
142      RegisterClass(&wc);
143      first = FALSE;
144   }
145
146   dwExStyle = 0;
147   dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
148
149   if (0) {
150      /*
151       * Don't hide the window -- useful for debugging what the application is
152       * drawing
153       */
154
155      dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW;
156   } else {
157      dwStyle |= WS_POPUPWINDOW;
158   }
159
160   rect.left = 0;
161   rect.top = 0;
162   rect.right = rect.left + iWidth;
163   rect.bottom = rect.top + iHeight;
164
165   /*
166    * The CreateWindowEx parameters are the total (outside) dimensions of the
167    * window, which can vary with Windows version and user settings.  Use
168    * AdjustWindowRect to get the required total area for the given client area.
169    *
170    * AdjustWindowRectEx does not accept WS_OVERLAPPED style (which is defined
171    * as 0), which means we need to use some other style instead, e.g.,
172    * WS_OVERLAPPEDWINDOW or WS_POPUPWINDOW as above.
173    */
174
175   AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
176
177   hWnd = CreateWindowEx(dwExStyle,
178                         "wglpbuffer", /* wc.lpszClassName */
179                         NULL,
180                         dwStyle,
181                         CW_USEDEFAULT, /* x */
182                         CW_USEDEFAULT, /* y */
183                         rect.right - rect.left, /* width */
184                         rect.bottom - rect.top, /* height */
185                         NULL,
186                         NULL,
187                         NULL,
188                         NULL);
189   if (!hWnd) {
190      return 0;
191   }
192
193#ifdef DEBUG
194   /*
195    * Verify the client area size matches the specified size.
196    */
197
198   GetClientRect(hWnd, &rect);
199   assert(rect.left == 0);
200   assert(rect.top == 0);
201   assert(rect.right - rect.left == iWidth);
202   assert(rect.bottom - rect.top == iHeight);
203#endif
204
205   hDC = GetDC(hWnd);
206   if (!hDC) {
207      return 0;
208   }
209
210   /*
211    * We can't pass non-displayable pixel formats to GDI, which is why we
212    * create the framebuffer object before calling SetPixelFormat().
213    */
214   fb = stw_framebuffer_create(hDC, iPixelFormat);
215   if (!fb) {
216      SetLastError(ERROR_NO_SYSTEM_RESOURCES);
217      return NULL;
218   }
219
220   fb->bPbuffer = TRUE;
221   iDisplayablePixelFormat = fb->iDisplayablePixelFormat;
222
223   stw_framebuffer_release(fb);
224
225   /*
226    * We need to set a displayable pixel format on the hidden window DC
227    * so that wglCreateContext and wglMakeCurrent are not overruled by GDI.
228    */
229   bRet = SetPixelFormat(hDC, iDisplayablePixelFormat, &pfd);
230   assert(bRet);
231
232   return (HPBUFFERARB)fb;
233}
234
235
236HDC WINAPI
237wglGetPbufferDCARB(HPBUFFERARB hPbuffer)
238{
239   struct stw_framebuffer *fb;
240   HDC hDC;
241
242   if (!hPbuffer) {
243      SetLastError(ERROR_INVALID_HANDLE);
244      return NULL;
245   }
246
247   fb = (struct stw_framebuffer *)hPbuffer;
248
249   hDC = GetDC(fb->hWnd);
250
251   assert(hDC == fb->hDC);
252
253   return hDC;
254}
255
256
257int WINAPI
258wglReleasePbufferDCARB(HPBUFFERARB hPbuffer,
259                       HDC hDC)
260{
261   struct stw_framebuffer *fb;
262
263   if (!hPbuffer) {
264      SetLastError(ERROR_INVALID_HANDLE);
265      return 0;
266   }
267
268   fb = (struct stw_framebuffer *)hPbuffer;
269
270   return ReleaseDC(fb->hWnd, hDC);
271}
272
273
274BOOL WINAPI
275wglDestroyPbufferARB(HPBUFFERARB hPbuffer)
276{
277   struct stw_framebuffer *fb;
278
279   if (!hPbuffer) {
280      SetLastError(ERROR_INVALID_HANDLE);
281      return FALSE;
282   }
283
284   fb = (struct stw_framebuffer *)hPbuffer;
285
286   /* This will destroy all our data */
287   return DestroyWindow(fb->hWnd);
288}
289
290
291BOOL WINAPI
292wglQueryPbufferARB(HPBUFFERARB hPbuffer,
293                   int iAttribute,
294                   int *piValue)
295{
296   struct stw_framebuffer *fb;
297
298   if (!hPbuffer) {
299      SetLastError(ERROR_INVALID_HANDLE);
300      return FALSE;
301   }
302
303   fb = (struct stw_framebuffer *)hPbuffer;
304
305   switch (iAttribute) {
306   case WGL_PBUFFER_WIDTH_ARB:
307      *piValue = fb->width;
308      return TRUE;
309   case WGL_PBUFFER_HEIGHT_ARB:
310      *piValue = fb->height;
311      return TRUE;
312   case WGL_PBUFFER_LOST_ARB:
313      /* We assume that no content is ever lost due to display mode change */
314      *piValue = FALSE;
315      return TRUE;
316   default:
317      SetLastError(ERROR_INVALID_DATA);
318      return FALSE;
319   }
320}
321