[OPENGL32]
[reactos.git] / dll / opengl / opengl32 / wgl.c
index f6feeac..a8547c1 100644 (file)
 /*
  * COPYRIGHT:            See COPYING in the top level directory
- * PROJECT:              ReactOS kernel
- * FILE:                 lib/opengl32/wgl.c
- * PURPOSE:              OpenGL32 lib, rosglXXX functions
- * PROGRAMMER:           Anich Gregor (blight)
- * UPDATE HISTORY:
- *                       Feb 2, 2004: Created
+ * PROJECT:              ReactOS
+ * FILE:                 dll/opengl/opengl32/wgl.c
+ * PURPOSE:              OpenGL32 DLL, WGL functions
  */
 
-#define OPENGL32_GL_FUNC_PROTOTYPES
 #include "opengl32.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+#include <pseh/pseh2.h>
 
-#if !defined(UNIMPLEMENTED)
-# define UNIMPLEMENTED DBGPRINT( "UNIMPLEMENTED" )
-#endif
+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;
 
-typedef struct _OPENGL_INFO
-{
-    DWORD Version;          /*!< Driver interface version */
-    DWORD DriverVersion;    /*!< Driver version */
-    WCHAR DriverName[256];  /*!< Driver name */
-} OPENGL_INFO, *POPENGL_INFO;
+LIST_ENTRY ContextListHead;
 
-/*! \brief Append OpenGL Rendering Context (GLRC) to list
- *
- * \param glrc [IN] Pointer to GLRC to append to list
- */
+/* FIXME: suboptimal */
 static
-void
-ROSGL_AppendContext( GLRC *glrc )
-{
-    /* synchronize */
-    if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
-        WAIT_FAILED)
+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)
     {
-        DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
-        return; /* FIXME: do we have to expect such an error and handle it? */
+        hwnd = WindowFromDC(hdc);
+        if(!hwnd)
+            return NULL;
+        id.hwnd = hwnd;
+        flags = WGL_DC_OBJ_DC;
     }
-
-    if (OPENGL32_processdata.glrc_list == NULL)
-        OPENGL32_processdata.glrc_list = glrc;
-    else
+    else if(objType == OBJ_MEMDC)
     {
-        GLRC *p = OPENGL32_processdata.glrc_list;
-        while (p->next != NULL)
-            p = p->next;
-        p->next = glrc;
+        id.hdc = hdc;
     }
-
-    /* release mutex */
-    if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
-        DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
-}
-
-
-/*! \brief Remove OpenGL Rendering Context (GLRC) from list
- *
- * \param glrc [IN] Pointer to GLRC to remove from list
- */
-static
-void
-ROSGL_RemoveContext( GLRC *glrc )
-{
-    /* synchronize */
-    if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
-        WAIT_FAILED)
+    else
     {
-        DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
-        return; /* FIXME: do we have to expect such an error and handle it? */
+        return NULL;
     }
 
-    if (glrc == OPENGL32_processdata.glrc_list)
-        OPENGL32_processdata.glrc_list = glrc->next;
-    else
+    EnterCriticalSection(&dc_data_cs);
+    data = dc_data_list;
+    while(data)
     {
-        GLRC *p = OPENGL32_processdata.glrc_list;
-        while (p != NULL)
+        if(data->owner.u == id.u)
         {
-            if (p->next == glrc)
-            {
-                p->next = glrc->next;
-                break;
-            }
-            p = p->next;
+            LeaveCriticalSection(&dc_data_cs);
+            return data;
         }
-        if (p == NULL)
-            DBGPRINT( "Error: GLRC 0x%08x not found in list!", glrc );
+        data = data->next;
     }
-
-    /* release mutex */
-    if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
-        DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
+    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;
 }
 
-
-/*! \brief Create a new GL Context (GLRC) and append it to the list
- *
- * \return Pointer to new GLRC on success
- * \retval NULL Returned on failure (i.e. Out of memory)
- */
-static
-GLRC *
-ROSGL_NewContext(void)
+void release_dc_data(struct wgl_dc_data* dc_data)
 {
-    GLRC *glrc;
-
-    /* allocate GLRC */
-    glrc = (GLRC*)HeapAlloc( GetProcessHeap(),
-                  HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, sizeof (GLRC) );
-
-    /* append to list */
-    ROSGL_AppendContext( glrc );
-
-    return glrc;
+    (void)dc_data;
 }
 
-/*! \brief Delete all GLDCDATA with this IDC
- *
- * \param icd [IN] Pointer to a ICD
- */
-static
-VOID
-ROSGL_DeleteDCDataForICD( GLDRIVERDATA *icd )
+struct wgl_context* get_context(HGLRC hglrc)
 {
-    GLDCDATA *p, **pptr;
+    struct wgl_context* context = (struct wgl_context*)hglrc;
     
-    return;
-
-    /* synchronize */
-    if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
-        WAIT_FAILED)
+    if(!hglrc)
+        return NULL;
+    
+    _SEH2_TRY
     {
-        DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
-        return;
+        if(context->magic != 'GLRC')
+            context = NULL;
     }
-
-    p = OPENGL32_processdata.dcdata_list;
-    pptr = &OPENGL32_processdata.dcdata_list;
-    while (p != NULL)
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        if (p->icd == icd)
-        {
-            *pptr = p->next;
-            OPENGL32_UnloadICD( p->icd );
-
-            if (!HeapFree( GetProcessHeap(), 0, p ))
-                DBGPRINT( "Warning: HeapFree() on GLDCDATA failed (%d)",
-                          GetLastError() );
-
-            p = *pptr;
-        }
-        else
-        {
-            pptr = &p->next;
-            p = p->next;
-        }
+        context = NULL;
     }
-
-    /* release mutex */
-    if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
-        DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
+    _SEH2_END;
+    
+    return context;
 }
 
