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

4067 lines
123 KiB
C

#include "precomp.h"
#pragma hdrstop
#include <imfuncs.h>
#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);
}