Home | History | Annotate | Download | only in wgl
      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 
     46 static LRESULT CALLBACK
     47 WndProc(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 
     67 HPBUFFERARB WINAPI
     68 wglCreatePbufferARB(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 
    236 HDC WINAPI
    237 wglGetPbufferDCARB(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 
    257 int WINAPI
    258 wglReleasePbufferDCARB(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 
    274 BOOL WINAPI
    275 wglDestroyPbufferARB(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 
    291 BOOL WINAPI
    292 wglQueryPbufferARB(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