-
-/*! \brief Delete a GL Context (GLRC) and remove it from the list
- *
- * \param glrc [IN] Pointer to GLRC to delete
- *
- * \retval TRUE  Success
- * \retval FALSE Failure
- */
-static
-BOOL
-ROSGL_DeleteContext( GLRC *glrc )
+INT WINAPI wglDescribePixelFormat(HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR *descr )
 {
-    /* unload icd */
-    if ((glrc->icd != NULL) && (!InterlockedDecrement((LONG*)&glrc->icd->refcount)))
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    INT ret;
+    
+    if(!dc_data)
     {
-        /* This is the last context, remove the ICD*/
-        ROSGL_DeleteDCDataForICD( glrc->icd );
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
     }
-
-    /* remove from list */
-    ROSGL_RemoveContext( glrc );
-
-    /* free memory */
-    HeapFree( GetProcessHeap(), 0, glrc );
-
-    return TRUE;
-}
-
-
-/*! \brief Check wether a GLRC is in the list
- *
- * \param glrc [IN] Pointer to GLRC to look for in the list
- *
- * \retval TRUE  GLRC was found
- * \retval FALSE GLRC was not found
- */
-static
-BOOL
-ROSGL_ContainsContext( GLRC *glrc )
-{
-    GLRC *p;
-    BOOL found = FALSE;
-
-    /* synchronize */
-    if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
-        WAIT_FAILED)
+    
+    ret = dc_data->nb_icd_formats + dc_data->nb_sw_formats;
+    
+    if(!descr)
     {
-        DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
-        return FALSE; /* FIXME: do we have to expect such an error and handle it? */
+        release_dc_data(dc_data);
+        return ret;
     }
-
-    p = OPENGL32_processdata.glrc_list;
-    while (p != NULL)
+    if((format == 0) || (format > ret) || (size != sizeof(*descr)))
     {
-        if (p == glrc)
+        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))
         {
-            found = TRUE;
-            break;
+            ret = 0;
         }
-        p = p->next;
     }
-
-    /* release mutex */
-    if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
-        DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
-
-    return found;
+    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;
 }
 
-
-/*! \brief Get GL private DC data.
- *
- * This function adds an empty GLDCDATA to the list if there is no data for the
- * given DC yet.
- *
- * \param hdc [IN] Handle to a Device Context for which to get the data
- *
- * \return Pointer to GLDCDATA on success
- * \retval NULL on failure
- */
-static
-GLDCDATA *
-ROSGL_GetPrivateDCData( HDC hdc )
+INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
 {
-    GLDCDATA *data;
-    HANDLE handle;
+    PIXELFORMATDESCRIPTOR format, best;
+    int i, count, best_format;
+    int bestDBuffer = -1, bestStereo = -1;
 
-    /* check hdc */
-    if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
-    {
-        DBGPRINT( "Error: hdc is not a DC handle!" );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return FALSE;
-    }
+    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 );
 
-    /* synchronize */
-    if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
-        WAIT_FAILED)
-    {
-        DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
-        return NULL; /* FIXME: do we have to expect such an error and handle it? */
-    }
+    count = wglDescribePixelFormat( hdc, 0, 0, NULL );
+    if (!count) return 0;
 
-    /* We must use the window to identify our data, as pixel format is
-     * specific to a window for device context */
-    handle = WindowFromDC(hdc);
-    if(!handle)
-        handle = hdc;
+    best_format = 0;
+    best.dwFlags = PFD_GENERIC_FORMAT;
+    best.cAlphaBits = -1;
+    best.cColorBits = -1;
+    best.cDepthBits = -1;
+    best.cStencilBits = -1;
+    best.cAuxBuffers = -1;
 
