xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/wgl/stw_ext_pbuffer.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 #ifndef _GAMING_XBOX
52     MINMAXINFO *pMMI;
53     switch (uMsg) {
54     case WM_GETMINMAXINFO:
55         // Allow to create a window bigger than the desktop
56         pMMI = (MINMAXINFO *)lParam;
57         pMMI->ptMaxSize.x = LARGE_WINDOW_SIZE;
58         pMMI->ptMaxSize.y = LARGE_WINDOW_SIZE;
59         pMMI->ptMaxTrackSize.x = LARGE_WINDOW_SIZE;
60         pMMI->ptMaxTrackSize.y = LARGE_WINDOW_SIZE;
61         break;
62     default:
63         break;
64     }
65 #endif /* _GAMING_XBOX */
66 
67     return DefWindowProc(hWnd, uMsg, wParam, lParam);
68 }
69 
70 struct stw_framebuffer *
stw_pbuffer_create(const struct stw_pixelformat_info * pfi,int iWidth,int iHeight,struct pipe_frontend_screen * fscreen)71 stw_pbuffer_create(const struct stw_pixelformat_info *pfi, int iWidth, int iHeight, struct pipe_frontend_screen *fscreen)
72 {
73    static bool first = true;
74 
75    /*
76     * Implement pbuffers through invisible windows
77     */
78 
79    if (first) {
80       WNDCLASS wc;
81       memset(&wc, 0, sizeof wc);
82       wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
83 #ifndef _GAMING_XBOX
84       wc.hCursor = LoadCursor(NULL, IDC_ARROW);
85       wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
86 #endif
87       wc.lpfnWndProc = WndProc;
88       wc.lpszClassName = "wglpbuffer";
89       wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
90       RegisterClass(&wc);
91       first = false;
92    }
93 
94    DWORD dwExStyle = 0;
95    DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
96 
97    if (0) {
98       /*
99        * Don't hide the window -- useful for debugging what the application is
100        * drawing
101        */
102 
103       dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW;
104    } else {
105       dwStyle |= WS_POPUPWINDOW;
106    }
107 
108    RECT rect = { 0, 0, iWidth, iHeight };
109 
110    /*
111     * The CreateWindowEx parameters are the total (outside) dimensions of the
112     * window, which can vary with Windows version and user settings.  Use
113     * AdjustWindowRect to get the required total area for the given client area.
114     *
115     * AdjustWindowRectEx does not accept WS_OVERLAPPED style (which is defined
116     * as 0), which means we need to use some other style instead, e.g.,
117     * WS_OVERLAPPEDWINDOW or WS_POPUPWINDOW as above.
118     */
119 
120    AdjustWindowRectEx(&rect, dwStyle, false, dwExStyle);
121 
122    HWND hWnd = CreateWindowEx(dwExStyle,
123                               "wglpbuffer", /* wc.lpszClassName */
124                               NULL,
125                               dwStyle,
126                               CW_USEDEFAULT, /* x */
127                               CW_USEDEFAULT, /* y */
128                               rect.right - rect.left, /* width */
129                               rect.bottom - rect.top, /* height */
130                               NULL,
131                               NULL,
132                               NULL,
133                               NULL);
134    if (!hWnd) {
135       return 0;
136    }
137 
138 #if MESA_DEBUG
139    /*
140     * Verify the client area size matches the specified size.
141     */
142 
143    GetClientRect(hWnd, &rect);
144    assert(rect.left == 0);
145    assert(rect.top == 0);
146    assert(rect.right - rect.left == iWidth);
147    assert(rect.bottom - rect.top == iHeight);
148 #endif
149 
150    return stw_framebuffer_create(hWnd, pfi, STW_FRAMEBUFFER_PBUFFER, fscreen);
151 }
152 
153 
154 HPBUFFERARB WINAPI
wglCreatePbufferARB(HDC hCurrentDC,int iPixelFormat,int iWidth,int iHeight,const int * piAttribList)155 wglCreatePbufferARB(HDC hCurrentDC,
156                     int iPixelFormat,
157                     int iWidth,
158                     int iHeight,
159                     const int *piAttribList)
160 {
161    const int *piAttrib;
162    int useLargest = 0;
163    struct stw_framebuffer *fb;
164    HWND hWnd;
165    int iDisplayablePixelFormat;
166    PIXELFORMATDESCRIPTOR pfd;
167    BOOL bRet;
168    int textureFormat = WGL_NO_TEXTURE_ARB;
169    int textureTarget = WGL_NO_TEXTURE_ARB;
170    BOOL textureMipmap = false;
171    const struct stw_pixelformat_info *pfi = stw_pixelformat_get_info(iPixelFormat);
172 
173    if (!pfi) {
174       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
175       return 0;
176    }
177 
178    if (iWidth <= 0 || iHeight <= 0) {
179       SetLastError(ERROR_INVALID_DATA);
180       return 0;
181    }
182 
183    if (piAttribList) {
184       for (piAttrib = piAttribList; *piAttrib; piAttrib++) {
185          switch (*piAttrib) {
186          case WGL_PBUFFER_LARGEST_ARB:
187             piAttrib++;
188             useLargest = *piAttrib;
189             break;
190           case WGL_TEXTURE_FORMAT_ARB:
191              /* WGL_ARB_render_texture */
192              piAttrib++;
193              textureFormat = *piAttrib;
194              if (textureFormat != WGL_TEXTURE_RGB_ARB &&
195                 textureFormat != WGL_TEXTURE_RGBA_ARB &&
196                 textureFormat != WGL_NO_TEXTURE_ARB) {
197                 SetLastError(ERROR_INVALID_DATA);
198                 return 0;
199              }
200              break;
201           case WGL_TEXTURE_TARGET_ARB:
202              /* WGL_ARB_render_texture */
203              piAttrib++;
204              textureTarget = *piAttrib;
205              if (textureTarget != WGL_TEXTURE_CUBE_MAP_ARB &&
206                  textureTarget != WGL_TEXTURE_1D_ARB &&
207                  textureTarget != WGL_TEXTURE_2D_ARB &&
208                  textureTarget != WGL_NO_TEXTURE_ARB) {
209                 SetLastError(ERROR_INVALID_DATA);
210                 return 0;
211              }
212              break;
213          case WGL_MIPMAP_TEXTURE_ARB:
214             /* WGL_ARB_render_texture */
215             piAttrib++;
216             textureMipmap = !!*piAttrib;
217             break;
218          default:
219             SetLastError(ERROR_INVALID_DATA);
220             debug_printf("wgl: Unsupported attribute 0x%x in %s\n",
221                          *piAttrib, __func__);
222             return 0;
223          }
224       }
225    }
226 
227    if (iWidth > stw_dev->max_2d_length) {
228       if (useLargest) {
229          iWidth = stw_dev->max_2d_length;
230       } else {
231          SetLastError(ERROR_NO_SYSTEM_RESOURCES);
232          return 0;
233       }
234    }
235 
236    if (iHeight > stw_dev->max_2d_length) {
237       if (useLargest) {
238          iHeight = stw_dev->max_2d_length;
239       } else {
240          SetLastError(ERROR_NO_SYSTEM_RESOURCES);
241          return 0;
242       }
243    }
244 
245    /*
246     * We can't pass non-displayable pixel formats to GDI, which is why we
247     * create the framebuffer object before calling SetPixelFormat().
248     */
249    fb = stw_pbuffer_create(pfi, iWidth, iHeight, stw_dev->fscreen);
250    if (!fb) {
251       SetLastError(ERROR_NO_SYSTEM_RESOURCES);
252       return NULL;
253    }
254 
255    /* WGL_ARB_render_texture fields */
256    fb->textureTarget = textureTarget;
257    fb->textureFormat = textureFormat;
258    fb->textureMipmap = textureMipmap;
259 
260    iDisplayablePixelFormat = fb->iDisplayablePixelFormat;
261    hWnd = fb->hWnd;
262 
263    stw_framebuffer_unlock(fb);
264 
265    /*
266     * We need to set a displayable pixel format on the hidden window DC
267     * so that wglCreateContext and wglMakeCurrent are not overruled by GDI.
268     */
269    bRet = SetPixelFormat(GetDC(hWnd), iDisplayablePixelFormat, &pfd);
270    assert(bRet);
271 
272    return (HPBUFFERARB)fb;
273 }
274 
275 
276 HDC WINAPI
wglGetPbufferDCARB(HPBUFFERARB hPbuffer)277 wglGetPbufferDCARB(HPBUFFERARB hPbuffer)
278 {
279    struct stw_framebuffer *fb;
280    HDC hDC;
281 
282    if (!hPbuffer) {
283       SetLastError(ERROR_INVALID_HANDLE);
284       return NULL;
285    }
286 
287    fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
288 
289    hDC = GetDC(fb->hWnd);
290 
291    return hDC;
292 }
293 
294 
295 int WINAPI
wglReleasePbufferDCARB(HPBUFFERARB hPbuffer,HDC hDC)296 wglReleasePbufferDCARB(HPBUFFERARB hPbuffer,
297                        HDC hDC)
298 {
299    struct stw_framebuffer *fb;
300 
301    if (!hPbuffer) {
302       SetLastError(ERROR_INVALID_HANDLE);
303       return 0;
304    }
305 
306    fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
307 
308    return ReleaseDC(fb->hWnd, hDC);
309 }
310 
311 
312 BOOL WINAPI
wglDestroyPbufferARB(HPBUFFERARB hPbuffer)313 wglDestroyPbufferARB(HPBUFFERARB hPbuffer)
314 {
315    struct stw_framebuffer *fb;
316 
317    if (!hPbuffer) {
318       SetLastError(ERROR_INVALID_HANDLE);
319       return false;
320    }
321 
322    fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
323 
324    /* This will destroy all our data */
325    return DestroyWindow(fb->hWnd);
326 }
327 
328 
329 BOOL WINAPI
wglQueryPbufferARB(HPBUFFERARB hPbuffer,int iAttribute,int * piValue)330 wglQueryPbufferARB(HPBUFFERARB hPbuffer,
331                    int iAttribute,
332                    int *piValue)
333 {
334    struct stw_framebuffer *fb;
335 
336    if (!hPbuffer) {
337       SetLastError(ERROR_INVALID_HANDLE);
338       return false;
339    }
340 
341    fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
342 
343    switch (iAttribute) {
344    case WGL_PBUFFER_WIDTH_ARB:
345       *piValue = fb->width;
346       return true;
347    case WGL_PBUFFER_HEIGHT_ARB:
348       *piValue = fb->height;
349       return true;
350    case WGL_PBUFFER_LOST_ARB:
351       /* We assume that no content is ever lost due to display mode change */
352       *piValue = false;
353       return true;
354    /* WGL_ARB_render_texture */
355    case WGL_TEXTURE_TARGET_ARB:
356       *piValue = fb->textureTarget;
357       return true;
358    case WGL_TEXTURE_FORMAT_ARB:
359       *piValue = fb->textureFormat;
360       return true;
361    case WGL_MIPMAP_TEXTURE_ARB:
362       *piValue = fb->textureMipmap;
363       return true;
364    case WGL_MIPMAP_LEVEL_ARB:
365       *piValue = fb->textureLevel;
366       return true;
367    case WGL_CUBE_MAP_FACE_ARB:
368       *piValue = fb->textureFace + WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
369       return true;
370    default:
371       SetLastError(ERROR_INVALID_DATA);
372       return false;
373    }
374 }
375