diff src/video/win32/SDL_win32opengl.c @ 1913:83420da906a5

Implemented Windows OpenGL support Fixed slowdown enumerating display modes, which was hosing OpenGL as well... Removed SDL_ from the render driver prefixes
author Sam Lantinga <slouken@libsdl.org>
date Mon, 17 Jul 2006 06:47:33 +0000
parents
children 307355678142
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/win32/SDL_win32opengl.c	Mon Jul 17 06:47:33 2006 +0000
@@ -0,0 +1,643 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2006 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_win32video.h"
+
+/* WGL implementation of SDL OpenGL support */
+
+#if SDL_VIDEO_OPENGL
+#include "SDL_opengl.h"
+
+#define DEFAULT_GL_DRIVER_PATH "OPENGL32.DLL"
+
+
+int
+WIN_GL_LoadLibrary(_THIS, const char *path)
+{
+    LPTSTR wpath;
+    HANDLE handle;
+
+    if (_this->gl_config.driver_loaded) {
+        if (path) {
+            SDL_SetError("OpenGL library already loaded");
+            return -1;
+        } else {
+            ++_this->gl_config.driver_loaded;
+            return 0;
+        }
+    }
+    if (path == NULL) {
+        path = DEFAULT_GL_DRIVER_PATH;
+    }
+    wpath = WIN_UTF8ToString(path);
+    handle = LoadLibrary(wpath);
+    SDL_free(wpath);
+    if (!handle) {
+        char message[1024];
+        SDL_snprintf(message, SDL_arraysize(message), "LoadLibrary(\"%s\")",
+                     path);
+        WIN_SetError(message);
+        return -1;
+    }
+
+    /* Load function pointers */
+    _this->gl_data->wglGetProcAddress = (void *(WINAPI *) (const char *))
+        GetProcAddress(handle, "wglGetProcAddress");
+    _this->gl_data->wglCreateContext = (HGLRC(WINAPI *) (HDC))
+        GetProcAddress(handle, "wglCreateContext");
+    _this->gl_data->wglDeleteContext = (BOOL(WINAPI *) (HGLRC))
+        GetProcAddress(handle, "wglDeleteContext");
+    _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
+        GetProcAddress(handle, "wglMakeCurrent");
+    _this->gl_data->wglSwapIntervalEXT = (void (WINAPI *) (int))
+        GetProcAddress(handle, "wglSwapIntervalEXT");
+    _this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *) (void))
+        GetProcAddress(handle, "wglGetSwapIntervalEXT");
+
+    if (!_this->gl_data->wglGetProcAddress ||
+        !_this->gl_data->wglCreateContext ||
+        !_this->gl_data->wglDeleteContext ||
+        !_this->gl_data->wglMakeCurrent) {
+        SDL_SetError("Could not retrieve OpenGL functions");
+        FreeLibrary(handle);
+        return -1;
+    }
+
+    _this->gl_config.dll_handle = handle;
+    SDL_strlcpy(_this->gl_config.driver_path, path,
+                SDL_arraysize(_this->gl_config.driver_path));
+    _this->gl_config.driver_loaded = 1;
+    return 0;
+}
+
+void *
+WIN_GL_GetProcAddress(_THIS, const char *proc)
+{
+    void *func;
+
+    /* This is to pick up extensions */
+    func = _this->gl_data->wglGetProcAddress(proc);
+    if (!func) {
+        /* This is probably a normal GL function */
+        func = GetProcAddress(_this->gl_config.dll_handle, proc);
+    }
+    return func;
+}
+
+static void
+WIN_GL_UnloadLibrary(_THIS)
+{
+    if (_this->gl_config.driver_loaded > 0) {
+        if (--_this->gl_config.driver_loaded > 0) {
+            return;
+        }
+        FreeLibrary((HMODULE) _this->gl_config.dll_handle);
+        _this->gl_config.dll_handle = NULL;
+    }
+}
+
+static void
+WIN_GL_SetupPixelFormat(_THIS, PIXELFORMATDESCRIPTOR * pfd)
+{
+    SDL_zerop(pfd);
+    pfd->nSize = sizeof(*pfd);
+    pfd->nVersion = 1;
+    pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
+    if (_this->gl_config.double_buffer) {
+        pfd->dwFlags |= PFD_DOUBLEBUFFER;
+    }
+    if (_this->gl_config.stereo) {
+        pfd->dwFlags |= PFD_STEREO;
+    }
+    pfd->iLayerType = PFD_MAIN_PLANE;
+    pfd->iPixelType = PFD_TYPE_RGBA;
+    pfd->cRedBits = _this->gl_config.red_size;
+    pfd->cGreenBits = _this->gl_config.green_size;
+    pfd->cBlueBits = _this->gl_config.blue_size;
+    pfd->cAlphaBits = _this->gl_config.alpha_size;
+    if (_this->gl_config.buffer_size) {
+        pfd->cColorBits =
+            _this->gl_config.buffer_size - _this->gl_config.alpha_size;
+    } else {
+        pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
+    }
+    pfd->cAccumRedBits = _this->gl_config.accum_red_size;
+    pfd->cAccumGreenBits = _this->gl_config.accum_green_size;
+    pfd->cAccumBlueBits = _this->gl_config.accum_blue_size;
+    pfd->cAccumAlphaBits = _this->gl_config.accum_alpha_size;
+    pfd->cAccumBits =
+        (pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
+         pfd->cAccumAlphaBits);
+    pfd->cDepthBits = _this->gl_config.depth_size;
+    pfd->cStencilBits = _this->gl_config.stencil_size;
+}
+
+static SDL_bool
+HasExtension(const char *extension, const char *extensions)
+{
+    const char *start;
+    const char *where, *terminator;
+
+    /* Extension names should not have spaces. */
+    where = SDL_strchr(extension, ' ');
+    if (where || *extension == '\0')
+        return SDL_FALSE;
+
+    if (!extensions)
+        return SDL_FALSE;
+
+    /* It takes a bit of care to be fool-proof about parsing the
+     * OpenGL extensions string. Don't be fooled by sub-strings,
+     * etc. */
+
+    start = extensions;
+
+    for (;;) {
+        where = SDL_strstr(start, extension);
+        if (!where)
+            break;
+
+        terminator = where + SDL_strlen(extension);
+        if (where == start || *(where - 1) == ' ')
+            if (*terminator == ' ' || *terminator == '\0')
+                return SDL_TRUE;
+
+        start = terminator;
+    }
+    return SDL_FALSE;
+}
+
+static void
+WIN_GL_InitExtensions(_THIS)
+{
+    HWND hwnd;
+    HDC hdc;
+    PIXELFORMATDESCRIPTOR pfd;
+    int pixel_format;
+    HGLRC hglrc;
+    const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
+    const GLubyte *(WINAPI * glGetStringFunc) (GLenum);
+    const char *extensions;
+
+    hwnd =
+        CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
+                     10, 10, NULL, NULL, SDL_Instance, NULL);
+    WIN_PumpEvents(_this);
+
+    hdc = GetDC(hwnd);
+
+    WIN_GL_SetupPixelFormat(_this, &pfd);
+    pixel_format = ChoosePixelFormat(hdc, &pfd);
+    SetPixelFormat(hdc, pixel_format, &pfd);
+
+    hglrc = _this->gl_data->wglCreateContext(hdc);
+    if (hglrc) {
+        _this->gl_data->wglMakeCurrent(hdc, hglrc);
+    }
+
+    wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
+        _this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
+    if (wglGetExtensionsStringARB) {
+        extensions = wglGetExtensionsStringARB(hdc);
+    } else {
+        extensions = NULL;
+    }
+
+    /* Check for WGL_ARB_pixel_format */
+    _this->gl_data->WGL_ARB_pixel_format = 0;
+    if (HasExtension("WGL_ARB_pixel_format", extensions)) {
+        _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
+                                                   (HDC, const int *,
+                                                    const FLOAT *, UINT,
+                                                    int *, UINT *))
+            WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
+        _this->gl_data->wglGetPixelFormatAttribivARB =
+            (BOOL(WINAPI *) (HDC, int, int, UINT, const int *, int *))
+            WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
+
+        if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
+            (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
+            _this->gl_data->WGL_ARB_pixel_format = 1;
+        }
+    }
+
+    glGetStringFunc = WIN_GL_GetProcAddress(_this, "glGetString");
+    if (glGetStringFunc) {
+        extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
+    } else {
+        /* Uh oh, something is seriously wrong here... */
+        extensions = NULL;
+    }
+
+    /* Check for WGL_EXT_swap_control */
+    if (HasExtension("WGL_EXT_swap_control", extensions)) {
+        _this->gl_data->wglSwapIntervalEXT =
+            WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
+        _this->gl_data->wglGetSwapIntervalEXT =
+            WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
+    }
+
+    if (hglrc) {
+        _this->gl_data->wglMakeCurrent(NULL, NULL);
+        _this->gl_data->wglDeleteContext(hglrc);
+    }
+    ReleaseDC(hwnd, hdc);
+    DestroyWindow(hwnd);
+    WIN_PumpEvents(_this);
+}
+
+static void
+WIN_GL_Shutdown(_THIS)
+{
+    if (!_this->gl_data || (--_this->gl_data->initialized > 0)) {
+        return;
+    }
+
+    WIN_GL_UnloadLibrary(_this);
+
+    SDL_free(_this->gl_data);
+    _this->gl_data = NULL;
+}
+
+static int
+WIN_GL_Initialize(_THIS)
+{
+    if (_this->gl_data) {
+        ++_this->gl_data->initialized;
+        return 0;
+    }
+
+    _this->gl_data =
+        (struct SDL_GLDriverData *) SDL_calloc(1,
+                                               sizeof(struct
+                                                      SDL_GLDriverData));
+    if (!_this->gl_data) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+    _this->gl_data->initialized = 1;
+
+    if (WIN_GL_LoadLibrary(_this, NULL) < 0) {
+        return -1;
+    }
+
+    /* Initialize extensions */
+    WIN_GL_InitExtensions(_this);
+
+    return 0;
+}
+
+int
+WIN_GL_SetupWindow(_THIS, SDL_Window * window)
+{
+    HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
+    PIXELFORMATDESCRIPTOR pfd;
+    int pixel_format;
+    unsigned int matching;
+    int iAttribs[64];
+    int *iAttr;
+    float fAttribs[1] = { 0 };
+
+    if (WIN_GL_Initialize(_this) < 0) {
+        return -1;
+    }
+
+    WIN_GL_SetupPixelFormat(_this, &pfd);
+
+    /* setup WGL_ARB_pixel_format attribs */
+    iAttr = &iAttribs[0];
+
+    *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
+    *iAttr++ = GL_TRUE;
+    *iAttr++ = WGL_ACCELERATION_ARB;
+    *iAttr++ = WGL_FULL_ACCELERATION_ARB;
+    *iAttr++ = WGL_RED_BITS_ARB;
+    *iAttr++ = _this->gl_config.red_size;
+    *iAttr++ = WGL_GREEN_BITS_ARB;
+    *iAttr++ = _this->gl_config.green_size;
+    *iAttr++ = WGL_BLUE_BITS_ARB;
+    *iAttr++ = _this->gl_config.blue_size;
+
+    if (_this->gl_config.alpha_size) {
+        *iAttr++ = WGL_ALPHA_BITS_ARB;
+        *iAttr++ = _this->gl_config.alpha_size;
+    }
+
+    *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
+    *iAttr++ = _this->gl_config.double_buffer;
+
+    *iAttr++ = WGL_DEPTH_BITS_ARB;
+    *iAttr++ = _this->gl_config.depth_size;
+
+    if (_this->gl_config.stencil_size) {
+        *iAttr++ = WGL_STENCIL_BITS_ARB;
+        *iAttr++ = _this->gl_config.stencil_size;
+    }
+
+    if (_this->gl_config.accum_red_size) {
+        *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
+        *iAttr++ = _this->gl_config.accum_red_size;
+    }
+
+    if (_this->gl_config.accum_green_size) {
+        *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
+        *iAttr++ = _this->gl_config.accum_green_size;
+    }
+
+    if (_this->gl_config.accum_blue_size) {
+        *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
+        *iAttr++ = _this->gl_config.accum_blue_size;
+    }
+
+    if (_this->gl_config.accum_alpha_size) {
+        *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
+        *iAttr++ = _this->gl_config.accum_alpha_size;
+    }
+
+    if (_this->gl_config.stereo) {
+        *iAttr++ = WGL_STEREO_ARB;
+        *iAttr++ = GL_TRUE;
+    }
+
+    if (_this->gl_config.multisamplebuffers) {
+        *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
+        *iAttr++ = _this->gl_config.multisamplebuffers;
+    }
+
+    if (_this->gl_config.multisamplesamples) {
+        *iAttr++ = WGL_SAMPLES_ARB;
+        *iAttr++ = _this->gl_config.multisamplesamples;
+    }
+
+    if (_this->gl_config.accelerated >= 0) {
+        *iAttr++ = WGL_ACCELERATION_ARB;
+        *iAttr++ =
+            (_this->gl_config.
+             accelerated ? WGL_GENERIC_ACCELERATION_ARB :
+             WGL_NO_ACCELERATION_ARB);
+    }
+
+    *iAttr = 0;
+
+    /* Choose and set the closest available pixel format */
+    if (!_this->gl_data->WGL_ARB_pixel_format
+        || !_this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
+                                                    1, &pixel_format,
+                                                    &matching) || !matching) {
+        pixel_format = ChoosePixelFormat(hdc, &pfd);
+    }
+    if (!pixel_format) {
+        SDL_SetError("No matching GL pixel format available");
+        return -1;
+    }
+    if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
+        WIN_SetError("SetPixelFormat()");
+        return (-1);
+    }
+    return 0;
+}
+
+void
+WIN_GL_CleanupWindow(_THIS, SDL_Window * window)
+{
+    WIN_GL_Shutdown(_this);
+}
+
+int
+WIN_GL_GetWindowAttribute(_THIS, SDL_Window * window, SDL_GLattr attrib,
+                          int *value)
+{
+    HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
+    int pixel_format;
+
+    pixel_format = GetPixelFormat(hdc);
+
+    if (_this->gl_data->WGL_ARB_pixel_format) {
+        int wgl_attrib;
+
+        switch (attrib) {
+        case SDL_GL_RED_SIZE:
+            wgl_attrib = WGL_RED_BITS_ARB;
+            break;
+        case SDL_GL_GREEN_SIZE:
+            wgl_attrib = WGL_GREEN_BITS_ARB;
+            break;
+        case SDL_GL_BLUE_SIZE:
+            wgl_attrib = WGL_BLUE_BITS_ARB;
+            break;
+        case SDL_GL_ALPHA_SIZE:
+            wgl_attrib = WGL_ALPHA_BITS_ARB;
+            break;
+        case SDL_GL_DOUBLEBUFFER:
+            wgl_attrib = WGL_DOUBLE_BUFFER_ARB;
+            break;
+        case SDL_GL_BUFFER_SIZE:
+            wgl_attrib = WGL_COLOR_BITS_ARB;
+            break;
+        case SDL_GL_DEPTH_SIZE:
+            wgl_attrib = WGL_DEPTH_BITS_ARB;
+            break;
+        case SDL_GL_STENCIL_SIZE:
+            wgl_attrib = WGL_STENCIL_BITS_ARB;
+            break;
+        case SDL_GL_ACCUM_RED_SIZE:
+            wgl_attrib = WGL_ACCUM_RED_BITS_ARB;
+            break;
+        case SDL_GL_ACCUM_GREEN_SIZE:
+            wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB;
+            break;
+        case SDL_GL_ACCUM_BLUE_SIZE:
+            wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB;
+            break;
+        case SDL_GL_ACCUM_ALPHA_SIZE:
+            wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB;
+            break;
+        case SDL_GL_STEREO:
+            wgl_attrib = WGL_STEREO_ARB;
+            break;
+        case SDL_GL_MULTISAMPLEBUFFERS:
+            wgl_attrib = WGL_SAMPLE_BUFFERS_ARB;
+            break;
+        case SDL_GL_MULTISAMPLESAMPLES:
+            wgl_attrib = WGL_SAMPLES_ARB;
+            break;
+        case SDL_GL_ACCELERATED_VISUAL:
+            wgl_attrib = WGL_ACCELERATION_ARB;
+            _this->gl_data->wglGetPixelFormatAttribivARB(hdc, pixel_format, 0,
+                                                         1, &wgl_attrib,
+                                                         value);
+            if (*value == WGL_NO_ACCELERATION_ARB) {
+                *value = SDL_FALSE;
+            } else {
+                *value = SDL_TRUE;
+            }
+            return 0;
+            break;
+        default:
+            return (-1);
+        }
+        _this->gl_data->wglGetPixelFormatAttribivARB(hdc, pixel_format, 0, 1,
+                                                     &wgl_attrib, value);
+        return 0;
+    } else {
+        PIXELFORMATDESCRIPTOR pfd;
+        int retval;
+
+        if (!DescribePixelFormat(hdc, pixel_format, sizeof(pfd), &pfd)) {
+            WIN_SetError("DescribePixelFormat()");
+            return -1;
+        }
+        retval = 0;
+        switch (attrib) {
+        case SDL_GL_RED_SIZE:
+            *value = pfd.cRedBits;
+            break;
+        case SDL_GL_GREEN_SIZE:
+            *value = pfd.cGreenBits;
+            break;
+        case SDL_GL_BLUE_SIZE:
+            *value = pfd.cBlueBits;
+            break;
+        case SDL_GL_ALPHA_SIZE:
+            *value = pfd.cAlphaBits;
+            break;
+        case SDL_GL_DOUBLEBUFFER:
+            if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
+                *value = 1;
+            } else {
+                *value = 0;
+            }
+            break;
+        case SDL_GL_BUFFER_SIZE:
+            *value = pfd.cColorBits;
+            break;
+        case SDL_GL_DEPTH_SIZE:
+            *value = pfd.cDepthBits;
+            break;
+        case SDL_GL_STENCIL_SIZE:
+            *value = pfd.cStencilBits;
+            break;
+        case SDL_GL_ACCUM_RED_SIZE:
+            *value = pfd.cAccumRedBits;
+            break;
+        case SDL_GL_ACCUM_GREEN_SIZE:
+            *value = pfd.cAccumGreenBits;
+            break;
+        case SDL_GL_ACCUM_BLUE_SIZE:
+            *value = pfd.cAccumBlueBits;
+            break;
+        case SDL_GL_ACCUM_ALPHA_SIZE:
+            *value = pfd.cAccumAlphaBits;
+            break;
+        case SDL_GL_STEREO:
+            if (pfd.dwFlags & PFD_STEREO) {
+                *value = 1;
+            } else {
+                *value = 0;
+            }
+            break;
+        case SDL_GL_MULTISAMPLEBUFFERS:
+            *value = 0;
+            break;
+        case SDL_GL_MULTISAMPLESAMPLES:
+            *value = 1;
+            break;
+        default:
+            retval = -1;
+            break;
+        }
+        return retval;
+    }
+}
+
+SDL_GLContext
+WIN_GL_CreateContext(_THIS, SDL_Window * window)
+{
+    HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
+
+    return _this->gl_data->wglCreateContext(hdc);
+}
+
+int
+WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+    HDC hdc;
+    int status;
+
+    if (window) {
+        hdc = ((SDL_WindowData *) window->driverdata)->hdc;
+    } else {
+        hdc = NULL;
+    }
+    if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
+        WIN_SetError("wglMakeCurrent()");
+        status = -1;
+    } else {
+        status = 0;
+    }
+    return status;
+}
+
+int
+WIN_GL_SetSwapInterval(_THIS, int interval)
+{
+    if (_this->gl_data->wglSwapIntervalEXT) {
+        _this->gl_data->wglSwapIntervalEXT(interval);
+        return 0;
+    } else {
+        SDL_Unsupported();
+        return -1;
+    }
+}
+
+int
+WIN_GL_GetSwapInterval(_THIS)
+{
+    if (_this->gl_data->wglGetSwapIntervalEXT) {
+        return _this->gl_data->wglGetSwapIntervalEXT();
+    } else {
+        SDL_Unsupported();
+        return -1;
+    }
+}
+
+void
+WIN_GL_SwapWindow(_THIS, SDL_Window * window)
+{
+    HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
+
+    SwapBuffers(hdc);
+}
+
+void
+WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
+{
+    if (context) {
+        _this->gl_data->wglDeleteContext((HGLRC) context);
+    }
+}
+
+#endif /* SDL_VIDEO_OPENGL */
+
+
+/* vi: set ts=4 sw=4 expandtab: */