-    /* look for data in list */
-    data = OPENGL32_processdata.dcdata_list;
-    while (data != NULL)
+    for (i = 1; i <= count; i++)
     {
-        if (data->handle == handle) /* found */
-            break;
-        data = data->next;
-    }
+        if (!wglDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
 
-    /* allocate new data if not found in list */
-    if (data == NULL)
-    {
-        data = HeapAlloc( GetProcessHeap(),
-                          HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS,
-                          sizeof (GLDCDATA) );
-        if (data == NULL)
+        if (ppfd->iPixelType != format.iPixelType)
         {
-            DBGPRINT( "Error: HeapAlloc() failed (%d)", GetLastError() );
+            TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
+            continue;
         }
-        else
+
+        /* only use bitmap capable formats for bitmap rendering */
+        if ((ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
         {
-            data->handle = handle;
+            TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
+            continue;
+        }
 
-            /* append data to list */
-            if (OPENGL32_processdata.dcdata_list == NULL)
-                OPENGL32_processdata.dcdata_list = data;
-            else
-            {
-                GLDCDATA *p = OPENGL32_processdata.dcdata_list;
-                while (p->next != NULL)
-                    p = p->next;
-                p->next = data;
-            }
+        /* 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;
         }
-    }
 
-    /* release mutex */
-    if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
-        DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
+        /* 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;
+        }
 
-    return data;
-}
+        /* 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.
+         */
 
-/*! \brief Get ICD from HDC.
- *
- * This function asks the display driver which OpenGL ICD to load for the given
- * HDC, loads it and returns a pointer to a GLDRIVERDATA struct on success.
- *
- * \param hdc [IN] Handle for DC for which to load/get the ICD
- *
- * \return Pointer to GLDRIVERDATA
- * \retval NULL Failure.
- */
-static
-GLDRIVERDATA *
-ROSGL_ICDForHDC( HDC hdc )
-{
-    GLDCDATA *dcdata;
-    GLDRIVERDATA *drvdata;
+        /* 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;
 
-    dcdata = ROSGL_GetPrivateDCData( hdc );
-    if (dcdata == NULL)
-        return NULL;
+            if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
+        }
 
-    if (dcdata->icd == NULL)
-    {
-        LPCWSTR driverName;
-        OPENGL_INFO info;
+        /* 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;
 
-        /* NOTE: This might be done by multiple threads simultaneously, but only the fastest
-                 actually gets to set the ICD! */
+            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. */
 
-        driverName = _wgetenv( L"OPENGL32_DRIVER" );
-        if (driverName == NULL)
+        if (ppfd->cColorBits)
         {
-            DWORD dwInput;
-            LONG ret;
+            if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
+                ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
+                goto found;
 
-            /* get driver name */
-            dwInput = OPENGL_GETINFO;
-            ret = ExtEscape( hdc, QUERYESCSUPPORT, sizeof (dwInput), (LPCSTR)&dwInput, 0, NULL );
-            if (ret > 0)
+            if (best.cColorBits != format.cColorBits)  /* Do further checks if the format is compatible */
             {
-                dwInput = 0;
-                ret = ExtEscape( hdc, OPENGL_GETINFO, sizeof (dwInput),
-                                 (LPCSTR)&dwInput, sizeof (OPENGL_INFO),
-                                 (LPSTR)&info );
+                TRACE( "color mismatch for iPixelFormat=%d\n", i );
+                continue;
             }
-            if (ret <= 0)
-            {
-                HKEY hKey;
-                DWORD type, size;
-
-                if (ret < 0)
-                {
-                    DBGPRINT( "Warning: ExtEscape to get the drivername failed! (%d)", GetLastError() );
-                    if (MessageBox( WindowFromDC( hdc ), L"Couldn't get installable client driver name!\nUsing default driver.",
-                                    L"OPENGL32.dll: Warning", MB_OKCANCEL | MB_ICONWARNING ) == IDCANCEL)
-                    {
-                        return NULL;
-                    }
-                }
-
-                /* open registry key */
-                ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, OPENGL_DRIVERS_SUBKEY, 0, KEY_QUERY_VALUE, &hKey );
-                if (ret != ERROR_SUCCESS)
-                {
-                    DBGPRINT( "Error: Couldn't open registry key '%ws'", OPENGL_DRIVERS_SUBKEY );
-                    SetLastError( ret );
-                    return NULL;
-                }
+        }
+        if (ppfd->cAlphaBits)
+        {
+            if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
+                ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
+                goto found;
 
-                /* query value */
-                size = sizeof (info.DriverName);
-                ret = RegQueryValueExW( hKey, L"DefaultDriver", 0, &type, (LPBYTE)info.DriverName, &size );
-                RegCloseKey( hKey );
-                if (ret != ERROR_SUCCESS || type != REG_SZ)
-                {
-                    DBGPRINT( "Error: Couldn't query DefaultDriver value or not a string" );
-                    SetLastError( ret );
-                    return NULL;
-                }
+            if (best.cAlphaBits != format.cAlphaBits)
+            {
+                TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
+                continue;
             }
         }
-        else
+        if (ppfd->cDepthBits)
         {
-            wcsncpy( info.DriverName, driverName, sizeof (info.DriverName) / sizeof (info.DriverName[0]) );
+            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;
+            }
         }
-        /* load driver (or get a reference) */
-        drvdata = OPENGL32_LoadICD( info.DriverName );
-        if (drvdata == NULL)
+        if (ppfd->cStencilBits)
         {
-            WCHAR Buffer[256];
-            snwprintf(Buffer, sizeof(Buffer)/sizeof(WCHAR),
-                      L"Couldn't load driver \"%s\".", info.DriverName);
-            MessageBox(WindowFromDC( hdc ), Buffer,
-                       L"OPENGL32.dll: Warning",
-                       MB_OK | MB_ICONWARNING);
+            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;
+            }
         }
-        else
+        if (ppfd->cAuxBuffers)
         {
-            /* Atomically set the ICD!!! */
-            if (InterlockedCompareExchangePointer((PVOID*)&dcdata->icd,
-                                                  (PVOID)drvdata,
-                                                  NULL) != NULL)
+            if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
+                ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
+                goto found;
+
+            if (best.cAuxBuffers != format.cAuxBuffers)
             {
-                /* Too bad, somebody else was faster... */
-                DBGTRACE("ICD is already set!\n");
+                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;
     }
 
-    return dcdata->icd;
+    TRACE( "returning %u\n", best_format );
+    return best_format;
 }
 
-
-/*! \brief SetContextCallBack passed to DrvSetContext.
- *
- * This function gets called by the OpenGL driver whenever the current GL
- * context (dispatch table) is to be changed.
- *
- * \param table [IN] Function pointer table (first DWORD is number of functions)
- *
- * \return unkown (maybe void? ERROR_SUCCESS at the moment)
- */
-DWORD
-CALLBACK
-ROSGL_SetContextCallBack( const ICDTable *table )
+BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
 {
-    TEB *teb;
-    PROC *tebTable, *tebDispatchTable;
-    INT size;
-
-    teb = NtCurrentTeb();
-    tebTable = (PROC *)teb->glTable;
-    tebDispatchTable = (PROC *)teb->glDispatchTable;
-
-    DBGTRACE( "Called!" );
-
-    if (table != NULL)
-    {
-        DBGPRINT( "Function count: %d\n", table->num_funcs );
-
-        /* save table */
-        size = sizeof (PROC) * table->num_funcs;
-        memcpy( tebTable, table->dispatch_table, size );
-        memset( tebTable + table->num_funcs, 0, DISPATCH_TABLE_SIZE - size );
-    }
-    else
+    struct wgl_context* ctx_src = get_context(hglrcSrc);
+    struct wgl_context* ctx_dst = get_context(hglrcDst);
+    
+    if(!ctx_src || !ctx_dst)
     {
-        DBGPRINT( "Unsetting current context" );
-        memset( tebTable, 0, DISPATCH_TABLE_SIZE );
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
     }
-
-    /* put in empty functions as long as we dont have a fallback */
-    #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
-        if (tebTable[icdidx] == NULL) \
-        { \
-            if (table != NULL) \
-                DBGPRINT( "Warning: GL proc '%s' is NULL", #func ); \
-            tebTable[icdidx] = (PROC)glEmptyFunc##stack; \
-        }
-    GLFUNCS_MACRO
-#undef X
-
-    /* fill teb->glDispatchTable for fast calls */
-#define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
-        if (tebidx >= 0) \
-            tebDispatchTable[tebidx] = tebTable[icdidx];
-    GLFUNCS_MACRO
-#undef X
-
-    DBGPRINT( "Done." );
-
-    return ERROR_SUCCESS;
-}
-
-
-/*! \brief Returns the current pixelformat.
- *
- * \param hdc [IN] Handle to DC to get the pixelformat from
- *
- * \return Pixelformat index
- * \retval 0 Failure
- */
-int
-WINAPI
-rosglGetPixelFormat( HDC hdc )
-{
-    GLDCDATA *dcdata;
-
-    DBGTRACE( "Called!" );
-
-    dcdata = ROSGL_GetPrivateDCData( hdc );
-    if (dcdata == NULL)
+    
+    /* Check this is the same pixel format */
+    if((ctx_dst->icd_data != ctx_src->icd_data) ||
+        (ctx_dst->pixelformat != ctx_src->pixelformat))
     {
-        DBGPRINT( "Error: ROSGL_GetPrivateDCData failed!" );
-        return 0;
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return FALSE;
     }
-
-    return dcdata->pixel_format;
+    
+    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);
 }
 
-
-/*! \brief Attempts to find the best matching pixel format for HDC
- *
- * This function is comparing each available format with the preferred one
- * and returns the one which is closest to it.
- * If PFD_DOUBLEBUFFER, PFD_STEREO or one of PFD_DRAW_TO_WINDOW,
- * PFD_DRAW_TO_BITMAP, PFD_SUPPORT_GDI and PDF_SUPPORT_OPENGL is given then
- * only formats which also support those will be enumerated (unless
- * PFD_DOUBLEBUFFER_DONTCARE or PFD_STEREO_DONTCARE is also set)
- *
- * \param hdc [IN] Handle to DC for which to get a pixel format index
- * \param pfd [IN] PFD describing what kind of format you want
- *
- * \return Pixel format index
- * \retval 0 Failed to find a suitable format
- */
-#define BUFFERDEPTH_SCORE(want, have) \
-    ((want == 0) ? (0) : ((want < have) ? (1) : ((want > have) ? (3) : (0))))
-
-/* Score if we want and not have it */
-#define FLAG_SCORE(want, have, flag) \
-    (((want & ~have) & flag) ? (1) : (0))
-
-/* Score if what we want is different than what we have, except when
-   _DONTCARE was set */
-#define FLAG_SCORE_DONTCARE(want, have, flag) \
-    ((!(have & flag ## _DONTCARE)) && ((want & flag) != (have & flag)) ? (1) : (0))
-
-int
-APIENTRY
-rosglChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
+HGLRC WINAPI wglCreateContext(HDC hdc)
 {
-    GLDRIVERDATA *icd;
-    PIXELFORMATDESCRIPTOR icdPfd;
-    int i;
-    int best = 0;
-    int score, bestScore = 0x7fff; /* used to choose a pfd if no exact match */
-    int icdNumFormats;
-
-    DBGTRACE( "Called!" );
-
-    /* load ICD */
-    icd = ROSGL_ICDForHDC( hdc );
-    if (icd == NULL)
-        return 0;
-
-    /* check input */
-    if (pfd->nSize != sizeof (PIXELFORMATDESCRIPTOR) || pfd->nVersion != 1)
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    struct wgl_context* context;
+    DHGLRC dhglrc;
+    
+    TRACE("Creating context for %p.\n", hdc);
+    
+    if(!dc_data)
     {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return 0;
+        WARN("Not a DC handle!\n");
+        SetLastError(ERROR_INVALID_HANDLE);
+        return NULL;
     }
-
-    /* get number of formats */
-    icdNumFormats = icd->DrvDescribePixelFormat( hdc, 1,
-                    sizeof (PIXELFORMATDESCRIPTOR), &icdPfd );
-    if (icdNumFormats == 0)
+    
+    if(!dc_data->pixelformat)
     {
-        DBGPRINT( "Error: DrvDescribePixelFormat failed (%d)", GetLastError() );
-        return 0;
+        WARN("Pixel format not set!\n");
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
     }
-    DBGPRINT( "Info: Enumerating %d pixelformats", icdNumFormats );
-
-    /* try to find best format */
-    for (i = 0; i < icdNumFormats; i++)
+    
+    if(!dc_data->icd_data)
     {
-        if (icd->DrvDescribePixelFormat( hdc, i + 1,
-            sizeof (PIXELFORMATDESCRIPTOR), &icdPfd ) == 0)
-        {
-            DBGPRINT( "Warning: DrvDescribePixelFormat failed (%d)",
-                         GetLastError() );
-            break;
-        }
-
-        if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) != 0) /* we do not support such kind of drivers */
-        {
-            continue;
-        }
-
-        score = 0; /* higher is worse */
-
-        /* compare flags */
-        score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_WINDOW);
-        score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_BITMAP);
-        score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_GDI);
-        score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_OPENGL);
-        score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_DOUBLEBUFFER);
-        score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_STEREO);
-
-        /* check other attribs */
-        if (pfd->iPixelType != icdPfd.iPixelType)
-            score += 5; /* this is really bad i think */
-        if (pfd->iLayerType != icdPfd.iLayerType)
-            score += 15; /* this is very very bad ;) */
-
-        score += BUFFERDEPTH_SCORE(pfd->cAlphaBits, icdPfd.cAlphaBits);
-        score += BUFFERDEPTH_SCORE(pfd->cAccumBits, icdPfd.cAccumBits);
-        score += BUFFERDEPTH_SCORE(pfd->cDepthBits, icdPfd.cDepthBits);
-        score += BUFFERDEPTH_SCORE(pfd->cStencilBits, icdPfd.cStencilBits);
-        score += BUFFERDEPTH_SCORE(pfd->cAuxBuffers, icdPfd.cAuxBuffers);
-
-        /* check score */
-        if (score < bestScore)
-        {
-            bestScore = score;
-            best = i + 1;
-            if (bestScore == 0)
-                break;
-        }
+        TRACE("Calling SW implementation.\n");
+        dhglrc = sw_CreateContext(dc_data);
+        TRACE("done\n");
     }
