/******************************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 #include #include #include #include #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; }