Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / dll / opengl / opengl32 / wgl.c
diff --git a/dll/opengl/opengl32/wgl.c b/dll/opengl/opengl32/wgl.c
new file mode 100644 (file)
index 0000000..82213d8
--- /dev/null
@@ -0,0 +1,932 @@
+/*
+ * COPYRIGHT:            See COPYING in the top level directory
+ * PROJECT:              ReactOS
+ * FILE:                 dll/opengl/opengl32/wgl.c
+ * PURPOSE:              OpenGL32 DLL, WGL functions
+ */
+
+#include "opengl32.h"
+
+#include <pseh/pseh2.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(wgl);
+
+static CRITICAL_SECTION dc_data_cs = {NULL, -1, 0, 0, 0, 0};
+static struct wgl_dc_data* dc_data_list = NULL;
+
+LIST_ENTRY ContextListHead;
+
+/* FIXME: suboptimal */
+static
+struct wgl_dc_data*
+get_dc_data(HDC hdc)
+{
+    HWND hwnd = NULL;
+    struct wgl_dc_data* data;
+    DWORD objType = GetObjectType(hdc);
+    ULONG flags = 0;
+    union
+    {
+        HWND hwnd;
+        HDC hdc;
+        HANDLE u;
+    } id;
+    
+    /* Look for the right data identifier */
+    if(objType == OBJ_DC)
+    {
+        hwnd = WindowFromDC(hdc);
+        if(!hwnd)
+            return NULL;
+        id.hwnd = hwnd;
+        flags = WGL_DC_OBJ_DC;
+    }
+    else if(objType == OBJ_MEMDC)
+    {
+        id.hdc = hdc;
+    }
+    else
+    {
+        return NULL;
+    }
+
+    EnterCriticalSection(&dc_data_cs);
+    data = dc_data_list;
+    while(data)
+    {
+        if(data->owner.u == id.u)
+        {
+            LeaveCriticalSection(&dc_data_cs);
+            return data;
+        }
+        data = data->next;
+    }
+    data= HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
+    if(!data)
+    {
+        LeaveCriticalSection(&dc_data_cs);
+        return NULL;
+    }
+    /* initialize the structure */
+    data->owner.u = id.u;
+    data->flags = flags;
+    data->pixelformat = 0;
+    data->sw_data = NULL;
+    /* Load the driver */
+    data->icd_data = IntGetIcdData(hdc);
+    /* Get the number of available formats for this DC once and for all */
+    if(data->icd_data)
+        data->nb_icd_formats = data->icd_data->DrvDescribePixelFormat(hdc, 0, 0, NULL);
+    else
+        data->nb_icd_formats = 0;
+    TRACE("ICD %S has %u formats for HDC %x.\n", data->icd_data ? data->icd_data->DriverName : NULL, data->nb_icd_formats, hdc);
+    data->nb_sw_formats = sw_DescribePixelFormat(hdc, 0, 0, NULL);
+    data->next = dc_data_list;
+    dc_data_list = data;
+    LeaveCriticalSection(&dc_data_cs);
+    return data;
+}
+
+void release_dc_data(struct wgl_dc_data* dc_data)
+{
+    (void)dc_data;
+}
+
+struct wgl_context* get_context(HGLRC hglrc)
+{
+    struct wgl_context* context = (struct wgl_context*)hglrc;
+    
+    if(!hglrc)
+        return NULL;
+    
+    _SEH2_TRY
+    {
+        if(context->magic != 'GLRC')
+            context = NULL;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        context = NULL;
+    }
+    _SEH2_END;
+    
+    return context;
+}
+
+INT WINAPI wglDescribePixelFormat(HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR *descr )
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    INT ret;
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    
+    ret = dc_data->nb_icd_formats + dc_data->nb_sw_formats;
+    
+    if(!descr)
+    {
+        release_dc_data(dc_data);
+        return ret;
+    }
+    if((format == 0) || (format > ret) || (size != sizeof(*descr)))
+    {
+        release_dc_data(dc_data);
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    
+    /* Query ICD if needed */
+    if(format <= dc_data->nb_icd_formats)
+    {
+        struct ICD_Data* icd_data = dc_data->icd_data;
+        /* SetPixelFormat may have NULLified this */
+        if (!icd_data)
+            icd_data = IntGetIcdData(hdc);
+        if(!icd_data->DrvDescribePixelFormat(hdc, format, size, descr))
+        {
+            ret = 0;
+        }
+    }
+    else
+    {
+        /* This is a software format */
+        format -= dc_data->nb_icd_formats;
+        if(!sw_DescribePixelFormat(hdc, format, size, descr))
+        {
+            ret = 0;
+        }
+    }
+    
+    release_dc_data(dc_data);
+    return ret;
+}
+
+INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
+{
+    PIXELFORMATDESCRIPTOR format, best;
+    int i, count, best_format;
+    int bestDBuffer = -1, bestStereo = -1;
+
+    TRACE_(wgl)( "%p %p: size %u version %u flags %u type %u color %u %u,%u,%u,%u "
+                 "accum %u depth %u stencil %u aux %u\n",
+                 hdc, ppfd, ppfd->nSize, ppfd->nVersion, ppfd->dwFlags, ppfd->iPixelType,
+                 ppfd->cColorBits, ppfd->cRedBits, ppfd->cGreenBits, ppfd->cBlueBits, ppfd->cAlphaBits,
+                 ppfd->cAccumBits, ppfd->cDepthBits, ppfd->cStencilBits, ppfd->cAuxBuffers );
+
+    count = wglDescribePixelFormat( hdc, 0, 0, NULL );
+    if (!count) return 0;
+
+    best_format = 0;
+    best.dwFlags = PFD_GENERIC_FORMAT;
+    best.cAlphaBits = -1;
+    best.cColorBits = -1;
+    best.cDepthBits = -1;
+    best.cStencilBits = -1;
+    best.cAuxBuffers = -1;
+
+    for (i = 1; i <= count; i++)
+    {
+        if (!wglDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
+
+        if (ppfd->iPixelType != format.iPixelType)
+        {
+            TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
+            continue;
+        }
+
+        /* only use bitmap capable formats for bitmap rendering */
+        if ((ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
+        {
+            TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
+            continue;
+        }
+
+        /* only use window capable formats for window rendering */
+        if ((ppfd->dwFlags & PFD_DRAW_TO_WINDOW) != (format.dwFlags & PFD_DRAW_TO_WINDOW))
+        {
+            TRACE( "PFD_DRAW_TO_WINDOW mismatch for iPixelFormat=%d\n", i );
+            continue;
+        }
+
+        /* only use opengl capable formats for opengl rendering */
+        if ((ppfd->dwFlags & PFD_SUPPORT_OPENGL) != (format.dwFlags & PFD_SUPPORT_OPENGL))
+        {
+            TRACE( "PFD_SUPPORT_OPENGL mismatch for iPixelFormat=%d\n", i );
+            continue;
+        }
+
+        /* only use GDI capable formats for GDI rendering */
+        if ((ppfd->dwFlags & PFD_SUPPORT_GDI) != (format.dwFlags & PFD_SUPPORT_GDI))
+        {
+            TRACE( "PFD_SUPPORT_GDI mismatch for iPixelFormat=%d\n", i );
+            continue;
+        }
+
+        /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
+         * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
+         * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
+         * formats without the given flag set.
+         * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
+         * has indicated that a format without stereo is returned when stereo is unavailable.
+         * So in case PFD_STEREO is set, formats that support it should have priority above formats
+         * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
+         *
+         * To summarize the following is most likely the correct behavior:
+         * stereo not set -> prefer non-stereo formats, but also accept stereo formats
+         * stereo set -> prefer stereo formats, but also accept non-stereo formats
+         * stereo don't care -> it doesn't matter whether we get stereo or not
+         *
+         * In Wine we will treat non-stereo the same way as don't care because it makes
+         * format selection even more complicated and second drivers with Stereo advertise
+         * each format twice anyway.
+         */
+
+        /* Doublebuffer, see the comments above */
+        if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE))
+        {
+            if (((ppfd->dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) &&
+                ((format.dwFlags & PFD_DOUBLEBUFFER) == (ppfd->dwFlags & PFD_DOUBLEBUFFER)))
+                goto found;
+
+            if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
+        }
+
+        /* Stereo, see the comments above. */
+        if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE))
+        {
+            if (((ppfd->dwFlags & PFD_STEREO) != bestStereo) &&
+                ((format.dwFlags & PFD_STEREO) == (ppfd->dwFlags & PFD_STEREO)))
+                goto found;
+
+            if (bestStereo != -1 && (format.dwFlags & PFD_STEREO) != bestStereo) continue;
+        }
+
+        /* Below we will do a number of checks to select the 'best' pixelformat.
+         * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
+         * The code works by trying to match the most important options as close as possible.
+         * When a reasonable format is found, we will try to match more options.
+         * It appears (see the opengl32 test) that Windows opengl drivers ignore options
+         * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
+         * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
+
+        if (ppfd->cColorBits)
+        {
+            if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
+                ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
+                goto found;
+
+            if (best.cColorBits != format.cColorBits)  /* Do further checks if the format is compatible */
+            {
+                TRACE( "color mismatch for iPixelFormat=%d\n", i );
+                continue;
+            }
+        }
+        if (ppfd->cAlphaBits)
+        {
+            if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
+                ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
+                goto found;
+
+            if (best.cAlphaBits != format.cAlphaBits)
+            {
+                TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
+                continue;
+            }
+        }
+        if (ppfd->cDepthBits)
+        {
+            if (((ppfd->cDepthBits > best.cDepthBits) && (format.cDepthBits > best.cDepthBits)) ||
+                ((format.cDepthBits >= ppfd->cDepthBits) && (format.cDepthBits < best.cDepthBits)))
+                goto found;
+
+            if (best.cDepthBits != format.cDepthBits)
+            {
+                TRACE( "depth mismatch for iPixelFormat=%d\n", i );
+                continue;
+            }
+        }
+        if (ppfd->cStencilBits)
+        {
+            if (((ppfd->cStencilBits > best.cStencilBits) && (format.cStencilBits > best.cStencilBits)) ||
+                ((format.cStencilBits >= ppfd->cStencilBits) && (format.cStencilBits < best.cStencilBits)))
+                goto found;
+
+            if (best.cStencilBits != format.cStencilBits)
+            {
+                TRACE( "stencil mismatch for iPixelFormat=%d\n", i );
+                continue;
+            }
+        }
+        if (ppfd->cAuxBuffers)
+        {
+            if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
+                ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
+                goto found;
+
+            if (best.cAuxBuffers != format.cAuxBuffers)
+            {
+                TRACE( "aux mismatch for iPixelFormat=%d\n", i );
+                continue;
+            }
+        }
+        continue;
+
+    found:
+        /* Prefer HW accelerated formats */
+        if ((format.dwFlags & PFD_GENERIC_FORMAT) && !(best.dwFlags & PFD_GENERIC_FORMAT))
+            continue;
+        best_format = i;
+        best = format;
+        bestDBuffer = format.dwFlags & PFD_DOUBLEBUFFER;
+        bestStereo = format.dwFlags & PFD_STEREO;
+    }
+
+    TRACE( "returning %u\n", best_format );
+    return best_format;
+}
+
+BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
+{
+    struct wgl_context* ctx_src = get_context(hglrcSrc);
+    struct wgl_context* ctx_dst = get_context(hglrcDst);
+    
+    if(!ctx_src || !ctx_dst)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    /* Check this is the same pixel format */
+    if((ctx_dst->icd_data != ctx_src->icd_data) ||
+        (ctx_dst->pixelformat != ctx_src->pixelformat))
+    {
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return FALSE;
+    }
+    
+    if(ctx_src->icd_data)
+        return ctx_src->icd_data->DrvCopyContext(ctx_src->dhglrc, ctx_dst->dhglrc, mask);
+    
+    return sw_CopyContext(ctx_src->dhglrc, ctx_dst->dhglrc, mask);
+}
+
+HGLRC WINAPI wglCreateContext(HDC hdc)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    struct wgl_context* context;
+    DHGLRC dhglrc;
+    
+    TRACE("Creating context for %p, format %i\n", hdc);
+    
+    if(!dc_data)
+    {
+        WARN("Not a DC handle!\n");
+        SetLastError(ERROR_INVALID_HANDLE);
+        return NULL;
+    }
+    
+    if(!dc_data->pixelformat)
+    {
+        WARN("Pixel format not set!\n");
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
+    }
+    
+    if(!dc_data->icd_data)
+    {
+        TRACE("Calling SW implementation.\n");
+        dhglrc = sw_CreateContext(dc_data);
+        TRACE("done\n");
+    }
+    else
+    {
+        TRACE("Calling ICD.\n");
+        dhglrc = dc_data->icd_data->DrvCreateContext(hdc);
+    }
+    
+    if(!dhglrc)
+    {
+        WARN("Failed!\n");
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
+    }
+    
+    context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
+    if(!context)
+    {
+        WARN("Failed to allocate a context!\n");
+        if(!dc_data->icd_data)
+            sw_DeleteContext(dhglrc);
+        else
+            dc_data->icd_data->DrvDeleteContext(dhglrc);
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+    /* Copy info from the DC data */
+    context->dhglrc = dhglrc;
+    context->icd_data = dc_data->icd_data;
+    context->pixelformat = dc_data->pixelformat;
+    context->thread_id = 0;
+    
+    /* Insert into the list */
+    InsertTailList(&ContextListHead, &context->ListEntry);
+
+    context->magic = 'GLRC';
+    TRACE("Success!\n");
+    return (HGLRC)context;
+}
+
+HGLRC WINAPI wglCreateLayerContext(HDC hdc, int iLayerPlane)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    struct wgl_context* context;
+    DHGLRC dhglrc;
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return NULL;
+    }
+    
+    if(!dc_data->pixelformat)
+    {
+        release_dc_data(dc_data);
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
+    }
+    
+    if(!dc_data->icd_data)
+    {
+        if(iLayerPlane != 0)
+        {
+            /* Not supported in SW implementation  */
+            release_dc_data(dc_data);
+            SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+            return NULL;
+        }
+        dhglrc = sw_CreateContext(dc_data);
+    }
+    else
+    {
+        dhglrc = dc_data->icd_data->DrvCreateLayerContext(hdc, iLayerPlane);
+    }
+    
+    if(!dhglrc)
+    {
+        release_dc_data(dc_data);
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
+    }
+    
+    context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
+    if(!context)
+    {
+        if(!dc_data->icd_data)
+            sw_DeleteContext(dhglrc);
+        else
+            dc_data->icd_data->DrvDeleteContext(dhglrc);
+        release_dc_data(dc_data);
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+    /* Copy info from the DC data */
+    context->dhglrc = dhglrc;
+    context->icd_data = dc_data->icd_data;
+    context->pixelformat = dc_data->pixelformat;
+    context->thread_id = 0;
+    
+    context->magic = 'GLRC';
+    
+    release_dc_data(dc_data);
+    return (HGLRC)context;
+}
+
+BOOL WINAPI wglDeleteContext(HGLRC hglrc)
+{
+    struct wgl_context* context = get_context(hglrc);
+    LONG thread_id = GetCurrentThreadId();
+    
+    if(!context)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    /* Own this context before touching it */
+    if(InterlockedCompareExchange(&context->thread_id, thread_id, 0) != 0)
+    {
+        /* We can't delete a context current to another thread */
+        if(context->thread_id != thread_id)
+        {
+            SetLastError(ERROR_BUSY);
+            return FALSE;
+        }
+        
+        /* This is in our thread. Release and try again */
+        if(!wglMakeCurrent(NULL, NULL))
+            return FALSE;
+        return wglDeleteContext(hglrc);
+    }
+    
+    if(context->icd_data)
+        context->icd_data->DrvDeleteContext(context->dhglrc);
+    else
+        sw_DeleteContext(context->dhglrc);
+    
+    context->magic = 0;
+    RemoveEntryList(&context->ListEntry);
+    HeapFree(GetProcessHeap(), 0, context);
+    
+    return TRUE;
+}
+
+BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
+                                  int iPixelFormat,
+                                  int iLayerPlane,
+                                  UINT nBytes,
+                                  LPLAYERPLANEDESCRIPTOR plpd)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    if(iPixelFormat <= dc_data->nb_icd_formats)
+        return dc_data->icd_data->DrvDescribeLayerPlane(hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
+    
+    /* SW implementation doesn't support this */
+    return FALSE;
+}
+
+HGLRC WINAPI wglGetCurrentContext(void)
+{
+    return IntGetCurrentRC();
+}
+
+HDC WINAPI wglGetCurrentDC(void)
+{
+    return IntGetCurrentDC();
+}
+
+PROC WINAPI wglGetDefaultProcAddress(LPCSTR lpszProc)
+{
+    /* undocumented... */
+    return NULL;
+}
+
+int WINAPI wglGetLayerPaletteEntries(HDC hdc, int iLayerPlane, int iStart, int cEntries, COLORREF* pcr )
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    
+    if(!dc_data->pixelformat)
+    {
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return 0;
+    }
+    
+    if(dc_data->icd_data)
+        return dc_data->icd_data->DrvGetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
+    
+    /* SW implementation doesn't support this */
+    return 0;
+}
+
+INT WINAPI wglGetPixelFormat(HDC hdc)
+{
+    INT ret;
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    
+    ret = dc_data->pixelformat;
+    release_dc_data(dc_data);
+    return ret;
+}
+
+PROC WINAPI wglGetProcAddress(LPCSTR name)
+{
+    struct wgl_context* context = get_context(IntGetCurrentRC());
+    if(!context)
+        return NULL;
+    
+    /* This shall fail for opengl 1.1 functions */
+#define USE_GL_FUNC(func, w, x, y, z) if(!strcmp(name, "gl" #func)) return NULL;
+#include "glfuncs.h"
+    
+    /* Forward */
+    if(context->icd_data)
+        return context->icd_data->DrvGetProcAddress(name);
+    return sw_GetProcAddress(name);
+}
+
+void APIENTRY set_api_table(const GLCLTPROCTABLE* table)
+{
+    IntSetCurrentDispatchTable(&table->glDispatchTable);
+}
+    
+BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
+{
+    struct wgl_context* ctx = get_context(hglrc);
+    struct wgl_context* old_ctx = get_context(IntGetCurrentRC());
+    const GLCLTPROCTABLE* apiTable;
+    LONG thread_id = (LONG)GetCurrentThreadId();
+    
+    if(ctx)
+    {
+        struct wgl_dc_data* dc_data = get_dc_data(hdc);
+        if(!dc_data)
+        {
+            ERR("wglMakeCurrent was passed an invalid DC handle.\n");
+            SetLastError(ERROR_INVALID_HANDLE);
+            return FALSE;
+        }
+        
+        /* Check compatibility */
+        if((ctx->icd_data != dc_data->icd_data) || (ctx->pixelformat != dc_data->pixelformat))
+        {
+            /* That's bad, man */
+            ERR("HGLRC %p and HDC %p are not compatible.\n", hglrc, hdc); 
+            release_dc_data(dc_data);
+            SetLastError(ERROR_INVALID_HANDLE);
+            return FALSE;
+        }
+        
+        /* Set the thread ID */
+        if(InterlockedCompareExchange(&ctx->thread_id, thread_id, 0) != 0)
+        {
+            /* Already current for a thread. Maybe it's us ? */
+            release_dc_data(dc_data);
+            if(ctx->thread_id != thread_id)
+                SetLastError(ERROR_BUSY);
+            return (ctx->thread_id == thread_id);
+        }
+        
+        if(old_ctx)
+        {
+            /* Unset it */
+            if(old_ctx->icd_data)
+                old_ctx->icd_data->DrvReleaseContext(old_ctx->dhglrc);
+            else
+                sw_ReleaseContext(old_ctx->dhglrc);
+            InterlockedExchange(&old_ctx->thread_id, 0);
+        }
+        
+        /* Call the ICD or SW implementation */
+        if(ctx->icd_data)
+        {
+            apiTable = ctx->icd_data->DrvSetContext(hdc, ctx->dhglrc, set_api_table);
+            if(!apiTable)
+            {
+                ERR("DrvSetContext failed!\n");
+                /* revert */
+                InterlockedExchange(&ctx->thread_id, 0);
+                IntSetCurrentDispatchTable(&StubTable.glDispatchTable);
+                SetLastError(ERROR_INVALID_PARAMETER);
+                return FALSE;
+            }
+            set_api_table(apiTable);
+            /* Make it current */
+            IntMakeCurrent(hglrc, hdc, dc_data);
+        }
+        else
+        {
+            /* We must set current before, SW implementation relies on it */
+            IntMakeCurrent(hglrc, hdc, dc_data);
+            if(!sw_SetContext(dc_data, ctx->dhglrc))
+            {
+                ERR("sw_SetContext failed!\n");
+                /* revert */
+                IntMakeCurrent(NULL, NULL, NULL);
+                InterlockedExchange(&ctx->thread_id, 0);
+                SetLastError(ERROR_INVALID_PARAMETER);
+                return FALSE;
+            }
+        }
+    }
+    else if(old_ctx)
+    {
+        if(old_ctx->icd_data)
+            old_ctx->icd_data->DrvReleaseContext(old_ctx->dhglrc);
+        else
+            sw_ReleaseContext(old_ctx->dhglrc);
+        InterlockedExchange(&old_ctx->thread_id, 0);
+        /* Unset it */
+        IntMakeCurrent(NULL, NULL, NULL);
+        /* Reset the no-op table */
+        set_api_table(&StubTable);
+        /* Test conformance (extreme cases) */
+        return hglrc == NULL;
+    }
+    else
+    {
+        /* Winetest conformance */
+        if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
+        {
+            ERR( "Error: hdc is not a DC handle!\n");
+            SetLastError( ERROR_INVALID_HANDLE );
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
+                                   int iLayerPlane,
+                                   BOOL bRealize)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    if(!dc_data->pixelformat)
+    {
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return FALSE;
+    }
+    
+    if(dc_data->icd_data)
+        return dc_data->icd_data->DrvRealizeLayerPalette(hdc, iLayerPlane, bRealize);
+    
+    /* SW implementation doesn't support this */
+    return FALSE;
+}
+
+int WINAPI wglSetLayerPaletteEntries(HDC hdc,
+                                     int iLayerPlane,
+                                     int iStart,
+                                     int cEntries,
+                                     const COLORREF *pcr)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    
+    if(!dc_data->pixelformat)
+    {
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return 0;
+    }
+    
+    if(dc_data->icd_data)
+        return dc_data->icd_data->DrvSetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
+    
+    /* SW implementation doesn't support this */
+    return 0;
+}
+
+BOOL WINAPI wglSetPixelFormat(HDC hdc, INT format, const PIXELFORMATDESCRIPTOR *descr)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    INT sw_format;
+    BOOL ret;
+    
+    TRACE("HDC %p, format %i.\n", hdc, format);
+    
+    if(!dc_data)
+    {
+        WARN("Not a valid DC!.\n");
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    if(!format)
+    {
+        WARN("format == 0!\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if(dc_data->pixelformat)
+    {
+        TRACE("DC format already set, %i.\n", dc_data->pixelformat);
+        return (format == dc_data->pixelformat);
+    }
+    
+    if(format <= dc_data->nb_icd_formats)
+    {
+        TRACE("Calling ICD.\n");
+        ret = dc_data->icd_data->DrvSetPixelFormat(hdc, format);
+        if(ret)
+        {
+            TRACE("Success!\n");
+            dc_data->pixelformat = format;
+        }
+        return ret;
+    }
+    
+    sw_format = format - dc_data->nb_icd_formats;
+    if(sw_format <= dc_data->nb_sw_formats)
+    {
+        TRACE("Calling SW implementation.\n");
+        ret = sw_SetPixelFormat(hdc, dc_data, sw_format);
+        if(ret)
+        {
+            TRACE("Success!\n");
+            /* This is now officially a software-only HDC */
+            dc_data->icd_data = NULL;
+            dc_data->pixelformat = format;
+        }
+        return ret;
+    }
+
+    TRACE("Invalid pixel format!\n");
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+}
+
+BOOL WINAPI wglShareLists(HGLRC hglrcSrc, HGLRC hglrcDst)
+{
+    struct wgl_context* ctx_src = get_context(hglrcSrc);
+    struct wgl_context* ctx_dst = get_context(hglrcDst);
+    
+    if(!ctx_src || !ctx_dst)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    /* Check this is the same pixel format */
+    if((ctx_dst->icd_data != ctx_src->icd_data) ||
+        (ctx_dst->pixelformat != ctx_src->pixelformat))
+    {
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return FALSE;
+    }
+    
+    if(ctx_src->icd_data)
+        return ctx_src->icd_data->DrvShareLists(ctx_src->dhglrc, ctx_dst->dhglrc);
+    
+    return sw_ShareLists(ctx_src->dhglrc, ctx_dst->dhglrc);
+}
+
+BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers(HDC hdc)
+{
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    
+    if(!dc_data->pixelformat)
+    {
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return FALSE;
+    }
+    
+    if(dc_data->icd_data)
+        return dc_data->icd_data->DrvSwapBuffers(hdc);
+    
+    return sw_SwapBuffers(hdc, dc_data);
+}
+
+BOOL WINAPI wglSwapLayerBuffers(HDC hdc, UINT fuPlanes)
+{
+    return FALSE;
+}
+
+DWORD WINAPI wglSwapMultipleBuffers(UINT count, CONST WGLSWAP * toSwap)
+{
+    return 0;
+}
+
+/* Clean up on DLL unload */
+void
+IntDeleteAllContexts(void)
+{
+    struct wgl_context* context;
+    LIST_ENTRY* Entry = ContextListHead.Flink;
+
+    while (Entry != &ContextListHead)
+    {
+        context = CONTAINING_RECORD(Entry, struct wgl_context, ListEntry);
+        wglDeleteContext((HGLRC)context);
+        Entry = Entry->Flink;
+    }
+}