-
-    if (best == 0)
-        SetLastError( 0 ); /* FIXME: set appropriate error */
-
-    DBGPRINT( "Info: Suggesting pixelformat %d", best );
-    return best;
-}
-
-
-/*! \brief Copy data specified by mask from one GLRC to another.
- *
- * \param src  [IN] Source GLRC
- * \param src  [OUT] Destination GLRC
- * \param mask [IN] Bitfield like given to glPushAttrib()
- *
- * \retval TRUE  Success
- * \retval FALSE Failure
- */
-BOOL
-APIENTRY
-rosglCopyContext( HGLRC hsrc, HGLRC hdst, UINT mask )
-{
-    GLRC *src = (GLRC *)hsrc;
-    GLRC *dst = (GLRC *)hdst;
-
-    /* check glrcs */
-    if (!ROSGL_ContainsContext( src ))
+    else
     {
-        DBGPRINT( "Error: src GLRC not found!" );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return FALSE;
+        TRACE("Calling ICD.\n");
+        dhglrc = dc_data->icd_data->DrvCreateContext(hdc);
     }
-    if (!ROSGL_ContainsContext( dst ))
+    
+    if(!dhglrc)
     {
-        DBGPRINT( "Error: dst GLRC not found!" );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return FALSE;
+        WARN("Failed!\n");
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
     }
-
-    /* I think this is only possible within one ICD */
-    if (src->icd != dst->icd)
+    
+    context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
+    if(!context)
     {
-        DBGPRINT( "Error: src and dst GLRC use different ICDs!" );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return FALSE;
+        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);
 
-    /* copy data (call ICD) */
-    return src->icd->DrvCopyContext( src->hglrc, dst->hglrc, mask );
+    context->magic = 'GLRC';
+    TRACE("Success!\n");
+    return (HGLRC)context;
 }
 
