/******************************Module*Header*******************************\ * Module Name: makecur.c * * wglMakeCurrent implementation * * Created: 02-10-1997 * * Copyright (c) 1993-1997 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include #include #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); }