/************************************************************************** * * Copyright 2010 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include <windows.h> #define WGL_WGLEXT_PROTOTYPES #include <GL/gl.h> #include <GL/wglext.h> #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "util/u_debug.h" #include "stw_device.h" #include "stw_pixelformat.h" #include "stw_framebuffer.h" #define LARGE_WINDOW_SIZE 60000 static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { MINMAXINFO *pMMI; switch (uMsg) { case WM_GETMINMAXINFO: // Allow to create a window bigger than the desktop pMMI = (MINMAXINFO *)lParam; pMMI->ptMaxSize.x = LARGE_WINDOW_SIZE; pMMI->ptMaxSize.y = LARGE_WINDOW_SIZE; pMMI->ptMaxTrackSize.x = LARGE_WINDOW_SIZE; pMMI->ptMaxTrackSize.y = LARGE_WINDOW_SIZE; break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } HPBUFFERARB WINAPI wglCreatePbufferARB(HDC hCurrentDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) { static boolean first = TRUE; const int *piAttrib; int useLargest = 0; const struct stw_pixelformat_info *info; struct stw_framebuffer *fb; DWORD dwExStyle; DWORD dwStyle; RECT rect; HWND hWnd; HDC hDC; int iDisplayablePixelFormat; PIXELFORMATDESCRIPTOR pfd; BOOL bRet; int textureFormat = WGL_NO_TEXTURE_ARB; int textureTarget = WGL_NO_TEXTURE_ARB; BOOL textureMipmap = FALSE; info = stw_pixelformat_get_info(iPixelFormat - 1); if (!info) { SetLastError(ERROR_INVALID_PIXEL_FORMAT); return 0; } if (iWidth <= 0 || iHeight <= 0) { SetLastError(ERROR_INVALID_DATA); return 0; } for (piAttrib = piAttribList; *piAttrib; piAttrib++) { switch (*piAttrib) { case WGL_PBUFFER_LARGEST_ARB: piAttrib++; useLargest = *piAttrib; break; case WGL_TEXTURE_FORMAT_ARB: /* WGL_ARB_render_texture */ piAttrib++; textureFormat = *piAttrib; if (textureFormat != WGL_TEXTURE_RGB_ARB && textureFormat != WGL_TEXTURE_RGBA_ARB && textureFormat != WGL_NO_TEXTURE_ARB) { SetLastError(ERROR_INVALID_DATA); return 0; } break; case WGL_TEXTURE_TARGET_ARB: /* WGL_ARB_render_texture */ piAttrib++; textureTarget = *piAttrib; if (textureTarget != WGL_TEXTURE_CUBE_MAP_ARB && textureTarget != WGL_TEXTURE_1D_ARB && textureTarget != WGL_TEXTURE_2D_ARB && textureTarget != WGL_NO_TEXTURE_ARB) { SetLastError(ERROR_INVALID_DATA); return 0; } break; case WGL_MIPMAP_TEXTURE_ARB: /* WGL_ARB_render_texture */ piAttrib++; textureMipmap = !!*piAttrib; break; default: SetLastError(ERROR_INVALID_DATA); debug_printf("wgl: Unsupported attribute 0x%x in %s\n", *piAttrib, __func__); return 0; } } if (iWidth > stw_dev->max_2d_length) { if (useLargest) { iWidth = stw_dev->max_2d_length; } else { SetLastError(ERROR_NO_SYSTEM_RESOURCES); return 0; } } if (iHeight > stw_dev->max_2d_length) { if (useLargest) { iHeight = stw_dev->max_2d_length; } else { SetLastError(ERROR_NO_SYSTEM_RESOURCES); return 0; } } /* * Implement pbuffers through invisible windows */ if (first) { WNDCLASS wc; memset(&wc, 0, sizeof wc); wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.lpfnWndProc = WndProc; wc.lpszClassName = "wglpbuffer"; wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; RegisterClass(&wc); first = FALSE; } dwExStyle = 0; dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; if (0) { /* * Don't hide the window -- useful for debugging what the application is * drawing */ dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW; } else { dwStyle |= WS_POPUPWINDOW; } rect.left = 0; rect.top = 0; rect.right = rect.left + iWidth; rect.bottom = rect.top + iHeight; /* * The CreateWindowEx parameters are the total (outside) dimensions of the * window, which can vary with Windows version and user settings. Use * AdjustWindowRect to get the required total area for the given client area. * * AdjustWindowRectEx does not accept WS_OVERLAPPED style (which is defined * as 0), which means we need to use some other style instead, e.g., * WS_OVERLAPPEDWINDOW or WS_POPUPWINDOW as above. */ AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle); hWnd = CreateWindowEx(dwExStyle, "wglpbuffer", /* wc.lpszClassName */ NULL, dwStyle, CW_USEDEFAULT, /* x */ CW_USEDEFAULT, /* y */ rect.right - rect.left, /* width */ rect.bottom - rect.top, /* height */ NULL, NULL, NULL, NULL); if (!hWnd) { return 0; } #ifdef DEBUG /* * Verify the client area size matches the specified size. */ GetClientRect(hWnd, &rect); assert(rect.left == 0); assert(rect.top == 0); assert(rect.right - rect.left == iWidth); assert(rect.bottom - rect.top == iHeight); #endif hDC = GetDC(hWnd); if (!hDC) { return 0; } /* * We can't pass non-displayable pixel formats to GDI, which is why we * create the framebuffer object before calling SetPixelFormat(). */ fb = stw_framebuffer_create(hDC, iPixelFormat); if (!fb) { SetLastError(ERROR_NO_SYSTEM_RESOURCES); return NULL; } fb->bPbuffer = TRUE; /* WGL_ARB_render_texture fields */ fb->textureTarget = textureTarget; fb->textureFormat = textureFormat; fb->textureMipmap = textureMipmap; iDisplayablePixelFormat = fb->iDisplayablePixelFormat; stw_framebuffer_unlock(fb); /* * We need to set a displayable pixel format on the hidden window DC * so that wglCreateContext and wglMakeCurrent are not overruled by GDI. */ bRet = SetPixelFormat(hDC, iDisplayablePixelFormat, &pfd); assert(bRet); return (HPBUFFERARB)fb; } HDC WINAPI wglGetPbufferDCARB(HPBUFFERARB hPbuffer) { struct stw_framebuffer *fb; HDC hDC; if (!hPbuffer) { SetLastError(ERROR_INVALID_HANDLE); return NULL; } fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); hDC = GetDC(fb->hWnd); return hDC; } int WINAPI wglReleasePbufferDCARB(HPBUFFERARB hPbuffer, HDC hDC) { struct stw_framebuffer *fb; if (!hPbuffer) { SetLastError(ERROR_INVALID_HANDLE); return 0; } fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); return ReleaseDC(fb->hWnd, hDC); } BOOL WINAPI wglDestroyPbufferARB(HPBUFFERARB hPbuffer) { struct stw_framebuffer *fb; if (!hPbuffer) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); /* This will destroy all our data */ return DestroyWindow(fb->hWnd); } BOOL WINAPI wglQueryPbufferARB(HPBUFFERARB hPbuffer, int iAttribute, int *piValue) { struct stw_framebuffer *fb; if (!hPbuffer) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); switch (iAttribute) { case WGL_PBUFFER_WIDTH_ARB: *piValue = fb->width; return TRUE; case WGL_PBUFFER_HEIGHT_ARB: *piValue = fb->height; return TRUE; case WGL_PBUFFER_LOST_ARB: /* We assume that no content is ever lost due to display mode change */ *piValue = FALSE; return TRUE; /* WGL_ARB_render_texture */ case WGL_TEXTURE_TARGET_ARB: *piValue = fb->textureTarget; return TRUE; case WGL_TEXTURE_FORMAT_ARB: *piValue = fb->textureFormat; return TRUE; case WGL_MIPMAP_TEXTURE_ARB: *piValue = fb->textureMipmap; return TRUE; case WGL_MIPMAP_LEVEL_ARB: *piValue = fb->textureLevel; return TRUE; case WGL_CUBE_MAP_FACE_ARB: *piValue = fb->textureFace + WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; return TRUE; default: SetLastError(ERROR_INVALID_DATA); return FALSE; } }