-
-/*! \brief Create a new GL Rendering Context.
- *
- * This function can create over- or underlay surfaces.
- *
- * \param hdc [IN] Handle for DC for which to create context
- * \param layer [IN] Layer number to bind (draw?) to
- *
- * \return Handle for the created GLRC
- * \retval NULL Failure
- */
-HGLRC
-APIENTRY
-rosglCreateLayerContext( HDC hdc, int layer )
+HGLRC WINAPI wglCreateLayerContext(HDC hdc, int iLayerPlane)
 {
-    GLDRIVERDATA *icd = NULL;
-    GLRC *glrc;
-    HGLRC drvHglrc = NULL;
-
-    DBGTRACE( "Called!" );
-
-/*     if (GetObjectType( hdc ) != OBJ_DC)
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    struct wgl_context* context;
+    DHGLRC dhglrc;
+    
+    if(!dc_data)
     {
-        DBGPRINT( "Error: hdc is not a DC handle!" );
+        SetLastError(ERROR_INVALID_HANDLE);
         return NULL;
     }
-*/
-
-    /* load ICD */
-    icd = ROSGL_ICDForHDC( hdc );
-    if (icd == NULL)
+    
+    if(!dc_data->pixelformat)
     {
-        DBGPRINT( "Couldn't get ICD by HDC :-(" );
-        /* FIXME: fallback? */
+        release_dc_data(dc_data);
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
         return NULL;
     }
-
-    /* create new GLRC */
-    glrc = ROSGL_NewContext();
-    if (glrc == NULL)
-        return NULL;
-
-    /* Don't forget to refcount it, icd will be released when last context is deleted */
-    InterlockedIncrement((LONG*)&icd->refcount);
-
-    /* You can't create a context without first setting a valid pixel format */
-    if(rosglGetPixelFormat(hdc) == 0)
+    
+    if(!dc_data->icd_data)
     {
-        ROSGL_DeleteContext( glrc );
+        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;
     }
-
-
-    /* create context */
-    if (icd->DrvCreateLayerContext != NULL)
-        drvHglrc = icd->DrvCreateLayerContext( hdc, layer );
-    if (drvHglrc == NULL)
+    
+    context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
+    if(!context)
     {
-        if (layer == 0 && icd->DrvCreateContext != NULL)
-            drvHglrc = icd->DrvCreateContext( hdc );
+        if(!dc_data->icd_data)
+            sw_DeleteContext(dhglrc);
         else
-            DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
-    }
-
-    if (drvHglrc == NULL)
-    {
-        /* FIXME: fallback to mesa? */
-        DBGPRINT( "Error: DrvCreate[Layer]Context failed! (%d)", GetLastError() );
-        ROSGL_DeleteContext( glrc );
+            dc_data->icd_data->DrvDeleteContext(dhglrc);
+        release_dc_data(dc_data);
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return NULL;
     }
-
-    /* we have our GLRC in glrc and the ICD's GLRC in drvHglrc */
-    glrc->hglrc = drvHglrc;
-    glrc->icd = icd;
-
-    return (HGLRC)glrc;
+    /* 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;
 }
 
-
-/*! \brief Create a new GL Rendering Context.
- *
- * \param hdc [IN] Handle for DC for which to create context
- *
- * \return Handle for the created GLRC
- * \retval NULL Failure
- */
-HGLRC
-APIENTRY
-rosglCreateContext( HDC hdc )
+BOOL WINAPI wglDeleteContext(HGLRC hglrc)
 {
-    return rosglCreateLayerContext( hdc, 0 );
-}
-
-
-/*! \brief Delete an OpenGL context
- *
- * \param hglrc [IN] Handle to GLRC to delete;
- *
- * \retval TRUE  Success
- * \retval FALSE Failure (i.e. GLRC is current for a thread)
- */
-BOOL
-APIENTRY
-rosglDeleteContext( HGLRC hglrc )
-{
-    GLRC *glrc = (GLRC *)hglrc;
-
-    /* check if we know about this context */
-    if (!ROSGL_ContainsContext( glrc ))
+    struct wgl_context* context = get_context(hglrc);
+    LONG thread_id = GetCurrentThreadId();
+    
+    if(!context)
     {
-        DBGPRINT( "Error: hglrc not found!" );
-        SetLastError( ERROR_INVALID_HANDLE );
+        SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
-
-    /* On windows, this is allowed to delete a context which is current */
-    if (glrc->is_current)
+    
+    /* Own this context before touching it */
+    if(InterlockedCompareExchange(&context->thread_id, thread_id, 0) != 0)
     {
-        /* But only for its own thread */
-        if(glrc->thread_id != GetCurrentThreadId())
+        /* We can't delete a context current to another thread */
+        if(context->thread_id != thread_id)
         {
-            DBGPRINT( "Error: GLRC is current for DC 0x%08x", glrc->hdc );
-            SetLastError( ERROR_INVALID_FUNCTION );
+            SetLastError(ERROR_BUSY);
             return FALSE;
         }
-        /* Unset it before going further */
-        rosglMakeCurrent(NULL, NULL);
-    }
-
-    /* release ICD's context */
-    if (glrc->hglrc != NULL)
-    {
-        if (!glrc->icd->DrvDeleteContext( glrc->hglrc ))
-        {
-            DBGPRINT( "Warning: DrvDeleteContext() failed (%d)", GetLastError() );
+        
+        /* This is in our thread. Release and try again */
+        if(!wglMakeCurrent(NULL, NULL))
             return FALSE;
-        }
+        return wglDeleteContext(hglrc);
     }
-
-    /* free resources */
-    return ROSGL_DeleteContext( glrc );
-}
-
-
-BOOL
-APIENTRY
-rosglDescribeLayerPlane( HDC hdc, int iPixelFormat, int iLayerPlane,
-                         UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd )
-{
-    UNIMPLEMENTED;
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
-    return FALSE;
+    
+    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;
 }
 
-
-/*! \brief Gets information about a pixelformat.
- *
- * \param hdc     [IN]  Handle to DC
- * \param iFormat [IN]  Pixelformat index
- * \param nBytes  [IN]  sizeof (pfd) - at most nBytes are copied into pfd
- * \param pfd     [OUT] Pointer to a PIXELFORMATDESCRIPTOR
- *
- * \return Maximum pixelformat index/number of formats
- * \retval 0 Failure
- */
-int
-APIENTRY
-rosglDescribePixelFormat( HDC hdc, int iFormat, UINT nBytes,
-                          LPPIXELFORMATDESCRIPTOR pfd )
+BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
+                                  int iPixelFormat,
+                                  int iLayerPlane,
+                                  UINT nBytes,
+                                  LPLAYERPLANEDESCRIPTOR plpd)
 {
-    int ret = 0;
-    GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
-
-    if (icd != NULL)
-    {
-        ret = icd->DrvDescribePixelFormat( hdc, iFormat, nBytes, pfd );
-        if (ret == 0)
-            DBGPRINT( "Error: DrvDescribePixelFormat(format=%d) failed (%d)", iFormat, GetLastError() );
-    }
-    else
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
     {
-        SetLastError( ERROR_INVALID_FUNCTION );
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
     }
-
-    return ret;
+    
+    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;
 }
 
-
-/*! \brief Return the thread's current GLRC
- *
- * \return Handle for thread's current GLRC
- * \retval NULL No current GLRC set
- */
-HGLRC
-APIENTRY
-rosglGetCurrentContext()
+HGLRC WINAPI wglGetCurrentContext(void)
 {
-    return NtCurrentTeb()->glCurrentRC;
+    return IntGetCurrentRC();
 }
 
-
-/*! \brief Return the thread's current DC
- *
- * \return Handle for thread's current DC
- * \retval NULL No current DC/GLRC set
- */
-HDC
-APIENTRY
-rosglGetCurrentDC()
+HDC WINAPI wglGetCurrentDC(void)
 {
-    GLRC* glrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
-    if(glrc) return glrc->hdc;
-    return NULL;
+    return IntGetCurrentDC();
 }
 
-
-int
-APIENTRY
-rosglGetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
-                             int cEntries, COLORREF *pcr )
+PROC WINAPI wglGetDefaultProcAddress(LPCSTR lpszProc)
 {
-    UNIMPLEMENTED;
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
-    return 0;
+    /* undocumented... */
+    return NULL;
 }
 
