stw_ext_pbuffer.c revision 90a95f4d2c50b63ffa4c114081a1cfa5cdfa05cb
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 _hDC,
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
85   info = stw_pixelformat_get_info(iPixelFormat);
86   if (!info) {
87      SetLastError(ERROR_INVALID_PIXEL_FORMAT);
88      return 0;
89   }
90
91   if (iWidth <= 0 || iHeight <= 0) {
92      SetLastError(ERROR_INVALID_DATA);
93      return 0;
94   }
95
96   for (piAttrib = piAttribList; *piAttrib; piAttrib++) {
97      switch (*piAttrib) {
98      case WGL_PBUFFER_LARGEST_ARB:
99         piAttrib++;
100         useLargest = *piAttrib;
101         break;
102      default:
103         SetLastError(ERROR_INVALID_DATA);
104         return 0;
105      }
106   }
107
108   if (iWidth > stw_dev->max_2d_length) {
109      if (useLargest) {
110         iWidth = stw_dev->max_2d_length;
111      } else {
112         SetLastError(ERROR_NO_SYSTEM_RESOURCES);
113         return 0;
114      }
115   }
116
117   if (iHeight > stw_dev->max_2d_length) {
118      if (useLargest) {
119         iHeight = stw_dev->max_2d_length;
120      } else {
121         SetLastError(ERROR_NO_SYSTEM_RESOURCES);
122         return 0;
123      }
124   }
125
126   /*
127    * Implement pbuffers through invisible windows
128    */
129
130   if (first) {
131      WNDCLASS wc;
132      memset(&wc, 0, sizeof wc);
133      wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
134      wc.hCursor = LoadCursor(NULL, IDC_ARROW);
135      wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
136      wc.lpfnWndProc = WndProc;
137      wc.lpszClassName = "wglpbuffer";
138      wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
139      RegisterClass(&wc);
140      first = FALSE;
141   }
142
143   dwExStyle = 0;
144   dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
145
146   if (0) {
147      /*
148       * Don't hide the window -- useful for debugging what the application is
149       * drawing
150       */
151
152      dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW;
153   } else {
154      dwStyle |= WS_POPUPWINDOW;
155   }
156
157   rect.left = 0;
158   rect.top = 0;
159   rect.right = rect.left + iWidth;
160   rect.bottom = rect.top + iHeight;
161
162   /*
163    * The CreateWindowEx parameters are the total (outside) dimensions of the
164    * window, which can vary with Windows version and user settings.  Use
165    * AdjustWindowRect to get the required total area for the given client area.
166    *
167    * AdjustWindowRectEx does not accept WS_OVERLAPPED style (which is defined
168    * as 0), which means we need to use some other style instead, e.g.,
169    * WS_OVERLAPPEDWINDOW or WS_POPUPWINDOW as above.
170    */
171
172   AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
173
174   hWnd = CreateWindowEx(dwExStyle,
175                         "wglpbuffer", /* wc.lpszClassName */
176                         NULL,
177                         dwStyle,
178                         CW_USEDEFAULT, /* x */
179                         CW_USEDEFAULT, /* y */
180                         rect.right - rect.left, /* width */
181                         rect.bottom - rect.top, /* height */
182                         NULL,
183                         NULL,
184                         NULL,
185                         NULL);
186   if (!hWnd) {
187      return 0;
188   }
189
190#ifdef DEBUG
191   /*
192    * Verify the client area size matches the specified size.
193    */
194
195   GetClientRect(hWnd, &rect);
196   assert(rect.left == 0);
197   assert(rect.top == 0);
198   assert(rect.right - rect.left == iWidth);
199   assert(rect.bottom - rect.top == iHeight);
200#endif
201
202   hDC = GetDC(hWnd);
203   if (!hDC) {
204      return 0;
205   }
206
207   SetPixelFormat(hDC, iPixelFormat, &info->pfd);
208
209   fb = stw_framebuffer_create(hDC, iPixelFormat);
210   if (!fb) {
211      SetLastError(ERROR_NO_SYSTEM_RESOURCES);
212   } else {
213      stw_framebuffer_release(fb);
214   }
215
216   return (HPBUFFERARB)fb;
217}
218
219
220HDC WINAPI
221wglGetPbufferDCARB(HPBUFFERARB hPbuffer)
222{
223   struct stw_framebuffer *fb;
224   HDC hDC;
225
226   fb = (struct stw_framebuffer *)hPbuffer;
227
228   hDC = GetDC(fb->hWnd);
229
230   assert(hDC == fb->hDC);
231
232   return hDC;
233}
234
235
236int WINAPI
237wglReleasePbufferDCARB(HPBUFFERARB hPbuffer,
238                       HDC hDC)
239{
240   struct stw_framebuffer *fb;
241
242   fb = (struct stw_framebuffer *)hPbuffer;
243
244   return ReleaseDC(fb->hWnd, hDC);
245}
246
247
248BOOL WINAPI
249wglDestroyPbufferARB(HPBUFFERARB hPbuffer)
250{
251   struct stw_framebuffer *fb;
252
253   fb = (struct stw_framebuffer *)hPbuffer;
254
255   /* This will destroy all our data */
256   return DestroyWindow(fb->hWnd);
257}
258
259
260BOOL WINAPI
261wglQueryPbufferARB(HPBUFFERARB hPbuffer,
262                   int iAttribute,
263                   int *piValue)
264{
265   struct stw_framebuffer *fb;
266
267   fb = (struct stw_framebuffer *)hPbuffer;
268
269   switch (iAttribute) {
270   case WGL_PBUFFER_WIDTH_ARB:
271      *piValue = fb->width;
272      return TRUE;
273   case WGL_PBUFFER_HEIGHT_ARB:
274      *piValue = fb->height;
275      return TRUE;
276   case WGL_PBUFFER_LOST_ARB:
277      /* We assume that no content is ever lost due to display mode change */
278      *piValue = FALSE;
279      return TRUE;
280   default:
281      SetLastError(ERROR_INVALID_DATA);
282      return FALSE;
283   }
284}
285