windows-nt/Source/XPSP1/NT/multimedia/opengl/client/wcreate.c

1497 lines
42 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/******************************Module*Header*******************************\
* Module Name: wcreate.c
*
* wgl Context creation routines
*
* Created: 08-27-1996
* Author: Drew Bliss [drewb]
*
* Copyright (c) 1996 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <ddrawpr.h>
#include <glscreen.h>
#include <glgenwin.h>
#include <gencx.h>
#include "metasup.h"
#include "wgldef.h"
// List of loaded GL drivers for the process.
// A driver is loaded only once per process. Once it is loaded,
// it will not be freed until the process quits.
static PGLDRIVER pGLDriverList = (PGLDRIVER) NULL;
/******************************Public*Routine******************************\
* iAllocLRC
*
* Allocates a LRC and a handle. Initializes the LDC to have the default
* attributes. Returns the handle index. On error returns INVALID_INDEX.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
static LRC lrcDefault =
{
0, // dhrc
0, // hrc
0, // iPixelFormat
LRC_IDENTIFIER, // ident
INVALID_THREAD_ID, // tidCurrent
NULL, // pGLDriver
GLWID_ERROR, NULL, NULL, NULL, // gwidCurrent
GLWID_ERROR, NULL, NULL, NULL, // gwidCreate
#ifdef GL_METAFILE
0, // uiGlsCaptureContext
0, // uiGlsPlaybackContext
FALSE, // fCapturing
0, 0, 0, 0, 0, // Metafile scaling constants
0, 0, 0, 0.0f, 0.0f,
#endif
NULL, // GLubyte *pszExtensions
#ifdef GL_METAFILE
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // XFORM xformMeta
NULL, // LPRECTL prclGlsBounds
#endif
NULL, 0, // DDraw texture formats
};
static ULONG iAllocLRC(int iPixelFormat)
{
ULONG irc = INVALID_INDEX;
PLRC plrc;
// Allocate a local RC.
plrc = (PLRC) ALLOC(sizeof(LRC));
if (plrc == (PLRC) NULL)
{
DBGERROR("Alloc failed\n");
return(irc);
}
// Initialize the local RC.
*plrc = lrcDefault;
plrc->iPixelFormat = iPixelFormat;
// Allocate a local handle.
irc = iAllocHandle(LO_RC, 0, (PVOID) plrc);
if (irc == INVALID_INDEX)
{
vFreeLRC(plrc);
return(irc);
}
return(irc);
}
/******************************Public*Routine******************************\
* vFreeLRC
*
* Free a local side RC.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Copied from gdi client.
\**************************************************************************/
VOID vFreeLRC(PLRC plrc)
{
// The driver will not be unloaded here. It is loaded for the process forever.
// Some assertions.
ASSERTOPENGL(plrc->ident == LRC_IDENTIFIER,
"vFreeLRC: Bad plrc\n");
ASSERTOPENGL(plrc->dhrc == (DHGLRC) 0,
"vFreeLRC: Driver RC is not freed!\n");
ASSERTOPENGL(plrc->tidCurrent == INVALID_THREAD_ID,
"vFreeLRC: RC is current!\n");
ASSERTOPENGL(plrc->gwidCurrent.iType == GLWID_ERROR,
"vFreeLRC: Current surface is not NULL!\n");
#ifdef GL_METAFILE
ASSERTOPENGL(plrc->uiGlsCaptureContext == 0,
"vFreeLRC: GLS capture context not freed");
ASSERTOPENGL(plrc->uiGlsPlaybackContext == 0,
"vFreeLRC: GLS playback context not freed");
ASSERTOPENGL(plrc->fCapturing == FALSE,
"vFreeLRC: GLS still capturing");
#endif
// Smash the identifier.
plrc->ident = 0;
// Free the memory.
if (plrc->pszExtensions)
FREE(plrc->pszExtensions);
if (plrc->pddsdTexFormats != NULL)
{
FREE(plrc->pddsdTexFormats);
}
FREE(plrc);
}
/******************************Public*Routine******************************\
* vCleanupAllLRC
*
* Process cleanup -- make sure all HGLRCs are deleted. This is done by
* scanning the local handle table for all currently allocated objects
* of type LO_RC and deleting them.
*
* Called *ONLY* during DLL process detach.
*
* History:
* 24-Jul-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID vCleanupAllLRC()
{
UINT ii;
if ( pLocalTable )
{
ENTERCRITICALSECTION(&semLocal);
// Scan handle table for handles of type LO_RC. Make sure to always
// read the commit value since we need to periodically release the
// semaphore.
for (ii = 0; ii < *((volatile ULONG *)&cLheCommitted); ii++)
{
if ( pLocalTable[ii].iType == LO_RC )
{
if ( !wglDeleteContext((HGLRC) ULongToPtr(LHANDLE(ii))) )
{
WARNING1("bCleanupAllLRC: failed to remove hrc = 0x%lx\n",
LHANDLE(ii));
}
}
}
LEAVECRITICALSECTION(&semLocal);
}
}
/******************************Public*Routine******************************\
*
* GetDrvRegInfo
*
* Looks up driver registry information by name.
* An old-style ICD registry entry has a REG_SZ value under the given name.
* A new-style ICD registry entry has a key of the given name with
* various values.
*
* This routine checks first for a key and then will optionally
* try the value. If a key is not found then extended driver information
* is filled out with the defaults.
*
* History:
* Tue Apr 01 17:33:12 1997 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
typedef struct _GLDRVINFO
{
DWORD dwFlags;
TCHAR tszDllName[MAX_GLDRIVER_NAME+1];
DWORD dwVersion;
DWORD dwDriverVersion;
} GLDRVINFO;
#ifdef _WIN95_
#define STR_OPENGL_DRIVER_LIST (PCSTR)"Software\\Microsoft\\Windows\\CurrentVersion\\OpenGLDrivers"
#else
#define STR_OPENGL_DRIVER_LIST (PCWSTR)L"Software\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers"
#endif
BOOL GetDrvRegInfo(PTCHAR ptszName, GLDRVINFO *pgdi)
{
HKEY hkDriverList = NULL;
HKEY hkDriverInfo;
DWORD dwDataType;
DWORD cjSize;
BOOL bRet;
bRet = FALSE;
// Open the registry key for the list of OpenGL drivers.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, STR_OPENGL_DRIVER_LIST,
0, KEY_READ, &hkDriverList) != ERROR_SUCCESS)
{
WARNING("RegOpenKeyEx failed\n");
return bRet;
}
// Force a terminator on the DLL name so that we can check for
// valid DLL name data.
pgdi->tszDllName[MAX_GLDRIVER_NAME] = 0;
cjSize = sizeof(TCHAR) * MAX_GLDRIVER_NAME;
// Attempt to open a key under the driver's name.
if (RegOpenKeyEx(hkDriverList, ptszName, 0, KEY_READ,
&hkDriverInfo) == ERROR_SUCCESS)
{
// New-style driver entry. Fetch information from values.
bRet = TRUE;
if (RegQueryValueEx(hkDriverInfo, __TEXT("DLL"), NULL, &dwDataType,
(LPBYTE)pgdi->tszDllName,
&cjSize) != ERROR_SUCCESS ||
dwDataType != REG_SZ)
{
WARNING("Invalid DLL value in ICD key\n");
bRet = FALSE;
}
cjSize = sizeof(DWORD);
if (bRet &&
(RegQueryValueEx(hkDriverInfo, __TEXT("Flags"), NULL, &dwDataType,
(LPBYTE)&pgdi->dwFlags,
&cjSize) != ERROR_SUCCESS ||
dwDataType != REG_DWORD))
{
WARNING("Invalid Flags value in ICD key\n");
bRet = FALSE;
}
if (bRet &&
(RegQueryValueEx(hkDriverInfo, __TEXT("Version"), NULL,
&dwDataType, (LPBYTE)&pgdi->dwVersion,
&cjSize) != ERROR_SUCCESS ||
dwDataType != REG_DWORD))
{
WARNING("Invalid Version value in ICD key\n");
bRet = FALSE;
}
if (bRet &&
(RegQueryValueEx(hkDriverInfo, __TEXT("DriverVersion"), NULL,
&dwDataType, (LPBYTE)&pgdi->dwDriverVersion,
&cjSize) != ERROR_SUCCESS ||
dwDataType != REG_DWORD))
{
WARNING("Invalid DriverVersion value in ICD key\n");
bRet = FALSE;
}
// Mark as having full information.
pgdi->dwFlags |= GLDRIVER_FULL_REGISTRY;
RegCloseKey(hkDriverInfo);
}
else
{
// Attempt to fetch value under driver's name.
if (RegQueryValueEx(hkDriverList, ptszName, NULL, &dwDataType,
(LPBYTE)pgdi->tszDllName,
&cjSize) != ERROR_SUCCESS ||
dwDataType != REG_SZ)
{
WARNING1("RegQueryValueEx failed, %d\n", GetLastError());
}
else
{
// We found old-style information which only provides the
// DLL name. Fill in the rest with defaults.
//
// Version and DriverVersion are not set here under the
// assumption that the display driver set them in the
// OPENGL_GETINFO escape since the old-style path requires
// the escape to occur before getting here.
pgdi->dwFlags = 0;
bRet = TRUE;
}
}
RegCloseKey(hkDriverList);
// Validate the driver name. It must have some characters and
// it must be terminated.
if (bRet &&
(pgdi->tszDllName[0] == 0 ||
pgdi->tszDllName[MAX_GLDRIVER_NAME] != 0))
{
WARNING("Invalid DLL name information for ICD\n");
bRet = FALSE;
}
#ifdef _WIN95_
// Force client-side buffer calls for Win95.
pgdi->dwFlags |= GLDRIVER_CLIENT_BUFFER_CALLS;
#endif
return bRet;
}
/******************************Public*Routine******************************\
* bGetDriverInfo
*
* The HDC is used to determine the display driver name. This name in turn
* is used as a subkey to search the registry for a corresponding OpenGL
* driver name.
*
* The OpenGL driver name is returned in the buffer pointed to by pwszDriver.
* If the name is not found or does not fit in the buffer, an error is
* returned.
*
* Returns:
* TRUE if sucessful.
* FALSE if the driver name does not fit in the buffer or if an error occurs.
*
* History:
* 16-Jan-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL bGetDriverInfo(HDC hdc, GLDRVINFO *pgdi)
{
GLDRVNAME dn;
GLDRVNAMERET dnRet;
// Get display driver name.
dn.oglget.ulSubEsc = OPENGL_GETINFO_DRVNAME;
if ( ExtEscape(hdc, OPENGL_GETINFO, sizeof(GLDRVNAME), (LPCSTR) &dn,
sizeof(GLDRVNAMERET), (LPSTR) &dnRet) <= 0 )
{
WARNING("ExtEscape(OPENGL_GETINFO, "
"OPENGL_GETINFO_DRVNAME) failed\n");
return FALSE;
}
pgdi->dwVersion = dnRet.ulVersion;
pgdi->dwDriverVersion = dnRet.ulDriverVersion;
if (GetDrvRegInfo((PTCHAR)dnRet.awch, pgdi))
{
// Verify that the client-side driver version information
// matches the information returned from the display driver.
// Is this too restrictive? Old scheme used
// DrvValidateVersion to allow the client-side DLL to validate
// the display driver's version however it felt like.
// In the new scheme DrvValidateVersion is mostly useless because
// of the below code.
return pgdi->dwVersion == dnRet.ulVersion &&
pgdi->dwDriverVersion == dnRet.ulDriverVersion;
}
else
{
return FALSE;
}
}
/*****************************Private*Routine******************************\
*
* wglCbSetCurrentValue
*
* Sets a thread-local value for a client-side driver
*
* History:
* Wed Dec 21 15:10:40 1994 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void APIENTRY wglCbSetCurrentValue(VOID *pv)
{
GLTEB_SET_CLTDRIVERSLOT(pv);
}
/*****************************Private*Routine******************************\
*
* wglCbGetCurrentValue
*
* Gets a thread-local value for a client-side driver
*
* History:
* Wed Dec 21 15:11:32 1994 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
PVOID APIENTRY wglCbGetCurrentValue(void)
{
return GLTEB_CLTDRIVERSLOT();
}
/******************************Public*Routine******************************\
*
* wglCbGetDhglrc
*
* Translates an HGLRC to a DHGLRC for a client-side driver
*
* History:
* Mon Jan 16 17:03:38 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DHGLRC APIENTRY wglCbGetDhglrc(HGLRC hrc)
{
PLRC plrc;
ULONG irc;
PLHE plheRC;
irc = MASKINDEX(hrc);
plheRC = pLocalTable + irc;
if ((irc >= cLheCommitted) ||
(!MATCHUNIQ(plheRC, hrc)) ||
((plheRC->iType != LO_RC))
)
{
DBGLEVEL1(LEVEL_ERROR, "wglCbGetDhglrc: invalid hrc 0x%lx\n", hrc);
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
plrc = (PLRC)plheRC->pv;
ASSERTOPENGL(plrc->ident == LRC_IDENTIFIER,
"wglCbGetDhglrc: Bad plrc\n");
return plrc->dhrc;
}
/******************************Public*Routine******************************\
*
* wglCbGetDdHandle
*
* Callback to allow ICDs to extract kernel-mode handles for DDraw surfaces
*
* History:
* Tue Feb 25 17:14:29 1997 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
HANDLE APIENTRY wglCbGetDdHandle(LPDIRECTDRAWSURFACE pdds)
{
return (HANDLE)(((LPDDRAWI_DDRAWSURFACE_INT)pdds)->lpLcl)->hDDSurface;
}
// wgl's default callback procedures
#define CALLBACK_PROC_COUNT 4
static PROC __wglCallbackProcs[CALLBACK_PROC_COUNT] =
{
(PROC)wglCbSetCurrentValue,
(PROC)wglCbGetCurrentValue,
(PROC)wglCbGetDhglrc,
(PROC)wglCbGetDdHandle
};
static char *pszDriverEntryPoints[] =
{
"DrvCreateContext",
"DrvDeleteContext",
"DrvSetContext",
"DrvReleaseContext",
"DrvCopyContext",
"DrvCreateLayerContext",
"DrvShareLists",
"DrvGetProcAddress",
"DrvDescribeLayerPlane",
"DrvSetLayerPaletteEntries",
"DrvGetLayerPaletteEntries",
"DrvRealizeLayerPalette",
"DrvSwapLayerBuffers",
"DrvCreateDirectDrawContext",
"DrvEnumTextureFormats",
"DrvBindDirectDrawTexture",
"DrvSwapMultipleBuffers",
"DrvDescribePixelFormat",
"DrvSetPixelFormat",
"DrvSwapBuffers"
};
#define DRIVER_ENTRY_POINTS (sizeof(pszDriverEntryPoints)/sizeof(char *))
/******************************Public*Routine******************************\
* pgldrvLoadInstalledDriver
*
* Loads the opengl driver for the given device. Once the driver is loaded,
* it will not be freed until the process goes away! It is loaded only once
* for each process that references it.
*
* Returns the GLDRIVER structure if the driver is loaded.
* Returns NULL if no driver is found or an error occurs.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Rewrote it.
\**************************************************************************/
PGLDRIVER APIENTRY pgldrvLoadInstalledDriver(HDC hdc)
{
GLDRVINFO gdi;
PGLDRIVER pGLDriverNext;
PGLDRIVER pGLDriver = (PGLDRIVER) NULL; // needed by clean up
PGLDRIVER pGLDriverRet = (PGLDRIVER) NULL; // return value, assume error
PFN_DRVVALIDATEVERSION pfnDrvValidateVersion = (PFN_DRVVALIDATEVERSION) NULL;
PFN_DRVSETCALLBACKPROCS pfnDrvSetCallbackProcs;
DWORD dwEscape;
int i;
PROC *pproc;
GLGENwindow *pwnd;
GLWINDOWID gwid;
DBGENTRY("pgldrvLoadInstalledDriver\n");
// Try to grab the cached pgldrv from the GLGENwindow if it exists.
// This only works for DCs that have a window with a device pixel format.
WindowIdFromHdc(hdc, &gwid);
pwnd = pwndGetFromID(&gwid);
if (pwnd)
{
ULONG ulFlags;
ulFlags = pwnd->ulFlags;
pGLDriverRet = (PGLDRIVER) pwnd->pvDriver;
pwndRelease(pwnd);
if ( ulFlags & GLGENWIN_DRIVERSET )
{
return pGLDriverRet;
}
}
// Do a quick check and see if this driver even understands OpenGL
dwEscape = OPENGL_GETINFO;
if (ExtEscape(hdc, QUERYESCSUPPORT, sizeof(dwEscape), (LPCSTR)&dwEscape,
0, NULL) <= 0)
{
// Don't output a message since this code path is traversed often
// for the pixel format routines.
#ifdef CHECK_DEFAULT_ICD
// The display driver doesn't support a specific ICD. Check
// for a default ICD. It must have full registry information.
if (!GetDrvRegInfo(__TEXT("Default"), &gdi) ||
(gdi.dwFlags & GLDRIVER_FULL_REGISTRY) == 0)
{
return NULL;
}
#else
return NULL;
#endif
}
// Determine driver info from hdc
else if ( !bGetDriverInfo(hdc, &gdi) )
{
WARNING("bGetDriverInfo failed\n");
return NULL;
}
// Load the driver only once per process.
ENTERCRITICALSECTION(&semLocal);
// Look for the OpenGL driver in the previously loaded driver list.
for (pGLDriverNext = pGLDriverList;
pGLDriverNext != (PGLDRIVER) NULL;
pGLDriverNext = pGLDriverNext->pGLDriver)
{
PTCHAR ptszDllName1 = pGLDriverNext->tszDllName;
PTCHAR ptszDllName2 = gdi.tszDllName;
while (*ptszDllName1 == *ptszDllName2)
{
// If we find one, return that driver.
if (*ptszDllName1 == 0)
{
DBGINFO("pgldrvLoadInstalledDriver: "
"return previously loaded driver\n");
pGLDriverRet = pGLDriverNext; // found one
goto pgldrvLoadInstalledDriver_crit_exit;
}
ptszDllName1++;
ptszDllName2++;
}
}
// Load the driver for the first time.
// Allocate the driver data.
pGLDriver = (PGLDRIVER) ALLOC(sizeof(GLDRIVER));
if (pGLDriver == (PGLDRIVER) NULL)
{
WARNING("Alloc failed\n");
goto pgldrvLoadInstalledDriver_crit_exit; // error
}
// Load the driver.
pGLDriver->hModule = LoadLibrary(gdi.tszDllName);
if (pGLDriver->hModule == (HINSTANCE) NULL)
{
WARNING("pgldrvLoadInstalledDriver: LoadLibrary failed\n");
goto pgldrvLoadInstalledDriver_crit_exit; // error
}
// Copy the driver info.
memcpy
(
pGLDriver->tszDllName,
gdi.tszDllName,
(MAX_GLDRIVER_NAME + 1) * sizeof(TCHAR)
);
pGLDriver->dwFlags = gdi.dwFlags;
// Get the proc addresses.
// DrvGetProcAddress is optional. It must be provided if a driver supports
// extensions.
pfnDrvValidateVersion = (PFN_DRVVALIDATEVERSION)
GetProcAddress(pGLDriver->hModule, "DrvValidateVersion");
pfnDrvSetCallbackProcs = (PFN_DRVSETCALLBACKPROCS)
GetProcAddress(pGLDriver->hModule, "DrvSetCallbackProcs");
pproc = (PROC *)&pGLDriver->pfnDrvCreateContext;
for (i = 0; i < DRIVER_ENTRY_POINTS; i++)
{
*pproc++ =
GetProcAddress(pGLDriver->hModule, pszDriverEntryPoints[i]);
}
if ((pGLDriver->pfnDrvCreateContext == NULL &&
pGLDriver->pfnDrvCreateLayerContext == NULL) ||
pGLDriver->pfnDrvDeleteContext == NULL ||
pGLDriver->pfnDrvSetContext == NULL ||
pGLDriver->pfnDrvReleaseContext == NULL ||
((gdi.dwFlags & GLDRIVER_CLIENT_BUFFER_CALLS) &&
(pGLDriver->pfnDrvDescribePixelFormat == NULL ||
pGLDriver->pfnDrvSetPixelFormat == NULL ||
pGLDriver->pfnDrvSwapBuffers == NULL)) ||
pfnDrvValidateVersion == NULL)
{
WARNING("pgldrvLoadInstalledDriver: GetProcAddress failed\n");
goto pgldrvLoadInstalledDriver_crit_exit; // error
}
// Validate the driver.
//!!!XXX -- Need to define a manifest constant for the ulVersion number
// in this release. Where should it go?
if ( gdi.dwVersion != 2 || !pfnDrvValidateVersion(gdi.dwDriverVersion) )
{
WARNING2("pgldrvLoadInstalledDriver: bad driver version "
"(0x%lx, 0x%lx)\n", gdi.dwVersion, gdi.dwDriverVersion);
goto pgldrvLoadInstalledDriver_crit_exit; // error
}
// Everything is golden.
// Add it to the driver list.
pGLDriver->pGLDriver = pGLDriverList;
pGLDriverList = pGLDriver;
pGLDriverRet = pGLDriver; // set return value
DBGINFO("pgldrvLoadInstalledDriver: Loaded an OpenGL driver\n");
// Set the callback procs for the driver if the driver supports doing so
if (pfnDrvSetCallbackProcs != NULL)
{
pfnDrvSetCallbackProcs(CALLBACK_PROC_COUNT, __wglCallbackProcs);
}
// Error clean up in the critical section.
pgldrvLoadInstalledDriver_crit_exit:
if (pGLDriverRet == (PGLDRIVER) NULL)
{
if (pGLDriver != (PGLDRIVER) NULL)
{
if (pGLDriver->hModule != (HINSTANCE) NULL)
if (!FreeLibrary(pGLDriver->hModule))
RIP("FreeLibrary failed\n");
FREE(pGLDriver);
}
}
LEAVECRITICALSECTION(&semLocal);
return(pGLDriverRet);
}
/******************************Public*Routine******************************\
*
* CreateAnyContext
*
* Base worker function for creating all kinds of contexts
*
* History:
* Mon Aug 26 14:41:31 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
HGLRC CreateAnyContext(GLSURF *pgsurf)
{
PLHE plheRC;
ULONG irc;
HGLRC hrc;
PLRC plrc;
#ifndef _WIN95_
// _OPENGL_NT_
// On NT, client-side drivers can use special fast TEB access macros
// which rely on glContext being at a fixed offset into the
// TEB. Assert that the offset is where we think it is
// to catch any TEB changes which could break client-side
// drivers
// This assert is here in wglCreateContext to ensure that it
// is checked very early in OpenGL operation
ASSERTOPENGL(FIELD_OFFSET(TEB, glContext) == TeglContext,
"TEB.glContext at wrong offset\n");
ASSERTOPENGL(FIELD_OFFSET(TEB, glDispatchTable) == TeglDispatchTable,
"TEB.glDispatchTable at wrong offset\n");
ASSERTOPENGL(FIELD_OFFSET(TEB, glReserved1) == TeglReserved1,
"TEB.glReserved1 at wrong offset\n");
#if !defined(_WIN64)
ASSERTOPENGL(FIELD_OFFSET(TEB, glReserved1)+(18 * sizeof(ULONG_PTR)) == TeglPaTeb,
"TEB.glPaTeb at wrong offset\n");
#endif
ASSERTOPENGL(FIELD_OFFSET(TEB, glReserved2) == TeglReserved2,
"TEB.glReserved2 at wrong offset\n");
ASSERTOPENGL(FIELD_OFFSET(TEB, glSectionInfo) == TeglSectionInfo,
"TEB.glSectionInfo at wrong offset\n");
ASSERTOPENGL(FIELD_OFFSET(TEB, glSection) == TeglSection,
"TEB.glSection at wrong offset\n");
ASSERTOPENGL(FIELD_OFFSET(TEB, glTable) == TeglTable,
"TEB.glTable at wrong offset\n");
ASSERTOPENGL(FIELD_OFFSET(TEB, glCurrentRC) == TeglCurrentRC,
"TEB.glCurrentRC at wrong offset\n");
#endif
// Create the local RC.
ENTERCRITICALSECTION(&semLocal);
irc = iAllocLRC(pgsurf->ipfd);
if (irc == INVALID_INDEX ||
cLockHandle((ULONG_PTR)(hrc = (HGLRC) ULongToPtr(LHANDLE(irc)))) <= 0)
{
// cLockHandle should never fail or we will need to free the handle.
ASSERTOPENGL(irc == INVALID_INDEX, "cLockHandle should not fail!\n");
LEAVECRITICALSECTION(&semLocal);
return((HGLRC) 0);
}
LEAVECRITICALSECTION(&semLocal);
plheRC = &pLocalTable[irc];
plrc = (PLRC) plheRC->pv;
// Remember the creation DC. This needs to be done early because
// it is referenced in some code paths.
plrc->gwidCreate.hdc = pgsurf->hdc;
if (pgsurf->dwFlags & GLSURF_HDC)
{
plrc->gwidCreate.hwnd = pgsurf->hwnd;
if (plrc->gwidCreate.hwnd == NULL)
{
plrc->gwidCreate.iType = GLWID_HDC;
}
else
{
plrc->gwidCreate.iType = GLWID_HWND;
}
plrc->gwidCreate.pdds = NULL;
}
else
{
plrc->gwidCreate.iType = GLWID_DDRAW;
plrc->gwidCreate.pdds = pgsurf->dd.gddsFront.pdds;
plrc->gwidCreate.hwnd = NULL;
}
if (!(pgsurf->pfd.dwFlags & PFD_GENERIC_FORMAT) &&
!(pgsurf->pfd.dwFlags & PFD_GENERIC_ACCELERATED))
{
// If it is a device format, load the installable OpenGL driver.
// Find and load the OpenGL driver referenced by this DC.
if (!(plrc->pGLDriver = pgldrvLoadInstalledDriver(pgsurf->hdc)))
goto wglCreateContext_error;
// Create a driver context.
// If the surface is a DirectDraw surface use the DirectDraw
// entry point
if (pgsurf->dwFlags & GLSURF_DIRECTDRAW)
{
if (plrc->pGLDriver->pfnDrvCreateDirectDrawContext == NULL)
{
SetLastError(ERROR_INVALID_FUNCTION);
goto wglCreateContext_error;
}
plrc->dhrc = plrc->pGLDriver->pfnDrvCreateDirectDrawContext(
pgsurf->hdc, pgsurf->dd.gddsFront.pdds, pgsurf->ipfd);
if (plrc->dhrc == 0)
{
WARNING("wglCreateContext: "
"pfnDrvCreateDirectDrawContext failed\n");
goto wglCreateContext_error;
}
}
// If the driver supports layers then create a context for the
// given layer. Otherwise reject all layers except for the
// main plane and call the layer-less create
else if (plrc->pGLDriver->pfnDrvCreateLayerContext != NULL)
{
if (!(plrc->dhrc =
plrc->pGLDriver->pfnDrvCreateLayerContext(pgsurf->hdc,
pgsurf->iLayer)))
{
WARNING("wglCreateContext: pfnDrvCreateLayerContext failed\n");
goto wglCreateContext_error;
}
}
else if (pgsurf->iLayer != 0)
{
WARNING("wglCreateContext: "
"Layer given for driver without layer support\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglCreateContext_error;
}
else if (!(plrc->dhrc =
plrc->pGLDriver->pfnDrvCreateContext(pgsurf->hdc)))
{
WARNING("wglCreateContext: pfnDrvCreateContext failed\n");
goto wglCreateContext_error;
}
}
else
{
GLCLTPROCTABLE *pgcpt;
GLEXTPROCTABLE *pgept;
__GLcontext *gc;
// Unless supported by MCD, the generic implementation doesn't
// support layers
if ((pgsurf->iLayer != 0) &&
!(pgsurf->pfd.dwFlags & PFD_GENERIC_ACCELERATED))
{
WARNING("wglCreateContext: Layer given to generic\n");
goto wglCreateContext_error;
}
#ifdef GL_METAFILE
// Create a metafile context if necessary
if (pgsurf->dwFlags & GLSURF_METAFILE)
{
if (!CreateMetaRc(pgsurf->hdc, plrc))
{
WARNING("wglCreateContext: CreateMetaRc failed\n");
goto wglCreateContext_error;
}
}
#endif
// If it is a generic format, call the generic OpenGL server.
// Create a server RC.
plheRC->hgre = (ULONG_PTR) __wglCreateContext(&plrc->gwidCreate, pgsurf);
if (plheRC->hgre == 0)
goto wglCreateContext_error;
// Set up the default dispatch tables for display list playback
gc = (__GLcontext *)plheRC->hgre;
if (gc->modes.colorIndexMode)
pgcpt = &glCltCIProcTable;
else
pgcpt = &glCltRGBAProcTable;
pgept = &glExtProcTable;
memcpy(&gc->savedCltProcTable.glDispatchTable, &pgcpt->glDispatchTable,
pgcpt->cEntries*sizeof(PROC));
memcpy(&gc->savedExtProcTable.glDispatchTable, &pgept->glDispatchTable,
pgept->cEntries*sizeof(PROC));
}
DBGLEVEL3(LEVEL_INFO,
"wglCreateContext: plrc = 0x%lx, pGLDriver = 0x%lx, hgre = 0x%lx\n",
plrc, plrc->pGLDriver, plheRC->hgre);
// Success, return the result.
plrc->hrc = hrc;
vUnlockHandle((ULONG_PTR)hrc);
return hrc;
wglCreateContext_error:
// Fail, clean up and return 0.
#ifdef GL_METAFILE
// Clean up metafile context if necessary
if (plrc->uiGlsCaptureContext != 0)
{
DeleteMetaRc(plrc);
}
#endif
DBGERROR("wglCreateContext failed\n");
ASSERTOPENGL(plrc->dhrc == (DHGLRC) 0, "wglCreateContext: dhrc != 0\n");
vFreeLRC(plrc);
vFreeHandle(irc); // it unlocks handle too
return NULL;
}
/******************************Public*Routine******************************\
*
* CreateMetafileSurf
*
* Fills out a GLSURF for a metafile DC
*
* History:
* Tue Aug 27 11:41:35 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#ifdef GL_METAFILE
void CreateMetafileSurf(HDC hdc, int iLayer, GLSURF *pgsurf)
{
pgsurf->dwFlags = GLSURF_HDC | GLSURF_METAFILE;
pgsurf->iLayer = iLayer;
// Metafile surfaces don't have a real pixel format
pgsurf->ipfd = 0;
// Create a fake format of 24-bit DIB with BGR
memset(&pgsurf->pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pgsurf->pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pgsurf->pfd.nVersion = 1;
pgsurf->pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL |
PFD_GENERIC_FORMAT;
pgsurf->pfd.iPixelType = PFD_TYPE_RGBA;
pgsurf->pfd.cColorBits = 24;
pgsurf->pfd.cStencilBits = 8;
pgsurf->pfd.cRedBits = 8;
pgsurf->pfd.cRedShift = 16;
pgsurf->pfd.cGreenBits = 8;
pgsurf->pfd.cGreenShift = 8;
pgsurf->pfd.cBlueBits = 8;
pgsurf->pfd.cBlueShift = 0;
pgsurf->pfd.cDepthBits = 16;
pgsurf->pfd.iLayerType = PFD_MAIN_PLANE;
pgsurf->hdc = hdc;
}
#endif
/******************************Public*Routine******************************\
* wglSurfacePixelFormat
*
* wglDescribePixelFormat doesn't describe the format of the surface we want
* to render into. Some fields need to be fixed up if the surface is RGB,
* BGR, or BITFIELDS.
*
* Expects a Describe'd pixel format as input
*
\**************************************************************************/
VOID APIENTRY wglSurfacePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR *ppfd)
{
HBITMAP hbm;
BITMAP bm;
ULONG cBitmapColorBits;
hbm = CreateCompatibleBitmap(hdc, 1, 1);
if ( hbm )
{
if ( GetObject(hbm, sizeof(bm), &bm) )
{
cBitmapColorBits = bm.bmPlanes * bm.bmBitsPixel;
#if DBG
// If dynamic color depth caused depth mismatch one of two
// things will happen: 1) bitmap creation will fail because
// we failed to fill in color format, or 2) drawing will
// be incorrect. We will not crash.
if (cBitmapColorBits != ppfd->cColorBits)
WARNING("pixel format/surface color depth mismatch\n");
#endif
if ( cBitmapColorBits >= 16 )
__wglGetBitfieldColorFormat(hdc, cBitmapColorBits, ppfd,
TRUE);
}
else
{
WARNING("wglSurfacePixelFormat: GetObject failed\n");
}
DeleteObject(hbm);
}
else
{
WARNING("wglSurfacePixelFormat: Unable to create cbm\n");
}
}
/******************************Public*Routine******************************\
* bLayerPixelFormat
*
* Fake up a pixel format using the layer descriptor format.
*
* We use this to describe the layer plane in a format that the generic
* context can understand.
*
* Expects a Describe'd pixel format as input for the flags
*
\**************************************************************************/
BOOL FASTCALL bLayerPixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR *ppfd,
int ipfd, LONG iLayer)
{
LAYERPLANEDESCRIPTOR lpd;
if (!wglDescribeLayerPlane(hdc, ipfd, iLayer, sizeof(lpd), &lpd))
return FALSE;
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
ppfd->dwFlags = (ppfd->dwFlags & (PFD_GENERIC_FORMAT |
PFD_GENERIC_ACCELERATED)) |
(lpd.dwFlags & ~(LPD_SHARE_DEPTH | LPD_SHARE_STENCIL |
LPD_SHARE_ACCUM | LPD_TRANSPARENT));
ppfd->iPixelType = lpd.iPixelType;
ppfd->cColorBits = lpd.cColorBits;
ppfd->cRedBits = lpd.cRedBits ;
ppfd->cRedShift = lpd.cRedShift ;
ppfd->cGreenBits = lpd.cGreenBits ;
ppfd->cGreenShift = lpd.cGreenShift;
ppfd->cBlueBits = lpd.cBlueBits ;
ppfd->cBlueShift = lpd.cBlueShift ;
ppfd->cAlphaBits = lpd.cAlphaBits ;
ppfd->cAlphaShift = lpd.cAlphaShift;
if (!(lpd.dwFlags & LPD_SHARE_ACCUM))
{
ppfd->cAccumBits = 0;
ppfd->cAccumRedBits = 0;
ppfd->cAccumGreenBits = 0;
ppfd->cAccumBlueBits = 0;
ppfd->cAccumAlphaBits = 0;
}
if (!(lpd.dwFlags & LPD_SHARE_DEPTH))
{
ppfd->cDepthBits = 0;
}
if (!(lpd.dwFlags & LPD_SHARE_STENCIL))
{
ppfd->cStencilBits = 0;
}
ppfd->cAuxBuffers = 0;
return TRUE;
}
/******************************Public*Routine******************************\
*
* IsDirectDrawDevice
*
* Returns surface associated with HDC if such an association exists
*
* History:
* Wed Sep 25 13:18:02 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL APIENTRY IsDirectDrawDevice(HDC hdc)
{
LPDIRECTDRAWSURFACE pdds;
HDC hdcDevice;
if (pfnGetSurfaceFromDC != NULL &&
pfnGetSurfaceFromDC(hdc, &pdds, &hdcDevice) == DD_OK)
{
// The call gave us a reference on the surface so release it.
pdds->lpVtbl->Release(pdds);
return TRUE;
}
else
{
return FALSE;
}
}
/******************************Public*Routine******************************\
*
* DdPixelDepth
*
* Determines the number of bits per pixel for a surface.
*
* History:
* Wed Nov 20 16:57:07 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BYTE APIENTRY DdPixelDepth(DDSURFACEDESC *pddsd)
{
if (pddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4)
{
return 4;
}
else if (pddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
{
return 8;
}
else
{
return (BYTE)DdPixDepthToCount(pddsd->ddpfPixelFormat.dwRGBBitCount);
}
}
/******************************Public*Routine******************************\
*
* wglIsDirectDevice
*
* Checks to see whether the given DC is a screen DC on the
* surface for which we have direct screen access
*
* History:
* Fri Apr 19 15:17:30 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL APIENTRY wglIsDirectDevice(HDC hdc)
{
if (wglObjectType(hdc) != OBJ_DC)
{
return FALSE;
}
// What about multiple displays?
return GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY;
}
/******************************Public*Routine******************************\
*
* InitDeviceSurface
*
* Fills out a GLSURF for an HDC-based surface
*
* History:
* Tue Aug 27 19:22:38 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL APIENTRY InitDeviceSurface(HDC hdc, int ipfd, int iLayer,
DWORD dwObjectType, BOOL bUpdatePfd,
GLSURF *pgsurf)
{
pgsurf->dwFlags = GLSURF_HDC;
pgsurf->iLayer = iLayer;
pgsurf->ipfd = ipfd;
pgsurf->hdc = hdc;
pgsurf->hwnd = NULL;
// Determine whether direct memory access is available for this surface
// or not. The two cases are:
// It's a screen surface and we have direct screen access
// It's a DIBSECTION memory surface
if (dwObjectType == OBJ_DC)
{
pgsurf->dwFlags |= GLSURF_DIRECTDC;
if (wglIsDirectDevice(hdc))
{
pgsurf->dwFlags |= GLSURF_SCREEN | GLSURF_VIDEO_MEMORY;
pgsurf->hwnd = WindowFromDC(hdc);
if (GLDIRECTSCREEN)
{
pgsurf->dwFlags |= GLSURF_DIRECT_ACCESS;
}
}
}
else if (dwObjectType == OBJ_MEMDC)
{
DIBSECTION ds;
if (GetObject(GetCurrentObject(hdc, OBJ_BITMAP), sizeof(ds), &ds) ==
sizeof(ds) && ds.dsBm.bmBits != NULL)
{
pgsurf->dwFlags |= GLSURF_DIRECT_ACCESS;
}
if (bUpdatePfd)
{
// Update pixel format with true surface information rather
// than device information
wglSurfacePixelFormat(hdc, &pgsurf->pfd);
}
}
if (bUpdatePfd &&
iLayer > 0 &&
!bLayerPixelFormat(hdc, &pgsurf->pfd, ipfd, iLayer))
{
return FALSE;
}
return TRUE;
}
/******************************Public*Routine******************************\
*
* InitDdSurface
*
* Completes a GLSURF for a DirectDraw-based surface.
* Pixel format information should already be filled in.
*
* History:
* Mon Aug 26 13:50:04 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL InitDdSurface(LPDIRECTDRAWSURFACE pdds, HDC hdcDevice, GLSURF *pgsurf)
{
DDSCAPS ddscaps;
LPDIRECTDRAWSURFACE pddsZ;
DDSURFACEDESC *pddsd;
pgsurf->hdc = hdcDevice;
pgsurf->dd.gddsFront.ddsd.dwSize = sizeof(DDSURFACEDESC);
pgsurf->dd.gddsZ.ddsd.dwSize = sizeof(DDSURFACEDESC);
pddsd = &pgsurf->dd.gddsFront.ddsd;
if (pdds->lpVtbl->GetSurfaceDesc(pdds, pddsd) != DD_OK)
{
return FALSE;
}
pgsurf->dwFlags = GLSURF_DIRECTDRAW | GLSURF_DIRECT_ACCESS;
pgsurf->iLayer = 0;
// Check for an attached Z buffer
memset(&ddscaps, 0, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_ZBUFFER;
pddsd = &pgsurf->dd.gddsZ.ddsd;
if (pdds->lpVtbl->GetAttachedSurface(pdds, &ddscaps, &pddsZ) == DD_OK)
{
if (pddsZ->lpVtbl->GetSurfaceDesc(pddsZ, pddsd) != DD_OK)
{
pddsZ->lpVtbl->Release(pddsZ);
return FALSE;
}
}
else
{
memset(&pgsurf->dd.gddsZ, 0, sizeof(pgsurf->dd.gddsZ));
}
// If both the color buffer and the Z buffer are in video memory
// then hardware acceleration is possible
if ((pgsurf->dd.gddsFront.ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
(pddsZ == NULL ||
(pgsurf->dd.gddsZ.ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)))
{
pgsurf->dwFlags |= GLSURF_VIDEO_MEMORY;
}
pgsurf->dd.gddsFront.pdds = pdds;
pgsurf->dd.gddsFront.dwBitDepth =
DdPixDepthToCount(pgsurf->dd.gddsFront.
ddsd.ddpfPixelFormat.dwRGBBitCount);
// GetAttachedSurface gave us a reference to the Z buffer
pgsurf->dd.gddsZ.pdds = pddsZ;
pgsurf->dd.gddsZ.dwBitDepth =
DdPixDepthToCount(pgsurf->dd.gddsZ.
ddsd.ddpfPixelFormat.dwZBufferBitDepth);
return TRUE;
}
/******************************Public*Routine******************************\
* wglCreateLayerContext(HDC hdc, int iLayer)
*
* Create a rendering context for a specific layer
*
* Arguments:
* hdc - Device context.
* iLayer - Layer
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Rewrote it.
\**************************************************************************/
HGLRC WINAPI wglCreateLayerContext(HDC hdc, int iLayer)
{
DWORD dwObjectType;
GLSURF gsurf;
LPDIRECTDRAWSURFACE pdds;
HDC hdcDevice;
HGLRC hrc;
DBGENTRY("wglCreateLayerContext\n");
// Flush OpenGL calls.
GLFLUSH();
// Validate the DC.
dwObjectType = wglObjectType(hdc);
switch (dwObjectType)
{
case OBJ_DC:
case OBJ_MEMDC:
break;
case OBJ_ENHMETADC:
#ifdef GL_METAFILE
if (pfnGdiAddGlsRecord == NULL)
{
DBGLEVEL1(LEVEL_ERROR, "wglCreateContext: metafile hdc: 0x%lx\n",
hdc);
SetLastError(ERROR_INVALID_HANDLE);
return((HGLRC) 0);
}
break;
#else
DBGLEVEL1(LEVEL_ERROR, "wglCreateContext: metafile hdc: 0x%lx\n", hdc);
SetLastError(ERROR_INVALID_HANDLE);
return((HGLRC) 0);
#endif
case OBJ_METADC:
default:
// 16-bit metafiles are not supported
DBGLEVEL1(LEVEL_ERROR, "wglCreateContext: bad hdc: 0x%lx\n", hdc);
SetLastError(ERROR_INVALID_HANDLE);
return((HGLRC) 0);
}
pdds = NULL;
hrc = NULL;
memset(&gsurf, 0, sizeof(gsurf));
gsurf.ipfd = GetPixelFormat(hdc);
#ifdef GL_METAFILE
// Skip pixel format checks for metafiles
if (dwObjectType == OBJ_ENHMETADC)
{
CreateMetafileSurf(hdc, iLayer, &gsurf);
goto NoPixelFormat;
}
#endif
// Get the current pixel format of the window or surface.
// If no pixel format has been set, return error.
if (gsurf.ipfd == 0)
{
WARNING("wglCreateContext: No pixel format set in hdc\n");
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
return ((HGLRC) 0);
}
if (!DescribePixelFormat(hdc, gsurf.ipfd, sizeof(gsurf.pfd), &gsurf.pfd))
{
DBGERROR("wglCreateContext: DescribePixelFormat failed\n");
return ((HGLRC) 0);
}
// Check for a DirectDraw surface
if (pfnGetSurfaceFromDC != NULL &&
pfnGetSurfaceFromDC(hdc, &pdds, &hdcDevice) == DD_OK)
{
// Don't allow layers for DirectDraw surfaces since
// layering is done through DirectDraw itself.
if (iLayer != 0 ||
!InitDdSurface(pdds, hdcDevice, &gsurf))
{
goto Exit;
}
}
else if (!InitDeviceSurface(hdc, gsurf.ipfd, iLayer, dwObjectType,
TRUE, &gsurf))
{
goto Exit;
}
#ifdef GL_METAFILE
NoPixelFormat:
#endif
hrc = CreateAnyContext(&gsurf);
Exit:
if (hrc == NULL)
{
if (pdds != NULL)
{
pdds->lpVtbl->Release(pdds);
// Release reference on Z buffer if necessary
if (gsurf.dd.gddsZ.pdds != NULL)
{
gsurf.dd.gddsZ.pdds->lpVtbl->Release(gsurf.dd.gddsZ.pdds);
}
}
}
return hrc;
}
/******************************Public*Routine******************************\
* wglCreateContext(HDC hdc)
*
* Create a rendering context.
*
* Arguments:
* hdc - Device context.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Rewrote it.
\**************************************************************************/
HGLRC WINAPI wglCreateContext(HDC hdc)
{
return wglCreateLayerContext(hdc, 0);
}