-
-/*! \brief Get the address for an OpenGL extension function.
- *
- * The addresses this function returns are only valid within the same thread
- * which it was called from.
- *
- * \param proc [IN] Name of the function to look for
- *
- * \return The address of the proc
- * \retval NULL Failure
- */
-PROC
-APIENTRY
-rosglGetProcAddress( LPCSTR proc )
+int WINAPI wglGetLayerPaletteEntries(HDC hdc, int iLayerPlane, int iStart, int cEntries, COLORREF* pcr )
 {
-    PROC func;
-    GLRC* glrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
-
-    /* FIXME we should Flush the gl here */
-
-    if (glrc == NULL)
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
     {
-        DBGPRINT( "Error: No current GLRC!" );
-        SetLastError( ERROR_INVALID_FUNCTION );
-        return NULL;
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
     }
-
-    func = glrc->icd->DrvGetProcAddress( proc );
-    if (func != NULL)
+    
+    if(!dc_data->pixelformat)
     {
-        DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
-        return func;
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return 0;
     }
-
-    /* FIXME: Should we return wgl/gl 1.1 functions? */
-    SetLastError( ERROR_PROC_NOT_FOUND );
-    return NULL;
+    
+    if(dc_data->icd_data)
+        return dc_data->icd_data->DrvGetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
+    
+    /* SW implementation doesn't support this */
+    return 0;
 }
 
-PROC
-APIENTRY
-rosglGetDefaultProcAddress( LPCSTR proc )
+INT WINAPI wglGetPixelFormat(HDC hdc)
 {
-    PROC func;
-    GLRC* glrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
-
-    /*  wglGetDefaultProcAddress does not flush the gl */
-
-    if (glrc == NULL)
-    {
-        DBGPRINT( "Error: No current GLRC!" );
-        SetLastError( ERROR_INVALID_FUNCTION );
-        return NULL;
-    }
-
-    func = glrc->icd->DrvGetProcAddress( proc );
-    if (func != NULL)
+    INT ret;
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
     {
-        DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
-        return func;
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
     }
-
-    /* FIXME: Should we return wgl/gl 1.1 functions? */
-    SetLastError( ERROR_PROC_NOT_FOUND );
-    return NULL;
+    
+    ret = dc_data->pixelformat;
+    release_dc_data(dc_data);
+    return ret;
 }
 
-
-/*! \brief Make the given GLRC the threads current GLRC for hdc
- *
- * \param hdc   [IN] Handle for a DC to be drawn on
- * \param hglrc [IN] Handle for a GLRC to make current
- *
- * \retval TRUE  Success
- * \retval FALSE Failure
- */
-BOOL
-APIENTRY
-rosglMakeCurrent( HDC hdc, HGLRC hglrc )
+PROC WINAPI wglGetProcAddress(LPCSTR name)
 {
-    GLRC *glrc = (GLRC *)hglrc;
-    ICDTable *icdTable = NULL;
-
-    DBGTRACE( "Called!" );
+    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);
+}
 
