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