#include "precomp.h" #pragma hdrstop #include #include "genci.h" #include "genrgb.h" #include "devlock.h" #include "imports.h" // // CJ_ALIGNDWORD computes the minimum size (in bytes) of a DWORD array that // contains at least cj bytes. // #define CJ_ALIGNDWORD(cj) ( ((cj) + (sizeof(DWORD)-1)) & (-((signed)sizeof(DWORD))) ) // // BITS_ALIGNDWORD computes the minimum size (in bits) of a DWORD array that // contains at least c bits. // // We assume that there will always be 8 bits in a byte and that sizeof() // always returns size in bytes. The rest is independent of the definition // of DWORD. // #define BITS_ALIGNDWORD(c) ( ((c) + ((sizeof(DWORD)*8)-1)) & (-((signed)(sizeof(DWORD)*8))) ) // change to "static" after debugging #define STATIC #if DBG // not multithreaded safe, but only for testing #define RANDOMDISABLE \ { \ long saveRandom = glRandomMallocFail; \ glRandomMallocFail = 0; #define RANDOMREENABLE \ if (saveRandom) \ glRandomMallocFail = saveRandom; \ } #else #define RANDOMDISABLE #define RANDOMREENABLE #endif /* DBG */ #define INITIAL_TIMESTAMP ((ULONG)-1) /* * Function Prototypes */ BOOL APIENTRY ValidateLayerIndex(int iLayer, PIXELFORMATDESCRIPTOR *ppfd); /* * Private functions */ void FASTCALL GetContextModes(__GLGENcontext *gengc); STATIC void FASTCALL ApplyViewport(__GLcontext *gc); GLboolean ResizeAncillaryBuffer(__GLGENbuffers *, __GLbuffer *, GLint, GLint); GLboolean ResizeHardwareBackBuffer(__GLGENbuffers *, __GLcolorBuffer *, GLint, GLint); GLboolean ResizeUnownedDepthBuffer(__GLGENbuffers *, __GLbuffer *, GLint, GLint); /******************************Public*Routine******************************\ * * EmptyFillStrokeCache * * Cleans up any objects in the fill and stroke cache * * History: * Tue Aug 15 15:37:30 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void FASTCALL EmptyFillStrokeCache(__GLGENcontext *gengc) { if (gengc->hbrFill != NULL) { DeleteObject(gengc->hbrFill); gengc->hbrFill = NULL; gengc->crFill = COLORREF_UNUSED; gengc->hdcFill = NULL; } #if DBG else { ASSERTOPENGL(gengc->crFill == COLORREF_UNUSED, "crFill inconsistent\n"); } #endif if (gengc->hpenStroke != NULL) { // Deselect the pen before deletion if necessary if (gengc->hdcStroke != NULL) { SelectObject(gengc->hdcStroke, GetStockObject(BLACK_PEN)); gengc->hdcStroke = NULL; } DeleteObject(gengc->hpenStroke); gengc->hpenStroke = NULL; gengc->cStroke.r = -1.0f; gengc->fStrokeInvalid = TRUE; } #if DBG else { ASSERTOPENGL(gengc->cStroke.r < 0.0f && gengc->fStrokeInvalid, "rStroke inconsistent\n"); } #endif } /******************************Public*Routine******************************\ * glsrvDeleteContext * * Deletes the generic context. * * Returns: * TRUE if successful, FALSE otherwise. * \**************************************************************************/ BOOL APIENTRY glsrvDeleteContext(__GLcontext *gc) { __GLGENcontext *gengc; gengc = (__GLGENcontext *)gc; /* Free ancillary buffer related data. Note that these calls do ** *not* free software ancillary buffers, just any related data ** stored in them. The ancillary buffers are freed on window destruction */ if (gc->modes.accumBits) { DBGLEVEL(LEVEL_ALLOC, "DestroyContext: Freeing accumulation buffer related data\n"); __glFreeAccum64(gc, &gc->accumBuffer); } if (gc->modes.depthBits) { DBGLEVEL(LEVEL_ALLOC, "DestroyContext: Freeing depth buffer related data\n"); __glFreeDepth32(gc, &gc->depthBuffer); } if (gc->modes.stencilBits) { DBGLEVEL(LEVEL_ALLOC, "DestroyContext: Freeing stencil buffer related data\n"); __glFreeStencil8(gc, &gc->stencilBuffer); } /* Free Translate & Inverse Translate vectors */ if ((gengc->pajTranslateVector != NULL) && (gengc->pajTranslateVector != gengc->xlatPalette)) GCFREE(gc, gengc->pajTranslateVector); if (gengc->pajInvTranslateVector != NULL) GCFREE(gc, gengc->pajInvTranslateVector); // Make sure that any cached GDI objects are freed // This is normally done in LoseCurrent but a context may be // left current and then cleaned up EmptyFillStrokeCache(gengc); /* /* Free the span dibs and storage. */ #ifndef _CLIENTSIDE_ if (gengc->StippleBitmap) EngDeleteSurface((HSURF)gengc->StippleBitmap); #endif wglDeleteScanlineBuffers(gengc); if (gengc->StippleBits) GCFREE(gc, gengc->StippleBits); // Free __GLGENbitmap front-buffer structure if (gc->frontBuffer.bitmap) GCFREE(gc, gc->frontBuffer.bitmap); #ifndef _CLIENTSIDE_ /* * Free the buffers that may have been allocated by feedback * or selection */ if ( NULL != gengc->RenderState.SrvSelectBuffer ) { #ifdef NT // match the allocation function FREE(gengc->RenderState.SrvSelectBuffer); #else GCFREE(gc, gengc->RenderState.SrvSelectBuffer); #endif } if ( NULL != gengc->RenderState.SrvFeedbackBuffer) { #ifdef NT // match the allocation function FREE(gengc->RenderState.SrvFeedbackBuffer); #else GCFREE(gc, gengc->RenderState.SrvFeedbackBuffer); #endif } #endif //_CLIENTSIDE_ #ifdef _CLIENTSIDE_ /* * Cleanup logical palette copy if it exists. */ if ( gengc->ppalBuf ) FREE(gengc->ppalBuf); #endif /* Destroy acceleration-specific context information */ __glGenDestroyAccelContext(gc); #ifdef _MCD_ /* Free the MCD state structure and associated resources. */ if (gengc->_pMcdState) { GenMcdDeleteContext(gengc->_pMcdState); } #endif /* Free any temporay buffers in abnormal process exit */ GC_TEMP_BUFFER_EXIT_CLEANUP(gc); // Release references to DirectDraw surfaces if (gengc->gsurf.dwFlags & GLSURF_DIRECTDRAW) { GLWINDOWID gwid; GLGENwindow *pwnd; // Destroy window created for this context gwid.iType = GLWID_DDRAW; gwid.pdds = gengc->gsurf.dd.gddsFront.pdds; gwid.hdc = gengc->gsurf.hdc; gwid.hwnd = NULL; pwnd = pwndGetFromID(&gwid); ASSERTOPENGL(pwnd != NULL, "Destroying DDraw context without window\n"); pwndCleanup(pwnd); gengc->gsurf.dd.gddsFront.pdds->lpVtbl-> Release(gengc->gsurf.dd.gddsFront.pdds); if (gengc->gsurf.dd.gddsZ.pdds != NULL) { gengc->gsurf.dd.gddsZ.pdds->lpVtbl-> Release(gengc->gsurf.dd.gddsZ.pdds); } } /* Destroy rest of software context (in soft code) */ __glDestroyContext(gc); return TRUE; } /******************************Public*Routine******************************\ * glsrvLoseCurrent * * Releases the current context (makes it not current). * \**************************************************************************/ VOID APIENTRY glsrvLoseCurrent(__GLcontext *gc) { __GLGENcontext *gengc; gengc = (__GLGENcontext *)gc; DBGENTRY("LoseCurrent\n"); ASSERTOPENGL(gc == GLTEB_SRVCONTEXT(), "LoseCurrent not current!"); /* ** Release lock if still held. */ if (gengc->fsLocks != 0) { glsrvReleaseLock(gengc); } /* ** Unscale derived state that depends upon the color scales. This ** is needed so that if this context is rebound to a memdc, it can ** then rescale all of those colors using the memdc color scales. */ __glContextUnsetColorScales(gc); memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent)); /* ** Clean up HDC-specific GDI objects */ EmptyFillStrokeCache(gengc); /* ** Free up fake window for IC's */ if ((gengc->dwCurrentFlags & GLSURF_METAFILE) && gengc->ipfdCurrent == 0) { GLGENwindow *pwnd; pwnd = gengc->pwndMakeCur; ASSERTOPENGL(pwnd != NULL, "IC with no pixel format but no fake window\n"); if (pwnd->buffers != NULL) { __glGenFreeBuffers(pwnd->buffers); } DeleteCriticalSection(&pwnd->sem); FREE(pwnd); } gengc->pwndMakeCur = NULL; #ifdef _MCD_ /* ** Disconnect MCD state. */ gengc->pMcdState = (GENMCDSTATE *) NULL; #endif gc->constants.width = 0; gc->constants.height = 0; // Set paTeb to NULL for debugging. gc->paTeb = NULL; GLTEB_SET_SRVCONTEXT(0); } /******************************Public*Routine******************************\ * glsrvSwapBuffers * * This uses the software implementation of double buffering. An engine * allocated bitmap is allocated for use as the back buffer. The SwapBuffer * routine copies the back buffer to the front buffer surface (which may * be another DIB, a device surface in DIB format, or a device managed * surface (with a device specific format). * * The SwapBuffer routine does not disturb the contents of the back buffer, * though the defined behavior for now is undefined. * * Note: the caller should be holding the per-window semaphore. * * History: * 19-Nov-1993 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL APIENTRY glsrvSwapBuffers(HDC hdc, GLGENwindow *pwnd) { DBGENTRY("glsrvSwapBuffers\n"); if ( pwnd->buffers ) { __GLGENbuffers *buffers; __GLGENbitmap *genBm; buffers = pwnd->buffers; if (buffers->pMcdSurf) { return GenMcdSwapBuffers(hdc, pwnd); } genBm = &buffers->backBitmap; // Make sure the backbuffer exists if (genBm->hbm) { if (!RECTLISTIsEmpty(&buffers->rl) && !buffers->fMax) { wglCopyBufRECTLIST( hdc, genBm->hdc, 0, 0, buffers->backBuffer.width, buffers->backBuffer.height, &buffers->rl ); } else { buffers->fMax = FALSE; wglCopyBuf( hdc, genBm->hdc, 0, 0, buffers->backBuffer.width, buffers->backBuffer.height ); } RECTLISTSetEmpty(&buffers->rl); } if( buffers->alphaBits && buffers->alphaBackBuffer && buffers->alphaFrontBuffer) { ASSERTOPENGL(buffers->alphaFrontBuffer->size == buffers->alphaBackBuffer->size, "Destination alpha buffer size mismatch\n"); // Destination alpha values are kept in separate buffers. // If this buffer set has destination alpha buffers, // copy the back alpha values into the front alpha buffer. RtlCopyMemory(buffers->alphaFrontBuffer->base, buffers->alphaBackBuffer->base, buffers->alphaBackBuffer->size); } return TRUE; } return FALSE; } /******************************Public*Routine******************************\ * gdiCopyPixels * * Copy span [(x, y), (x + cx, y)) (inclusive-exclusive) to/from specified * color buffer cfb from/to the scanline buffer. * * If bIn is TRUE, the copy is from the scanline buffer to the buffer. * If bIn is FALSE, the copy is from the buffer to the scanline buffer. * \**************************************************************************/ void gdiCopyPixels(__GLGENcontext *gengc, __GLcolorBuffer *cfb, GLint x, GLint y, GLint cx, BOOL bIn) { wglCopyBits(gengc, gengc->pwndLocked, gengc->ColorsBitmap, x, y, cx, bIn); } /******************************Public*Routine******************************\ * dibCopyPixels * * Special case version of gdiCopyPixels that is used when cfb is a DIB, * either a real DIB or a device surface which has a DIB format. * * This function *must* be used in lieu of gdiCopyPixels if we are * directly accessing the screen as it is not safe to call GDI entry * points with the screen locked * * History: * 24-May-1995 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ void dibCopyPixels(__GLGENcontext *gengc, __GLcolorBuffer *cfb, GLint x, GLint y, GLint cx, BOOL bIn) { VOID *pvDib; UINT cjPixel = gengc->gsurf.pfd.cColorBits >> 3; ULONG ulSpanVisibility; GLint cWalls; GLint *pWalls; // Don't handle VGA DIBs. // // We are not supposed to call GDI if directly accessing the screen. However, // we should be able to assume that 4bpp devices do not support // direct access making it OK for us to punt this call to the GDI version. // This is true for Win95 and, according to AndrewGo, will be // true for WinNT SUR. if (gengc->gsurf.pfd.cColorBits <= 4) { ASSERTOPENGL( !((cfb->buf.flags & DIB_FORMAT) && !(cfb->buf.flags & MEMORY_DC)), "dibCopyPixels: unexpected 4bpp direct surface\n" ); gdiCopyPixels(gengc, cfb, x, y, cx, bIn); return; } // Find out clipping info. if ((cfb->buf.flags & (NO_CLIP | DIB_FORMAT)) == (NO_CLIP | DIB_FORMAT)) { ulSpanVisibility = WGL_SPAN_ALL; } else { ulSpanVisibility = wglSpanVisible(x, y, cx, &cWalls, &pWalls); } // Completely clipped, nothing to do. if (ulSpanVisibility == WGL_SPAN_NONE) return; // Completely visible. // // Actually, if bIn == FALSE (i.e., copy from screen to scanline buffer) // we can cheat a little and ignore the clipping. else if ( (ulSpanVisibility == WGL_SPAN_ALL) || !bIn ) { // Get pointer into DIB at position (x, y). pvDib = (VOID *) (((BYTE *) gengc->gc.front->buf.base) + gengc->gc.front->buf.outerWidth * y + cjPixel * x); // If bIn == TRUE, copy from scanline buffer to DIB. // Otherwise, copy from DIB to scanline buffer. if (bIn) RtlCopyMemory_UnalignedDst(pvDib, gengc->ColorsBits, cjPixel * cx); else RtlCopyMemory_UnalignedSrc(gengc->ColorsBits, pvDib, cjPixel * cx); } // Partially visible. else { GLint xEnd = x + cx; // end of the span UINT cjSpan; // size of the current portion of span to copy VOID *pvBits; // current copy position in the scanline buf BYTE *pjScan; // address of scan line in DIB ASSERTOPENGL( cWalls && pWalls, "dibCopyPixels(): bad wall array\n"); // The walls are walked until either the end of the array is reached // or the walls exceed the end of the span. The do..while loop // construct was choosen because the first iteration will always // copy something and after the first iteration we are guaranteed // to be in the "cWalls is even" case. This makes the testing the // walls against the span end easier. // // If cWalls is even, clip the span to each pair of walls in pWalls. // If cWalls is odd, form the first pair with (x, pWalls[0]) and then // pair the remaining walls starting with pWalls[1]. pjScan = (VOID *) (((BYTE *) gengc->gc.front->buf.base) + gengc->gc.front->buf.outerWidth * y); do { //!!!XXX -- Make faster by pulling the odd case out of the loop if (cWalls & 0x1) { pvDib = (VOID *) (pjScan + (cjPixel * x)); pvBits = gengc->ColorsBits; if ( pWalls[0] <= xEnd ) cjSpan = cjPixel * (pWalls[0] - x); else cjSpan = cjPixel * cx; pWalls++; cWalls--; // Now cWalls is even! } else { pvDib = (VOID *) (pjScan + (cjPixel * pWalls[0])); pvBits = (VOID *) (((BYTE *) gengc->ColorsBits) + cjPixel * (pWalls[0] - x)); if ( pWalls[1] <= xEnd ) cjSpan = cjPixel * (pWalls[1] - pWalls[0]); else cjSpan = cjPixel * (xEnd - pWalls[0]); pWalls += 2; cWalls -= 2; } // We are going to cheat and ignore clipping when copying from // the dib to the scanline buffer (i.e., we are going to handle // the !bIn case as if it were WGL_SPAN_ALL). Thus, we can assume // that bIn == TRUE if we get to here. // // If clipping is needed to read the DIB, its trivial to turn it // back on. // // RtlCopyMemory(bIn ? pvDib : pvBits, // bIn ? pvBits : pvDib, // cjSpan); //!!!dbug -- Possible COMPILER BUG (compiler should check for //!!!dbug alignment before doing the "rep movsd"). Keep around //!!!dbug as a test case. #if 1 RtlCopyMemory_UnalignedDst(pvDib, pvBits, cjSpan); #else RtlCopyMemory(pvDib, pvBits, cjSpan); #endif } while ( cWalls && (pWalls[0] < xEnd) ); } } /******************************Public*Routine******************************\ * MaskFromBits * * Support routine for GetContextModes. Computes a color mask given that * colors bit count and shift position. * \**************************************************************************/ #define MaskFromBits(shift, count) \ ((0xffffffff >> (32-(count))) << (shift)) /******************************Public*Routine******************************\ * GetContextModes * * Convert the information from Gdi into OpenGL format after checking that * the formats are compatible and that the surface is compatible with the * format. * * Called during a glsrvMakeCurrent(). * \**************************************************************************/ void FASTCALL GetContextModes(__GLGENcontext *gengc) { PIXELFORMATDESCRIPTOR *pfmt; __GLcontextModes *Modes; DBGENTRY("GetContextModes\n"); Modes = &((__GLcontext *)gengc)->modes; pfmt = &gengc->gsurf.pfd; if (pfmt->iPixelType == PFD_TYPE_RGBA) Modes->rgbMode = GL_TRUE; else Modes->rgbMode = GL_FALSE; Modes->colorIndexMode = !Modes->rgbMode; if (pfmt->dwFlags & PFD_DOUBLEBUFFER) Modes->doubleBufferMode = GL_TRUE; else Modes->doubleBufferMode = GL_FALSE; if (pfmt->dwFlags & PFD_STEREO) Modes->stereoMode = GL_TRUE; else Modes->stereoMode = GL_FALSE; Modes->accumBits = pfmt->cAccumBits; Modes->haveAccumBuffer = GL_FALSE; Modes->auxBits = NULL; // This is a pointer Modes->depthBits = pfmt->cDepthBits; Modes->haveDepthBuffer = GL_FALSE; Modes->stencilBits = pfmt->cStencilBits; Modes->haveStencilBuffer= GL_FALSE; if (pfmt->cColorBits > 8) Modes->indexBits = 8; else Modes->indexBits = pfmt->cColorBits; Modes->indexFractionBits= 0; // The Modes->{Red,Green,Blue}Bits are used in soft Modes->redBits = pfmt->cRedBits; Modes->greenBits = pfmt->cGreenBits; Modes->blueBits = pfmt->cBlueBits; Modes->alphaBits = pfmt->cAlphaBits; Modes->redMask = MaskFromBits(pfmt->cRedShift, pfmt->cRedBits); Modes->greenMask = MaskFromBits(pfmt->cGreenShift, pfmt->cGreenBits); Modes->blueMask = MaskFromBits(pfmt->cBlueShift, pfmt->cBlueBits); Modes->alphaMask = MaskFromBits(pfmt->cAlphaShift, pfmt->cAlphaBits); Modes->rgbMask = Modes->redMask | Modes->greenMask | Modes->blueMask; Modes->allMask = Modes->redMask | Modes->greenMask | Modes->blueMask | Modes->alphaMask; Modes->maxAuxBuffers = 0; Modes->isDirect = GL_FALSE; Modes->level = 0; #if DBG DBGBEGIN(LEVEL_INFO) DbgPrint("GL generic server get modes: rgbmode %d, cimode %d, index bits %d\n", Modes->rgbMode, Modes->colorIndexMode); DbgPrint(" redmask 0x%x, greenmask 0x%x, bluemask 0x%x\n", Modes->redMask, Modes->greenMask, Modes->blueMask); DbgPrint(" redbits %d, greenbits %d, bluebits %d\n", Modes->redBits, Modes->greenBits, Modes->blueBits); DbgPrint("GetContext Modes flags %X\n", gengc->gsurf.dwFlags); DBGEND #endif /* DBG */ } /******************************Public*Routine******************************\ * wglGetSurfacePalette * * Initialize the array of RGBQUADs to match the color table or palette * of the DC's surface. * * Note: * Should be called only for 8bpp or lesser surfaces. * * History: * 12-Jun-1995 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL wglGetSurfacePalette( __GLGENcontext *gengc, RGBQUAD *prgbq, BOOL bTranslateDdb ) { int nColors; BOOL bRet; BOOL bConvert; PALETTEENTRY ppe[256]; int i; ASSERTOPENGL(gengc->gsurf.pfd.cColorBits <= 8, "wglGetSurfacePalette called for deep surface\n"); ASSERTOPENGL((gengc->dwCurrentFlags & GLSURF_METAFILE) == 0, "wglGetSurfacePalette called for metafile\n"); nColors = 1 << gengc->gsurf.pfd.cColorBits; if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW) { LPDIRECTDRAWPALETTE pddp; HRESULT hr; // Retrieve DirectDraw palette from surface if (gengc->gsurf.dd.gddsFront.pdds->lpVtbl-> GetPalette(gengc->gsurf.dd.gddsFront.pdds, &pddp) != DD_OK || pddp == NULL) { return FALSE; } hr = pddp->lpVtbl->GetEntries(pddp, 0, 0, nColors, ppe); pddp->lpVtbl->Release(pddp); bRet = hr == DD_OK; bConvert = TRUE; } else if (GLSURF_IS_DIRECTDC(gengc->dwCurrentFlags)) { // Direct DC, so get the RGB values from the system palette. bRet = wglGetSystemPaletteEntries(gengc->gwidCurrent.hdc, 0, nColors, ppe); bConvert = TRUE; } else if (gengc->dwCurrentFlags & GLSURF_DIRECT_ACCESS) { // DIB section, so copy the color table. bRet = GetDIBColorTable(gengc->gwidCurrent.hdc, 0, nColors, prgbq); bConvert = FALSE; } else { // DDB surface, so use the logical palette. bRet = GetPaletteEntries(GetCurrentObject(gengc->gwidCurrent.hdc, OBJ_PAL), 0, nColors, ppe); // For certain DDB surfaces we need the palette to be permuted // by the forward translation vector before use. if (bRet && bTranslateDdb) { BYTE *pjTrans; bConvert = FALSE; // Convert to RGBQUAD with forward translation permutation. pjTrans = gengc->pajTranslateVector; for (i = 0; i < nColors; i++) { prgbq[pjTrans[i]].rgbRed = ppe[i].peRed; prgbq[pjTrans[i]].rgbGreen = ppe[i].peGreen; prgbq[pjTrans[i]].rgbBlue = ppe[i].peBlue; prgbq[pjTrans[i]].rgbReserved = 0; } } else { bConvert = TRUE; } } if (bRet && bConvert) { // Convert to RGBQUAD. for (i = 0; i < nColors; i++) { prgbq[i].rgbRed = ppe[i].peRed; prgbq[i].rgbGreen = ppe[i].peGreen; prgbq[i].rgbBlue = ppe[i].peBlue; prgbq[i].rgbReserved = 0; } } return bRet; } /******************************Public*Routine******************************\ * SyncDibColorTables * * Setup the color table in each DIB associated with the specified * GLGENcontext to match the system palette. * * Called only for <= 8bpp surfaces. * * History: * 24-Oct-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ void SyncDibColorTables(__GLGENcontext *gengc) { __GLGENbuffers *buffers = gengc->pwndLocked->buffers; ASSERTOPENGL(gengc->gsurf.pfd.cColorBits <= 8, "SyncDibColorTables(): bad surface type"); if (gengc->ColorsBitmap || buffers->backBitmap.hbm) { RGBQUAD rgbq[256]; if (wglGetSurfacePalette(gengc, rgbq, TRUE)) { int nColors; // If color table was obtained, setup the DIBs. nColors = 1 << gengc->gsurf.pfd.cColorBits; // Scan-line DIB. if (gengc->ColorsBitmap) SetDIBColorTable(gengc->ColorsMemDC, 0, nColors, rgbq); // Back buffer if (buffers->backBitmap.hbm) SetDIBColorTable(buffers->backBitmap.hdc, 0, nColors, rgbq); } else { WARNING("SyncDibColorTables: Unable to get surface palette\n"); } } } static BYTE vubSystemToRGB8[20] = { 0x00, 0x04, 0x20, 0x24, 0x80, 0x84, 0xa0, 0xf6, 0xf6, 0xf5, 0xff, 0xad, 0xa4, 0x07, 0x38, 0x3f, 0xc0, 0xc7, 0xf8, 0xff }; // ComputeInverseTranslationVector // Computes the inverse translation vector for 4-bit and 8-bit. // // Synopsis: // void ComputeInverseTranslation( // __GLGENcontext *gengc specifies the generic RC // int cColorEntries specifies the number of color entries // BYTE iPixeltype specifies the pixel format type // // Assumtions: // The inverse translation vector has been allocated and initialized with // zeros. // // History: // 23-NOV-93 Eddie Robinson [v-eddier] Wrote it. // void FASTCALL ComputeInverseTranslationVector(__GLGENcontext *gengc, int cColorEntries, int iPixelType) { BYTE *pXlate, *pInvXlate; int i, j; pInvXlate = gengc->pajInvTranslateVector; pXlate = gengc->pajTranslateVector; for (i = 0; i < cColorEntries; i++) { if (pXlate[i] == i) { // Look for trivial mapping first pInvXlate[i] = (BYTE)i; } else { for (j = 0; j < cColorEntries; j++) { if (pXlate[j] == i) // Look for exact match { pInvXlate[i] = (BYTE)j; goto match_found; } } // // If we reach here, there is no exact match, so we should find the // closest fit. These indices should match the system colors // for 8-bit devices. // // Note that these pixel values cannot be generated by OpenGL // drawing with the current foreground translation vector. // if (cColorEntries == 256) { if (i <= 9) { if (iPixelType == PFD_TYPE_RGBA) pInvXlate[i] = vubSystemToRGB8[i]; else pInvXlate[i] = (BYTE)i; } else if (i >= 246) { if (iPixelType == PFD_TYPE_RGBA) pInvXlate[i] = vubSystemToRGB8[i-236]; else pInvXlate[i] = i-236; } } } match_found:; } } // er: similar to function in so_textu.c, but rounds up the result /* ** Return the log based 2 of a number ** ** logTab1 returns (int)ceil(log2(index)) ** logTab2 returns (int)log2(index)+1 */ static GLubyte logTab1[256] = { 0, 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; static GLubyte logTab2[256] = { 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; static GLint FASTCALL Log2RoundUp(GLint i) { if (i & 0xffff0000) { if (i & 0xff000000) { if (i & 0x00ffffff) return(logTab2[i >> 24] + 24); else return(logTab1[i >> 24] + 24); } else { if (i & 0x0000ffff) return(logTab2[i >> 16] + 16); else return(logTab1[i >> 16] + 16); } } else { if (i & 0xff00) { if (i & 0x00ff) return (logTab2[i >> 8] + 8); else return (logTab1[i >> 8] + 8); } else { return (logTab1[i]); } } } // default translation vector for 4-bit RGB static GLubyte vujRGBtoVGA[16] = { 0x0, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf }; // SetColorTranslationVector // Sets up the translation vector, which may take 2 forms: // - In all 8,4-bit surfaces, get the translation vector with // wglCopyTranslateVector(), with 2**numBits byte entries. // - For 16,24,32 ColorIndex, get the mapping from index to RGB // value with wglGetPalette(). All entries in the table are unsigned // longs, with the first entry being the number of entries. This table // always has (2**n) <= 4096 entries, because gl assumes n bits are // used for color index. // // Synopsis: // void SetColorTranslationVector // __GLGENcontext *gengc generic RC // int cColorEntries number of color entries // int cColorBits number of color bits // int iPixelType specifies RGB or ColorIndex // // History: // Feb. 02 Eddie Robinson [v-eddier] Added support for 4-bit and 8-bit // Jan. 29 Marc Fortier [v-marcf] Wrote it. void SetColorTranslationVector(__GLGENcontext *gengc, int cColorEntries, int cColorBits, int iPixelType) { int numEntries, numBits; __GLcontextModes *Modes; BYTE ajBGRtoRGB[256]; BYTE ajTmp[256]; Modes = &((__GLcontext *)gengc)->modes; // Handle formats with a hardware palette (i.e., 4bpp and 8bpp). if ( cColorBits <= 8 ) { int i; BYTE *pXlate; // Compute logical to system palette forward translation vector. if (!wglCopyTranslateVector(gengc, gengc->pajTranslateVector, cColorEntries)) { // if foreground translation vector doesn't exist, build one pXlate = gengc->pajTranslateVector; if (cColorBits == 4) { // for RGB, map 1-1-1 to VGA colors. For CI, just map 1 to 1 if (iPixelType == PFD_TYPE_COLORINDEX) { for (i = 0; i < 16; i++) pXlate[i] = (BYTE)i; } else { for (i = 0; i < 16; i++) pXlate[i] = vujRGBtoVGA[i]; } } else { // for RGB, map 1 to 1. For CI display, 1 - 20 to system colors // for CI DIB, just map 1 to 1 if ((iPixelType == PFD_TYPE_COLORINDEX) && GLSURF_IS_DIRECTDC(gengc->dwCurrentFlags)) { for (i = 0; i < 10; i++) pXlate[i] = (BYTE)i; for (i = 10; i < 20; i++) pXlate[i] = i + 236; } else { for (i = 0; i < cColorEntries; i++) pXlate[i] = (BYTE)i; } } } // Some MCD pixelformats specify a 233BGR (i.e., 2-bits blue in least // significant bits, etc.) bit ordering. Unfortunately, this is the // slow path for simulations. For those formats, we force the ordering // to RGB internally and reorder the pajTranslateVector to convert it // back to BGR before writing to the surface. if (gengc->flags & GENGC_MCD_BGR_INTO_RGB) { pXlate = gengc->pajTranslateVector; // Compute a 233BGR to 332RGB translation vector. for (i = 0; i < 256; i++) { ajBGRtoRGB[i] = (((i & 0x03) << 6) | // blue ((i & 0x1c) << 1) | // green ((i & 0xe0) >> 5)) // red & 0xff; } // Remap the tranlation vector to 332RGB. RtlCopyMemory(ajTmp, pXlate, 256); for (i = 0; i < 256; i++) { pXlate[ajBGRtoRGB[i]] = ajTmp[i]; } } //!!!XXX -- I think the code below to fixup 4bpp is no longer needed. //!!!XXX There is now special case code in wglCopyTranslateVector #if 0 // wglCopyTranslateVector = TRUE, and 4-bit: need some fixing up // For now, zero out upper nibble of returned xlate vector else if( cColorBits == 4 ) { pXlate = gengc->pajTranslateVector; for( i = 0; i < 16; i ++ ) pXlate[i] &= 0xf; } #endif ComputeInverseTranslationVector( gengc, cColorEntries, iPixelType ); #ifdef _CLIENTSIDE_ SyncDibColorTables( gengc ); #endif } // Handle formats w/o a hardware format (i.e., 16bpp, 24bpp, 32bpp). else { if( cColorEntries <= 256 ) { numEntries = 256; numBits = 8; } else { numBits = Log2RoundUp( cColorEntries ); numEntries = 1 << numBits; } // We will always allocate 4096 entries for CI mode with > 8 bits // of color. This enables us to use a constant (0xfff) mask for // color-index clamping. ASSERTOPENGL(numEntries <= MAXPALENTRIES, "Maximum color-index size exceeded"); if( (numBits == Modes->indexBits) && (gengc->pajTranslateVector != NULL) ) { // New palette same size as previous ULONG *pTrans; int i; // zero out some entries pTrans = (ULONG *)gengc->pajTranslateVector + cColorEntries + 1; for( i = cColorEntries + 1; i < MAXPALENTRIES; i ++ ) *pTrans++ = 0; } else { __GLcontext *gc = (__GLcontext *) gengc; __GLcolorBuffer *cfb; // New palette has different size if( gengc->pajTranslateVector != NULL && (gengc->pajTranslateVector != gengc->xlatPalette) ) GCFREE(gc, gengc->pajTranslateVector ); gengc->pajTranslateVector = GCALLOCZ(gc, (MAXPALENTRIES+1)*sizeof(ULONG)); // Change indexBits Modes->indexBits = numBits; // For depths greater than 8 bits, cfb->redMax must change if the // number of entries in the palette changes. // Also, change the writemask so that if the palette grows, the // new planes will be enabled by default. if (cfb = gc->front) { GLint oldRedMax; oldRedMax = cfb->redMax; cfb->redMax = (1 << gc->modes.indexBits) - 1; gc->state.raster.writeMask |= ~oldRedMax; gc->state.raster.writeMask &= cfb->redMax; } if (cfb = gc->back) { GLint oldRedMax; oldRedMax = cfb->redMax; cfb->redMax = (1 << gc->modes.indexBits) - 1; gc->state.raster.writeMask |= ~oldRedMax; gc->state.raster.writeMask &= cfb->redMax; } // store procs may need to be picked based on the change in // palette size __GL_DELAY_VALIDATE(gc); #ifdef _MCD_ MCD_STATE_DIRTY(gc, FBUFCTRL); #endif } // Compute index-to-color table from current palette information wglComputeIndexedColors( gengc, (unsigned long *) gengc->pajTranslateVector, MAXPALENTRIES ); } } // HandlePaletteChanges // Check if palette has changed, update translation vectors // XXX add support for malloc failures at attention time // Synopsis: // void HandlePaletteChanges( // __GLGENcontext *gengc specifies the generic RC // // Assumtions: // x wglPaletteChanged() will always return 0 when no palette is set // by the client. This has proved to be not always true. // // History: // Feb. 25 Fixed by rightful owner // Feb. ?? Mutilated by others // Jan. 29 Marc Fortier [v-marcf] Wrote it. void HandlePaletteChanges( __GLGENcontext *gengc, GLGENwindow *pwnd ) { ULONG Timestamp; GLuint paletteSize; PIXELFORMATDESCRIPTOR *pfmt; // No palettes for IC's if (gengc->dwCurrentFlags & GLSURF_METAFILE) { return; } Timestamp = wglPaletteChanged(gengc, pwnd); if (Timestamp != gengc->PaletteTimestamp) { pfmt = &gengc->gsurf.pfd; if (pfmt->iPixelType == PFD_TYPE_COLORINDEX) { if (pfmt->cColorBits <= 8) { paletteSize = 1 << pfmt->cColorBits; } else { paletteSize = min(wglPaletteSize(gengc), MAXPALENTRIES); } } else { #ifndef _CLIENTSIDE_ /* Only update RGB at makecurrent time */ if( (gengc->PaletteTimestamp == INITIAL_TIMESTAMP) && (pfmt->cColorBits <= 8) ) #else if (pfmt->cColorBits <= 8) #endif { paletteSize = 1 << pfmt->cColorBits; } else { paletteSize = 0; } } if (paletteSize) { SetColorTranslationVector( gengc, paletteSize, pfmt->cColorBits, pfmt->iPixelType ); } EmptyFillStrokeCache(gengc); gengc->PaletteTimestamp = Timestamp; } } #ifdef _CLIENTSIDE_ /******************************Public*Routine******************************\ * wglFillBitfields * * Return the Red, Green, and Blue color masks based on the DC surface * format. The masks are returned in the pdwColorFields array in the * order: red mask, green mask, blue mask. * * Note: * Should be called only for 16bpp or greater surfaces. * * History: * 12-Jun-1995 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ void wglFillBitfields(PIXELFORMATDESCRIPTOR *ppfd, DWORD *pdwColorFields) { *pdwColorFields++ = MaskFromBits(ppfd->cRedShift, ppfd->cRedBits ); *pdwColorFields++ = MaskFromBits(ppfd->cGreenShift, ppfd->cGreenBits); *pdwColorFields++ = MaskFromBits(ppfd->cBlueShift, ppfd->cBlueBits ); } /******************************Public*Routine******************************\ * wglCreateBitmap * * Create a DIB section and color table that matches the specified format. * * Returns: * A valid bitmap handle if sucessful, NULL otherwise. * * History: * 20-Sep-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ HBITMAP wglCreateBitmap( __GLGENcontext *gengc, SIZEL sizl, PVOID *ppvBits ) { BITMAPINFO *pbmi; HBITMAP hbmRet = (HBITMAP) NULL; size_t cjbmi; DWORD dwCompression; DWORD cjImage = 0; WORD wBitCount; int cColors = 0; *ppvBits = (PVOID) NULL; // Figure out what kind of DIB needs to be created based on the // DC format. switch ( gengc->gsurf.pfd.cColorBits ) { case 4: cjbmi = sizeof(BITMAPINFO) + 16*sizeof(RGBQUAD); dwCompression = BI_RGB; wBitCount = 4; cColors = 16; break; case 8: cjbmi = sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD); dwCompression = BI_RGB; wBitCount = 8; cColors = 256; break; case 16: cjbmi = sizeof(BITMAPINFO) + 3*sizeof(RGBQUAD); dwCompression = BI_BITFIELDS; cjImage = sizl.cx * sizl.cy * 2; wBitCount = 16; break; case 24: cjbmi = sizeof(BITMAPINFO); dwCompression = BI_RGB; wBitCount = 24; break; case 32: cjbmi = sizeof(BITMAPINFO) + 3*sizeof(RGBQUAD); dwCompression = BI_BITFIELDS; cjImage = sizl.cx * sizl.cy * 4; wBitCount = 32; break; default: WARNING1("wglCreateBitmap: unknown format 0x%lx\n", gengc->gsurf.pfd.cColorBits); return (HBITMAP) NULL; } // Allocate the BITMAPINFO structure and color table. pbmi = ALLOC(cjbmi); if (pbmi) { pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbmi->bmiHeader.biWidth = sizl.cx; pbmi->bmiHeader.biHeight = sizl.cy; pbmi->bmiHeader.biPlanes = 1; pbmi->bmiHeader.biBitCount = wBitCount; pbmi->bmiHeader.biCompression = dwCompression; pbmi->bmiHeader.biSizeImage = cjImage; pbmi->bmiHeader.biXPelsPerMeter = 0; pbmi->bmiHeader.biYPelsPerMeter = 0; pbmi->bmiHeader.biClrUsed = 0; pbmi->bmiHeader.biClrImportant = 0; // Initialize DIB color table. switch (gengc->gsurf.pfd.cColorBits) { case 4: case 8: if (!wglGetSurfacePalette(gengc, &pbmi->bmiColors[0], FALSE)) { return NULL; } break; case 16: case 32: wglFillBitfields(&gengc->gsurf.pfd, (DWORD *) &pbmi->bmiColors[0]); break; case 24: // Color table is assumed to be BGR for 24BPP DIBs. Nothing to do. break; } // Create DIB section. hbmRet = CreateDIBSection(gengc->gwidCurrent.hdc, pbmi, DIB_RGB_COLORS, ppvBits, NULL, 0); #if DBG if ( hbmRet == (HBITMAP) NULL ) WARNING("wglCreateBitmap(): DIB section creation failed\n"); #endif FREE(pbmi); } else { WARNING("wglCreateBitmap(): memory allocation error\n"); } return hbmRet; } #endif /******************************Public*Routine******************************\ * wglCreateScanlineBuffers * * Allocate the scanline buffers. The scanline buffers are used by the * generic implementation to write data to the target (display or bitmap) * a span at a time when the target surface is not directly accessible. * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 17-Apr-1996 -by- Gilman Wong [gilmanw] * Taken from CreateGDIObjects and made into function. \**************************************************************************/ BOOL FASTCALL wglCreateScanlineBuffers(__GLGENcontext *gengc) { BOOL bRet = FALSE; PIXELFORMATDESCRIPTOR *pfmt; UINT cBits; UINT cBytes; SIZEL size; int cColorEntries; __GLcontext *gc; gc = (__GLcontext *)gengc; pfmt = &gengc->gsurf.pfd; // // Bitmap must have DWORD sized scanlines. // cBits = BITS_ALIGNDWORD(__GL_MAX_WINDOW_WIDTH * pfmt->cColorBits); cBytes = cBits / 8; // // Create color scanline DIB buffer. // size.cx = cBits / pfmt->cColorBits; size.cy = 1; gengc->ColorsMemDC = CreateCompatibleDC(gengc->gwidCurrent.hdc); gengc->ColorsBitmap = wglCreateBitmap(gengc, size, &gengc->ColorsBits); if ( (NULL == gengc->ColorsMemDC) || (NULL == gengc->ColorsBitmap) || (NULL == gengc->ColorsBits) || !SelectObject(gengc->ColorsMemDC, gengc->ColorsBitmap) ) { #if DBG if (!gengc->ColorsMemDC) WARNING("wglCreateScanlineBuffers: dc creation failed, ColorsMemDC\n"); if (!gengc->ColorsBitmap) WARNING("wglCreateScanlineBuffers: bitmap creation failed, ColorsBitmap\n"); if (!gengc->ColorsBits) WARNING("wglCreateScanlineBuffers: bitmap creation failed, ColorsBits\n"); #endif goto wglCreateScanlineBuffers_exit; } // // Screen to DIB BitBlt performance on Win95 is very poor. // By doing the BitBlt via an intermediate DDB, we can avoid // a lot of unnecessary overhead. So create an intermediate // scanline DDB to match ColorsBitmap. // if ((gengc->dwCurrentFlags & GLSURF_DIRECTDRAW) == 0) { gengc->ColorsDdbDc = CreateCompatibleDC(gengc->gwidCurrent.hdc); gengc->ColorsDdb = CreateCompatibleBitmap(gengc->gwidCurrent.hdc, size.cx, size.cy); //!!!Viper fix -- Diamond Viper (Weitek 9000) fails //!!! CreateCompatibleBitmap for some (currently unknown) //!!! reason if ( !gengc->ColorsDdb ) { WARNING("wglCreateScanlineBuffers: " "CreateCompatibleBitmap failed\n"); if (gengc->ColorsDdbDc) DeleteDC(gengc->ColorsDdbDc); gengc->ColorsDdbDc = (HDC) NULL; } else { if ( (NULL == gengc->ColorsDdbDc) || !SelectObject(gengc->ColorsDdbDc, gengc->ColorsDdb) ) { #if DBG if (!gengc->ColorsDdbDc) WARNING("wglCreateScanlineBuffers: " "dc creation failed, ColorsDdbDc\n"); if (!gengc->ColorsDdb) WARNING("wglCreateScanlineBuffers: " "bitmap creation failed, ColorsDdb\n"); #endif goto wglCreateScanlineBuffers_exit; } } } // // Success. // bRet = TRUE; wglCreateScanlineBuffers_exit: if (!bRet) { // // Error case. Delete whatever may have been allocated. // wglDeleteScanlineBuffers(gengc); } return bRet; } /******************************Public*Routine******************************\ * wglDeleteScanlineBuffers * * Delete the scanline buffers. The scanline buffers are used by the * generic implementation to write data to the target (display or bitmap) * a span at a time when the target surface is not directly accessible. * * History: * 17-Apr-1996 -by- Gilman Wong [gilmanw] * Taken from CreateGDIObjects and made into function. \**************************************************************************/ VOID FASTCALL wglDeleteScanlineBuffers(__GLGENcontext *gengc) { __GLcontext *gc = (__GLcontext *)gengc; // // Delete color scanline DIB buffer. // if (gengc->ColorsMemDC) { DeleteDC(gengc->ColorsMemDC); gengc->ColorsMemDC = NULL; } if (gengc->ColorsBitmap) { if (!DeleteObject(gengc->ColorsBitmap)) ASSERTOPENGL(FALSE, "wglDeleteScanlineBuffers: DeleteObject failed"); gengc->ColorsBitmap = NULL; gengc->ColorsBits = NULL; // deleted for us when DIB section dies } // // Delete intermediate color scanline DDB buffer. // if (gengc->ColorsDdbDc) { if (!DeleteDC(gengc->ColorsDdbDc)) { ASSERTOPENGL(FALSE, "wglDeleteScanlineBuffers: DDB DeleteDC failed"); } gengc->ColorsDdbDc = NULL; } if (gengc->ColorsDdb) { if (!DeleteObject(gengc->ColorsDdb)) { ASSERTOPENGL(FALSE, "wglDeleteScanlineBuffers: DDB DeleteObject failed"); } gengc->ColorsDdb = NULL; } } /******************************Public*Routine******************************\ * wglInitializeColorBuffers * * Initialize the color buffer (front and/or back) information. * * History: * 17-Apr-1996 -by- Gilman Wong [gilmanw] * Taken out of glsrvCreateContext and made into function. \**************************************************************************/ VOID FASTCALL wglInitializeColorBuffers(__GLGENcontext *gengc) { __GLcontext *gc = &gengc->gc; gc->front = &gc->frontBuffer; if ( gc->modes.doubleBufferMode) { gc->back = &gc->backBuffer; if (gc->modes.colorIndexMode) { __glGenInitCI(gc, gc->front, GL_FRONT); __glGenInitCI(gc, gc->back, GL_BACK); } else { __glGenInitRGB(gc, gc->front, GL_FRONT); __glGenInitRGB(gc, gc->back, GL_BACK); } } else { if (gc->modes.colorIndexMode) { __glGenInitCI(gc, gc->front, GL_FRONT); } else { __glGenInitRGB(gc, gc->front, GL_FRONT); } } } /******************************Public*Routine******************************\ * wglInitializeDepthBuffer * * Initialize the depth buffer information. * * History: * 17-Apr-1996 -by- Gilman Wong [gilmanw] * Taken out of glsrvCreateContext and made into function. \**************************************************************************/ VOID FASTCALL wglInitializeDepthBuffer(__GLGENcontext *gengc) { __GLcontext *gc = &gengc->gc; if (gc->modes.depthBits) { if (gengc->_pMcdState) { // This is not the final initialization of the MCD depth buffer. // This is being done now so that the validate proc can be done // in glsrvCreateContext. The real initialization will occur // during glsrvMakeCurrent. GenMcdInitDepth(gc, &gc->depthBuffer); gc->depthBuffer.scale = gengc->_pMcdState->McdRcInfo.depthBufferMax; } else if (gc->modes.depthBits == 16) { DBGINFO("CALLING: __glInitDepth16\n"); __glInitDepth16(gc, &gc->depthBuffer); gc->depthBuffer.scale = 0x7fff; } else { DBGINFO("CALLING: __glInitDepth32\n"); __glInitDepth32(gc, &gc->depthBuffer); gc->depthBuffer.scale = 0x7fffffff; } /* * Note: scale factor does not use the high bit (this avoids * floating point exceptions). */ // XXX (mf) I changed 16 bit depth buffer to use high bit, since // there is no possibility of overflow on conversion to float. For // 32-bit, (float) 0xffffffff overflows to 0. I was able to avoid // overflow in this case by using a scale factor of 0xffffff7f, but // this is a weird number, and 31 bits is enough resolution anyways. // !! Note asserts in px_fast.c that have hardcoded depth scales. } #ifdef _MCD_ else { // This is not the final initialization of the MCD depth buffer. // This is being done now so that the validate proc can be done // in glsrvCreateContext. The real initialization will occur // during glsrvMakeCurrent. GenMcdInitDepth(gc, &gc->depthBuffer); gc->depthBuffer.scale = 0x7fffffff; } #endif } /******************************Public*Routine******************************\ * wglInitializePixelCopyFuncs * * Set the appropriate CopyPixels and PixelVisible functions in the context. * * History: * 18-Apr-1996 -by- Gilman Wong [gilmanw] * Taken out of glsrvCreateContext and made into function. \**************************************************************************/ VOID FASTCALL wglInitializePixelCopyFuncs(__GLGENcontext *gengc) { __GLcontext *gc = &gengc->gc; if ( gc->front->buf.flags & DIB_FORMAT ) gengc->pfnCopyPixels = dibCopyPixels; else { if (gengc->pMcdState) { gengc->ColorsBits = gengc->pMcdState->pMcdSurf->McdColorBuf.pv; gengc->pfnCopyPixels = GenMcdCopyPixels; } else gengc->pfnCopyPixels = gdiCopyPixels; } gengc->pfnPixelVisible = wglPixelVisible; } /******************************Public*Routine******************************\ * CreateGDIObjects * * Create various buffers, and GDI objects that we will always need. * * Called from glsrvCreateContext(). * * Returns: * TRUE if sucessful, FALSE if error. * \**************************************************************************/ BOOL FASTCALL CreateGDIObjects(__GLGENcontext *gengc) { PIXELFORMATDESCRIPTOR *pfmt; UINT cBytes; SIZEL size; int cColorEntries; __GLcontext *gc; gc = (__GLcontext *)gengc; pfmt = &gengc->gsurf.pfd; // // Palette translation vectors. // // If not a true color surface, need space for the foreground xlation // if (pfmt->cColorBits <= 8) { cColorEntries = 1 << pfmt->cColorBits; ASSERTOPENGL(NULL == gengc->pajTranslateVector, "have a xlate vector"); // // Just set the translation vector to the cache space in the gc: // gengc->pajTranslateVector = gengc->xlatPalette; // // Allocate the inverse translation vector. // ASSERTOPENGL(NULL == gengc->pajInvTranslateVector, "have an inv xlate vector"); gengc->pajInvTranslateVector = GCALLOCZ(gc, cColorEntries); if (NULL == gengc->pajInvTranslateVector) { WARNING("CreateGDIObjects: memory allocation failed, pajInvTrans\n"); goto ERROR_EXIT; } } // // Scanline buffers. // // Always create engine bitmaps to provide a generic means of performing // pixel transfers using the ColorsBits and StippleBits buffers. // if (NULL == gengc->ColorsBits) { // // Color scanline buffer // #ifdef _MCD_ // // If MCD the ColorBits will be set when the MCD surface is // created, so nothing to do. // // Otherwise, create the generic scanline buffer. // // if (!gengc->_pMcdState) #endif { // // Generic case. // if (!wglCreateScanlineBuffers(gengc)) { WARNING("CreateGDIObjects: wglCreateScanlineBuffers failed\n"); goto ERROR_EXIT; } } // // Stipple scanline buffer. // // Bitmap must have DWORD sized scanlines. Note that stipple only // requires a 1 bit per pel bitmap. ASSERTOPENGL(NULL == gengc->StippleBits, "StippleBits not null"); size.cx = BITS_ALIGNDWORD(__GL_MAX_WINDOW_WIDTH); cBytes = size.cx / 8; gengc->StippleBits = GCALLOCZ(gc, cBytes); if (NULL == gengc->StippleBits) { WARNING("CreateGDIObjects: memory allocation failed, StippleBits\n"); goto ERROR_EXIT; } ASSERTOPENGL(NULL == gengc->StippleBitmap, "StippleBitmap not null"); #ifndef _CLIENTSIDE_ //!!!XXX -- why are we even bothering to make the stipple an engine bitmap? //!!!XXX It is never used as such (at least not yet). gengc->StippleBitmap = EngCreateBitmap( size, cBytes, BMF_1BPP, 0, gengc->StippleBits); if (NULL == gengc->StippleBitmap) { WARNING("CreateGDIObjects: memory allocation failed, StippleBitmap\n"); goto ERROR_EXIT; } #else gengc->StippleBitmap = (HBITMAP) NULL; #endif } return TRUE; ERROR_EXIT: // // Error cleanup -- // Destroy everything we might have created, return false so makecurrent fails. // if (gengc->pajTranslateVector && (gengc->pajTranslateVector != gengc->xlatPalette)) { GCFREE(gc,gengc->pajTranslateVector); gengc->pajTranslateVector = NULL; } if (gengc->pajInvTranslateVector) { GCFREE(gc,gengc->pajInvTranslateVector); gengc->pajInvTranslateVector = NULL; } wglDeleteScanlineBuffers(gengc); if (gengc->StippleBits) { GCFREE(gc,gengc->StippleBits); gengc->StippleBits = NULL; } #ifndef _CLIENTSIDE_ if (gengc->StippleBitmap) { if (!EngDeleteSurface((HSURF)gengc->StippleBitmap)) ASSERTOPENGL(FALSE, "EngDeleteSurface failed"); gengc->StippleBitmap = NULL; } #endif return FALSE; } /******************************Public*Routine******************************\ * ApplyViewport * * Recompute viewport state and clipbox. May also be called via the * applyViewport function pointer in the gc's proc table. * \**************************************************************************/ // This routine can be called because of a user vieport command, or because // of a change in the size of the window static void FASTCALL ApplyViewport(__GLcontext *gc) { GLint xlow, ylow, xhigh, yhigh; GLint llx, lly, urx, ury; GLboolean lastReasonable; GLGENwindow *pwnd; GLint clipLeft, clipRight, clipTop, clipBottom; __GLGENcontext *gengc = (__GLGENcontext *) gc; DBGENTRY("ApplyViewport\n"); ASSERTOPENGL(gengc->pwndLocked != NULL, "ApplyViewport called without lock\n"); pwnd = gengc->pwndLocked; if (pwnd) { gengc->visibleWidth = pwnd->rclBounds.right - pwnd->rclBounds.left; gengc->visibleHeight = pwnd->rclBounds.bottom - pwnd->rclBounds.top; } else { gengc->visibleWidth = 0; gengc->visibleHeight = 0; } // Sanity check the info from window. ASSERTOPENGL( gengc->visibleWidth <= __GL_MAX_WINDOW_WIDTH && gengc->visibleHeight <= __GL_MAX_WINDOW_HEIGHT, "ApplyViewport(): bad visible rect size\n" ); /* If this viewport is fully contained in the window, we note this fact, ** and this can save us on scissoring tests. */ if (gc->state.enables.general & __GL_SCISSOR_TEST_ENABLE) { xlow = gc->state.scissor.scissorX; xhigh = xlow + gc->state.scissor.scissorWidth; ylow = gc->state.scissor.scissorY; yhigh = ylow + gc->state.scissor.scissorHeight; } else { xlow = 0; ylow = 0; xhigh = gc->constants.width; yhigh = gc->constants.height; } /* ** convert visible region to GL coords and intersect with scissor */ if (pwnd) { clipLeft = pwnd->rclBounds.left - pwnd->rclClient.left; clipRight = pwnd->rclBounds.right - pwnd->rclClient.left; clipTop = gc->constants.height - (pwnd->rclBounds.top - pwnd->rclClient.top); clipBottom = gc->constants.height - (pwnd->rclBounds.bottom - pwnd->rclClient.top); } else { clipLeft = 0; clipRight = 0; clipTop = 0; clipBottom = 0; } if (xlow < clipLeft) xlow = clipLeft; if (xhigh > clipRight) xhigh = clipRight; if (ylow < clipBottom) ylow = clipBottom; if (yhigh > clipTop) yhigh = clipTop; // ComputeClipBox { if (xlow >= xhigh || ylow >= yhigh) { gc->transform.clipX0 = gc->constants.viewportXAdjust; gc->transform.clipX1 = gc->constants.viewportXAdjust; gc->transform.clipY0 = gc->constants.viewportYAdjust; gc->transform.clipY1 = gc->constants.viewportYAdjust; } else { gc->transform.clipX0 = xlow + gc->constants.viewportXAdjust; gc->transform.clipX1 = xhigh + gc->constants.viewportXAdjust; if (gc->constants.yInverted) { gc->transform.clipY0 = (gc->constants.height - yhigh) + gc->constants.viewportYAdjust; gc->transform.clipY1 = (gc->constants.height - ylow) + gc->constants.viewportYAdjust; } else { gc->transform.clipY0 = ylow + gc->constants.viewportYAdjust; gc->transform.clipY1 = yhigh + gc->constants.viewportYAdjust; } } } llx = (GLint)gc->state.viewport.x; lly = (GLint)gc->state.viewport.y; urx = llx + (GLint)gc->state.viewport.width; ury = lly + (GLint)gc->state.viewport.height; #ifdef NT gc->transform.miny = (gc->constants.height - ury) + gc->constants.viewportYAdjust; gc->transform.maxy = gc->transform.miny + (GLint)gc->state.viewport.height; gc->transform.fminy = (__GLfloat)gc->transform.miny; gc->transform.fmaxy = (__GLfloat)gc->transform.maxy; // The viewport xScale, xCenter, yScale and yCenter values are computed in // first MakeCurrent and subsequent glViewport calls. When the window is // resized (i.e. gc->constatns.height changes), however, we need to recompute // yCenter if yInverted is TRUE. if (gc->constants.yInverted) { __GLfloat hh, h2; h2 = gc->state.viewport.height * __glHalf; hh = h2 - gc->constants.viewportEpsilon; gc->state.viewport.yCenter = gc->constants.height - (gc->state.viewport.y + h2) + gc->constants.fviewportYAdjust; #if 0 DbgPrint("AV ys %.3lf, yc %.3lf (%.3lf)\n", -hh, gc->state.viewport.yCenter, gc->constants.height - (gc->state.viewport.y + h2)); #endif } #else ww = gc->state.viewport.width * __glHalf; hh = gc->state.viewport.height * __glHalf; gc->state.viewport.xScale = ww; gc->state.viewport.xCenter = gc->state.viewport.x + ww + gc->constants.fviewportXAdjust; if (gc->constants.yInverted) { gc->state.viewport.yScale = -hh; gc->state.viewport.yCenter = (gc->constants.height - gc->constants.viewportEpsilon) - (gc->state.viewport.y + hh) + gc->constants.fviewportYAdjust; } else { gc->state.viewport.yScale = hh; gc->state.viewport.yCenter = gc->state.viewport.y + hh + gc->constants.fviewportYAdjust; } #endif // Remember the current reasonableViewport. If it changes, we may // need to change the pick procs. lastReasonable = gc->transform.reasonableViewport; // Is viewport entirely within the visible bounding rectangle (which // includes scissoring if it is turned on)? reasonableViewport is // TRUE if so, FALSE otherwise. // The viewport must also have a non-zero size to be reasonable if (llx >= xlow && lly >= ylow && urx <= xhigh && ury <= yhigh && urx-llx >= 1 && ury-lly >= 1) { gc->transform.reasonableViewport = GL_TRUE; } else { gc->transform.reasonableViewport = GL_FALSE; } #if 0 DbgPrint("%3X:Clipbox %4d,%4d - %4d,%4d, reasonable %d, g %p, w %p\n", GetCurrentThreadId(), gc->transform.clipX0, gc->transform.clipY0, gc->transform.clipX1, gc->transform.clipY1, gc->transform.reasonableViewport, gc, ((__GLGENcontext *)gc)->pwndLocked); #endif #ifdef NT // To be safe than sorry. The new poly array does not break up Begin/End pair. if (lastReasonable != gc->transform.reasonableViewport) __GL_DELAY_VALIDATE(gc); #ifdef _MCD_ MCD_STATE_DIRTY(gc, VIEWPORT); #endif #else // Old code use to use __GL_DELAY_VALIDATE() macro, this would // blow up if resize/position changed and a flush occured between // a glBegin/End pair. Only need to pick span, line, & triangle procs // since that is safe if (lastReasonable != gc->transform.reasonableViewport) { (*gc->procs.pickSpanProcs)(gc); (*gc->procs.pickTriangleProcs)(gc); (*gc->procs.pickLineProcs)(gc); } #endif } /******************************Public*Routine******************************\ * __glGenFreeBuffers * * Free the __GLGENbuffers structure and its associated ancillary and * back buffers. * \**************************************************************************/ void FASTCALL __glGenFreeBuffers(__GLGENbuffers *buffers) { if (buffers == NULL) { return; } #if DBG DBGBEGIN(LEVEL_INFO) DbgPrint("glGenFreeBuffers 0x%x, 0x%x, 0x%x, 0x%x\n", buffers->accumBuffer.base, buffers->stencilBuffer.base, buffers->depthBuffer.base, buffers); DBGEND; #endif // // Free ancillary buffers // if (buffers->accumBuffer.base) { DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing accumulation buffer\n"); FREE(buffers->accumBuffer.base); } if (buffers->stencilBuffer.base) { DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing stencil buffer\n"); FREE(buffers->stencilBuffer.base); } // // Free alpha buffers // if (buffers->alphaBuffer0.base) { DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing alpha buffer 0\n"); FREE(buffers->alphaBuffer0.base); } if (buffers->alphaBuffer1.base) { DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing alpha buffer 1\n"); FREE(buffers->alphaBuffer1.base); } // // If its not an MCD managed depth buffer, free the depth // buffer. // if (buffers->resizeDepth != ResizeUnownedDepthBuffer) { if (buffers->depthBuffer.base) { DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing depth buffer\n"); FREE(buffers->depthBuffer.base); } } // // Free back buffer if we allocated one // if (buffers->backBitmap.pvBits) { // Note: the DIB section deletion will delete // buffers->backBitmap.pvBits for us if (!DeleteDC(buffers->backBitmap.hdc)) WARNING("__glGenFreeBuffers: DeleteDC failed\n"); DeleteObject(buffers->backBitmap.hbm); } #ifdef _MCD_ // // Free MCD surface. // if (buffers->pMcdSurf) { GenMcdDeleteSurface(buffers->pMcdSurf); } #endif // // free up swap hint region // { PYLIST pylist; PXLIST pxlist; RECTLISTSetEmpty(&buffers->rl); // // Free up the free lists // pylist = buffers->pylist; while (pylist) { PYLIST pylistKill = pylist; pylist = pylist->pnext; FREE(pylistKill); } buffers->pylist = NULL; pxlist = buffers->pxlist; while (pxlist) { PXLIST pxlistKill = pxlist; pxlist = pxlist->pnext; FREE(pxlistKill); } buffers->pxlist = NULL; } // // Free the private structure // FREE(buffers); } /******************************Public*Routine******************************\ * __glGenAllocAndInitPrivateBufferStruct * * Allocates and initializes a __GLGENbuffers structure and saves it as * the drawable private data. * * The __GLGENbuffers structure contains the shared ancillary and back * buffers, as well as the cache of clip rectangles enumerated from the * CLIPOBJ. * * The __GLGENbuffers structure and its data is freed by calling * __glGenFreeBuffers. * * Returns: * NULL if error. * \**************************************************************************/ static __GLGENbuffers * __glGenAllocAndInitPrivateBufferStruct(__GLcontext *gc) { __GLGENbuffers *buffers; __GLGENcontext *gengc = (__GLGENcontext *)gc; PIXELFORMATDESCRIPTOR *ppfd = &gengc->gsurf.pfd; /* No private structure, no ancillary buffers */ DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: No private struct existed\n"); buffers = (__GLGENbuffers *)ALLOCZ(sizeof(__GLGENbuffers)); if (NULL == buffers) return(NULL); buffers->resize = ResizeAncillaryBuffer; buffers->resizeDepth = ResizeAncillaryBuffer; buffers->accumBuffer.elementSize = gc->accumBuffer.buf.elementSize; buffers->depthBuffer.elementSize = gc->depthBuffer.buf.elementSize; buffers->stencilBuffer.elementSize = gc->stencilBuffer.buf.elementSize; buffers->stencilBits = ppfd->cStencilBits; buffers->depthBits = ppfd->cDepthBits; buffers->accumBits = ppfd->cAccumBits; buffers->colorBits = ppfd->cColorBits; buffers->alphaBits = ppfd->cAlphaBits; if (gc->modes.accumBits) { gc->accumBuffer.buf.base = 0; gc->accumBuffer.buf.size = 0; gc->accumBuffer.buf.outerWidth = 0; } buffers->alphaFrontBuffer = buffers->alphaBackBuffer = NULL; // These base values must *always* be set to 0, regardless of alphaBits, // since base will be free'd if non-zero on buffer deletion buffers->alphaBuffer0.base = 0; buffers->alphaBuffer1.base = 0; if (gc->modes.alphaBits) { buffers->alphaBuffer0.size = 0; buffers->alphaBuffer0.outerWidth = 0; buffers->alphaFrontBuffer = &buffers->alphaBuffer0; if (gc->modes.doubleBufferMode) { buffers->alphaBuffer1.size = 0; buffers->alphaBuffer1.outerWidth = 0; buffers->alphaBackBuffer = &buffers->alphaBuffer1; } } if (gc->modes.depthBits) { gc->depthBuffer.buf.base = 0; gc->depthBuffer.buf.size = 0; gc->depthBuffer.buf.outerWidth = 0; } if (gc->modes.stencilBits) { gc->stencilBuffer.buf.base = 0; gc->stencilBuffer.buf.size = 0; gc->stencilBuffer.buf.outerWidth = 0; } // If double-buffered, initialize the fake window for the back buffer if (gc->modes.doubleBufferMode) { buffers->backBitmap.pwnd = &buffers->backBitmap.wnd; buffers->backBitmap.wnd.clipComplexity = DC_TRIVIAL; buffers->backBitmap.wnd.rclBounds.left = 0; buffers->backBitmap.wnd.rclBounds.top = 0; buffers->backBitmap.wnd.rclBounds.right = 0; buffers->backBitmap.wnd.rclBounds.bottom = 0; buffers->backBitmap.wnd.rclClient = buffers->backBitmap.wnd.rclBounds; } #ifdef _MCD_ if (gengc->_pMcdState && !(gengc->flags & GLGEN_MCD_CONVERTED_TO_GENERIC)) { if (bInitMcdSurface(gengc, gengc->pwndLocked, buffers)) { if (gengc->pMcdState->pDepthSpan) { gc->depthBuffer.buf.base = gengc->pMcdState->pDepthSpan; buffers->depthBuffer.base = gengc->pMcdState->pDepthSpan; buffers->resizeDepth = ResizeUnownedDepthBuffer; } } else { WARNING("__glGenAllocAndInitPrivateBufferStruct: bInitMcdSurface failed\n"); FREE(buffers); return NULL; } } else #endif if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW) { // DDraw surfaces provide their own depth buffers buffers->resizeDepth = ResizeUnownedDepthBuffer; } buffers->clip.WndUniq = -1; // // init swap hint region // buffers->pxlist = NULL; buffers->pylist = NULL; buffers->rl.buffers = buffers; buffers->rl.pylist = NULL; buffers->fMax = FALSE; return buffers; } /******************************Public*Routine******************************\ * __glGenCheckBufferStruct * * Check if context and buffer struct are compatible. * * To satisfy this requirement, the attributes of the shared buffers * (back, depth, stencil, and accum) must match. Otherwise, the context * cannot be used with the given set of buffers. * * Returns: * TRUE if compatible, FALSE otherwise. * * History: * 17-Jul-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ GLboolean __glGenCheckBufferStruct(__GLcontext *gc, __GLGENbuffers *buffers) { BOOL bRet = FALSE; __GLGENcontext *gengc = (__GLGENcontext *)gc; PIXELFORMATDESCRIPTOR *ppfd = &gengc->gsurf.pfd; if ((buffers->stencilBits == ppfd->cStencilBits) && (buffers->depthBits == ppfd->cDepthBits ) && (buffers->accumBits == ppfd->cAccumBits ) && (buffers->colorBits == ppfd->cColorBits ) && (buffers->alphaBits == ppfd->cAlphaBits )) { bRet = TRUE; } return (GLboolean)bRet; } /******************************Public*Routine******************************\ * glsrvMakeCurrent * * Make generic context current to this thread with specified DC. * * Returns: * TRUE if sucessful. * \**************************************************************************/ // Upper level code should make sure that this context is not current to // any other thread, that we "lose" the old context first // Called with DEVLOCK held, free to modify window // // FALSE will be returned if we cannot create the objects we need // rcobj.cxx will set the error code to show we are out of memory BOOL APIENTRY glsrvMakeCurrent(GLWINDOWID *pgwid, __GLcontext *gc, GLGENwindow *pwnd) { __GLGENcontext *gengc; __GLGENbuffers *buffers; GLint width, height; BOOL bFreePwnd = FALSE; BOOL bUninitSem = FALSE; DBGENTRY("Generic MakeCurrent\n"); // Common initialization gengc = (__GLGENcontext *)gc; ASSERTOPENGL(GLTEB_SRVCONTEXT() == 0, "current context in makecurrent!"); ASSERTOPENGL(gengc->pwndMakeCur == NULL && gengc->pwndLocked == NULL, "Non-current context has window pointers\n"); gengc->gwidCurrent = *pgwid; if (pwnd == NULL) { ASSERTOPENGL((gengc->gsurf.dwFlags & GLSURF_METAFILE), "Non-metafile surface without a window\n"); // Drawing on an IC, create a fake window with no visible area pwnd = (GLGENwindow *)ALLOC(sizeof(GLGENwindow)); if (pwnd == NULL) { WARNING("glsrvMakeCurrent: memory allocation failure " "(IC, window)\n"); goto ERROR_EXIT; } bFreePwnd = TRUE; RtlZeroMemory(pwnd, sizeof(GLGENwindow)); pwnd->clipComplexity = DC_TRIVIAL; // This window data is private so technically there'll never // be another thread accessing it so this critsec is unnecessary. // However, having it eliminates special cases where // window locks are taken or checked for ownership. __try { InitializeCriticalSection(&pwnd->sem); } __except(EXCEPTION_EXECUTE_HANDLER) { goto ERROR_EXIT; } bUninitSem = TRUE; // Set this so CreateGDIObjects doesn't attempt to create // zero-size objects gengc->ColorsBits = (void *)1; gengc->dwCurrentFlags = gengc->gsurf.dwFlags; } else if (pgwid->iType == GLWID_DDRAW) { gengc->dwCurrentFlags = gengc->gsurf.dwFlags; } else { GLSURF gsurf; if (!InitDeviceSurface(pgwid->hdc, pwnd->ipfd, gengc->gsurf.iLayer, wglObjectType(pgwid->hdc), FALSE, &gsurf)) { goto ERROR_EXIT; } gengc->dwCurrentFlags = gsurf.dwFlags; } if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW) { gengc->pgddsFront = &gengc->gsurf.dd.gddsFront; } else if (GLDIRECTSCREEN && GLSURF_IS_SCREENDC(gengc->dwCurrentFlags)) { gengc->pgddsFront = &GLSCREENINFO->gdds; } else { gengc->pgddsFront = NULL; } // We need this field to tell whether we're using a fake window // or a real one. gengc->ipfdCurrent = pwnd->ipfd; gengc->pwndMakeCur = pwnd; ENTER_WINCRIT_GC(pwnd, gengc); width = pwnd->rclClient.right - pwnd->rclClient.left; height = pwnd->rclClient.bottom - pwnd->rclClient.top; gengc->errorcode = 0; // Sanity check the info from window. ASSERTOPENGL( width <= __GL_MAX_WINDOW_WIDTH && height <= __GL_MAX_WINDOW_HEIGHT, "glsrvMakeCurrrent(): bad window client size\n" ); // Make our context current in the TEB. // If failures after this point, make sure to reset TEB entry // Set up this thread's paTeb pointer. gc->paTeb = GLTEB_CLTPOLYARRAY(); GLTEB_SET_SRVCONTEXT(gc); buffers = pwnd->buffers; /* We inherit any drawable state */ if (buffers) { gc->constants.width = buffers->width; gc->constants.height = buffers->height; if (!__glGenCheckBufferStruct(gc, buffers)) { WARNING("glsrvMakeCurrent: __glGenCheckBufferStruct failed\n"); goto ERROR_EXIT; } #ifdef _MCD_ if (GLSURF_IS_DIRECTDC(gengc->dwCurrentFlags)) { if (!(gengc->flags & GLGEN_MCD_CONVERTED_TO_GENERIC) && !(buffers->flags & GLGENBUF_MCD_LOST)) { gengc->pMcdState = gengc->_pMcdState; // Reset MCD scaling values since we're now using // MCD hardware acceleration: GenMcdSetScaling(gengc); if (gengc->pMcdState) { gengc->pMcdState->pMcdSurf = buffers->pMcdSurf; if (buffers->pMcdSurf) { gengc->pMcdState->pDepthSpan = buffers->pMcdSurf->pDepthSpan; } else { WARNING("glsrvMakeCurrent: MCD context, generic surface\n"); goto ERROR_EXIT; } } else { // Generic context. If the surface is an MCD surface, we // cannot continue. The context is generic but the pixelfmt // is MCD, so what must have happened is that we attempted // to create an MCD context, but failed, so we reverted // to generic. if (buffers->pMcdSurf) { WARNING("glsrvMakeCurrent: generic context, MCD surface\n"); goto ERROR_EXIT; } } } else { gengc->pMcdState = (GENMCDSTATE *)NULL; // Reset MCD scaling values since we've fallen back to // software: GenMcdSetScaling(gengc); // If MCD context (or former context), either surface or context // needs conversion. // // The only other way to get here is if this is a generic context // an a converted surface, which is perfectly OK and requires no // further conversion. //!!!SP1 -- should be able to skip this section if no conversion //!!!SP1 needed, but we miss out on the forced repick, which //!!!SP! could be risky for NT4.0 //if (gengc->_pMcdState && // (!(gengc->flags & GLGEN_MCD_CONVERTED_TO_GENERIC) || // !(buffers->flags & GLGENBUF_MCD_LOST))) if (gengc->_pMcdState) { BOOL bConverted; // Do conversion. We must have color scales set to do the // conversion, but we must restore color scales afterwards. __glContextSetColorScales(gc); bConverted = GenMcdConvertContext(gengc, buffers); __glContextUnsetColorScales(gc); // Fail makecurrent if conversion failed. if (!bConverted) { WARNING("glsrvMakeCurrent: GenMcdConvertContext failed\n"); goto ERROR_EXIT; } } } } else gengc->pMcdState = (GENMCDSTATE *)NULL; #endif if (buffers->accumBuffer.base && gc->modes.accumBits) { DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Accumulation buffer existed\n"); gc->accumBuffer.buf.base = buffers->accumBuffer.base; gc->accumBuffer.buf.size = buffers->accumBuffer.size; gc->accumBuffer.buf.outerWidth = buffers->width; gc->modes.haveAccumBuffer = GL_TRUE; } else { /* No Accum buffer at this point in time */ DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Accum buffer doesn't exist\n"); gc->accumBuffer.buf.base = 0; gc->accumBuffer.buf.size = 0; gc->accumBuffer.buf.outerWidth = 0; } if (buffers->depthBuffer.base && gc->modes.depthBits) { DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Depth buffer existed\n"); gc->depthBuffer.buf.base = buffers->depthBuffer.base; gc->depthBuffer.buf.size = buffers->depthBuffer.size; gc->depthBuffer.buf.outerWidth = buffers->width; gc->modes.haveDepthBuffer = GL_TRUE; } else { /* No Depth buffer at this point in time */ DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Depth buffer doesn't exist\n"); gc->depthBuffer.buf.base = 0; gc->depthBuffer.buf.size = 0; gc->depthBuffer.buf.outerWidth = 0; } if (buffers->stencilBuffer.base && gc->modes.stencilBits) { DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Stencil buffer existed\n"); gc->stencilBuffer.buf.base = buffers->stencilBuffer.base; gc->stencilBuffer.buf.size = buffers->stencilBuffer.size; gc->stencilBuffer.buf.outerWidth = buffers->width; gc->modes.haveStencilBuffer = GL_TRUE; } else { /* No Stencil buffer at this point in time */ DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent:Stencil buffer doesn't exist\n"); gc->stencilBuffer.buf.base = 0; gc->stencilBuffer.buf.size = 0; gc->stencilBuffer.buf.outerWidth = 0; } } else { gc->modes.haveStencilBuffer = GL_FALSE; gc->modes.haveDepthBuffer = GL_FALSE; gc->modes.haveAccumBuffer = GL_FALSE; } /* ** Allocate and initialize ancillary buffers structures if none were ** inherited. This will happen if an RC has previously been current ** and is made current to a new window. */ if (!buffers) { buffers = __glGenAllocAndInitPrivateBufferStruct(gc); if (NULL == buffers) { WARNING("glsrvMakeCurrent: __glGenAllocAndInitPrivateBufferStruct failed\n"); goto ERROR_EXIT; } pwnd->buffers = buffers; } // Setup pointer to generic back buffer if ( gc->modes.doubleBufferMode) { gc->backBuffer.bitmap = &buffers->backBitmap; UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer); } // Setup alpha buffer pointers if ( buffers->alphaBits ) { UpdateSharedBuffer( &gc->frontBuffer.alphaBuf.buf, buffers->alphaFrontBuffer ); buffers->alphaFrontBuffer->elementSize = gc->frontBuffer.alphaBuf.buf.elementSize; if ( gc->modes.doubleBufferMode) { UpdateSharedBuffer( &gc->backBuffer.alphaBuf.buf, buffers->alphaBackBuffer ); buffers->alphaBackBuffer->elementSize = gc->backBuffer.alphaBuf.buf.elementSize; } } if (gc->gcSig != GC_SIGNATURE) { __GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_ALL); #ifdef _MCD_ MCD_STATE_DIRTY(gc, ALL); #endif // After initializing all of the individual buffer structures, make // sure we copy the element size back into the shared buffer. // This is a little clumsy, buffers->accumBuffer.elementSize = gc->accumBuffer.buf.elementSize; buffers->depthBuffer.elementSize = gc->depthBuffer.buf.elementSize; buffers->stencilBuffer.elementSize = gc->stencilBuffer.buf.elementSize; // We always need to initialize the MCD-related scaling values: GenMcdSetScaling(gengc); /* ** Need some stuff to exist before doing viewport stuff. */ (*gc->procs.validate)(gc); /* ** The first time a context is made current the spec requires that ** the viewport be initialized. The code below does it. ** The ApplyViewport() routine will be called inside Viewport() */ __glim_Viewport(0, 0, width, height); __glim_Scissor(0, 0, width, height); /* ** Now that viewport is set, need to revalidate (initializes all ** the proc pointers). */ (*gc->procs.validate)(gc); gc->gcSig = GC_SIGNATURE; } else /* Not the first makecurrent for this RC */ { /* This will check the window size, and recompute relevant state */ ApplyViewport(gc); } #ifdef _MCD_ if (gengc->pMcdState) { // Now that we are assured that the mcd state is fully initialized, // configure the depth buffer. GenMcdInitDepth(gc, &gc->depthBuffer); if (gc->modes.depthBits) { gc->depthBuffer.scale = gengc->pMcdState->McdRcInfo.depthBufferMax; } else { gc->depthBuffer.scale = 0x7fffffff; } // Bind MCD context to window. if (!GenMcdMakeCurrent(gengc, pwnd)) { goto ERROR_EXIT; } gengc->pMcdState->mcdFlags |= (MCD_STATE_FORCEPICK | MCD_STATE_FORCERESIZE); __GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_ALL); MCD_STATE_DIRTY(gc, ALL); } #endif // Common initialization // Select correct pixel-copy function wglInitializePixelCopyFuncs(gengc); // Set front-buffer HDC, window to current HDC, window gc->front->bitmap->hdc = pgwid->hdc; ASSERT_WINCRIT(pwnd); gc->front->bitmap->pwnd = pwnd; // Make sure our GDI object cache is empty // It should always be empty at MakeCurrent time since // the objects in the cache are HDC-specific and so // they cannot be cached between MakeCurrents since the // HDC could change // // This should be done before HandlePaletteChanges since the // cache is used there ASSERTOPENGL(gengc->crFill == COLORREF_UNUSED && gengc->hbrFill == NULL && gengc->hdcFill == NULL, "Fill cache inconsistent at MakeCurrent\n"); ASSERTOPENGL(gengc->cStroke.r < 0.0f && gengc->hpenStroke == NULL && gengc->hdcStroke == NULL && gengc->fStrokeInvalid, "Stroke cache inconsistent at MakeCurrent\n"); // Get current xlation gengc->PaletteTimestamp = INITIAL_TIMESTAMP; HandlePaletteChanges(gengc, pwnd); // Force attention code to check if resize is needed gengc->WndUniq = -1; gengc->WndSizeUniq = -1; // Check for allocation failures during MakeCurrent if (gengc->errorcode) { WARNING1("glsrvMakeCurrent: errorcode 0x%lx\n", gengc->errorcode); goto ERROR_EXIT; } /* ** Default value for rasterPos needs to be yInverted. The ** defaults are filled in during SoftResetContext ** we do the adjusting here. */ if (gc->constants.yInverted) { gc->state.current.rasterPos.window.y = height + gc->constants.fviewportYAdjust - gc->constants.viewportEpsilon; } /* ** Scale all state that depends upon the color scales. */ __glContextSetColorScales(gc); LEAVE_WINCRIT_GC(pwnd, gengc); return TRUE; ERROR_EXIT: memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent)); // Set paTeb to NULL for debugging. gc->paTeb = NULL; GLTEB_SET_SRVCONTEXT(0); // Remove window pointers. if (gengc->pwndLocked != NULL) { LEAVE_WINCRIT_GC(pwnd, gengc); } if (bFreePwnd) { if (bUninitSem) { DeleteCriticalSection(&pwnd->sem); } FREE(pwnd); } gengc->pwndMakeCur = NULL; return FALSE; } /******************************Public*Routine******************************\ * AddSwapHintRectWIN() * * 17-Feb-1995 mikeke Created \**************************************************************************/ void APIPRIVATE __glim_AddSwapHintRectWIN( GLint xs, GLint ys, GLint xe, GLint ye) { __GLGENbuffers *buffers; __GL_SETUP(); buffers = ((__GLGENcontext *)gc)->pwndLocked->buffers; if (xs < 0) xs = 0; if (xe > buffers->backBuffer.width) xe = buffers->backBuffer.width; if (ys < 0) ys = 0; if (ye > buffers->backBuffer.height) ye = buffers->backBuffer.height; if (xs < xe && ys < ye) { if (gc->constants.yInverted) { RECTLISTAddRect(&buffers->rl, xs, buffers->backBuffer.height - ye, xe, buffers->backBuffer.height - ys); } else { RECTLISTAddRect(&buffers->rl, xs, ys, xe, ye); } } } /******************************Public*Routine******************************\ * wglFixupPixelFormat * * Fixes up certain MCD pixel format cases * * History: * 21-Apr-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID FASTCALL wglFixupPixelFormat(__GLGENcontext *gengc, PIXELFORMATDESCRIPTOR *ppfd) { // Some MCD pixelformats specify a 233BGR (i.e., 2-bits blue in least // significant bits, etc.) bit ordering. Unfortunately, this is the // slow path for simulations. For those formats, we force the ordering // to RGB internally and reorder the pajTranslateVector to convert it // back to BGR before writing to the surface. if (((ppfd->dwFlags & (PFD_NEED_SYSTEM_PALETTE | PFD_GENERIC_ACCELERATED)) == (PFD_NEED_SYSTEM_PALETTE | PFD_GENERIC_ACCELERATED)) && (ppfd->cRedBits == 3) && (ppfd->cRedShift == 5) && (ppfd->cGreenBits == 3) && (ppfd->cGreenShift == 2) && (ppfd->cBlueBits == 2) && (ppfd->cBlueShift == 0)) { ppfd->cRedShift = 0; ppfd->cGreenShift = 3; ppfd->cBlueShift = 6; gengc->flags |= GENGC_MCD_BGR_INTO_RGB; } else { gengc->flags &= ~GENGC_MCD_BGR_INTO_RGB; } } /******************************Public*Routine******************************\ * glsrvCreateContext * * Create a generic context. * * Returns: * NULL for failure. * \**************************************************************************/ // hdc is the dc used to create the context, hrc is how the server // identifies the GL context, the GLcontext pointer that is return is how // the generic code identifies the context. The server will pass that pointer // in all calls. PVOID APIENTRY glsrvCreateContext(GLWINDOWID *pgwid, GLSURF *pgsurf) { __GLGENcontext *gengc; __GLcontext *gc; RANDOMDISABLE; DBGENTRY("__glsrvCreateContext\n"); // Initialize the temporary memory allocation table if (!InitTempAlloc()) { return NULL; } gengc = ALLOCZ(sizeof(*gengc)); if (gengc == NULL) { WARNING("bad alloc\n"); return NULL; } gengc->hrc = NULL; gc = (__GLcontext *)gengc; // Initialize cached objects to nothing gengc->crFill = COLORREF_UNUSED; gengc->hbrFill = NULL; gengc->hdcFill = NULL; gengc->cStroke.r = -1.0f; gengc->fStrokeInvalid = TRUE; gengc->hpenStroke = NULL; gengc->hdcStroke = NULL; gc->gcSig = 0; /* * Add a bunch of constants to the context */ gc->constants.maxViewportWidth = __GL_MAX_WINDOW_WIDTH; gc->constants.maxViewportHeight = __GL_MAX_WINDOW_HEIGHT; gc->constants.viewportXAdjust = __GL_VERTEX_X_BIAS+ __GL_VERTEX_X_FIX; gc->constants.viewportYAdjust = __GL_VERTEX_Y_BIAS+ __GL_VERTEX_Y_FIX; gc->constants.subpixelBits = __GL_WGL_SUBPIXEL_BITS; gc->constants.numberOfLights = __GL_WGL_NUMBER_OF_LIGHTS; gc->constants.numberOfClipPlanes = __GL_WGL_NUMBER_OF_CLIP_PLANES; gc->constants.numberOfTextures = __GL_WGL_NUMBER_OF_TEXTURES; gc->constants.numberOfTextureEnvs = __GL_WGL_NUMBER_OF_TEXTURE_ENVS; gc->constants.maxTextureSize = __GL_WGL_MAX_MIPMAP_LEVEL;/*XXX*/ gc->constants.maxMipMapLevel = __GL_WGL_MAX_MIPMAP_LEVEL; gc->constants.maxListNesting = __GL_WGL_MAX_LIST_NESTING; gc->constants.maxEvalOrder = __GL_WGL_MAX_EVAL_ORDER; gc->constants.maxPixelMapTable = __GL_WGL_MAX_PIXEL_MAP_TABLE; gc->constants.maxAttribStackDepth = __GL_WGL_MAX_ATTRIB_STACK_DEPTH; gc->constants.maxClientAttribStackDepth = __GL_WGL_MAX_CLIENT_ATTRIB_STACK_DEPTH; gc->constants.maxNameStackDepth = __GL_WGL_MAX_NAME_STACK_DEPTH; gc->constants.pointSizeMinimum = (__GLfloat)__GL_WGL_POINT_SIZE_MINIMUM; gc->constants.pointSizeMaximum = (__GLfloat)__GL_WGL_POINT_SIZE_MAXIMUM; gc->constants.pointSizeGranularity = (__GLfloat)__GL_WGL_POINT_SIZE_GRANULARITY; gc->constants.lineWidthMinimum = (__GLfloat)__GL_WGL_LINE_WIDTH_MINIMUM; gc->constants.lineWidthMaximum = (__GLfloat)__GL_WGL_LINE_WIDTH_MAXIMUM; gc->constants.lineWidthGranularity = (__GLfloat)__GL_WGL_LINE_WIDTH_GRANULARITY; #ifndef NT gc->dlist.optimizer = __glDlistOptimizer; gc->dlist.checkOp = __glNopGCListOp; gc->dlist.listExec = __gl_GenericDlOps; gc->dlist.baseListExec = __glListExecTable; #endif gc->dlist.initState = __glNopGC; __glEarlyInitContext( gc ); if (gengc->errorcode) { WARNING1("Context error is %d\n", gengc->errorcode); glsrvDeleteContext(gc); return NULL; } RANDOMREENABLE; // Many routines depend on a current surface so set it temporarily gengc->gwidCurrent = *pgwid; gengc->dwCurrentFlags = pgsurf->dwFlags; // Get copy of current pixelformat if (pgsurf->iLayer == 0 && (pgsurf->pfd.dwFlags & (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED)) == (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED)) { wglFixupPixelFormat(gengc, &pgsurf->pfd); } gengc->gsurf = *pgsurf; #ifdef _MCD_ // Is the pixelformat compatible with the generic code, or is it some // weird h/w (MCD) format generic cannot handle? if (GenMcdGenericCompatibleFormat(gengc)) gengc->flags |= GENGC_GENERIC_COMPATIBLE_FORMAT; #endif // Extract information from pixel format to set up modes GetContextModes(gengc); ASSERTOPENGL(GLSURF_IS_MEMDC(gengc->dwCurrentFlags) ? !gc->modes.doubleBufferMode : 1, "Double buffered memdc!"); // XXX! Reset buffer dimensions to force Bitmap resize call // We should eventually handle the Bitmap as we do ancilliary buffers gc->constants.width = 0; gc->constants.height = 0; __GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_ALL); #ifdef _MCD_ MCD_STATE_DIRTY(gc, ALL); #endif gc->constants.yInverted = GL_TRUE; gc->constants.ySign = -1; // Allocate GDI objects that we will need if (!CreateGDIObjects(gengc)) { goto ERROR_EXIT; } // Allocate __GLGENbitmap front-buffer structure if (!(gc->frontBuffer.bitmap = GCALLOCZ(gc, sizeof(__GLGENbitmap)))) { goto ERROR_EXIT; } // Create MCD rendering context, if MCD is available. if (gengc->gsurf.dwFlags & GLSURF_VIDEO_MEMORY) { GLGENwindow *pwnd; BOOL bMcdContext; // Validate layer index if (pgsurf->iLayer && !ValidateLayerIndex(pgsurf->iLayer, &pgsurf->pfd)) { WARNING("glsrvCreateContext: bad iLayer\n"); goto ERROR_EXIT; } pwnd = pwndGetFromID(pgwid); if (pwnd == NULL) { goto ERROR_EXIT; } // If this fails, _pMcdState is NULL and we fall back on // the software-only implementation. // // Unless we were trying to create a layer context. Generic // does not support layers, so fail if we cannot create an // MCD context. bMcdContext = bInitMcdContext(gengc, pwnd); if (!(gengc->flags & GENGC_GENERIC_COMPATIBLE_FORMAT) && !bMcdContext) { goto ERROR_EXIT; } pwndRelease(pwnd); } /* * Initialize front/back color buffer(s) */ wglInitializeColorBuffers(gengc); /* * Initialize any other ancillary buffers */ // Init accum buffer. if (gc->modes.accumBits) { switch (gc->modes.accumBits) { case 16: // We will now internally use a 32-bit accum for accumBits=16 case 32: __glInitAccum32(gc, &gc->accumBuffer); break; case 64: default: __glInitAccum64(gc, &gc->accumBuffer); break; } } // Initialize depth buffer. wglInitializeDepthBuffer(gengc); // Init stencil buffer. if (gc->modes.stencilBits) { __glInitStencil8( gc, &gc->stencilBuffer); } // Look at REX code for procs to make CPU specific gc->procs.bitmap = __glDrawBitmap; gc->procs.clipPolygon = __glClipPolygon; gc->procs.validate = __glGenericValidate; gc->procs.pickAllProcs = __glGenericPickAllProcs; gc->procs.pickBlendProcs = __glGenericPickBlendProcs; gc->procs.pickFogProcs = __glGenericPickFogProcs; gc->procs.pickParameterClipProcs = __glGenericPickParameterClipProcs; gc->procs.pickStoreProcs = __glGenPickStoreProcs; gc->procs.pickTextureProcs = __glGenericPickTextureProcs; gc->procs.copyImage = __glGenericPickCopyImage; gc->procs.pixel.spanReadCI = __glSpanReadCI; gc->procs.pixel.spanReadCI2 = __glSpanReadCI2; gc->procs.pixel.spanReadRGBA = __glSpanReadRGBA; gc->procs.pixel.spanReadRGBA2 = __glSpanReadRGBA2; gc->procs.pixel.spanReadDepth = __glSpanReadDepth; gc->procs.pixel.spanReadDepth2 = __glSpanReadDepth2; gc->procs.pixel.spanReadStencil = __glSpanReadStencil; gc->procs.pixel.spanReadStencil2 = __glSpanReadStencil2; gc->procs.pixel.spanRenderCI = __glSpanRenderCI; gc->procs.pixel.spanRenderCI2 = __glSpanRenderCI2; gc->procs.pixel.spanRenderRGBA = __glSpanRenderRGBA; gc->procs.pixel.spanRenderRGBA2 = __glSpanRenderRGBA2; gc->procs.pixel.spanRenderDepth = __glSpanRenderDepth; gc->procs.pixel.spanRenderDepth2 = __glSpanRenderDepth2; gc->procs.pixel.spanRenderStencil = __glSpanRenderStencil; gc->procs.pixel.spanRenderStencil2 = __glSpanRenderStencil2; gc->procs.applyViewport = ApplyViewport; gc->procs.pickBufferProcs = __glGenericPickBufferProcs; gc->procs.pickColorMaterialProcs = __glGenericPickColorMaterialProcs; gc->procs.pickPixelProcs = __glGenericPickPixelProcs; gc->procs.pickClipProcs = __glGenericPickClipProcs; gc->procs.pickLineProcs = __fastGenPickLineProcs; gc->procs.pickSpanProcs = __fastGenPickSpanProcs; gc->procs.pickTriangleProcs = __fastGenPickTriangleProcs; gc->procs.pickRenderBitmapProcs = __glGenericPickRenderBitmapProcs; gc->procs.pickPointProcs = __glGenericPickPointProcs; gc->procs.pickVertexProcs = __glGenericPickVertexProcs; gc->procs.pickDepthProcs = __glGenericPickDepthProcs; gc->procs.convertPolygonStipple = __glConvertStipple; /* Now reset the context to its default state */ RANDOMDISABLE; __glSoftResetContext(gc); // Check for allocation failures during SoftResetContext if (gengc->errorcode) { goto ERROR_EXIT; } /* Create acceleration-specific context information */ if (!__glGenCreateAccelContext(gc)) { goto ERROR_EXIT; } /* ** Now that we have a context, we can initialize ** all the proc pointers. */ (*gc->procs.validate)(gc); /* ** NOTE: now that context is initialized reset to use the global ** table. */ RANDOMREENABLE; // We won't be fully initialized until the first MakeCurrent // so set the signature to uninitialized gc->gcSig = 0; memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent)); gengc->dwCurrentFlags = 0; /* * End stuff that may belong in the hardware context */ return (PVOID)gc; ERROR_EXIT: memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent)); gengc->dwCurrentFlags = 0; glsrvDeleteContext(gc); return NULL; } /******************************Public*Routine******************************\ * UpdateSharedBuffer * * Make the context buffer state consistent with the shared buffer state. * This is called separately for each of the shared buffers. * \**************************************************************************/ void UpdateSharedBuffer(__GLbuffer *to, __GLbuffer *from) { to->width = from->width; to->height = from->height; to->base = from->base; to->outerWidth = from->outerWidth; } /******************************Public*Routine******************************\ * ResizeUnownedDepthBuffer * * Resizes a general-purpose hardware depth buffer. Just updates structure. * * Returns: * TRUE always. * \**************************************************************************/ GLboolean ResizeUnownedDepthBuffer(__GLGENbuffers *buffers, __GLbuffer *fb, GLint w, GLint h) { fb->width = w; fb->height = h; return TRUE; } /******************************Public*Routine******************************\ * ResizeHardwareBackBuffer * * Resizes a general-purpose hardware color buffer. Just updates structure. * * Returns: * TRUE always. * \**************************************************************************/ GLboolean ResizeHardwareBackBuffer(__GLGENbuffers *buffers, __GLcolorBuffer *cfb, GLint w, GLint h) { __GLGENbitmap *genBm = cfb->bitmap; __GLGENcontext *gengc = (__GLGENcontext *) cfb->buf.gc; // Fake up some of the __GLGENbitmap information. The window is required // for clipping of the hardware back buffer. The hdc is required to // retrieve drawing data from GDI. ASSERT_WINCRIT(gengc->pwndLocked); genBm->pwnd = gengc->pwndLocked; genBm->hdc = gengc->gwidCurrent.hdc; buffers->backBuffer.width = w; buffers->backBuffer.height = h; UpdateSharedBuffer(&cfb->buf, &buffers->backBuffer); return TRUE; } /******************************Public*Routine******************************\ * ResizeAncillaryBuffer * * Resizes the indicated shared buffer via a realloc (to preserve as much of * the existing data as possible). * * This is currently used for each of ancillary shared buffers except for * the back buffer. * * Returns: * TRUE if successful, FALSE if error. * \**************************************************************************/ GLboolean ResizeAncillaryBuffer(__GLGENbuffers *buffers, __GLbuffer *fb, GLint w, GLint h) { size_t newSize = (size_t) (w * h * fb->elementSize); __GLbuffer oldbuf, *ofb; GLboolean result; GLint i, imax, rowsize; void *to, *from; ofb = &oldbuf; oldbuf = *fb; if (newSize > 0) { fb->base = ALLOC(newSize); } else { // Buffer has no size. If we tried to allocate zero the debug alloc // would complain, so skip directly to the underlying allocator fb->base = HeapAlloc(GetProcessHeap(), 0, 0); } ASSERTOPENGL((ULONG_PTR)fb->base % 4 == 0, "base not aligned"); fb->size = newSize; fb->width = w; fb->height = h; fb->outerWidth = w; // element size if (fb->base) { result = GL_TRUE; if (ofb->base) { if (ofb->width > fb->width) rowsize = fb->width * fb->elementSize; else rowsize = ofb->width * fb->elementSize; if (ofb->height > fb->height) imax = fb->height; else imax = ofb->height; from = ofb->base; to = fb->base; for (i = 0; i < imax; i++) { __GL_MEMCOPY(to, from, rowsize); (ULONG_PTR)from += (ofb->width * ofb->elementSize); (ULONG_PTR)to += (fb->width * fb->elementSize); } } } else { result = GL_FALSE; } if (ofb->base) { FREE(ofb->base); } return result; } /******************************Private*Routine******************************\ * ResizeBitmapBuffer * * Used to resize the backbuffer that is implemented as a bitmap. Cannot * use same code as ResizeAncillaryBuffer() because each scanline must be * dword aligned. We also have to create engine objects for the bitmap. * * This code handles the case of a bitmap that has never been initialized. * * History: * 18-Nov-1993 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ void ResizeBitmapBuffer(__GLGENbuffers *buffers, __GLcolorBuffer *cfb, GLint w, GLint h) { __GLGENcontext *gengc = (__GLGENcontext *) cfb->buf.gc; __GLcontext *gc = cfb->buf.gc; __GLGENbitmap *genBm; UINT cBytes; // size of the bitmap in bytes LONG cBytesPerScan; // size of a scanline (DWORD aligned) SIZEL size; // dimensions of the bitmap PIXELFORMATDESCRIPTOR *pfmt = &gengc->gsurf.pfd; GLint cBitsPerScan; #ifndef _CLIENTSIDE_ void *newbits; #endif DBGENTRY("Entering ResizeBitmapBuffer\n"); genBm = cfb->bitmap; ASSERTOPENGL( &gc->backBuffer == cfb, "ResizeBitmapBuffer(): not back buffer!\n" ); ASSERTOPENGL( genBm == &buffers->backBitmap, "ResizeBitmapBuffer(): bad __GLGENbitmap * in cfb\n" ); // Compute the size of the bitmap. // The engine bitmap must have scanlines that are DWORD aligned. cBitsPerScan = BITS_ALIGNDWORD(w * pfmt->cColorBits); cBytesPerScan = cBitsPerScan / 8; cBytes = h * cBytesPerScan; // Setup size structure with dimensions of the bitmap. size.cx = cBitsPerScan / pfmt->cColorBits; size.cy = h; #ifndef _CLIENTSIDE_ // Malloc new buffer if ( (!cBytes) || (NULL == (newbits = GCALLOC(gc, cBytes))) ) { gengc->errorcode = GLGEN_OUT_OF_MEMORY; goto ERROR_EXIT_ResizeBitmapBuffer; } // If old buffer existed: if ( genBm->pvBits ) { GLint i, imax, rowsize; void *to, *from; // Transfer old contents to new buffer rowsize = min(-cfb->buf.outerWidth, cBytesPerScan); imax = min(cfb->buf.height, h); from = genBm->pvBits; to = newbits; for (i = 0; i < imax; i++) { __GL_MEMCOPY(to, from, rowsize); (GLint) from -= cfb->buf.outerWidth; (GLint) to += cBytesPerScan; } // Free old bitmap and delete old surface EngDeleteSurface((HSURF) genBm->hbm); GCFREE(gc, genBm->pvBits); } genBm->pvBits = newbits; // Create new surface if ( (genBm->hbm = EngCreateBitmap(size, cBytesPerScan, gengc->iFormatDC, 0, genBm->pvBits)) == (HBITMAP) 0 ) { gengc->errorcode = GLGEN_GRE_FAILURE; GCFREE(gc, genBm->pvBits); genBm->pvBits = (PVOID) NULL; goto ERROR_EXIT_ResizeBitmapBuffer; } #else // Zero sized bitmap. The error case will set the dimensions to // zero, thereby preventing drawing operations. if ( !cBytes ) goto ERROR_EXIT_ResizeBitmapBuffer; // Delete old back buffer. if ( genBm->hbm ) { if (!DeleteDC(genBm->hdc)) WARNING("ResizeBitmapBuffer: DeleteDC failed\n"); genBm->hdc = (HDC) NULL; if (!DeleteObject(genBm->hbm)) WARNING("ResizeBitmapBuffer: DeleteBitmap failed"); genBm->hbm = (HBITMAP) NULL; genBm->pvBits = (PVOID) NULL; // DIBsect deletion freed pvBits } if ( (genBm->hdc = CreateCompatibleDC(gengc->gwidCurrent.hdc)) == (HDC) 0 ) { gengc->errorcode = GLGEN_GRE_FAILURE; genBm->pvBits = (PVOID) NULL; goto ERROR_EXIT_ResizeBitmapBuffer; } // Create new surface if ( (genBm->hbm = wglCreateBitmap(gengc, size, &genBm->pvBits)) == (HBITMAP) 0 ) { gengc->errorcode = GLGEN_GRE_FAILURE; genBm->pvBits = (PVOID) NULL; // DIBsect deletion freed pvBits DeleteDC(genBm->hdc); genBm->hdc = (HDC) NULL; goto ERROR_EXIT_ResizeBitmapBuffer; } if ( !SelectObject(genBm->hdc, genBm->hbm) ) { gengc->errorcode = GLGEN_GRE_FAILURE; DeleteDC(genBm->hdc); genBm->hdc = (HDC) NULL; DeleteObject(genBm->hbm); genBm->hbm = (HBITMAP) NULL; genBm->pvBits = (PVOID) NULL; // DIBsect deletion freed pvBits goto ERROR_EXIT_ResizeBitmapBuffer; } #endif // Update buffer data structure // Setup the buffer to point to the DIB. A DIB is "upside down" // from our perspective, so we will set buf.base to point to the // last scan of the buffer and set buf.outerWidth to be negative // (causing us to move "up" through the DIB with increasing y). buffers->backBuffer.outerWidth = -(cBytesPerScan); buffers->backBuffer.base = (PVOID) (((BYTE *)genBm->pvBits) + (cBytesPerScan * (h - 1))); buffers->backBuffer.xOrigin = 0; buffers->backBuffer.yOrigin = 0; buffers->backBuffer.width = w; buffers->backBuffer.height = h; buffers->backBuffer.size = cBytes; UpdateSharedBuffer(&cfb->buf, &buffers->backBuffer); // Update the dummy window for the back buffer ASSERTOPENGL(genBm->wnd.clipComplexity == DC_TRIVIAL, "Back buffer complexity non-trivial\n"); genBm->wnd.rclBounds.right = w; genBm->wnd.rclBounds.bottom = h; genBm->wnd.rclClient = genBm->wnd.rclBounds; return; ERROR_EXIT_ResizeBitmapBuffer: // If we get to here, memory allocation or bitmap creation failed. #if DBG switch (gengc->errorcode) { case 0: break; case GLGEN_GRE_FAILURE: WARNING("ResizeBitmapBuffer(): object creation failed\n"); break; case GLGEN_OUT_OF_MEMORY: if ( w && h ) WARNING("ResizeBitmapBuffer(): mem alloc failed\n"); break; default: WARNING1("ResizeBitmapBuffer(): errorcode = 0x%lx\n", gengc->errorcode); break; } #endif // If we've blown away the bitmap, we need to set the back buffer info // to a consistent state. if (!genBm->pvBits) { buffers->backBuffer.width = 0; buffers->backBuffer.height = 0; buffers->backBuffer.base = (PVOID) NULL; } cfb->buf.width = 0; // error state: empty buffer cfb->buf.height = 0; cfb->buf.outerWidth = 0; } /* Lazy allocation of ancillary buffers */ void FASTCALL LazyAllocateDepth(__GLcontext *gc) { GLint w = gc->constants.width; GLint h = gc->constants.height; __GLGENcontext *gengc = (__GLGENcontext *)gc; __GLGENbuffers *buffers; GLint depthIndex = gc->state.depth.testFunc; ASSERTOPENGL(gc->modes.depthBits, "LazyAllocateDepth: zero depthBits\n"); buffers = gengc->pwndLocked->buffers; buffers->createdDepthBuffer = GL_TRUE; // If we're using the DDI, we've already allocated depth buffers // on the device, so at this point we may simply assume that // our depth buffer is available. #ifdef _MCD_ // If we're using MCD, we allocated the depth buffer when we created // the MCD context. if ((gengc->pMcdState) && (gengc->pMcdState->pDepthSpan)) { gc->modes.haveDepthBuffer = GL_TRUE; return; } #endif // Depth buffer should never be touched because // no output should be generated if (gengc->dwCurrentFlags & GLSURF_METAFILE) { gc->modes.haveDepthBuffer = GL_TRUE; return; } if (buffers->depthBuffer.base) { /* buffer already allocated by another RC */ UpdateSharedBuffer(&gc->depthBuffer.buf, &buffers->depthBuffer); } else { DBGLEVEL(LEVEL_ALLOC, "Depth buffer must be allocated\n"); (*buffers->resize)(buffers, &buffers->depthBuffer, w, h); UpdateSharedBuffer(&gc->depthBuffer.buf, &buffers->depthBuffer); } if (gc->depthBuffer.buf.base) { gc->modes.haveDepthBuffer = GL_TRUE; } else { gc->modes.haveDepthBuffer = GL_FALSE; __glSetError(GL_OUT_OF_MEMORY); } __GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_DEPTH); // Note similar code in so_pick.c // Don't need to handle (depthBits == 0) case because LazyAllocateDepth // is not called unless depthBits is non-zero. depthIndex -= GL_NEVER; if( gc->state.depth.writeEnable == GL_FALSE ) { depthIndex += 8; } if( gc->depthBuffer.buf.elementSize == 2 ) depthIndex += 16; (*gc->depthBuffer.pick)(gc, &gc->depthBuffer, depthIndex); } void FASTCALL LazyAllocateStencil(__GLcontext *gc) { GLint w = gc->constants.width; GLint h = gc->constants.height; __GLGENbuffers *buffers; __GLGENcontext *gengc = (__GLGENcontext *)gc; ASSERTOPENGL(gc->modes.stencilBits, "LazyAllocateStencil: zero stencilBits\n"); buffers = gengc->pwndLocked->buffers; buffers->createdStencilBuffer = GL_TRUE; // Depth buffer should never be touched because // no output should be generated if (gengc->dwCurrentFlags & GLSURF_METAFILE) { gc->modes.haveStencilBuffer = GL_TRUE; return; } if (buffers->stencilBuffer.base) { /* buffer already allocated by another RC */ UpdateSharedBuffer(&gc->stencilBuffer.buf, &buffers->stencilBuffer); } else { DBGLEVEL(LEVEL_ALLOC, "stencil buffer must be allocated\n"); (*buffers->resize)(buffers, &buffers->stencilBuffer, w, h); UpdateSharedBuffer(&gc->stencilBuffer.buf, &buffers->stencilBuffer); } if (gc->stencilBuffer.buf.base) { gc->modes.haveStencilBuffer = GL_TRUE; } else { gc->modes.haveStencilBuffer = GL_FALSE; __glSetError(GL_OUT_OF_MEMORY); } __GL_DELAY_VALIDATE(gc); gc->validateMask |= (__GL_VALIDATE_STENCIL_FUNC | __GL_VALIDATE_STENCIL_OP); (*gc->stencilBuffer.pick)(gc, &gc->stencilBuffer); } void FASTCALL LazyAllocateAccum(__GLcontext *gc) { GLint w = gc->constants.width; GLint h = gc->constants.height; __GLGENbuffers *buffers; __GLGENcontext *gengc = (__GLGENcontext *)gc; ASSERTOPENGL(gc->modes.accumBits, "LazyAllocateAccum: zero accumBits\n"); buffers = gengc->pwndLocked->buffers; buffers->createdAccumBuffer = GL_TRUE; // Depth buffer should never be touched because // no output should be generated if (gengc->dwCurrentFlags & GLSURF_METAFILE) { gc->modes.haveAccumBuffer = GL_TRUE; return; } if (buffers->accumBuffer.base) { /* buffer already allocated by another RC */ UpdateSharedBuffer(&gc->accumBuffer.buf, &buffers->accumBuffer); } else { DBGLEVEL(LEVEL_ALLOC, "Accum buffer must be allocated\n"); (*buffers->resize)(buffers, &buffers->accumBuffer, w, h); UpdateSharedBuffer(&gc->accumBuffer.buf, &buffers->accumBuffer); } if (gc->accumBuffer.buf.base) { gc->modes.haveAccumBuffer = GL_TRUE; } else { gc->modes.haveAccumBuffer = GL_FALSE; __glSetError(GL_OUT_OF_MEMORY); } __GL_DELAY_VALIDATE(gc); (*gc->accumBuffer.pick)(gc, &gc->accumBuffer); } /******************************Public*Routine******************************\ * glGenInitCommon * * Called from __glGenInitRGB and __glGenInitCI to handle the shared * initialization chores. * \**************************************************************************/ void FASTCALL glGenInitCommon(__GLGENcontext *gengc, __GLcolorBuffer *cfb, GLenum type) { __GLbuffer *bp; bp = &cfb->buf; // If front buffer, we need to setup the buffer if we think its DIB format. if (type == GL_FRONT) { #ifdef _MCD_ if (gengc->_pMcdState) { // Assume that MCD surface is not accessible. Accessibility // must be determined on a per-batch basis by calling // GenMcdUpdateBufferInfo. bp->flags &= ~(DIB_FORMAT | MEMORY_DC | NO_CLIP); } #endif { if (gengc->dwCurrentFlags & GLSURF_DIRECT_ACCESS) { // These fields will be updated at attention time bp->base = NULL; bp->outerWidth = 0; cfb->buf.flags = DIB_FORMAT; } if (GLSURF_IS_MEMDC(gengc->dwCurrentFlags)) { bp->flags = bp->flags | (MEMORY_DC | NO_CLIP); } else if (gengc->gsurf.dwFlags & GLSURF_DIRECTDRAW) { LPDIRECTDRAWCLIPPER pddc; HRESULT hr; hr = gengc->gsurf.dd.gddsFront.pdds->lpVtbl-> GetClipper(gengc->gsurf.dd.gddsFront.pdds, &pddc); if (hr == DDERR_NOCLIPPERATTACHED) { bp->flags = bp->flags | NO_CLIP; } } } } // If back buffer, we assume its a DIB, or a hardware backbuffer. // In the case of a DIB, the bitmap memory will be allocated via // ResizeBitmapBuffer(). else { #ifdef _MCD_ if (gengc->_pMcdState) { // Assume that MCD surface is not accessible. Accessibility // must be determined on a per-batch basis by calling // GenMcdUpdateBufferInfo. cfb->resize = ResizeHardwareBackBuffer; bp->flags &= ~(DIB_FORMAT | MEMORY_DC | NO_CLIP); } else #endif { cfb->resize = ResizeBitmapBuffer; bp->flags = DIB_FORMAT | MEMORY_DC | NO_CLIP; } } } /******************************Public*Routine******************************\ * glsrvCleanupWindow * * Called from wglCleanupWindow to remove the pwnd reference from the * context. * * History: * 05-Jul-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID APIENTRY glsrvCleanupWindow(__GLcontext *gc, GLGENwindow *pwnd) { __GLGENcontext *gengc = (__GLGENcontext *) gc; // The window in gengc should be consistent with the one in the rc object. // wglCleanupWindow should have already checked to see if the pwnd in the // rc is one we need to remove, so we can just assert here. ASSERTOPENGL(gengc->pwndMakeCur == pwnd, "glsrvCleanupWindow(): bad pwnd\n"); gengc->pwndLocked = NULL; gengc->pwndMakeCur = NULL; } /* ** Fetch the data for a query in its internal type, then convert it to the ** type that the user asked for. ** ** This only handles the NT generic driver specific values (so far just the ** GL_ACCUM_*_BITS values). All others fall back to the soft code function, ** __glDoGet(). */ // These types are stolen from ..\soft\so_get.c. To minimize changes to // the soft code, we will pull them into here rather than moving them to // a header file and changing so_get.c to use the header file. #define __GL_FLOAT 0 /* __GLfloat */ #define __GL_FLOAT32 1 /* api 32 bit float */ #define __GL_FLOAT64 2 /* api 64 bit float */ #define __GL_INT32 3 /* api 32 bit int */ #define __GL_BOOLEAN 4 /* api 8 bit boolean */ #define __GL_COLOR 5 /* unscaled color in __GLfloat */ #define __GL_SCOLOR 6 /* scaled color in __GLfloat */ extern void __glDoGet(GLenum, void *, GLint, const char *); extern void __glConvertResult(__GLcontext *, GLint, const void *, GLint, void *, GLint); void FASTCALL __glGenDoGet(GLenum sq, void *result, GLint type, const char *procName) { GLint iVal; __GLGENcontext *gengc; __GL_SETUP_NOT_IN_BEGIN(); gengc = (__GLGENcontext *) gc; switch (sq) { case GL_ACCUM_RED_BITS: iVal = gengc->gsurf.pfd.cAccumRedBits; break; case GL_ACCUM_GREEN_BITS: iVal = gengc->gsurf.pfd.cAccumGreenBits; break; case GL_ACCUM_BLUE_BITS: iVal = gengc->gsurf.pfd.cAccumBlueBits; break; case GL_ACCUM_ALPHA_BITS: iVal = gengc->gsurf.pfd.cAccumAlphaBits; break; default: __glDoGet(sq, result, type, procName); return; } __glConvertResult(gc, __GL_INT32, &iVal, type, result, 1); } /******************************Public*Routine******************************\ * * glsrvCopyContext * * Copies state from one context to another * * History: * Mon Jun 05 16:53:42 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY glsrvCopyContext(__GLcontext *gcSource, __GLcontext *gcDest, GLuint mask) { return (BOOL)__glCopyContext(gcDest, gcSource, mask); }