-    /* Is t a new context ? */
-    if (glrc != NULL)
+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)
     {
-        /* check hdc */
-        if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
+        struct wgl_dc_data* dc_data = get_dc_data(hdc);
+        if(!dc_data)
         {
-            DBGPRINT( "Error: hdc is not a DC handle!" );
-            SetLastError( ERROR_INVALID_HANDLE );
+            ERR("wglMakeCurrent was passed an invalid DC handle.\n");
+            SetLastError(ERROR_INVALID_HANDLE);
             return FALSE;
         }
-
-        /* check if we know about this glrc */
-        if (!ROSGL_ContainsContext( glrc ))
+        
+        /* Check compatibility */
+        if((ctx->icd_data != dc_data->icd_data) || (ctx->pixelformat != dc_data->pixelformat))
         {
-            DBGPRINT( "Error: hglrc not found!" );
-            SetLastError( ERROR_INVALID_HANDLE );
+            /* 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;
         }
-
-        /* check if it is available */
-        if (glrc->is_current && glrc->thread_id != GetCurrentThreadId()) /* used by another thread */
+        
+        /* Set the thread ID */
+        if(InterlockedCompareExchange(&ctx->thread_id, thread_id, 0) != 0)
         {
-            DBGPRINT( "Error: hglrc is current for thread 0x%08x", glrc->thread_id );
-            SetLastError( ERROR_INVALID_HANDLE );
-            return FALSE;
+            /* 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);
         }
-
-        /* Unset previous one */
-        if (NtCurrentTeb()->glCurrentRC != NULL)
+        
+        if(old_ctx)
         {
-            GLRC *oldglrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
-            oldglrc->is_current = FALSE;
-            oldglrc->thread_id = 0;
-            oldglrc->hdc = NULL;
-            oldglrc->icd->DrvReleaseContext(oldglrc->hglrc);
+            /* 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 */
-        if (glrc->hglrc != NULL)
+        
+        /* Call the ICD or SW implementation */
+        if(ctx->icd_data)
         {
-            DBGPRINT( "Info: Calling DrvSetContext!" );
-            SetLastError( ERROR_SUCCESS );
-            icdTable = glrc->icd->DrvSetContext( hdc, glrc->hglrc,
-                                                 (void *)ROSGL_SetContextCallBack );
-            if (icdTable == NULL)
+            apiTable = ctx->icd_data->DrvSetContext(hdc, ctx->dhglrc, set_api_table);
+            if(!apiTable)
             {
-                DBGPRINT( "Error: DrvSetContext failed (%d)\n", GetLastError() );
-                NtCurrentTeb()->glCurrentRC = NULL;
+                ERR("DrvSetContext failed!\n");
+                /* revert */
+                InterlockedExchange(&ctx->thread_id, 0);
+                IntSetCurrentDispatchTable(NULL);
+                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;
             }
-            DBGPRINT( "Info: DrvSetContext succeeded!" );
         }
-
-        /* make it current */
-        glrc->is_current = TRUE;
-        glrc->thread_id = GetCurrentThreadId();
-        glrc->hdc = hdc;
-        NtCurrentTeb()->glCurrentRC = (HGLRC)glrc;
     }
-    else if(NtCurrentTeb()->glCurrentRC)
+    else if(old_ctx)
     {
-        /* This is a call to unset the context */
-        GLRC *oldglrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
-        oldglrc->is_current = FALSE;
-        oldglrc->thread_id = 0;
-        oldglrc->hdc = NULL;
-        oldglrc->icd->DrvReleaseContext(oldglrc->hglrc);
-        NtCurrentTeb()->glCurrentRC = NULL;
+        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);
+        IntSetCurrentDispatchTable(NULL);
+        /* Test conformance (extreme cases) */
+        return hglrc == NULL;
     }
     else
     {
-        /*
-         * To make wine tests happy.
-         * Now, who cares if MakeCurrentContext(NULL, NULL) fails when current context is already NULL
-         */
+        /* Winetest conformance */
         if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
         {
-            DBGPRINT( "Error: hdc is not a DC handle!" );
+            ERR( "Error: hdc is not a DC handle!\n");
             SetLastError( ERROR_INVALID_HANDLE );
             return FALSE;
         }
     }
 
-    if (ROSGL_SetContextCallBack( icdTable ) != ERROR_SUCCESS && icdTable == NULL)
-    {
-        DBGPRINT( "Warning: ROSGL_SetContextCallBack failed!" );
-    }
-
     return TRUE;
 }
 
-
-BOOL
-APIENTRY
-rosglRealizeLayerPalette( HDC hdc, int iLayerPlane, BOOL bRealize )
+BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
+                                   int iLayerPlane,
+                                   BOOL bRealize)
 {
-    UNIMPLEMENTED;
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
+    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
-APIENTRY
-rosglSetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
-                             int cEntries, CONST COLORREF *pcr )
-{
-    UNIMPLEMENTED;
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
-    return 0;
-}
-
-
-/*! \brief Set a DCs pixelformat
- *
- * \param hdc     [IN] Handle to DC for which to set the format
- * \param iFormat [IN] Index of the pixelformat to set
- * \param pfd     [IN] Not sure what this is for
- *
- * \retval TRUE  Success
- * \retval FALSE Failure
- */
-BOOL
-WINAPI
-rosglSetPixelFormat( HDC hdc, int iFormat, CONST PIXELFORMATDESCRIPTOR *pfd )
+int WINAPI wglSetLayerPaletteEntries(HDC hdc,
+                                     int iLayerPlane,
+                                     int iStart,
+                                     int cEntries,
+                                     const COLORREF *pcr)
 {
-    GLDCDATA *dcdata;
-    GLDRIVERDATA* icd;
-
-    DBGTRACE( "Called!" );
-
-    /* Get private DC data */
-    dcdata = ROSGL_GetPrivateDCData( hdc );
-    if (dcdata == NULL)
+    struct wgl_dc_data* dc_data = get_dc_data(hdc);
+    
+    if(!dc_data)
     {
-        DBGPRINT( "Error: ROSGL_GetPrivateDCData() failed!" );
-        return FALSE;
-    }
-    /* you can set the same pixel format twice, but you can't modify it */
-    if(dcdata->pixel_format) return dcdata->pixel_format == iFormat;
-
-    icd = ROSGL_ICDForHDC(hdc);
-    if(icd == NULL)
+        SetLastError(ERROR_INVALID_HANDLE);
         return 0;
-
-    /* Call ICD function */
-    if (!icd->DrvSetPixelFormat( hdc, iFormat, pfd ))
+    }
+    
+    if(!dc_data->pixelformat)
     {
-        DBGPRINT( "Warning: DrvSetPixelFormat(format=%d) failed (%d)",
-                  iFormat, GetLastError() );
-        return FALSE;
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return 0;
     }
