NT4/private/windows/opengl/client/wgl.c
2020-09-30 17:12:29 +02:00

2570 lines
76 KiB
C

/******************************Module*Header*******************************\
* Module Name: wgl.c
*
* Routines to integrate Windows NT and OpenGL.
*
* Created: 10-26-1993
* Author: Hock San Lee [hockl]
*
* Copyright (c) 1993 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <ntcsrdll.h>
#include <ntpsapi.h>
#include <wingdip.h>
#include <gldci.h>
#include <glgenwin.h>
#include "batchinf.h"
#include "glapi.h"
#include "glsbcltu.h"
#include "wgldef.h"
#include "metasup.h"
#include "glclt.h"
#include "gencx.h"
#include "context.h"
#include "global.h"
// Macro to call glFlush only if a RC is current.
#define GLFLUSH() if (GLTEB_CLTCURRENTRC()) glFlush()
// 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;
// Static functions prototypes
static ULONG iAllocLRC(int iPixelFormat);
static VOID vFreeLRC(PLRC plrc);
static BOOL bMakeNoCurrent();
static PROC pfnGenGlExtProc(LPCSTR lpszProc);
static PROC pfnSimGlExtProc(LPCSTR lpszProc);
/******************************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
NULL, // hdcCurrent
#ifdef GL_METAFILE
0, // uiGlsCaptureContext
0, // uiGlsPlaybackContext
FALSE, // fCapturing
NULL, // hdcMeta
0, 0, 0, 0, 0, // Metafile scaling constants
0, 0, 0, 0.0f, 0.0f,
#endif
#ifdef NT_DEADCODE_VERTEXARRAY
// ARRAYPOINTER apVertex
4, GL_FLOAT, 0, 0, 0, FALSE, (PFNCLTVECTOR)glVertex4fv, 4 * sizeof(GL_FLOAT),
// ARRAYPOINTER apNormal
3, GL_FLOAT, 0, 0, 0, FALSE, (PFNCLTVECTOR)glNormal3fv, 3 * sizeof(GL_FLOAT),
// ARRAYPOINTER apColor
4, GL_FLOAT, 0, 0, 0, FALSE, (PFNCLTVECTOR)glColor4fv, 4 * sizeof(GL_FLOAT),
// ARRAYPOINTER apIndex
1, GL_FLOAT, 0, 0, 0, FALSE, (PFNCLTVECTOR)glIndexfv, 1 * sizeof(GL_FLOAT),
// ARRAYPOINTER apTexCoord
4, GL_FLOAT, 0, 0, 0, FALSE, (PFNCLTVECTOR)glTexCoord4fv, 4 * sizeof(GL_FLOAT),
// ARRAYPOINTER apEdgeFlag
1, GL_UNSIGNED_BYTE, 0, 0, 0, FALSE, (PFNCLTVECTOR)glEdgeFlagv, sizeof(GL_UNSIGNED_BYTE),
NULL, // PFNENABLE pfnEnable
NULL, // PFNDISABLE pfnDisable
NULL, // PFNISENABLED pfnIsEnabled
NULL, // PFNGETBOOLEANV pfnGetBooleanv
NULL, // PFNGETDOUBLEV pfnGetDoublev
NULL, // PFNGETFLOATV pfnGetFloatv
NULL, // PFNGETINTEGERV pfnGetIntegerv
NULL, // PFNGETSTRING pfnGetString
#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
};
static ULONG iAllocLRC(int iPixelFormat)
{
ULONG irc = INVALID_INDEX;
PLRC plrc;
// Allocate a local RC.
plrc = (PLRC) LocalAlloc(LPTR, sizeof(LRC));
if (plrc == (PLRC) NULL)
{
DBGERROR("LocalAlloc 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.
\**************************************************************************/
static 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->hdcCurrent == (HDC) 0,
"vFreeLRC: hdcCurrent 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)
if (LocalFree(plrc->pszExtensions))
RIP("LocalFree failed\n");
if (LocalFree(plrc))
RIP("LocalFree failed\n");
}
/******************************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) LHANDLE(ii)) )
{
WARNING1("bCleanupAllLRC: failed to remove hrc = 0x%lx\n",
LHANDLE(ii));
}
}
}
LEAVECRITICALSECTION(&semLocal);
}
}
/******************************Public*Routine******************************\
* bGetDriverName
*
* 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.
\**************************************************************************/
#define WSTR_OPENGL_DRIVER_LIST (PCWSTR)L"Software\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers"
#define STR_OPENGL_DRIVER_LIST (PCSTR)"Software\\Microsoft\\Windows\\CurrentVersion\\OpenGLDrivers"
BOOL bGetDriverName(HDC hdc, LPWSTR pwszDriver, UINT cwcDriver,
PULONG pulVer, PULONG pulDrvVer)
{
BOOL bRet = FALSE;
HKEY hkDriverList = (HKEY) NULL;
DWORD dwDataType;
DWORD cjSize;
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 )
{
// Too noisy in Win95 since PixelFormat calls have to go through
// Escapes.
WARNING("ExtEscape(OPENGL_GETINFO, OPENGL_GETINFO_DRVNAME) failed\n");
goto bGetDriverName_exit; // error
}
*pulVer = dnRet.ulVersion;
*pulDrvVer = dnRet.ulDriverVersion;
// Open the registry key for the list of OpenGL drivers.
if (
( NT_PLATFORM &&
( RegOpenKeyExW(HKEY_LOCAL_MACHINE,
WSTR_OPENGL_DRIVER_LIST,
0,
KEY_QUERY_VALUE,
&hkDriverList) != ERROR_SUCCESS ) )
||
( WIN95_PLATFORM &&
( RegOpenKeyExA(HKEY_LOCAL_MACHINE,
STR_OPENGL_DRIVER_LIST,
0,
KEY_QUERY_VALUE,
&hkDriverList) != ERROR_SUCCESS ) )
)
{
WARNING("RegOpenKeyEx failed\n");
goto bGetDriverName_exit; // error
}
// Query for the OpenGL driver name using the display driver name as the
// value.
//XXX Need to convert dnRet.awch to ansi before making the call in win95.
cjSize = (DWORD) cwcDriver * sizeof(WCHAR);
if (
( NT_PLATFORM &&
( (RegQueryValueExW(hkDriverList,
dnRet.awch,
(LPDWORD) NULL,
&dwDataType,
(LPBYTE) pwszDriver,
&cjSize) != ERROR_SUCCESS)
|| (dwDataType != REG_SZ) ) )
||
( WIN95_PLATFORM &&
( (RegQueryValueExA(hkDriverList,
(LPSTR) dnRet.awch,
(LPDWORD) NULL,
&dwDataType,
(LPBYTE) pwszDriver,
&cjSize) != ERROR_SUCCESS)
|| (dwDataType != REG_SZ) ) )
)
{
WARNING("RegQueryValueW failed\n");
goto bGetDriverName_exit; // error
}
bRet = TRUE;
bGetDriverName_exit:
if (hkDriverList)
if (RegCloseKey(hkDriverList) != ERROR_SUCCESS)
RIP("RegCloseKey failed\n");
return bRet;
}
/*****************************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;
}
// wgl's default callback procedures
#define CALLBACK_PROC_COUNT 3
static PROC __wglCallbackProcs[CALLBACK_PROC_COUNT] =
{
(PROC)wglCbSetCurrentValue,
(PROC)wglCbGetCurrentValue,
(PROC)wglCbGetDhglrc
};
static char *pszDriverEntryPoints[] =
{
"DrvCreateContext",
"DrvDeleteContext",
"DrvSetContext",
"DrvReleaseContext",
"DrvCopyContext",
"DrvCreateLayerContext",
"DrvShareLists",
"DrvGetProcAddress",
"DrvDescribeLayerPlane",
"DrvSetLayerPaletteEntries",
"DrvGetLayerPaletteEntries",
"DrvRealizeLayerPalette",
"DrvSwapLayerBuffers"
#if defined(_WIN95_)
,
"DrvDescribePixelFormat",
"DrvSetPixelFormat",
"DrvSwapBuffers"
#endif
};
#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)
{
WCHAR wszDrvName[MAX_GLDRIVER_NAME+1];
LPWSTR pwszDrvName = (LPWSTR) wszDrvName;
LPSTR pszDrvName = (LPSTR) wszDrvName;
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;
ULONG ulVer; // engine and driver version numbers for
ULONG ulDrvVer; // validation of client OpenGL driver
int i;
PROC *pproc;
GLGENwindow *pwnd;
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.
pwnd = pwndGetFromDC(hdc);
if (pwnd)
{
pGLDriverRet = (PGLDRIVER) pwnd->pvDriver;
pwndRelease(pwnd);
if ( pGLDriverRet )
{
goto pgldrvLoadInstalledDriver_exit;
}
}
// 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
return NULL;
}
// Determine driver name from hdc
memset((void *)wszDrvName, 0, sizeof(wszDrvName));
if ( !bGetDriverName(hdc, pwszDrvName, MAX_GLDRIVER_NAME,
&ulVer, &ulDrvVer) )
{
WARNING("bGetDriverName failed\n");
goto pgldrvLoadInstalledDriver_exit; // error
}
// If no driver is found, return error.
if (
( NT_PLATFORM &&
( pwszDrvName[0] == (WCHAR) 0
|| pwszDrvName[MAX_GLDRIVER_NAME] != (WCHAR) 0 ) )
||
( WIN95_PLATFORM &&
( pszDrvName[0] == (CHAR) 0
|| pszDrvName[MAX_GLDRIVER_NAME] != (CHAR) 0 ) )
)
{
WARNING("pgldrvLoadInstalledDriver: No OpenGL installable driver\n");
SetLastError(ERROR_BAD_DRIVER);
goto pgldrvLoadInstalledDriver_exit; // error
}
// Load the driver only once per process.
ENTERCRITICALSECTION(&semLocal);
// Look for the OpenGL driver in the previously loaded driver list.
if ( NT_PLATFORM )
for (pGLDriverNext = pGLDriverList;
pGLDriverNext != (PGLDRIVER) NULL;
pGLDriverNext = pGLDriverNext->pGLDriver)
{
LPWSTR pwszDrvName1 = pGLDriverNext->wszDrvName;
LPWSTR pwszDrvName2 = pwszDrvName;
while (*pwszDrvName1 == *pwszDrvName2)
{
// If we find one, return that driver.
if (*pwszDrvName1 == (WCHAR) 0)
{
DBGINFO("pgldrvLoadInstalledDriver: return previously loaded driver\n");
pGLDriverRet = pGLDriverNext; // found one
goto pgldrvLoadInstalledDriver_crit_exit;
}
pwszDrvName1++;
pwszDrvName2++;
}
}
else if ( WIN95_PLATFORM )
for (pGLDriverNext = pGLDriverList;
pGLDriverNext != (PGLDRIVER) NULL;
pGLDriverNext = pGLDriverNext->pGLDriver)
{
LPSTR pszDrvName1 = (LPSTR) pGLDriverNext->wszDrvName;
LPSTR pszDrvName2 = pszDrvName;
while (*pszDrvName1 == *pszDrvName2)
{
// If we find one, return that driver.
if (*pszDrvName1 == (CHAR) 0)
{
DBGINFO("pgldrvLoadInstalledDriver: return previously loaded driver\n");
pGLDriverRet = pGLDriverNext; // found one
goto pgldrvLoadInstalledDriver_crit_exit;
}
pszDrvName1++;
pszDrvName2++;
}
}
// Load the driver for the first time.
// Allocate the driver data.
pGLDriver = (PGLDRIVER) LocalAlloc(LMEM_FIXED, sizeof(GLDRIVER));
if (pGLDriver == (PGLDRIVER) NULL)
{
WARNING("LocalAlloc failed\n");
goto pgldrvLoadInstalledDriver_crit_exit; // error
}
// Load the driver.
pGLDriver->hModule = (NT_PLATFORM) ? LoadLibraryW(pwszDrvName) :
(WIN95_PLATFORM) ? LoadLibraryA(pszDrvName) :
(HINSTANCE) NULL;
if (pGLDriver->hModule == (HINSTANCE) NULL)
{
WARNING("pgldrvLoadInstalledDriver: LoadLibraryW failed\n");
goto pgldrvLoadInstalledDriver_crit_exit; // error
}
// Copy the driver name.
memcpy
(
pGLDriver->wszDrvName,
pwszDrvName,
(MAX_GLDRIVER_NAME + 1) * sizeof(WCHAR)
);
// 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 ||
#if defined(_WIN95_)
pGLDriver->pfnDrvDescribePixelFormat == NULL ||
pGLDriver->pfnDrvSetPixelFormat == NULL ||
pGLDriver->pfnDrvSwapBuffers == NULL ||
#endif
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 ( ulVer != 2 || !pfnDrvValidateVersion(ulDrvVer) )
{
WARNING2("pgldrvLoadInstalledDriver: bad driver version (0x%lx, 0x%lx)\n", ulVer, ulDrvVer);
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");
if (LocalFree(pGLDriver))
RIP("LocalFree failed\n");
}
}
LEAVECRITICALSECTION(&semLocal);
// Non-critical section error cleanup.
pgldrvLoadInstalledDriver_exit:
return(pGLDriverRet);
}
/******************************Public*Routine******************************\
*
* wglObjectType
*
* Returns GetObjectType result with the exception that
* metafile-spooled printer DC's come back as metafile objects
*
* History:
* Fri Jun 16 12:10:07 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD APIENTRY wglObjectType(HDC hdc)
{
DWORD dwObjectType;
dwObjectType = GetObjectType(hdc);
#ifdef GL_METAFILE
if (dwObjectType == OBJ_DC &&
pfnGdiIsMetaPrintDC != NULL &&
GlGdiIsMetaPrintDC(hdc))
{
dwObjectType = OBJ_ENHMETADC;
}
#endif
return dwObjectType;
}
/******************************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)
{
PLHE plheRC;
ULONG irc;
HGLRC hrc;
PLRC plrc;
int iPixelFormat;
PIXELFORMATDESCRIPTOR pfd;
DWORD dwObjectType;
HDC hdcSrv;
DBGENTRY("wglCreateLayerContext\n");
#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) == 3056,
"TEB.glContext must be at offset 3056\n");
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");
ASSERTOPENGL(FIELD_OFFSET(TEB, glReserved1)+72 == TeglPaTeb,
"TEB.glPaTeb at wrong offset\n");
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
// 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);
}
#ifdef GL_METAFILE
// Skip pixel format checks for metafiles
if (dwObjectType == OBJ_ENHMETADC)
{
#ifndef _CLIENTSIDE_
// Switch DC's to the reference DC
hdcSrv = GdiGetMfReferenceDC(hdc);
#else
hdcSrv = hdc;
#endif
iPixelFormat = 0;
pfd.dwFlags = PFD_GENERIC_FORMAT;
goto NoPixelFormat;
}
else
#endif
{
hdcSrv = NULL;
}
// Get the current pixel format of the window or surface.
// If no pixel format has been set, return error.
if (!(iPixelFormat = GetPixelFormat(hdc)))
{
WARNING("wglCreateContext: No pixel format set in hdc\n");
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
return ((HGLRC) 0);
}
if (!DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd))
{
DBGERROR("wglCreateContext: DescribePixelFormat failed\n");
return ((HGLRC) 0);
}
#ifdef GL_METAFILE
NoPixelFormat:
#endif
// Create the local RC.
ENTERCRITICALSECTION(&semLocal);
irc = iAllocLRC(iPixelFormat);
if (irc == INVALID_INDEX ||
cLockHandle((ULONG)(hrc = (HGLRC) 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;
if (!(pfd.dwFlags & PFD_GENERIC_FORMAT))
{
// 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(hdc)))
goto wglCreateContext_error;
// Create a driver context.
// 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
if (plrc->pGLDriver->pfnDrvCreateLayerContext != NULL)
{
if (!(plrc->dhrc =
plrc->pGLDriver->pfnDrvCreateLayerContext(hdc, iLayer)))
{
WARNING("wglCreateContext: pfnDrvCreateLayerContext failed\n");
goto wglCreateContext_error;
}
}
else if (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(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 ((iLayer != 0) && !(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 (dwObjectType == OBJ_ENHMETADC)
{
if (!CreateMetaRc(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) __wglCreateContext(hdc, hdcSrv, iLayer);
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)hrc);
return(hrc);
// Fail, clean up and return 0.
wglCreateContext_error:
#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((HGLRC) 0);
}
/******************************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);
}
/******************************Public*Routine******************************\
* wglDeleteContext(HGLRC hrc)
*
* Delete the rendering context
*
* Arguments:
* hrc - Rendering context.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Rewrote it.
\**************************************************************************/
BOOL WINAPI wglDeleteContext(HGLRC hrc)
{
PLHE plheRC;
ULONG irc;
PLRC plrc;
BOOL bRet = FALSE;
DBGENTRY("wglDeleteContext\n");
// Flush OpenGL calls.
GLFLUSH();
// Validate the RC.
if (cLockHandle((ULONG)hrc) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglDeleteContext: can't lock hrc 0x%lx\n", hrc);
return(bRet);
}
irc = MASKINDEX(hrc);
plheRC = pLocalTable + irc;
plrc = (PLRC) plheRC->pv;
ASSERTOPENGL(plrc->ident == LRC_IDENTIFIER, "wglDeleteContext: Bad plrc\n");
DBGLEVEL2(LEVEL_INFO, "wglDeleteContext: hrc: 0x%lx, plrc: 0x%lx\n", hrc, plrc);
if (plrc->tidCurrent != INVALID_THREAD_ID)
{
// The RC must be current to this thread because makecurrent locks
// down the handle.
ASSERTOPENGL(plrc->tidCurrent == GetCurrentThreadId(),
"wglDeleteCurrent: hrc is current to another thread\n");
// Make the RC inactive first.
if (!bMakeNoCurrent())
{
DBGERROR("wglDeleteCurrent: bMakeNoCurrent failed\n");
}
}
if (plrc->dhrc)
{
// If it is a device format, call the driver to delete its context.
bRet = plrc->pGLDriver->pfnDrvDeleteContext(plrc->dhrc);
plrc->dhrc = (DHGLRC) 0;
}
else
{
#ifdef GL_METAFILE
// If we have metafile state, clean it up
if (plrc->uiGlsCaptureContext != 0 ||
plrc->uiGlsPlaybackContext != 0)
{
DeleteMetaRc(plrc);
}
#endif
// If it is a generic format, call the server to delete its context.
bRet = __wglDeleteContext((HANDLE) plheRC->hgre);
}
// Always clean up local objects.
vFreeLRC(plrc);
vFreeHandle(irc); // it unlocks handle too
if (!bRet)
DBGERROR("wglDeleteContext failed\n");
return(bRet);
}
void APIENTRY
__wglSetProcTable(PGLCLTPROCTABLE pglCltProcTable)
{
if (pglCltProcTable == (PGLCLTPROCTABLE) NULL)
return;
// It must have either 306 entries for version 1.0 or 336 entries for 1.1
if (pglCltProcTable->cEntries != OPENGL_VERSION_100_ENTRIES &&
pglCltProcTable->cEntries != OPENGL_VERSION_110_ENTRIES)
{
return;
}
// This function is called by client drivers which do not use
// the EXT procs provided by opengl32. Use the null EXT proc
// table to disable those stubs since they should never be
// called anyway
SetCltProcTable(pglCltProcTable, &glNullExtProcTable, TRUE);
}
/******************************Public*Routine******************************\
* wglMakeCurrent(HDC hdc, HGLRC hrc)
*
* Make the hrc current.
* Both hrc and hdc must have the same pixel format.
*
* If an error occurs, the current RC, if any, is made not current!
*
* Arguments:
* hdc - Device context.
* hrc - Rendering context.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hrc)
{
HGLRC hrcSrv;
PLRC plrc;
DWORD tidCurrent;
ULONG irc;
PLHE plheRC;
int iPixelFormat;
PGLCLTPROCTABLE pglProcTable;
PGLEXTPROCTABLE pglExtProcTable;
XFORM xform;
POINT pt;
int iRgn;
HRGN hrgnTmp;
#ifdef NT_DEADCODE_VERTEXARRAY
PGLDISPATCHTABLE pfnDispatch;
PGLDISPATCHTABLE_FAST pfnDispatchFast;
#endif
DWORD dwObjectType;
HDC hdcSrv;
POLYARRAY *pa;
DBGENTRY("wglMakeCurrent\n");
// If this is a new, uninitialized thread, try to initialize it
if (CURRENT_GLTEBINFO() == NULL)
{
GLInitializeThread(DLL_THREAD_ATTACH);
// If the teb was not set up at thread initialization, return failure.
if (!CURRENT_GLTEBINFO())
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
}
// Flush OpenGL calls.
GLFLUSH();
// There are four cases:
//
// 1. hrc is NULL and there is no current RC.
// 2. hrc is NULL and there is a current RC.
// 3. hrc is not NULL and there is a current RC.
// 4. hrc is not NULL and there is no current RC.
// Case 1: hrc is NULL and there is no current RC.
// This is a noop, return success.
if (hrc == (HGLRC) 0 && (GLTEB_CLTCURRENTRC() == (PLRC) NULL))
return(TRUE);
// Case 2: hrc is NULL and there is a current RC.
// Make the current RC inactive.
if (hrc == (HGLRC) 0 && (GLTEB_CLTCURRENTRC() != (PLRC) NULL))
return(bMakeNoCurrent());
// Get the current thread id.
tidCurrent = GetCurrentThreadId();
ASSERTOPENGL(tidCurrent != INVALID_THREAD_ID,
"wglMakeCurrent: GetCurrentThreadId returned a bad value\n");
// Validate the handles. hrc is not NULL here.
ASSERTOPENGL(hrc != (HGLRC) NULL, "wglMakeCurrent: hrc is NULL\n");
// 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, "wglMakeCurrent: metafile hdc: 0x%lx\n",
hdc);
SetLastError(ERROR_INVALID_HANDLE);
goto wglMakeCurrent_error_nolock;
}
break;
#else
DBGLEVEL1(LEVEL_ERROR, "wglMakeCurrent: metafile hdc: 0x%lx\n", hdc);
SetLastError(ERROR_INVALID_HANDLE);
goto wglMakeCurrent_error_nolock;
#endif
case OBJ_METADC:
default:
// 16-bit metafiles are not supported
DBGLEVEL1(LEVEL_ERROR, "wglMakeCurrent: bad hdc: 0x%lx\n", hdc);
SetLastError(ERROR_INVALID_HANDLE);
goto wglMakeCurrent_error_nolock;
}
// Validate the RC.
if (cLockHandle((ULONG)hrc) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglMakeCurrent: can't lock hrc 0x%lx\n", hrc);
goto wglMakeCurrent_error_nolock;
}
irc = MASKINDEX(hrc);
plheRC = pLocalTable + irc;
plrc = (PLRC) plheRC->pv;
hrcSrv = (HGLRC) plheRC->hgre;
ASSERTOPENGL(plrc->ident == LRC_IDENTIFIER, "wglMakeCurrent: Bad plrc\n");
#ifdef GL_METAFILE
// Ensure that metafile RC's are made current only to
// metafile DC's
if (plrc->uiGlsCaptureContext != 0 && dwObjectType != OBJ_ENHMETADC)
{
DBGLEVEL(LEVEL_ERROR,
"wglMakeCurrent: attempt to make meta RC current "
"to non-meta DC\n");
SetLastError(ERROR_INVALID_HANDLE);
vUnlockHandle((ULONG)hrc);
return FALSE;
}
// Ensure that non-metafile RC's are made current only to
// non-metafile DC's
if (plrc->uiGlsCaptureContext == 0 && dwObjectType == OBJ_ENHMETADC)
{
DBGLEVEL(LEVEL_ERROR,
"wglMakeCurrent: attempt to make non-meta RC current "
"to meta DC\n");
SetLastError(ERROR_METAFILE_NOT_SUPPORTED);
vUnlockHandle((ULONG)hrc);
return FALSE;
}
#endif
// If the RC is current, it must be current to this thread because
// makecurrent locks down the handle.
// If the given RC is already current to this thread, we will release it first,
// then make it current again. This is to support DC/RC attribute bindings in
// this function.
ASSERTOPENGL(plrc->tidCurrent == INVALID_THREAD_ID || plrc->tidCurrent == tidCurrent,
"wglMakeCurrent: hrc is current to another thread\n");
// Case 3: hrc is not NULL and there is a current RC.
// This is case 2 followed by case 4.
if (GLTEB_CLTCURRENTRC())
{
// First, make the current RC inactive.
if (!bMakeNoCurrent())
{
DBGERROR("wglMakeCurrent: bMakeNoCurrent failed\n");
vUnlockHandle((ULONG)hrc);
return(FALSE);
}
// Second, make hrc current. Fall through to case 4.
}
// Case 4: hrc is not NULL and there is no current RC.
ASSERTOPENGL(GLTEB_CLTCURRENTRC() == (PLRC) NULL,
"wglMakeCurrent: There is a current RC!\n");
#ifdef GL_METAFILE
// For metafile RC's, use the reference HDC rather than the
// metafile DC
// Skip pixel format checks
if (plrc->uiGlsCaptureContext != 0)
{
#ifndef _CLIENTSIDE_
hdcSrv = GdiGetMfReferenceDC(hdc);
#else
hdcSrv = hdc;
#endif
goto NoPixelFormat;
}
else
#endif
{
hdcSrv = NULL;
}
// Get the current pixel format of the window or surface.
// If no pixel format has been set, return error.
if (!(iPixelFormat = GetPixelFormat(hdc)))
{
WARNING("wglMakeCurrent: No pixel format set in hdc\n");
goto wglMakeCurrent_error;
}
// If the pixel format of the window or surface is different from that of
// the RC, return error.
if (iPixelFormat != plrc->iPixelFormat)
{
DBGERROR("wglMakeCurrent: different hdc and hrc pixel formats\n");
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
goto wglMakeCurrent_error;
}
#ifdef GL_METAFILE
NoPixelFormat:
#endif
// For release 1, GDI transforms must be identity.
// This is to allow GDI transform binding in future.
switch (GetMapMode(hdc))
{
SIZE szW, szV;
case MM_TEXT:
break;
case MM_ANISOTROPIC:
if (!GetWindowExtEx(hdc, &szW)
|| !GetViewportExtEx(hdc, &szV)
|| szW.cx != szV.cx
|| szW.cy != szV.cy)
goto wglMakeCurrent_xform_error;
break;
default:
goto wglMakeCurrent_xform_error;
}
if (!GetViewportOrgEx(hdc, &pt) || pt.x != 0 || pt.y != 0)
goto wglMakeCurrent_xform_error;
if (!GetWindowOrgEx(hdc, &pt) || pt.x != 0 || pt.y != 0)
goto wglMakeCurrent_xform_error;
if (!GetWorldTransform(hdc, &xform))
{
// Win95 does not support GetWorldTransform.
if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
goto wglMakeCurrent_xform_error;
}
else if (xform.eDx != 0.0f || xform.eDy != 0.0f
|| xform.eM12 != 0.0f || xform.eM21 != 0.0f
|| xform.eM11 < 0.999f || xform.eM11 > 1.001f // allow rounding errors
|| xform.eM22 < 0.999f || xform.eM22 > 1.001f)
{
wglMakeCurrent_xform_error:
DBGERROR("wglMakeCurrent: GDI transforms not identity\n");
SetLastError(ERROR_TRANSFORM_NOT_SUPPORTED);
goto wglMakeCurrent_error;
}
// For release 1, GDI clip region is not allowed.
// This is to allow GDI clip region binding in future.
if (!(hrgnTmp = CreateRectRgn(0, 0, 0, 0)))
goto wglMakeCurrent_error;
iRgn = GetClipRgn(hdc, hrgnTmp);
if (!DeleteObject(hrgnTmp))
ASSERTOPENGL(FALSE, "DeleteObject failed");
switch (iRgn)
{
case -1: // error
WARNING("wglMakeCurrent: GetClipRgn failed\n");
goto wglMakeCurrent_error;
case 0: // no initial clip region
break;
case 1: // has initial clip region
DBGERROR("wglMakeCurrent: GDI clip region not allowed\n");
SetLastError(ERROR_CLIPPING_NOT_SUPPORTED);
goto wglMakeCurrent_error;
}
// Since the client code manages the function table, we will make
// either the server or the driver current.
if (!plrc->dhrc)
{
// If this is a generic format, tell the server to make it current.
#ifndef _CLIENTSIDE_
// If the subbatch data has not been set up for this thread, set it up now.
if (GLTEB_CLTSHAREDSECTIONINFO() == NULL)
{
if (!glsbCreateAndDuplicateSection(SHARED_SECTION_SIZE))
{
WARNING("wglMakeCurrent: unable to create section\n");
goto wglMakeCurrent_error;
}
}
#endif // !_CLIENTSIDE_
if (!__wglMakeCurrent(hdc, hrcSrv, hdcSrv))
{
DBGERROR("wglMakeCurrent: server failed\n");
goto wglMakeCurrent_error;
}
// Get the generic function table or metafile function table
#ifdef GL_METAFILE
if (plrc->fCapturing)
{
MetaGlProcTables(&pglProcTable, &pglExtProcTable);
}
else
#endif
{
// Use RGBA or CI proc table depending on the color mode.
// The gc should be available by now.
__GL_SETUP();
if (gc->modes.colorIndexMode)
pglProcTable = &glCltCIProcTable;
else
pglProcTable = &glCltRGBAProcTable;
pglExtProcTable = &glExtProcTable;
}
}
else
{
// If this is a device format, tell the driver to make it current.
// Get the driver function table from the driver.
// pfnDrvSetContext returns the address of the driver OpenGL function
// table if successful; NULL otherwise.
ASSERTOPENGL(plrc->pGLDriver, "wglMakeCurrent: No GLDriver\n");
pglProcTable = plrc->pGLDriver->pfnDrvSetContext(hdc, plrc->dhrc,
__wglSetProcTable);
if (pglProcTable == (PGLCLTPROCTABLE) NULL)
{
DBGERROR("wglMakeCurrent: pfnDrvSetContext failed\n");
goto wglMakeCurrent_error;
}
// It must have either 306 entries for version 1.0 or 336 entries for 1.1
if (pglProcTable->cEntries != OPENGL_VERSION_100_ENTRIES &&
pglProcTable->cEntries != OPENGL_VERSION_110_ENTRIES)
{
DBGERROR("wglMakeCurrent: pfnDrvSetContext returned bad table\n");
plrc->pGLDriver->pfnDrvReleaseContext(plrc->dhrc);
SetLastError(ERROR_BAD_DRIVER);
goto wglMakeCurrent_error;
}
DBGLEVEL1(LEVEL_INFO, "wglMakeCurrent: driver function table 0x%lx\n",
pglProcTable);
// Always use the null EXT proc table since client drivers don't
// use opengl32's stubs for EXT procs
pglExtProcTable = &glNullExtProcTable;
}
// Make hrc current.
plrc->tidCurrent = tidCurrent;
plrc->hdcCurrent = hdc;
GLTEB_SET_CLTCURRENTRC(plrc);
SetCltProcTable(pglProcTable, pglExtProcTable, TRUE);
#ifdef GL_METAFILE
// Set up metafile context if necessary
if (plrc->fCapturing)
{
__GL_SETUP();
ActivateMetaRc(plrc, hdc);
// Set the metafile's base dispatch table by resetting
// the proc table. Since we know we're capturing, this
// will cause the GLS capture exec table to be updated
// with the RGBA or CI proc table, preparing the
// GLS context for correct passthrough
if (gc->modes.colorIndexMode)
pglProcTable = &glCltCIProcTable;
else
pglProcTable = &glCltRGBAProcTable;
pglExtProcTable = &glExtProcTable;
SetCltProcTable(pglProcTable, pglExtProcTable, FALSE);
}
#endif
#ifdef NT_DEADCODE_VERTEXARRAY
// Initialize the vertex array data
pfnDispatch = GLTEB_CLTDISPATCHTABLE();
plrc->pfnEnable = pfnDispatch->glEnable ;
plrc->pfnDisable = pfnDispatch->glDisable ;
plrc->pfnIsEnabled = pfnDispatch->glIsEnabled ;
plrc->pfnGetBooleanv = pfnDispatch->glGetBooleanv;
plrc->pfnGetDoublev = pfnDispatch->glGetDoublev ;
plrc->pfnGetFloatv = pfnDispatch->glGetFloatv ;
plrc->pfnGetIntegerv = pfnDispatch->glGetIntegerv;
plrc->pfnGetString = pfnDispatch->glGetString ;
if (strstr(plrc->pfnGetString(GL_EXTENSIONS), "GL_EXT_vertex_array") == NULL
|| !plrc->dhrc)
{
pfnDispatchFast = GLTEB_CLTDISPATCHTABLE_FAST();
pfnDispatchFast->glEnable = VArrayEnable ;
pfnDispatch->glEnable = VArrayEnable ;
pfnDispatchFast->glDisable = VArrayDisable ;
pfnDispatch->glDisable = VArrayDisable ;
pfnDispatch->glIsEnabled = VArrayIsEnabled ;
pfnDispatch->glGetBooleanv = VArrayGetBooleanv;
pfnDispatch->glGetDoublev = VArrayGetDoublev ;
pfnDispatch->glGetFloatv = VArrayGetFloatv ;
pfnDispatch->glGetIntegerv = VArrayGetIntegerv;
pfnDispatch->glGetString = VArrayGetString ;
}
#endif
// Initialize polyarray structure in the TEB.
pa = GLTEB_CLTPOLYARRAY();
pa->flags = 0; // not in begin mode
if (!plrc->dhrc)
{
POLYMATERIAL *pm;
__GL_SETUP();
pa->pdBufferNext = &gc->vertex.pdBuf[0];
pa->pdBuffer0 = &gc->vertex.pdBuf[0];
pa->pdBufferMax = &gc->vertex.pdBuf[gc->vertex.pdBufSize - 1];
pa->nextMsgOffset = (ULONG) -1; // reset next DPA message offset
// Vertex buffer size may have changed. For example, a generic gc's
// vertex buffer may be of a different size than a MCD vertex buffer.
// If it has changed, free the polymaterial array and realloc it later.
pm = GLTEB_CLTPOLYMATERIAL();
if (pm)
{
if (pm->aMatSize != gc->vertex.pdBufSize * 2 / POLYMATERIAL_ARRAY_SIZE + 1)
FreePolyMaterial();
}
}
// Keep the handle locked while it is current.
return(TRUE);
// An error has occured, release the current RC.
wglMakeCurrent_error:
vUnlockHandle((ULONG)hrc);
wglMakeCurrent_error_nolock:
if (GLTEB_CLTCURRENTRC() != (PLRC) NULL)
(void) bMakeNoCurrent();
return(FALSE);
}
/******************************Public*Routine******************************\
* bMakeNoCurrent
*
* Make the current RC inactive.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
static BOOL bMakeNoCurrent()
{
BOOL bRet = FALSE; // assume error
PLRC plrc = GLTEB_CLTCURRENTRC();
DBGENTRY("bMakeNoCurrent\n");
ASSERTOPENGL(plrc != (PLRC) NULL, "bMakeNoCurrent: No current RC!\n");
ASSERTOPENGL(plrc->tidCurrent == GetCurrentThreadId(),
"bMakeNoCurrent: Current RC does not belong to this thread!\n");
ASSERTOPENGL(plrc->hdcCurrent != (HDC) 0, "bMakeNoCurrent: hdcCurrent is NULL!\n");
if (!plrc->dhrc)
{
#ifdef GL_METAFILE
// Reset metafile context if necessary
if (plrc->uiGlsCaptureContext != 0)
{
DeactivateMetaRc(plrc);
}
#endif
// If this is a generic format, tell the server to make the current RC inactive.
bRet = __wglMakeCurrent((HDC) 0, (HANDLE) 0, 0);
if (!bRet)
{
DBGERROR("bMakeNoCurrent: server failed\n");
}
}
else
{
// If this is a device format, tell the driver to make the current RC inactive.
ASSERTOPENGL(plrc->pGLDriver, "wglMakeCurrent: No GLDriver\n");
bRet = plrc->pGLDriver->pfnDrvReleaseContext(plrc->dhrc);
if (!bRet)
{
DBGERROR("bMakeNoCurrent: pfnDrvReleaseContext failed\n");
}
}
// Always make the current RC inactive.
// The handle is also unlocked when the RC becomes inactive.
plrc->tidCurrent = INVALID_THREAD_ID;
plrc->hdcCurrent = (HDC) 0;
GLTEB_SET_CLTCURRENTRC(NULL);
SetCltProcTable(&glNullCltProcTable, &glNullExtProcTable, TRUE);
vUnlockHandle((ULONG)(plrc->hrc));
return(bRet);
}
/******************************Public*Routine******************************\
* wglGetCurrentContext(VOID)
*
* Return the current rendering context
*
* Arguments:
* None
*
* Returns:
* hrc - Rendering context.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
HGLRC WINAPI wglGetCurrentContext(VOID)
{
DBGENTRY("wglGetCurrentContext\n");
if (GLTEB_CLTCURRENTRC())
return(GLTEB_CLTCURRENTRC()->hrc);
else
return((HGLRC) 0);
}
/******************************Public*Routine******************************\
* wglGetCurrentDC(VOID)
*
* Return the device context that is associated with the current rendering
* context
*
* Arguments:
* None
*
* Returns:
* hdc - device context.
*
* History:
* Mon Jan 31 12:15:12 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
HDC WINAPI wglGetCurrentDC(VOID)
{
DBGENTRY("wglGetCurrentDC\n");
if (GLTEB_CLTCURRENTRC())
return(GLTEB_CLTCURRENTRC()->hdcCurrent);
else
return((HDC) 0);
}
/******************************Public*Routine******************************\
* wglUseFontBitmapsA
* wglUseFontBitmapsW
*
* Stubs that call wglUseFontBitmapsAW with the bUnicode flag set
* appropriately.
*
* History:
* 11-Mar-1994 gilmanw
* Changed to call wglUseFontBitmapsAW.
*
* 17-Dec-1993 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL WINAPI wglUseFontBitmapsAW(HDC hdc, DWORD first, DWORD count,
DWORD listBase, BOOL bUnicode);
BOOL WINAPI
wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
{
return wglUseFontBitmapsAW(hdc, first, count, listBase, FALSE);
}
BOOL WINAPI
wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
{
return wglUseFontBitmapsAW(hdc, first, count, listBase, TRUE);
}
/******************************Public*Routine******************************\
* wglUseFontBitmapsAW
*
* Uses the current font in the specified DC to generate a series of OpenGL
* display lists, each of which consists of a glyph bitmap.
*
* Each glyph bitmap is generated by calling ExtTextOut to draw the glyph
* into a memory DC. The contents of the memory DC are then copied into
* a buffer by GetDIBits and then put into the OpenGL display list.
*
* ABC spacing is used (if GetCharABCWidth() is supported by the font) to
* determine proper placement of the glyph origin and character advance width.
* Otherwise, A = C = 0 spacing is assumed and GetCharWidth() is used for the
* advance widths.
*
* Returns:
*
* TRUE if successful, FALSE otherwise.
*
* History:
* 17-Dec-1993 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL WINAPI
wglUseFontBitmapsAW(
HDC hdc, // use HFONT from this DC
DWORD first, // generate glyphs starting with this Unicode codepoint
DWORD count, // range is this long [first, first+count-1]
DWORD listBase, // starting display list number
BOOL bUnicode // TRUE for if in Unicode mode, FALSE if in Ansi mode
)
{
BOOL bRet = FALSE; // return value
HDC hdcMem; // render glyphs to this memory DC
HBITMAP hbm; // monochrome bitmap for memory DC
LPABC pabc, pabcTmp, pabcEnd; // array of ABC spacing
LPINT piWidth, piTmp, piWidthEnd; // array of char adv. widths
WCHAR wc; // current Unicode char to render
RECT rc; // background rectangle to clear
TEXTMETRICA tm; // metrics of the font
BOOL bTrueType; // TrueType supports ABC spacing
int iMaxWidth = 1; // maximum glyph width
int iBitmapWidth; // DWORD aligned bitmap width
BYTE ajBmi[sizeof(BITMAPINFO) + sizeof(RGBQUAD)];
BITMAPINFO *pbmi = (BITMAPINFO *)ajBmi;// bitmap info for GetDIBits
GLint iUnpackRowLength; // save GL_UNPACK_ROW_LENGTH
GLint iUnpackAlign; // save GL_UNPACK_ALIGNMENT
PVOID pv; // pointer to glyph bitmap buffer
// Return error if there is no current RC.
if (!GLTEB_CLTCURRENTRC())
{
WARNING("wglUseFontBitmap: no current RC\n");
SetLastError(ERROR_INVALID_HANDLE);
return bRet;
}
// Get TEXTMETRIC. The only fields used are those that are invariant with
// respect to Unicode vs. ANSI. Therefore, we can call GetTextMetricsA for
// both cases.
if ( !GetTextMetricsA(hdc, &tm) )
{
WARNING("GetTextMetricsA failed\n");
return bRet;
}
// If its a TrueType font, we can get ABC spacing.
if ( bTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) )
{
// Allocate memory for array of ABC data.
if ( (pabc = (LPABC) LocalAlloc(LMEM_FIXED, sizeof(ABC) * count)) == (LPABC) NULL )
{
WARNING("LocalAlloc(pabc) failed\n");
return bRet;
}
// Get ABC metrics.
if ( bUnicode )
{
if ( !GetCharABCWidthsW(hdc, first, first + count - 1, pabc) )
{
WARNING("GetCharABCWidthsW failed\n");
LocalFree(pabc);
return bRet;
}
}
else
{
if ( !GetCharABCWidthsA(hdc, first, first + count - 1, pabc) )
{
WARNING("GetCharABCWidthsA failed\n");
LocalFree(pabc);
return bRet;
}
}
// Find max glyph width.
for (pabcTmp = pabc, pabcEnd = pabc + count;
pabcTmp < pabcEnd;
pabcTmp++)
{
if (iMaxWidth < (int) pabcTmp->abcB)
iMaxWidth = pabcTmp->abcB;
}
}
// Otherwise we will have to use just the advance width and assume
// A = C = 0.
else
{
// Allocate memory for array of ABC data.
if ( (piWidth = (LPINT) LocalAlloc(LMEM_FIXED, sizeof(INT) * count)) == (LPINT) NULL )
{
WARNING("LocalAlloc(pabc) failed\n");
return bRet;
}
// Get char widths.
if ( bUnicode )
{
if ( !GetCharWidthW(hdc, first, first + count - 1, piWidth) )
{
WARNING("GetCharWidthW failed\n");
LocalFree(piWidth);
return bRet;
}
}
else
{
if ( !GetCharWidthA(hdc, first, first + count - 1, piWidth) )
{
WARNING("GetCharWidthA failed\n");
LocalFree(piWidth);
return bRet;
}
}
// Find max glyph width.
for (piTmp = piWidth, piWidthEnd = piWidth + count;
piTmp < piWidthEnd;
piTmp++)
{
if (iMaxWidth < *piTmp)
iMaxWidth = *piTmp;
}
}
// Compute the dword aligned width. Bitmap scanlines must be aligned.
iBitmapWidth = (iMaxWidth + 31) & -32;
// Allocate memory for the DIB.
if ( (pv = (PVOID) LocalAlloc(LMEM_FIXED, (iBitmapWidth / 8) * tm.tmHeight)) == (PVOID) NULL )
{
WARNING("LocalAlloc(pv) failed\n");
(bTrueType) ? LocalFree(pabc) : LocalFree(piWidth);
return bRet;
}
// Create compatible DC/bitmap big enough to accomodate the biggest glyph
// in the range requested.
//!!!XXX -- Future optimization: use CreateDIBSection so that we
//!!!XXX don't need to do a GetDIBits for each glyph. Saves
//!!!XXX lots of CSR overhead.
hdcMem = CreateCompatibleDC(hdc);
if ( (hbm = CreateBitmap(iBitmapWidth, tm.tmHeight, 1, 1, (VOID *) NULL)) == (HBITMAP) NULL )
{
WARNING("CreateBitmap failed\n");
(bTrueType) ? LocalFree(pabc) : LocalFree(piWidth);
LocalFree(pv);
DeleteDC(hdcMem);
return bRet;
}
SelectObject(hdcMem, hbm);
SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT));
SetMapMode(hdcMem, MM_TEXT);
SetTextAlign(hdcMem, TA_TOP | TA_LEFT);
SetBkColor(hdcMem, RGB(0, 0, 0));
SetBkMode(hdcMem, OPAQUE);
SetTextColor(hdcMem, RGB(255, 255, 255));
// Setup bitmap info header to retrieve a DIB from the compatible bitmap.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = iBitmapWidth;
pbmi->bmiHeader.biHeight = tm.tmHeight;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 1;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
pbmi->bmiColors[0].rgbRed = 0;
pbmi->bmiColors[0].rgbGreen = 0;
pbmi->bmiColors[0].rgbBlue = 0;
pbmi->bmiColors[1].rgbRed = 0xff;
pbmi->bmiColors[1].rgbGreen = 0xff;
pbmi->bmiColors[1].rgbBlue = 0xff;
// Setup OpenGL to accept our bitmap format.
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &iUnpackRowLength);
glPixelStorei(GL_UNPACK_ROW_LENGTH, iBitmapWidth);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &iUnpackAlign);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
// Get the glyphs. Each glyph is rendered one at a time into the the
// memory DC with ExtTextOutW (notice that the optional rectangle is
// used to clear the background). Each glyph is then copied out of the
// memory DC's bitmap with GetDIBits into a buffer. This buffer is passed
// to glBitmap as each display list is created.
rc.left = 0;
rc.top = 0;
rc.right = iBitmapWidth;
rc.bottom = tm.tmHeight;
pabcTmp = pabc;
piTmp = piWidth;
for (wc = (WCHAR) first; wc < (WCHAR) (first + count); wc++, listBase++)
{
//!!!XXX -- Future optimization: grab all the glyphs with a single
//!!!XXX call to ExtTextOutA and GetDIBits into a large bitmap.
//!!!XXX This would save a lot of per glyph CSR and call overhead.
//!!!XXX A tall, thin bitmap with the glyphs arranged vertically
//!!!XXX would be convenient because then we wouldn't have to change
//!!!XXX the OpenGL pixel store row length for each glyph (which
//!!!XXX we would need to do if the glyphs were printed horizontal).
if ( bUnicode )
{
if ( !ExtTextOutW(hdcMem, bTrueType ? -pabcTmp->abcA : 0, 0, ETO_OPAQUE, &rc, &wc, 1, (INT *) NULL) ||
!GetDIBits(hdcMem, hbm, 0, tm.tmHeight, pv, pbmi, DIB_RGB_COLORS) )
{
WARNING("failed to render glyph\n");
goto wglUseFontBitmapsAW_cleanup;
}
}
else
{
if ( !ExtTextOutA(hdcMem, bTrueType ? -pabcTmp->abcA : 0, 0, ETO_OPAQUE, &rc, (LPCSTR) &wc, 1, (INT *) NULL) ||
!GetDIBits(hdcMem, hbm, 0, tm.tmHeight, pv, pbmi, DIB_RGB_COLORS) )
{
WARNING("failed to render glyph\n");
goto wglUseFontBitmapsAW_cleanup;
}
}
glNewList(listBase, GL_COMPILE);
glBitmap((GLsizei) iBitmapWidth,
(GLsizei) tm.tmHeight,
(GLfloat) (bTrueType ? -pabcTmp->abcA : 0),
(GLfloat) tm.tmDescent,
(GLfloat) (bTrueType ? (pabcTmp->abcA + pabcTmp->abcB + pabcTmp->abcC) : *piTmp),
(GLfloat) 0.0,
(GLubyte *) pv);
glEndList();
if (bTrueType)
pabcTmp++;
else
piTmp++;
}
// We can finally return success.
bRet = TRUE;
// Free resources.
wglUseFontBitmapsAW_cleanup:
glPixelStorei(GL_UNPACK_ROW_LENGTH, iUnpackRowLength);
glPixelStorei(GL_UNPACK_ALIGNMENT, iUnpackAlign);
(bTrueType) ? LocalFree(pabc) : LocalFree(piWidth);
LocalFree(pv);
DeleteDC(hdcMem);
DeleteObject(hbm);
return bRet;
}
/******************************Public*Routine******************************\
*
* wglShareLists
*
* Allows a rendering context to share the display lists of another RC
*
* Returns:
* TRUE if successful, FALSE otherwise
*
* History:
* Tue Dec 13 14:57:17 1994 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL WINAPI
wglShareLists(HGLRC hrcSource, HGLRC hrcShare)
{
BOOL fRet;
PLRC plrcSource, plrcShare;
ULONG irc;
PLHE plheRC;
HANDLE hrcSrvSource, hrcSrvShare;
GLFLUSH();
fRet = FALSE;
// Validate the contexts
if (cLockHandle((ULONG)hrcSource) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglShareLists: can't lock hrcSource 0x%lx\n",
hrcSource);
goto wglShareListsEnd_nolock;
}
irc = MASKINDEX(hrcSource);
plheRC = pLocalTable + irc;
plrcSource = (PLRC)plheRC->pv;
hrcSrvSource = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcSource->ident == LRC_IDENTIFIER,
"wglShareLists: Bad plrc\n");
if (cLockHandle((ULONG)hrcShare) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglShareLists: can't lock hrcShare 0x%lx\n",
hrcShare);
goto wglShareListsEnd_onelock;
}
irc = MASKINDEX(hrcShare);
plheRC = pLocalTable + irc;
plrcShare = (PLRC)plheRC->pv;
hrcSrvShare = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcShare->ident == LRC_IDENTIFIER,
"wglShareLists: Bad plrc\n");
#ifdef GL_METAFILE
// Metafile RC's can't share lists to ensure that metafiles are
// completely self-sufficient
if (plrcSource->uiGlsCaptureContext != 0 ||
plrcShare->uiGlsCaptureContext != 0 ||
plrcSource->uiGlsPlaybackContext != 0 ||
plrcShare->uiGlsPlaybackContext != 0)
{
DBGLEVEL(LEVEL_ERROR,
"wglShareLists: Attempt to share metafile RC\n");
SetLastError(ERROR_INVALID_HANDLE);
goto wglShareListsEnd;
}
#endif
// Lists can only be shared between like implementations so make
// sure that both contexts are either driver contexts or generic
// contexts
if ((plrcSource->dhrc != 0) != (plrcShare->dhrc != 0))
{
DBGLEVEL(LEVEL_ERROR, "wglShareLists: mismatched implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglShareListsEnd;
}
if (plrcSource->dhrc == 0)
{
PIXELFORMATDESCRIPTOR *ppfdShare, *ppfdSource;
// Fail sharing unless color parameters match for the two contexts
ppfdShare = &((__GLGENcontext *)hrcSrvShare)->CurrentFormat;
ppfdSource = &((__GLGENcontext *)hrcSrvSource)->CurrentFormat;
if (ppfdShare->iPixelType != ppfdSource->iPixelType ||
ppfdShare->cColorBits != ppfdSource->cColorBits ||
ppfdShare->cRedBits != ppfdSource->cRedBits ||
ppfdShare->cRedShift != ppfdSource->cRedShift ||
ppfdShare->cGreenBits != ppfdSource->cGreenBits ||
ppfdShare->cGreenShift != ppfdSource->cGreenShift ||
ppfdShare->cBlueBits != ppfdSource->cBlueBits ||
ppfdShare->cBlueShift != ppfdSource->cBlueShift ||
ppfdShare->cAlphaBits != ppfdSource->cAlphaBits ||
ppfdShare->cAlphaShift != ppfdSource->cAlphaShift ||
(ppfdShare->dwFlags & PFD_GENERIC_ACCELERATED) !=
(ppfdSource->dwFlags & PFD_GENERIC_ACCELERATED))
{
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
goto wglShareListsEnd;
}
// For generic contexts, tell the server to share the lists
fRet = __wglShareLists(hrcSrvShare, hrcSrvSource);
if (!fRet)
{
DBGERROR("wglShareLists: server call failed\n");
}
}
else
{
// For device contexts tell the server to share the lists
// Ensure that both implementations are the same
if (plrcSource->pGLDriver != plrcShare->pGLDriver)
{
DBGLEVEL(LEVEL_ERROR, "wglShareLists: mismatched "
"implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglShareListsEnd;
}
ASSERTOPENGL(plrcSource->pGLDriver != NULL,
"wglShareLists: No GLDriver\n");
// Older drivers may not support this entry point, so
// fail the call if they don't
if (plrcSource->pGLDriver->pfnDrvShareLists == NULL)
{
WARNING("wglShareLists called on driver context "
"without driver support\n");
SetLastError(ERROR_NOT_SUPPORTED);
}
else
{
fRet = plrcSource->pGLDriver->pfnDrvShareLists(plrcSource->dhrc,
plrcShare->dhrc);
}
}
wglShareListsEnd:
vUnlockHandle((ULONG)hrcShare);
wglShareListsEnd_onelock:
vUnlockHandle((ULONG)hrcSource);
wglShareListsEnd_nolock:
return fRet;
}
/******************************Public*Routine******************************\
*
* wglGetDefaultProcAddress
*
* Returns generic extension functions for metafiling
*
* History:
* Tue Nov 28 16:40:35 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
PROC WINAPI wglGetDefaultProcAddress(LPCSTR lpszProc)
{
return pfnGenGlExtProc(lpszProc);
}
/******************************Public*Routine******************************\
* wglGetProcAddress
*
* The wglGetProcAddress function returns the address of an OpenGL extension
* function to be used with the current OpenGL rendering context.
*
* Arguments:
* lpszProc - Points to a null-terminated string containing the function
* name. The function must be an extension supported by the
* implementation.
*
* Returns:
* If the function succeeds, the return value is the address of the extension
* function. If no current context exists or the function fails, the return
* value is NULL. To get extended error information, call GetLastError.
*
* History:
* Thu Dec 01 13:50:22 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
PROC WINAPI wglGetProcAddress(LPCSTR lpszProc)
{
PLRC plrc = GLTEB_CLTCURRENTRC();
DBGENTRY("wglGetProcAddress\n");
// Flush OpenGL calls.
GLFLUSH();
// Return error if there is no current RC.
if (!plrc)
{
WARNING("wglGetProcAddress: no current RC\n");
SetLastError(ERROR_INVALID_HANDLE);
return((PROC) NULL);
}
// Handle generic RC.
// Return the generic extension function entry point
if (!plrc->dhrc)
return(pfnGenGlExtProc(lpszProc));
// Handle driver RC.
// There are 3 cases:
// 1. New drivers that support DrvGetProcAddress.
// 2. Old drivers that don't support DrvGetProcAddress but export the function
// 3. If we fail to obtain a function address in 1 and 2, it may still be
// simulated by the generic implemenation for the driver
// (e.g. glDrawArraysEXT). Return the simulated entry point if found.
if (plrc->pGLDriver->pfnDrvGetProcAddress)
{
// Case 1
PROC pfn = plrc->pGLDriver->pfnDrvGetProcAddress(lpszProc);
if (pfn)
return(pfn);
}
#ifdef OBSOLETE
else
{
// Case 2
PROC pfn = GetProcAddress(plrc->pGLDriver->hModule, lpszProc);
if (pfn)
return(pfn);
}
#endif
// Case 3
return (pfnSimGlExtProc(lpszProc));
}
/******************************Public*Routine******************************\
* pfnGenGlExtProc
*
* Return the generic implementation extension function address.
*
* Returns NULL if the function is not found.
*
* History:
* Thu Dec 01 13:50:22 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
typedef struct _GLEXTPROC {
LPCSTR szProc; // extension function name
PROC Proc; // extension function address
} GLEXTPROC, *PGLEXTPROC;
// Extension functions supported by the generic implementation
// See also genglExtProcsSim for simulations.
// NOTE: remember to update GL_EXTENSIONS in glGetString.
GLEXTPROC genglExtProcs[] =
{
#ifdef NT_DEADCODE_VERTEXARRAY
{ "glArrayElementEXT" , (PROC) glsimArrayElementEXT },
{ "glDrawArraysEXT" , (PROC) glsimDrawArraysEXT },
{ "glVertexPointerEXT" , (PROC) glsimVertexPointerEXT },
{ "glNormalPointerEXT" , (PROC) glsimNormalPointerEXT },
{ "glColorPointerEXT" , (PROC) glsimColorPointerEXT },
{ "glIndexPointerEXT" , (PROC) glsimIndexPointerEXT },
{ "glTexCoordPointerEXT" , (PROC) glsimTexCoordPointerEXT },
{ "glEdgeFlagPointerEXT" , (PROC) glsimEdgeFlagPointerEXT },
{ "glGetPointervEXT" , (PROC) glsimGetPointervEXT },
{ "glArrayElementArrayEXT" , (PROC) glsimArrayElementArrayEXT },
#endif
{ "glAddSwapHintRectWIN" , (PROC) glAddSwapHintRectWIN },
{ "glColorTableEXT" , (PROC) glColorTableEXT },
{ "glColorSubTableEXT" , (PROC) glColorSubTableEXT },
{ "glGetColorTableEXT" , (PROC) glGetColorTableEXT },
{ "glGetColorTableParameterivEXT", (PROC) glGetColorTableParameterivEXT},
{ "glGetColorTableParameterfvEXT", (PROC) glGetColorTableParameterfvEXT},
};
static PROC pfnGenGlExtProc(LPCSTR lpszProc)
{
CONST CHAR *pch1, *pch2;
int i;
DBGENTRY("pfnGenGlExtProc\n");
// Return extension function address if it is found.
for (i = 0; i < sizeof(genglExtProcs) / sizeof(genglExtProcs[0]); i++)
{
// Compare names.
for (pch1 = lpszProc, pch2 = genglExtProcs[i].szProc;
*pch1 == *pch2 && *pch1;
pch1++, pch2++)
;
// If found, return the address.
if (*pch1 == *pch2 && !*pch1)
return genglExtProcs[i].Proc;
}
// Extension is not supported by the generic implementation, return NULL.
SetLastError(ERROR_PROC_NOT_FOUND);
return((PROC) NULL);
}
/******************************Public*Routine******************************\
* pfnSimGlExtProc
*
* Return the extension function address that is the generic implemenation's
* simulation for the client drivers. The simulation is used only if the
* driver does not support an extension that is desirable to apps.
*
* Returns NULL if the function is not found.
*
* History:
* Thu Dec 01 13:50:22 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
// Extension functions simulated by the generic implementation for the client
// drivers
// NOTE: remember to update GL_EXTENSIONS in glGetString.
#ifdef NT_DEADCODE_VERTEXARRAY
GLEXTPROC genglExtProcsSim[] =
{
// Remember to update GL_EXTENSIONS in glGetString!
{ "glArrayElementEXT" , (PROC) glsimArrayElementEXT },
{ "glDrawArraysEXT" , (PROC) glsimDrawArraysEXT },
{ "glVertexPointerEXT" , (PROC) glsimVertexPointerEXT },
{ "glNormalPointerEXT" , (PROC) glsimNormalPointerEXT },
{ "glColorPointerEXT" , (PROC) glsimColorPointerEXT },
{ "glIndexPointerEXT" , (PROC) glsimIndexPointerEXT },
{ "glTexCoordPointerEXT" , (PROC) glsimTexCoordPointerEXT },
{ "glEdgeFlagPointerEXT" , (PROC) glsimEdgeFlagPointerEXT },
{ "glGetPointervEXT" , (PROC) glsimGetPointervEXT },
{ "glArrayElementArrayEXT" , (PROC) glsimArrayElementArrayEXT }
};
#endif
static PROC pfnSimGlExtProc(LPCSTR lpszProc)
{
#ifdef NT_DEADCODE_VERTEXARRAY
CONST CHAR *pch1, *pch2;
int i;
DBGENTRY("pfnSimGlExtProc\n");
// Return extension function address if it is found.
for (i = 0; i < sizeof(genglExtProcsSim) / sizeof(genglExtProcsSim[0]); i++)
{
// Compare names.
for (pch1 = lpszProc, pch2 = genglExtProcsSim[i].szProc;
*pch1 == *pch2 && *pch1;
pch1++, pch2++)
;
// If found, return the address.
if (*pch1 == *pch2 && !*pch1)
return genglExtProcsSim[i].Proc;
}
#endif
// Extension is not supported by the generic implementation, return NULL.
SetLastError(ERROR_PROC_NOT_FOUND);
return((PROC) NULL);
}
/******************************Public*Routine******************************\
*
* wglCopyContext
*
* Copies all of one context's state to another one
*
* Returns:
* TRUE if successful, FALSE otherwise
*
* History:
* Fri May 26 14:57:17 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL WINAPI
wglCopyContext(HGLRC hrcSource, HGLRC hrcDest, UINT fuMask)
{
BOOL fRet;
PLRC plrcSource, plrcDest;
ULONG irc;
PLHE plheRC;
HANDLE hrcSrvSource, hrcSrvDest;
GLFLUSH();
fRet = FALSE;
// Validate the contexts
if (cLockHandle((ULONG)hrcSource) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglCopyContext: can't lock hrcSource 0x%lx\n",
hrcSource);
goto wglCopyContextEnd_nolock;
}
irc = MASKINDEX(hrcSource);
plheRC = pLocalTable + irc;
plrcSource = (PLRC)plheRC->pv;
hrcSrvSource = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcSource->ident == LRC_IDENTIFIER,
"wglCopyContext: Bad plrc\n");
if (cLockHandle((ULONG)hrcDest) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglCopyContext: can't lock hrcDest 0x%lx\n",
hrcDest);
goto wglCopyContextEnd_onelock;
}
irc = MASKINDEX(hrcDest);
plheRC = pLocalTable + irc;
plrcDest = (PLRC)plheRC->pv;
hrcSrvDest = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcDest->ident == LRC_IDENTIFIER,
"wglCopyContext: Bad plrc\n");
// Context can only be copied between like implementations so make
// sure that both contexts are either driver contexts or generic
// contexts
if ((plrcSource->dhrc != 0) != (plrcDest->dhrc != 0))
{
DBGLEVEL(LEVEL_ERROR, "wglCopyContext: mismatched implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglCopyContextEnd;
}
// The destination context cannot be current to a thread
if (plrcDest->tidCurrent != INVALID_THREAD_ID)
{
DBGLEVEL(LEVEL_ERROR, "wglCopyContext: destination has tidCurrent\n");
SetLastError(ERROR_INVALID_HANDLE);
goto wglCopyContextEnd;
}
if (plrcSource->dhrc == 0)
{
// For generic contexts, tell the server to share the lists
fRet = __wglCopyContext(hrcSrvSource, hrcSrvDest, fuMask);
if (!fRet)
{
DBGERROR("wglCopyContext: server call failed\n");
}
}
else
{
// For device contexts tell the driver to copy the context
// Ensure that both implementations are the same
if (plrcSource->pGLDriver != plrcDest->pGLDriver)
{
DBGLEVEL(LEVEL_ERROR, "wglCopyContext: mismatched "
"implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglCopyContextEnd;
}
ASSERTOPENGL(plrcSource->pGLDriver != NULL,
"wglCopyContext: No GLDriver\n");
// Older drivers may not support this entry point, so
// fail the call if they don't
if (plrcSource->pGLDriver->pfnDrvCopyContext == NULL)
{
WARNING("wglCopyContext called on driver context "
"without driver support\n");
SetLastError(ERROR_NOT_SUPPORTED);
}
else
{
fRet = plrcSource->pGLDriver->pfnDrvCopyContext(plrcSource->dhrc,
plrcDest->dhrc,
fuMask);
}
}
wglCopyContextEnd:
vUnlockHandle((ULONG)hrcDest);
wglCopyContextEnd_onelock:
vUnlockHandle((ULONG)hrcSource);
wglCopyContextEnd_nolock:
return fRet;
}