windows-nt/Source/XPSP1/NT/multimedia/opengl/client/makecur.c
2020-09-26 16:20:57 +08:00

659 lines
18 KiB
C

/******************************Module*Header*******************************\
* Module Name: makecur.c
*
* wglMakeCurrent implementation
*
* Created: 02-10-1997
*
* Copyright (c) 1993-1997 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <context.h>
#include <global.h>
#include "metasup.h"
#include "wgldef.h"
/******************************Public*Routine******************************\
*
* __wglSetProcTable
*
* Callback function given to ICDs to set a proc table
*
\**************************************************************************/
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******************************\
*
* CheckDeviceModes
*
* Ensures that the HDC doesn't have any disallowed state
*
* History:
* Mon Aug 26 15:03:28 1996 -by- Drew Bliss [drewb]
* Split from wglMakeCurrent
*
\**************************************************************************/
BOOL CheckDeviceModes(HDC hdc)
{
SIZE szW, szV;
XFORM xform;
POINT pt;
HRGN hrgnTmp;
int iRgn;
// For release 1, GDI transforms must be identity.
// This is to allow GDI transform binding in future.
switch (GetMapMode(hdc))
{
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);
return FALSE;
}
// 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)))
return FALSE;
iRgn = GetClipRgn(hdc, hrgnTmp);
if (!DeleteObject(hrgnTmp))
ASSERTOPENGL(FALSE, "DeleteObject failed");
switch (iRgn)
{
case -1: // error
WARNING("wglMakeCurrent: GetClipRgn failed\n");
return FALSE;
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);
return FALSE;
}
return TRUE;
}
/******************************Public*Routine******************************\
*
* MakeAnyCurrent
*
* Makes any type of context current
*
* History:
* Mon Aug 26 15:00:44 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL MakeAnyCurrent(HGLRC hrc, int ipfd, DWORD dwObjectType,
GLWINDOWID *pgwid)
{
HGLRC hrcSrv;
PLRC plrc;
DWORD tidCurrent;
ULONG irc;
PLHE plheRC;
PGLCLTPROCTABLE pglProcTable;
PGLEXTPROCTABLE pglExtProcTable;
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);
}
}
// 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 RC.
if (cLockHandle((ULONG_PTR)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_PTR)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_PTR)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_PTR)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");
// If the pixel format of the window or surface is different from that of
// the RC, return error.
if (ipfd != plrc->iPixelFormat)
{
DBGERROR("wglMakeCurrent: different hdc and hrc pixel formats\n");
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
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(pgwid, hrcSrv, plrc->uiGlsCaptureContext != 0))
{
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(pgwid->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->gwidCurrent = *pgwid;
GLTEB_SET_CLTCURRENTRC(plrc);
SetCltProcTable(pglProcTable, pglExtProcTable, TRUE);
#ifdef GL_METAFILE
// Set up metafile context if necessary
if (plrc->fCapturing)
{
__GL_SETUP();
ActivateMetaRc(plrc, pgwid->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
// 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];
// reset next DPA message offset
pa->nextMsgOffset = PA_nextMsgOffset_RESET_VALUE;
// 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_PTR)hrc);
wglMakeCurrent_error_nolock:
if (GLTEB_CLTCURRENTRC() != (PLRC) NULL)
(void) bMakeNoCurrent();
return(FALSE);
}
/******************************Public*Routine******************************\
*
* WindowIdFromHdc
*
* Fills out a GLWINDOWID for an HDC
*
* History:
* Wed Aug 28 18:33:19 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void APIENTRY WindowIdFromHdc(HDC hdc, GLWINDOWID *pgwid)
{
LPDIRECTDRAWSURFACE pdds;
HDC hdcDriver;
if (pfnGetSurfaceFromDC != NULL &&
pfnGetSurfaceFromDC(hdc, &pdds, &hdcDriver) == DD_OK)
{
// Release reference on the surface since this surface value
// is only used as an identifier.
pdds->lpVtbl->Release(pdds);
pgwid->iType = GLWID_DDRAW;
pgwid->hwnd = NULL;
pgwid->hdc = hdcDriver;
pgwid->pdds = pdds;
}
else
{
pgwid->hdc = hdc;
pgwid->hwnd = WindowFromDC(hdc);
if (pgwid->hwnd == NULL)
{
pgwid->iType = GLWID_HDC;
}
else
{
pgwid->iType = GLWID_HWND;
}
pgwid->pdds = NULL;
}
}
/******************************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)
{
int iPixelFormat;
DWORD dwObjectType;
GLWINDOWID gwid;
DBGENTRY("wglMakeCurrent\n");
if (GLTEB_CLTCURRENTRC() != NULL)
{
// Flush OpenGL calls.
glFlush();
// Avoid HDC validation for simple make-non-current cases
if (hrc == NULL)
{
return bMakeNoCurrent();
}
}
// 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);
return FALSE;
}
break;
#else
DBGLEVEL1(LEVEL_ERROR, "wglMakeCurrent: metafile hdc: 0x%lx\n", hdc);
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
#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);
return FALSE;
}
if (!CheckDeviceModes(hdc))
{
return FALSE;
}
#ifdef GL_METAFILE
// For metafile RC's, use the reference HDC rather than the
// metafile DC
// Skip pixel format checks
if (dwObjectType == OBJ_ENHMETADC)
{
iPixelFormat = 0;
goto NoPixelFormat;
}
#endif
// 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");
return FALSE;
}
#ifdef GL_METAFILE
NoPixelFormat:
#endif
WindowIdFromHdc(hdc, &gwid);
return MakeAnyCurrent(hrc, iPixelFormat, dwObjectType, &gwid);
}
/******************************Public*Routine******************************\
* bMakeNoCurrent
*
* Make the current RC inactive.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
BOOL bMakeNoCurrent(void)
{
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->gwidCurrent.iType != GLWID_ERROR,
"bMakeNoCurrent: Current surface 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(NULL, NULL, FALSE);
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->gwidCurrent.iType = GLWID_ERROR;
GLTEB_SET_CLTCURRENTRC(NULL);
SetCltProcTable(&glNullCltProcTable, &glNullExtProcTable, TRUE);
vUnlockHandle((ULONG_PTR)(plrc->hrc));
return(bRet);
}