-    dcdata->pixel_format = iFormat;
-
-    return TRUE;
+    
+    if(dc_data->icd_data)
+        return dc_data->icd_data->DrvSetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
+    
+    /* SW implementation doesn't support this */
+    return 0;
 }
 
-
-/*! \brief Enable display-list sharing between multiple GLRCs
- *
- * This will only work if both GLRCs are from the same driver.
- *
- * \param hglrc1 [IN] GLRC number 1
- * \param hglrc2 [IN] GLRC number 2
- *
- * \retval TRUE  Success
- * \retval FALSE Failure
- */
-BOOL
-APIENTRY
-rosglShareLists( HGLRC hglrc1, HGLRC hglrc2 )
+BOOL WINAPI wglSetPixelFormat(HDC hdc, INT format, const PIXELFORMATDESCRIPTOR *descr)
 {
-    GLRC *glrc1 = (GLRC *)hglrc1;
-    GLRC *glrc2 = (GLRC *)hglrc2;
-
-    /* check glrcs */
-    if (!ROSGL_ContainsContext( glrc1 ))
+    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)
     {
-        DBGPRINT( "Error: hglrc1 not found!" );
-        SetLastError( ERROR_INVALID_HANDLE );
+        WARN("Not a valid DC!.\n");
+        SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
-    if (!ROSGL_ContainsContext( glrc2 ))
+    
+    if(!format)
     {
-        DBGPRINT( "Error: hglrc2 not found!" );
-        SetLastError( ERROR_INVALID_HANDLE );
+        WARN("format == 0!\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
-    /* I think this is only possible within one ICD */
-    if (glrc1->icd != glrc2->icd)
+    if(dc_data->pixelformat)
     {
-        DBGPRINT( "Error: hglrc1 and hglrc2 use different ICDs!" );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return FALSE;
+        TRACE("DC format already set, %i.\n", dc_data->pixelformat);
+        return (format == dc_data->pixelformat);
     }
-
-    /* share lists (call ICD) */
-    return glrc1->icd->DrvShareLists( glrc1->hglrc, glrc2->hglrc );
-}
-
-
-/*! \brief Flushes GL and swaps front/back buffer if appropriate
- *
- * \param hdc [IN] Handle to device context to swap buffers for
- *
- * \retval TRUE  Success
- * \retval FALSE Failure
- */
-BOOL
-APIENTRY
-rosglSwapBuffers( HDC hdc )
-{
-    GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
-    DBGTRACE( "Called!" );
-    if (icd != NULL)
+    
+    if(format <= dc_data->nb_icd_formats)
     {
-        DBGPRINT( "Swapping buffers!" );
-        if (!icd->DrvSwapBuffers( hdc ))
+        TRACE("Calling ICD.\n");
+        ret = dc_data->icd_data->DrvSetPixelFormat(hdc, format);
+        if(ret)
         {
-            DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
-            return FALSE;
+            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 TRUE;
+        return ret;
     }
 
-    /* FIXME: implement own functionality? */
-    SetLastError( ERROR_INVALID_FUNCTION );
+    TRACE("Invalid pixel format!\n");
+    SetLastError(ERROR_INVALID_PARAMETER);
     return FALSE;
 }
 
-
-BOOL
-APIENTRY
-rosglSwapLayerBuffers( HDC hdc, UINT fuPlanes )
+BOOL WINAPI wglShareLists(HGLRC hglrcSrc, HGLRC hglrcDst)
 {
-    BOOL ret = FALSE;
-
-    if(fuPlanes & WGL_SWAP_MAIN_PLANE)
-        ret = rosglSwapBuffers(hdc);
-
-    if(fuPlanes &~WGL_SWAP_MAIN_PLANE)
-        DBGTRACE("wglSwapLayerBuffers is not fully implemented\n");
-
-    return ret;
+    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
-APIENTRY
-rosglUseFontBitmapsA( HDC hdc, DWORD first, DWORD count, DWORD listBase )
+BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers(HDC hdc)
 {
-    return IntUseFontBitmapsA(hdc, first, count, listBase);
+    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
-APIENTRY
-rosglUseFontBitmapsW( HDC hdc, DWORD first, DWORD count, DWORD listBase )
+BOOL WINAPI wglSwapLayerBuffers(HDC hdc, UINT fuPlanes)
 {
-    return IntUseFontBitmapsW(hdc, first, count, listBase);
+    return FALSE;
 }
 
-BOOL
-APIENTRY
-rosglUseFontOutlinesA( HDC hdc, DWORD first, DWORD count, DWORD listBase,
-                       FLOAT deviation, FLOAT extrusion, int format,
-                       GLYPHMETRICSFLOAT *pgmf )
+DWORD WINAPI wglSwapMultipleBuffers(UINT count, CONST WGLSWAP * toSwap)
 {
-    return IntUseFontOutlinesA(hdc, first, count, listBase, deviation, extrusion, format, pgmf);
+    return 0;
 }
 
-
-BOOL
-APIENTRY
-rosglUseFontOutlinesW( HDC hdc, DWORD first, DWORD count, DWORD listBase,
-                       FLOAT deviation, FLOAT extrusion, int format,
-                       GLYPHMETRICSFLOAT *pgmf )
+/* Clean up on DLL unload */
+void
+IntDeleteAllContexts(void)
 {
-    return IntUseFontOutlinesW(hdc, first, count, listBase, deviation, extrusion, format, pgmf);
-}
-
-#ifdef __cplusplus
-}; /* extern "C" */
-#endif /* __cplusplus */
+    struct wgl_context* context;
+    LIST_ENTRY* Entry = ContextListHead.Flink;
 
-/* EOF */
+    while (Entry != &ContextListHead)
+    {
+        context = CONTAINING_RECORD(Entry, struct wgl_context, ListEntry);
+        wglDeleteContext((HGLRC)context);
+        Entry = Entry->Flink;
+    }
+}