mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1847 lines
57 KiB
1847 lines
57 KiB
/*
|
|
** Copyright 1991, 1992, Silicon Graphics, Inc.
|
|
** All Rights Reserved.
|
|
**
|
|
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
|
|
** the contents of this file may not be disclosed to third parties, copied or
|
|
** duplicated in any form, in whole or in part, without the prior written
|
|
** permission of Silicon Graphics, Inc.
|
|
**
|
|
** RESTRICTED RIGHTS LEGEND:
|
|
** Use, duplication or disclosure by the Government is subject to restrictions
|
|
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
|
|
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
|
|
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
|
|
** rights reserved under the Copyright Laws of the United States.
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include <ntcsrdll.h> // CSR declarations and data structures.
|
|
|
|
// #define DETECT_FPE
|
|
#ifdef DETECT_FPE
|
|
#include <float.h>
|
|
#endif
|
|
|
|
#include "glsbmsg.h"
|
|
#include "glsbmsgh.h"
|
|
#include "glsrvspt.h"
|
|
#include "devlock.h"
|
|
#include "global.h"
|
|
|
|
#include "gldci.h"
|
|
|
|
typedef VOID * (FASTCALL *SERVERPROC)(__GLcontext *, IN VOID *);
|
|
|
|
#define LASTPROCOFFSET(ProcTable) (sizeof(ProcTable) - sizeof(SERVERPROC))
|
|
|
|
extern GLSRVSBPROCTABLE glSrvSbProcTable;
|
|
#if DBG
|
|
char *glSrvSbStringTable[] = {
|
|
|
|
NULL, /* Make First Entry NULL */
|
|
|
|
/* gl Entry points */
|
|
|
|
"glDrawPolyArray ",
|
|
"glBitmap ",
|
|
"glColor4fv ",
|
|
"glEdgeFlag ",
|
|
"glIndexf ",
|
|
"glNormal3fv ",
|
|
"glRasterPos4fv ",
|
|
"glTexCoord4fv ",
|
|
"glClipPlane ",
|
|
"glColorMaterial ",
|
|
"glCullFace ",
|
|
"glAddSwapHintRectWIN ",
|
|
"glFogfv ",
|
|
"glFrontFace ",
|
|
"glHint ",
|
|
"glLightfv ",
|
|
"glLightModelfv ",
|
|
"glLineStipple ",
|
|
"glLineWidth ",
|
|
"glMaterialfv ",
|
|
"glPointSize ",
|
|
"glPolygonMode ",
|
|
"glPolygonStipple ",
|
|
"glScissor ",
|
|
"glShadeModel ",
|
|
"glTexParameterfv ",
|
|
"glTexParameteriv ",
|
|
"glTexImage1D ",
|
|
"glTexImage2D ",
|
|
"glTexEnvfv ",
|
|
"glTexEnviv ",
|
|
"glTexGenfv ",
|
|
"glFeedbackBuffer ",
|
|
"glSelectBuffer ",
|
|
"glRenderMode ",
|
|
"glInitNames ",
|
|
"glLoadName ",
|
|
"glPassThrough ",
|
|
"glPopName ",
|
|
"glPushName ",
|
|
"glDrawBuffer ",
|
|
"glClear ",
|
|
"glClearAccum ",
|
|
"glClearIndex ",
|
|
"glClearColor ",
|
|
"glClearStencil ",
|
|
"glClearDepth ",
|
|
"glStencilMask ",
|
|
"glColorMask ",
|
|
"glDepthMask ",
|
|
"glIndexMask ",
|
|
"glAccum ",
|
|
"glDisable ",
|
|
"glEnable ",
|
|
"glPopAttrib ",
|
|
"glPushAttrib ",
|
|
"glMap1d ",
|
|
"glMap1f ",
|
|
"glMap2d ",
|
|
"glMap2f ",
|
|
"glMapGrid1f ",
|
|
"glMapGrid2f ",
|
|
"glAlphaFunc ",
|
|
"glBlendFunc ",
|
|
"glLogicOp ",
|
|
"glStencilFunc ",
|
|
"glStencilOp ",
|
|
"glDepthFunc ",
|
|
"glPixelZoom ",
|
|
"glPixelTransferf ",
|
|
"glPixelTransferi ",
|
|
"glPixelStoref ",
|
|
"glPixelStorei ",
|
|
"glPixelMapfv ",
|
|
"glPixelMapuiv ",
|
|
"glPixelMapusv ",
|
|
"glReadBuffer ",
|
|
"glCopyPixels ",
|
|
"glReadPixels ",
|
|
"glDrawPixels ",
|
|
"glGetBooleanv ",
|
|
"glGetClipPlane ",
|
|
"glGetDoublev ",
|
|
"glGetError ",
|
|
"glGetFloatv ",
|
|
"glGetIntegerv ",
|
|
"glGetLightfv ",
|
|
"glGetLightiv ",
|
|
"glGetMapdv ",
|
|
"glGetMapfv ",
|
|
"glGetMapiv ",
|
|
"glGetMaterialfv ",
|
|
"glGetMaterialiv ",
|
|
"glGetPixelMapfv ",
|
|
"glGetPixelMapuiv ",
|
|
"glGetPixelMapusv ",
|
|
"glGetPolygonStipple ",
|
|
"glGetTexEnvfv ",
|
|
"glGetTexEnviv ",
|
|
"glGetTexGendv ",
|
|
"glGetTexGenfv ",
|
|
"glGetTexGeniv ",
|
|
"glGetTexImage ",
|
|
"glGetTexParameterfv ",
|
|
"glGetTexParameteriv ",
|
|
"glGetTexLevelParameterfv ",
|
|
"glGetTexLevelParameteriv ",
|
|
"glIsEnabled ",
|
|
"glDepthRange ",
|
|
"glFrustum ",
|
|
"glLoadIdentity ",
|
|
"glLoadMatrixf ",
|
|
"glMatrixMode ",
|
|
"glMultMatrixf ",
|
|
"glOrtho ",
|
|
"glPopMatrix ",
|
|
"glPushMatrix ",
|
|
"glRotatef ",
|
|
"glScalef ",
|
|
"glTranslatef ",
|
|
"glViewport ",
|
|
"glAreTexturesResident ",
|
|
"glBindTexture ",
|
|
"glCopyTexImage1D ",
|
|
"glCopyTexImage2D ",
|
|
"glCopyTexSubImage1D ",
|
|
"glCopyTexSubImage2D ",
|
|
"glDeleteTextures ",
|
|
"glGenTextures ",
|
|
"glIsTexture ",
|
|
"glPrioritizeTextures ",
|
|
"glTexSubImage1D ",
|
|
"glTexSubImage2D ",
|
|
"glColorTableEXT ",
|
|
"glColorSubTableEXT ",
|
|
"glGetColorTableEXT ",
|
|
"glGetColorTableParameterivEXT",
|
|
"glGetColorTableParameterfvEXT",
|
|
"glPolygonOffset ",
|
|
|
|
};
|
|
#endif
|
|
|
|
#ifdef DOGLMSGBATCHSTATS
|
|
#define STATS_INC_SERVERCALLS() pMsgBatchInfo->BatchStats.ServerCalls++
|
|
#define STATS_INC_SERVERTRIPS() (pMsgBatchInfo->BatchStats.ServerTrips++)
|
|
#else
|
|
#define STATS_INC_SERVERCALLS()
|
|
#define STATS_INC_SERVERTRIPS()
|
|
#endif
|
|
|
|
DWORD BATCH_LOCK_TICKMAX = 99;
|
|
DWORD TICK_RANGE_LO = 60;
|
|
DWORD TICK_RANGE_HI = 100;
|
|
DWORD gcmsOpenGLTimer;
|
|
|
|
// The GDISAVESTATE structure is used to save/restore DC drawing state
|
|
// that could affect OpenGL rasterization.
|
|
|
|
typedef struct _GDISAVESTATE {
|
|
int iRop2;
|
|
} GDISAVESTATE;
|
|
|
|
void FASTCALL vSaveGdiState(HDC, GDISAVESTATE *);
|
|
void FASTCALL vRestoreGdiState(HDC, GDISAVESTATE *);
|
|
|
|
#if DBG
|
|
extern long glDebugLevel;
|
|
#endif
|
|
|
|
|
|
/***************************************************************************\
|
|
* CheckCritSectionIn
|
|
*
|
|
* This function asserts that the current thread owns the specified
|
|
* critical section. If it doesn't it display some output on the debugging
|
|
* terminal and breaks into the debugger. At some point we'll have RIPs
|
|
* and this will be a little less harsh.
|
|
*
|
|
* The function is used in code where global values that both the RIT and
|
|
* application threads access are used to verify they are protected via
|
|
* the raw input critical section. There's a macro to use this function
|
|
* called CheckCritIn() which will be defined to nothing for a non-debug
|
|
* version of the system.
|
|
*
|
|
* History:
|
|
* 11-29-90 DavidPe Created.
|
|
\***************************************************************************/
|
|
|
|
#if DBG
|
|
|
|
VOID APIENTRY CheckCritSectionIn(
|
|
LPCRITICAL_SECTION pcs)
|
|
{
|
|
//!!!dbug -- implement
|
|
#if 0
|
|
/*
|
|
* If the current thread doesn't own this critical section,
|
|
* that's bad.
|
|
*/
|
|
if (NtCurrentTeb()->ClientId.UniqueThread != pcs->OwningThread)
|
|
{
|
|
RIP("CheckCritSectionIn: Not in critical section!");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID APIENTRY CheckCritSectionOut(
|
|
LPCRITICAL_SECTION pcs)
|
|
{
|
|
//!!!dbug -- implement
|
|
#if 0
|
|
/*
|
|
* If the current thread owns this critical section, that's bad.
|
|
*/
|
|
if (NtCurrentTeb()->ClientId.UniqueThread == pcs->OwningThread)
|
|
{
|
|
RIP("CheckCritSectionOut: In critical section!");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ResizeAncillaryBufs
|
|
*
|
|
* Resize each of the ancillary buffers associated with the drawable.
|
|
*
|
|
* Returns:
|
|
* No return value.
|
|
\**************************************************************************/
|
|
|
|
static void ResizeAncillaryBufs(__GLcontext *gc, __GLdrawablePrivate *dp,
|
|
GLint width, GLint height)
|
|
{
|
|
__GLGENbuffers *buffers;
|
|
__GLbuffer *common, *local;
|
|
GLboolean forcePick = GL_FALSE;
|
|
|
|
buffers = dp->data;
|
|
|
|
if (buffers->createdAccumBuffer)
|
|
{
|
|
common = &buffers->accumBuffer;
|
|
local = &gc->accumBuffer.buf;
|
|
gc->modes.haveAccumBuffer =
|
|
(*buffers->resize)(dp, common, width, height);
|
|
|
|
UpdateSharedBuffer(local, common);
|
|
if (!gc->modes.haveAccumBuffer) // Lost the ancillary buffer
|
|
{
|
|
forcePick = GL_TRUE;
|
|
__glSetError(GL_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
if (buffers->createdDepthBuffer)
|
|
{
|
|
common = &buffers->depthBuffer;
|
|
local = &gc->depthBuffer.buf;
|
|
gc->modes.haveDepthBuffer =
|
|
(*buffers->resizeDepth)(dp, common, width, height);
|
|
|
|
UpdateSharedBuffer(local, common);
|
|
if (!gc->modes.haveDepthBuffer) // Lost the ancillary buffer
|
|
{
|
|
forcePick = GL_TRUE;
|
|
__glSetError(GL_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
if (buffers->createdStencilBuffer)
|
|
{
|
|
common = &buffers->stencilBuffer;
|
|
local = &gc->stencilBuffer.buf;
|
|
gc->modes.haveStencilBuffer =
|
|
(*buffers->resize)(dp, common, width, height);
|
|
|
|
UpdateSharedBuffer(local, common);
|
|
if (!gc->modes.haveStencilBuffer) // Lost the ancillary buffer
|
|
{
|
|
forcePick = GL_TRUE;
|
|
gc->validateMask |= (__GL_VALIDATE_STENCIL_FUNC |
|
|
__GL_VALIDATE_STENCIL_OP);
|
|
__glSetError(GL_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
if (forcePick)
|
|
{
|
|
// Cannot use DELAY_VALIDATE, may be in glBegin/End
|
|
|
|
__GL_INVALIDATE(gc);
|
|
(*gc->procs.validate)(gc);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglResizeBuffers
|
|
*
|
|
* Resize the back and ancillary buffers.
|
|
*
|
|
* History:
|
|
* 20-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID wglResizeBuffers(__GLGENcontext *gengc, GLint width, GLint height)
|
|
{
|
|
__GLcontext *gc = &gengc->gc;
|
|
WNDOBJ *pwo;
|
|
__GLdrawablePrivate *dp;
|
|
__GLGENbuffers *buffers;
|
|
|
|
pwo = gengc->pwo;
|
|
ASSERTOPENGL(pwo, "wglResizeBuffers: bad WNDOBJ\n");
|
|
|
|
dp = (__GLdrawablePrivate *)pwo->pvConsumer;
|
|
ASSERTOPENGL(dp, "wglResizeBuffers: bad pvConsumer\n");
|
|
|
|
buffers = dp->data;
|
|
ASSERTOPENGL(buffers, "wglResizeBuffers: bad private data\n");
|
|
|
|
// Resize back buffer.
|
|
|
|
gengc->errorcode = 0;
|
|
#ifdef _MCD_
|
|
if ( gengc->pMcdState )
|
|
{
|
|
// If the shared buffer struct has not lost its MCD info and
|
|
// the MCD buffers are still valid, we can use MCD.
|
|
|
|
if ( !(buffers->flags & GLGENBUF_MCD_LOST) &&
|
|
GenMcdResizeBuffers(gengc) )
|
|
{
|
|
UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
|
|
if (gc->modes.doubleBufferMode)
|
|
(*gc->back->resize)(dp, gc->back, width, height);
|
|
}
|
|
else
|
|
{
|
|
// If GenMcdConvertContext succeeds, then pMcdState will
|
|
// no longer exist. The context is now an "ordinary"
|
|
// generic context.
|
|
|
|
if ( !GenMcdConvertContext(gengc, buffers) )
|
|
{
|
|
// Not only have we lost the MCD buffers, but we cannot
|
|
// convert the context to generic. For now, disable
|
|
// drawing (by setting the window bounds to empty). On
|
|
// the next batch we will reattempt MCD buffer access
|
|
// and context conversion.
|
|
|
|
buffers->width = 0;
|
|
buffers->height = 0;
|
|
gc->constants.width = 0;
|
|
gc->constants.height = 0;
|
|
|
|
(*gc->procs.applyViewport)(gc);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
goto wglResizeBuffers_GenericBackBuf;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
wglResizeBuffers_GenericBackBuf:
|
|
|
|
if ( gc->modes.doubleBufferMode )
|
|
{
|
|
// Have to update the back buffer BEFORE resizing because
|
|
// another thread may have changed the shared back buffer
|
|
// already, but this thread was unlucky enough to get yet
|
|
// ANOTHER window resize.
|
|
|
|
UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
|
|
|
|
gengc->errorcode = 0;
|
|
(*gc->back->resize)(dp, gc->back, width, height);
|
|
|
|
// If resize failed, set width & height to 0
|
|
|
|
if ( gengc->errorcode )
|
|
{
|
|
gc->constants.width = 0;
|
|
gc->constants.height = 0;
|
|
|
|
// Memory failure has occured. But if a resize happens
|
|
// that returns window size to size before memory error
|
|
// occurred (i.e., consistent with original
|
|
// buffers->{width|height}) we will not try to resize again.
|
|
// Therefore, we need to set buffers->{width|height} to zero
|
|
// to ensure that next thread will attempt to resize.
|
|
|
|
buffers->width = 0;
|
|
buffers->height = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
(*gc->procs.applyViewport)(gc);
|
|
|
|
// Check if new size caused a memory failure.
|
|
// The viewport code will set width & height to zero
|
|
// punt on ancillary buffers, will try next time.
|
|
|
|
if (gengc->errorcode)
|
|
return;
|
|
|
|
// Resize ancillary buffers (depth, stencil, accum).
|
|
|
|
ResizeAncillaryBufs(gc, dp, width, height);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglUpdateBuffers
|
|
*
|
|
* The __GLGENbuffers structure contains the data specifying the shared
|
|
* buffers (back, depth, stencil, accum, etc.).
|
|
*
|
|
* This function updates the context with the shared buffer information.
|
|
*
|
|
* Returns:
|
|
* TRUE if one of the existence of any of the buffers changes (i.e.,
|
|
* gained or lost). FALSE if the state is the same as before.
|
|
*
|
|
* In other words, if function returns TRUE, the pick procs need to
|
|
* be rerun because one or more of the buffers changed.
|
|
*
|
|
* History:
|
|
* 20-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL wglUpdateBuffers(__GLGENcontext *gengc, __GLGENbuffers *buffers)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
__GLcontext *gc = &gengc->gc;
|
|
|
|
UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
|
|
UpdateSharedBuffer(&gc->accumBuffer.buf, &buffers->accumBuffer);
|
|
UpdateSharedBuffer(&gc->depthBuffer.buf, &buffers->depthBuffer);
|
|
UpdateSharedBuffer(&gc->stencilBuffer.buf, &buffers->stencilBuffer);
|
|
|
|
(*gc->procs.applyViewport)(gc);
|
|
|
|
// Check if any ancillary buffers were lost or regained.
|
|
|
|
if ( ( gc->modes.haveAccumBuffer && (buffers->accumBuffer.base == NULL)) ||
|
|
(!gc->modes.haveAccumBuffer && (buffers->accumBuffer.base != NULL)) )
|
|
{
|
|
if ( buffers->accumBuffer.base == NULL )
|
|
gc->modes.haveAccumBuffer = GL_FALSE;
|
|
else
|
|
gc->modes.haveAccumBuffer = GL_TRUE;
|
|
bRet = TRUE;
|
|
}
|
|
if ( ( gc->modes.haveDepthBuffer && (buffers->depthBuffer.base == NULL)) ||
|
|
(!gc->modes.haveDepthBuffer && (buffers->depthBuffer.base != NULL)) )
|
|
{
|
|
if ( buffers->depthBuffer.base == NULL )
|
|
gc->modes.haveDepthBuffer = GL_FALSE;
|
|
else
|
|
gc->modes.haveDepthBuffer = GL_TRUE;
|
|
bRet = TRUE;
|
|
}
|
|
if ( ( gc->modes.haveStencilBuffer && (buffers->stencilBuffer.base == NULL)) ||
|
|
(!gc->modes.haveStencilBuffer && (buffers->stencilBuffer.base != NULL)) )
|
|
{
|
|
if ( buffers->stencilBuffer.base == NULL )
|
|
gc->modes.haveStencilBuffer = GL_FALSE;
|
|
else
|
|
gc->modes.haveStencilBuffer = GL_TRUE;
|
|
gc->validateMask |= (__GL_VALIDATE_STENCIL_FUNC |
|
|
__GL_VALIDATE_STENCIL_OP);
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UpdateWindowInfo
|
|
*
|
|
* Update context data if window changed
|
|
* position
|
|
* size
|
|
* palette
|
|
*
|
|
* No need to worry about clipping changes, the lower level routines grab
|
|
* the WNDOBJ/CLIPOBJ directly
|
|
*
|
|
* Returns:
|
|
* No return value.
|
|
\**************************************************************************/
|
|
|
|
void UpdateWindowInfo(__GLGENcontext *gengc)
|
|
{
|
|
WNDOBJ *pwo;
|
|
__GLdrawablePrivate *dp;
|
|
__GLGENbuffers *buffers;
|
|
__GLcontext *gc = (__GLcontext *)gengc;
|
|
GLint width, height, visWidth, visHeight;
|
|
GLboolean forcePick = GL_FALSE;
|
|
|
|
pwo = gengc->pwo;
|
|
ASSERTOPENGL(pwo, "UpdateWindowInfo(): bad WNDOBJ\n");
|
|
dp = (__GLdrawablePrivate *)pwo->pvConsumer;
|
|
ASSERTOPENGL(dp, "UpdateWindowInfo(): bad pvConsumer\n");
|
|
buffers = dp->data;
|
|
ASSERTOPENGL(buffers, "UpdateWindowInfo(): bad private data\n");
|
|
|
|
// Memory DC case -- need to check bitmap size. The DC is not bound to
|
|
// a window, so there is no message or DCI to inform us of size changes.
|
|
|
|
if ( gengc->iDCType == DCTYPE_MEMORY )
|
|
{
|
|
DIBSECTION ds;
|
|
int iRetVal;
|
|
|
|
if ( iRetVal = GetObject(GetCurrentObject(gengc->CurrentDC, OBJ_BITMAP),
|
|
sizeof(ds), &ds) )
|
|
{
|
|
ASSERTOPENGL(pwo->rclClient.left == 0 &&
|
|
pwo->rclClient.top == 0,
|
|
"UpdateWindowInfo(): bad rclClient for memDc\n");
|
|
|
|
// Bitmap may have changed. If DIB, force reload of base pointer and
|
|
// outer width (buffer pitch).
|
|
|
|
if ( (iRetVal == sizeof(ds)) && ds.dsBm.bmBits )
|
|
{
|
|
// For backwards compatibility with Get/SetBitmapBits, GDI does
|
|
// not accurately report the bitmap pitch in bmWidthBytes. It
|
|
// always computes bmWidthBytes assuming WORD-aligned scanlines
|
|
// regardless of the platform.
|
|
//
|
|
// Therefore, if the platform is WinNT, which uses DWORD-aligned
|
|
// scanlines, adjust the bmWidthBytes value.
|
|
|
|
if ( dwPlatformId == VER_PLATFORM_WIN32_NT )
|
|
{
|
|
ds.dsBm.bmWidthBytes = (ds.dsBm.bmWidthBytes + 3) & ~3;
|
|
}
|
|
|
|
// If biHeight is positive, then the bitmap is a bottom-up DIB.
|
|
// If biHeight is negative, then the bitmap is a top-down DIB.
|
|
|
|
if ( ds.dsBmih.biHeight > 0 )
|
|
{
|
|
gengc->gc.frontBuffer.buf.base = (PVOID) (((int) ds.dsBm.bmBits) +
|
|
(ds.dsBm.bmWidthBytes * (ds.dsBm.bmHeight - 1)));
|
|
gengc->gc.frontBuffer.buf.outerWidth = -ds.dsBm.bmWidthBytes;
|
|
}
|
|
else
|
|
{
|
|
gengc->gc.frontBuffer.buf.base = ds.dsBm.bmBits;
|
|
gengc->gc.frontBuffer.buf.outerWidth = ds.dsBm.bmWidthBytes;
|
|
}
|
|
}
|
|
|
|
// Bitmap size different from WNDOBJ?
|
|
|
|
if ( ds.dsBm.bmWidth != pwo->rclClient.right ||
|
|
ds.dsBm.bmHeight != pwo->rclClient.bottom )
|
|
{
|
|
// Save new size.
|
|
|
|
pwo->rclClient.right = ds.dsBm.bmWidth;
|
|
pwo->rclClient.bottom = ds.dsBm.bmHeight;
|
|
pwo->coClient.rclBounds.right = ds.dsBm.bmWidth;
|
|
pwo->coClient.rclBounds.bottom = ds.dsBm.bmHeight;
|
|
|
|
// Increment uniqueness numbers.
|
|
// Don't let it hit -1. -1 is special and is used by
|
|
// MakeCurrent to signal that an update is required
|
|
|
|
buffers->WndUniq++;
|
|
|
|
buffers->WndSizeUniq++;
|
|
|
|
if (buffers->WndUniq == -1)
|
|
buffers->WndUniq = 0;
|
|
|
|
if (buffers->WndSizeUniq == -1)
|
|
buffers->WndSizeUniq = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("UpdateWindowInfo: could not get bitmap info for memDc\n");
|
|
}
|
|
}
|
|
|
|
// Compute current WNDOBJ dimensions.
|
|
|
|
width = pwo->rclClient.right - pwo->rclClient.left;
|
|
height = pwo->rclClient.bottom - pwo->rclClient.top;
|
|
|
|
#ifdef _MCD_
|
|
//!!!dbug mcd -- Originally, we needed to call MCDAllocBuffers per-batch
|
|
// to make sure the buffers still exist. Is this still
|
|
// still required, or can we do it on resize only?
|
|
|
|
// Check MCD buffers.
|
|
|
|
if ( gengc->pMcdState )
|
|
{
|
|
BOOL bAllocOK;
|
|
|
|
// Do we need an initial MCDAlloc (via GenMcdResizeBuffers)?
|
|
// The bAllocOK flag will be set to FALSE if the resize fails.
|
|
|
|
if ( gengc->pMcdState->mcdFlags & MCD_STATE_FORCERESIZE )
|
|
{
|
|
// Attempt resize. If it fails, convert context (see below).
|
|
|
|
if (GenMcdResizeBuffers(gengc))
|
|
{
|
|
UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
|
|
if (gc->modes.doubleBufferMode)
|
|
(*gc->back->resize)(dp, gc->back, width, height);
|
|
|
|
bAllocOK = TRUE;
|
|
}
|
|
else
|
|
bAllocOK = FALSE;
|
|
|
|
// Clear the flag. If resize succeeded, we don't need to
|
|
// force the resize again. If resize failed, the context
|
|
// will be converted, so we don't need to force the resize.
|
|
|
|
gengc->pMcdState->mcdFlags &= ~MCD_STATE_FORCERESIZE;
|
|
}
|
|
else
|
|
bAllocOK = TRUE;
|
|
|
|
// If the shared buffer struct has lost its MCD info or we could
|
|
// not do the initial allocate, convert the context.
|
|
|
|
if ( (buffers->flags & GLGENBUF_MCD_LOST) || !bAllocOK )
|
|
{
|
|
// If GenMcdConvertContext succeeds, then pMcdState will
|
|
// no longer exist. The context is now an "ordinary"
|
|
// generic context.
|
|
|
|
if ( !GenMcdConvertContext(gengc, buffers) )
|
|
{
|
|
// Not only have we lost the MCD buffers, but we cannot
|
|
// convert the context to generic. For now, disable
|
|
// drawing (by setting the window bounds to empty). On
|
|
// the next batch we will reattempt MCD buffer access
|
|
// and context conversion.
|
|
|
|
buffers->width = 0;
|
|
buffers->height = 0;
|
|
gc->constants.width = 0;
|
|
gc->constants.height = 0;
|
|
|
|
(*gc->procs.applyViewport)(gc);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Check the uniqueness signature. If different, the window client area
|
|
// state has changed.
|
|
//
|
|
// Note that we actually have two uniqueness numbers, WndUniq and WndSizeUniq.
|
|
// WndUniq is incremented whenever any client window state (size or position)
|
|
// changes. WndSizeUniq is incremented only when the size changes and is
|
|
// maintained as an optimization. WndSizeUniq allows us to skip copying
|
|
// the shared buffer info and recomputing the viewport if only the position
|
|
// has changed.
|
|
//
|
|
// WndSizeUniq is a subset of WndUniq, so checking only WndUniq suffices at
|
|
// this level.
|
|
|
|
if ( gengc->WndUniq != buffers->WndUniq )
|
|
{
|
|
// Update origin of front buffer in case it moved
|
|
|
|
if ( !gengc->pDrvAccel )
|
|
{
|
|
gc->frontBuffer.buf.xOrigin = pwo->rclClient.left;
|
|
gc->frontBuffer.buf.yOrigin = pwo->rclClient.top;
|
|
}
|
|
else
|
|
{
|
|
gc->frontBuffer.buf.xOrigin = 0;
|
|
gc->frontBuffer.buf.yOrigin = 0;
|
|
}
|
|
|
|
// If acceleration is wired-in, set the offsets for line drawing.
|
|
|
|
if ( gengc->pPrivateArea )
|
|
{
|
|
__fastLineComputeOffsets(gengc);
|
|
}
|
|
|
|
// Check for size changed
|
|
// Update viewport and ancillary buffers
|
|
|
|
visWidth = pwo->coClient.rclBounds.right -
|
|
pwo->coClient.rclBounds.left;
|
|
visHeight = pwo->coClient.rclBounds.bottom -
|
|
pwo->coClient.rclBounds.top;
|
|
|
|
// Sanity check the info from WNDOBJ.
|
|
|
|
ASSERTOPENGL(
|
|
width <= __GL_MAX_WINDOW_WIDTH && height <= __GL_MAX_WINDOW_HEIGHT,
|
|
"UpdateWindowInfo(): bad window client size\n"
|
|
);
|
|
ASSERTOPENGL(
|
|
visWidth <= __GL_MAX_WINDOW_WIDTH && visHeight <= __GL_MAX_WINDOW_HEIGHT,
|
|
"UpdateWindowInfo(): bad visible size\n"
|
|
);
|
|
|
|
(*gc->front->resize)(dp, gc->front, width, height);
|
|
|
|
if ( (width != buffers->width) ||
|
|
(height != buffers->height) )
|
|
{
|
|
gc->constants.width = width;
|
|
gc->constants.height = height;
|
|
|
|
// This RC needs to resize back & ancillary buffers
|
|
|
|
gengc->errorcode = 0;
|
|
wglResizeBuffers(gengc, width, height);
|
|
|
|
// Check if new size caused a memory failure
|
|
// viewport code will set width & height to zero
|
|
// punt on ancillary buffers, will try next time
|
|
|
|
if (gengc->errorcode)
|
|
return;
|
|
|
|
buffers->width = width;
|
|
buffers->height = height;
|
|
}
|
|
else if ( (gengc->WndSizeUniq != buffers->WndSizeUniq) ||
|
|
(width != gc->constants.width) ||
|
|
(height != gc->constants.height) )
|
|
{
|
|
// The buffer size is consistent with the WNDOBJ, so another thread
|
|
// has already resized the buffer, but we need to update the
|
|
// gc shared buffers and recompute the viewport.
|
|
|
|
gc->constants.width = width;
|
|
gc->constants.height = height;
|
|
|
|
forcePick = wglUpdateBuffers(gengc, buffers);
|
|
|
|
if ( forcePick )
|
|
{
|
|
/* Cannot use DELAY_VALIDATE, may be in glBegin/End */
|
|
__GL_INVALIDATE(gc);
|
|
(*gc->procs.validate)(gc);
|
|
}
|
|
}
|
|
else if ( (visWidth != gengc->visibleWidth) ||
|
|
(visHeight != gengc->visibleHeight) )
|
|
{
|
|
// The buffer size has not changed. However, the visibility of
|
|
// the window has changed so the viewport data must be recomputed.
|
|
|
|
(*gc->procs.applyViewport)(gc);
|
|
}
|
|
|
|
// Make sure we swap the whole window
|
|
|
|
{
|
|
__GLdrawablePrivate *private;
|
|
__GLGENbuffers *buffers;
|
|
|
|
private = gc->drawablePrivate;
|
|
buffers = (__GLGENbuffers *) private->data;
|
|
|
|
buffers->fMax = TRUE;
|
|
}
|
|
|
|
// The context is now up-to-date with the buffer size. Set the
|
|
// uniqueness numbers to match.
|
|
|
|
gengc->WndUniq = buffers->WndUniq;
|
|
gengc->WndSizeUniq = buffers->WndSizeUniq;
|
|
}
|
|
|
|
// Update palette info is palette has changed
|
|
|
|
HandlePaletteChanges(gengc, (GLGENwindow *)pwo);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vSaveGdiState
|
|
*
|
|
* Saves current GDI drawing state to the GDISAVESTATE structure passed in.
|
|
* Sets GDI state needed for OpenGL rendering.
|
|
*
|
|
* History:
|
|
* 19-Jul-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void FASTCALL vSaveGdiState(HDC hdc, GDISAVESTATE *pGdiState)
|
|
{
|
|
// Currently, the only state needed is the line code which may use
|
|
// GDI lines. Rop2 must be R2_COPYPEN (draws with the pen color).
|
|
|
|
pGdiState->iRop2 = SetROP2(hdc, R2_COPYPEN);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vRestoreGdiState
|
|
*
|
|
* Restores GDI drawing state from the GDISAVESTATE structure passed in.
|
|
*
|
|
* History:
|
|
* 19-Jul-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void FASTCALL vRestoreGdiState(HDC hdc, GDISAVESTATE *pGdiState)
|
|
{
|
|
SetROP2(hdc, pGdiState->iRop2);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WNDOBJ_vLock
|
|
*
|
|
* Acquire WNDOBJ lock.
|
|
\**************************************************************************/
|
|
|
|
#define WNDOBJ_vLock(pwo) \
|
|
if (pwo) \
|
|
EnterCriticalSection( &(pwo)->sem );
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WNDOBJ_vUnlock
|
|
*
|
|
* Release WNDOBJ lock.
|
|
\**************************************************************************/
|
|
|
|
#define WNDOBJ_vUnlock(pwo) \
|
|
if (pwo) \
|
|
LeaveCriticalSection( &(pwo)->sem );
|
|
|
|
/******************************Public*Routine******************************\
|
|
* MyDCIBeginAccess
|
|
*
|
|
* Private version of DCIBeginAccess that handles screen resolution changes.
|
|
*
|
|
* If the screen resolution changes, the DCI surface is invalidated. To
|
|
* regain access, the DCI primary surface must be recreated. If successful,
|
|
* the pointer to the primary surface passed into this function will be
|
|
* modified.
|
|
*
|
|
* Note: as currently written, generic implementation of OpenGL cannot
|
|
* handle color depth changes. So we fail the call if this is detected.
|
|
*
|
|
* History:
|
|
* 21-Mar-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG MyDCIBeginAccess(GLGENwindow *pwnd, PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
DCIRVAL dciRet = DCI_FAIL_GENERIC;
|
|
LPDCISURFACEINFO *ppDCISurfInfo = &(GLDCIINFO->pDCISurfInfo);
|
|
int x = pwnd->wo.rclClient.left;
|
|
int y = pwnd->wo.rclClient.top;
|
|
int width = pwnd->wo.rclClient.right - pwnd->wo.rclClient.left;
|
|
int height = pwnd->wo.rclClient.bottom - pwnd->wo.rclClient.top;
|
|
|
|
// Win95 version of DCI provides global synchronization throughout the system.
|
|
// This cannot be done in WinNT, but we can provide per-process synchronization
|
|
// with a global (i.e., per-process semaphore) semaphore within our library.
|
|
|
|
EnterCriticalSection(&gcsDci);
|
|
|
|
// Do not acquire DCI access if gengc format does not match pixelformat.
|
|
|
|
if ((*ppDCISurfInfo)->dwBitCount != ppfd->cColorBits)
|
|
{
|
|
WARNING("MyDCIBeginAccess: surface not compatible with context\n");
|
|
goto MyDCIBeginAccess_exit;
|
|
}
|
|
|
|
// OK to call DCI now.
|
|
|
|
dciRet = DCIBeginAccess(*ppDCISurfInfo, x, y, width, height);
|
|
|
|
// If DCIBeginAccess failed because of a resolution change, try to recreate
|
|
// the primary surface.
|
|
|
|
if ( dciRet == DCI_FAIL_INVALIDSURFACE )
|
|
{
|
|
LPDCISURFACEINFO pDCISurfNew = (LPDCISURFACEINFO) NULL;
|
|
|
|
// Create a new DCI surface.
|
|
|
|
if ( (DCICreatePrimary(GLDCIINFO->hdc, &pDCISurfNew) >= DCI_OK) &&
|
|
(pDCISurfNew != (LPDCISURFACEINFO) NULL) )
|
|
{
|
|
// While OpenGL generic implementation can handle screen dimension
|
|
// changes, it cannot yet deal with a color depth change.
|
|
|
|
if (pDCISurfNew->dwBitCount == (*ppDCISurfInfo)->dwBitCount)
|
|
{
|
|
__GLdrawablePrivate *dp = (__GLdrawablePrivate *) NULL;
|
|
__GLGENbuffers *buffers = (__GLGENbuffers *) NULL;
|
|
|
|
// If screen changes, the MCD surfaces are lost and must be
|
|
// recreated from scratch. This can be triggered by simply
|
|
// changing the window uniqueness numbers.
|
|
|
|
if (dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer)
|
|
buffers = (__GLGENbuffers *)dp->data;
|
|
|
|
if (buffers)
|
|
{
|
|
buffers->WndUniq++;
|
|
|
|
buffers->WndSizeUniq++;
|
|
|
|
// Don't let it hit -1. -1 is special and is used by
|
|
// MakeCurrent to signal that an update is required
|
|
|
|
if (buffers->WndUniq == -1)
|
|
buffers->WndUniq = 0;
|
|
|
|
if (buffers->WndSizeUniq == -1)
|
|
buffers->WndSizeUniq = 0;
|
|
}
|
|
|
|
// Delete the current DCI surface and replace it with the new
|
|
// surface.
|
|
|
|
DCIDestroy(*ppDCISurfInfo);
|
|
*ppDCISurfInfo = pDCISurfNew;
|
|
|
|
// Try DCIBeginAccess with the new surface.
|
|
|
|
dciRet = DCIBeginAccess(*ppDCISurfInfo, x, y, width, height);
|
|
}
|
|
else
|
|
{
|
|
// Delete the new surface.
|
|
//
|
|
// Even though the old surface is invalid, we will keep it
|
|
// around in case the color is invalid, we will keep it around
|
|
// in case the color depth changes back to the original depth
|
|
// (but not necessarily the same screen dimensions). If that
|
|
// happens, when we recreate the surface we will succeed.
|
|
|
|
DCIDestroy(pDCISurfNew);
|
|
dciRet = DCI_FAIL_GENERIC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dciRet = DCI_FAIL_GENERIC;
|
|
}
|
|
}
|
|
|
|
MyDCIBeginAccess_exit:
|
|
|
|
// If we really have access to the surface, set the lock flag.
|
|
// Otherwise, reset the lock flag and return error.
|
|
|
|
if (dciRet >= DCI_OK)
|
|
{
|
|
ASSERTOPENGL(((*ppDCISurfInfo)->dwOffSurface != 0),
|
|
"MyDCIBeginAccess: expected non-NULL dwOffSurface\n");
|
|
|
|
pwnd->ulFlags |= GLGENWIN_DCILOCK;
|
|
}
|
|
else
|
|
{
|
|
pwnd->ulFlags &= ~GLGENWIN_DCILOCK;
|
|
|
|
LeaveCriticalSection(&gcsDci);
|
|
}
|
|
|
|
return dciRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* MyDCIEndAccess
|
|
*
|
|
* Release DCI lock acquired via MyDCIBeginAccess.
|
|
*
|
|
* History:
|
|
* 28-Mar-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID MyDCIEndAccess(GLGENwindow *pwnd)
|
|
{
|
|
ASSERTOPENGL(pwnd->ulFlags & GLGENWIN_DCILOCK,
|
|
"MyDCIEndAccess: not in DCI lock!\n");
|
|
|
|
if (pwnd->ulFlags & GLGENWIN_DCILOCK)
|
|
{
|
|
pwnd->ulFlags &= ~GLGENWIN_DCILOCK;
|
|
DCIEndAccess(GLDCIINFO->pDCISurfInfo);
|
|
|
|
LeaveCriticalSection(&gcsDci);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glsrvGrabDci
|
|
*
|
|
* Acquire DCI lock and handle any changes that occurred since the
|
|
* last acquisition
|
|
*
|
|
* History:
|
|
* Tue Apr 02 13:10:26 1996 -by- Drew Bliss [drewb]
|
|
* Split out of glsrvGrabLock
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY glsrvGrabDci(__GLGENcontext *gengc,
|
|
GLGENwindow *pwnd)
|
|
{
|
|
#if DBG
|
|
// If debugging, remember the surface offset in case it changes when we grab
|
|
// the lock.
|
|
|
|
static DWORD curSurf = 0;
|
|
#endif
|
|
|
|
BOOL bRet = FALSE;
|
|
BOOL bDoOver;
|
|
DCIRVAL dciRet;
|
|
|
|
if (gengc->iDCType == DCTYPE_INFO ||
|
|
gengc->ulLockType != DISPLAY_LOCK)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// We already check this in glsrvAttention, but there are other
|
|
// functions that call this so check that the WNDOBJ is correct
|
|
// to be safe.
|
|
|
|
if (pwnd != (GLGENwindow *)gengc->pwo)
|
|
{
|
|
// One way an app could cause this is if the current HDC is released
|
|
// without releasing (wglMakeCurrent(0, 0)) the corresponding HGLRC.
|
|
// If GetDC returns this same HDC but for a different window, then
|
|
// pwndGetFromDC will return the pwnd associated with the new window.
|
|
// However, the HGLRC is still bound to the original window. In
|
|
// such a situation we must fail the lock.
|
|
|
|
WARNING("glsrvGrabDci: mismatched WNDOBJs\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Grab, test, and release the DCI lock until the visregion is stable.
|
|
|
|
do
|
|
{
|
|
UpdateWindowInfo(gengc);
|
|
|
|
// Grab the DCI lock.
|
|
|
|
dciRet = MyDCIBeginAccess(pwnd, &gengc->CurrentFormat);
|
|
|
|
if (dciRet < DCI_OK)
|
|
{
|
|
WARNING1("glsrvGrabLock(): "
|
|
"DCIBeginAccess failed code 0x%lx\n", dciRet);
|
|
goto glsrvGrabDci_exit;
|
|
}
|
|
|
|
// Did the window change during the time the DCI lock was released?
|
|
// If so, we need recompute the clip list and call UpdateWindowInfo
|
|
// again.
|
|
|
|
if ( bDoOver = WinWatchDidStatusChange(pwnd->hww) )
|
|
{
|
|
BOOL bHaveClip;
|
|
|
|
bHaveClip = wglGetClipList(gengc->pwo);
|
|
|
|
// Release DCI access because we're going to loop around
|
|
// to UpdateWindowInfo again and it makes a lot of
|
|
// GDI calls.
|
|
|
|
MyDCIEndAccess(pwnd);
|
|
|
|
if (!bHaveClip)
|
|
{
|
|
WARNING("glsrvGrabDci(): wglGetClipList failed\n");
|
|
goto glsrvGrabDci_exit;
|
|
}
|
|
}
|
|
} while ( bDoOver );
|
|
|
|
// Base and width may have changed since last BeginAccess. Refresh
|
|
// the data in the gengc.
|
|
|
|
#ifdef _MCD_
|
|
if (gengc->pMcdState)
|
|
{
|
|
if (!(gpMcdTable->pMCDLock)(&gengc->pMcdState->McdContext))
|
|
{
|
|
WARNING("glsrvGrabLock(): MCDLock failed\n");
|
|
goto glsrvGrabDci_exit;
|
|
}
|
|
|
|
GenMcdUpdateBufferInfo(gengc);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
gengc->gc.frontBuffer.buf.base =
|
|
(VOID *) GLDCIINFO->pDCISurfInfo->dwOffSurface;
|
|
gengc->gc.frontBuffer.buf.outerWidth =
|
|
GLDCIINFO->pDCISurfInfo->lStride;
|
|
}
|
|
|
|
#if DBG
|
|
#define LEVEL_DCI LEVEL_INFO
|
|
|
|
// Did the DCI surface offset change? If so, report it if debugging.
|
|
|
|
if (curSurf != GLDCIINFO->pDCISurfInfo->dwOffSurface)
|
|
{
|
|
DBGLEVEL (LEVEL_DCI, "=============================\n");
|
|
DBGLEVEL (LEVEL_DCI, "DCI surface offset changed\n\n");
|
|
DBGLEVEL1(LEVEL_DCI, "\tdwOffSurface = 0x%lx\n",
|
|
GLDCIINFO->pDCISurfInfo->dwOffSurface);
|
|
DBGLEVEL (LEVEL_DCI, "=============================\n");
|
|
|
|
curSurf = GLDCIINFO->pDCISurfInfo->dwOffSurface;
|
|
}
|
|
#endif
|
|
|
|
bRet = TRUE;
|
|
|
|
glsrvGrabDci_exit:
|
|
#if DBG
|
|
if (dciRet < 0)
|
|
{
|
|
WARNING2("glsrvGrabDci(): dciRet = %ld (%s)\n", dciRet,
|
|
(dciRet == DCI_FAIL_GENERIC ) ? "DCI_FAIL_GENERIC " :
|
|
(dciRet == DCI_FAIL_UNSUPPORTEDVERSION) ? "DCI_FAIL_UNSUPPORTEDVERSION" :
|
|
(dciRet == DCI_FAIL_INVALIDSURFACE ) ? "DCI_FAIL_INVALIDSURFACE " :
|
|
(dciRet == DCI_FAIL_UNSUPPORTED ) ? "DCI_FAIL_UNSUPPORTED " :
|
|
(dciRet == DCI_ERR_CURRENTLYNOTAVAIL ) ? "DCI_ERR_CURRENTLYNOTAVAIL " :
|
|
(dciRet == DCI_ERR_INVALIDRECT ) ? "DCI_ERR_INVALIDRECT " :
|
|
(dciRet == DCI_ERR_UNSUPPORTEDFORMAT ) ? "DCI_ERR_UNSUPPORTEDFORMAT " :
|
|
(dciRet == DCI_ERR_UNSUPPORTEDMASK ) ? "DCI_ERR_UNSUPPORTEDMASK " :
|
|
(dciRet == DCI_ERR_TOOBIGHEIGHT ) ? "DCI_ERR_TOOBIGHEIGHT " :
|
|
(dciRet == DCI_ERR_TOOBIGWIDTH ) ? "DCI_ERR_TOOBIGWIDTH " :
|
|
(dciRet == DCI_ERR_TOOBIGSIZE ) ? "DCI_ERR_TOOBIGSIZE " :
|
|
(dciRet == DCI_ERR_OUTOFMEMORY ) ? "DCI_ERR_OUTOFMEMORY " :
|
|
(dciRet == DCI_ERR_INVALIDPOSITION ) ? "DCI_ERR_INVALIDPOSITION " :
|
|
(dciRet == DCI_ERR_INVALIDSTRETCH ) ? "DCI_ERR_INVALIDSTRETCH " :
|
|
(dciRet == DCI_ERR_INVALIDCLIPLIST ) ? "DCI_ERR_INVALIDCLIPLIST " :
|
|
(dciRet == DCI_ERR_SURFACEISOBSCURED ) ? "DCI_ERR_SURFACEISOBSCURED " :
|
|
(dciRet == DCI_ERR_XALIGN ) ? "DCI_ERR_XALIGN " :
|
|
(dciRet == DCI_ERR_YALIGN ) ? "DCI_ERR_YALIGN " :
|
|
(dciRet == DCI_ERR_XYALIGN ) ? "DCI_ERR_XYALIGN " :
|
|
(dciRet == DCI_ERR_WIDTHALIGN ) ? "DCI_ERR_WIDTHALIGN " :
|
|
(dciRet == DCI_ERR_HEIGHTALIGN ) ? "DCI_ERR_HEIGHTALIGN " :
|
|
"unknown");
|
|
}
|
|
#endif
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glsrvReleaseDci
|
|
*
|
|
* Releases all resources held for DCI access
|
|
*
|
|
* History:
|
|
* Tue Apr 02 13:18:52 1996 -by- Drew Bliss [drewb]
|
|
* Split from glsrvReleaseLock
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY glsrvReleaseDci(__GLGENcontext *gengc,
|
|
GLGENwindow *pwnd)
|
|
{
|
|
if (gengc->iDCType == DCTYPE_INFO ||
|
|
gengc->ulLockType != DISPLAY_LOCK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
// NULL out our front-buffer information to ensure that we
|
|
// can't access the surface unless we're really holding the lock
|
|
|
|
gengc->gc.frontBuffer.buf.base = NULL;
|
|
gengc->gc.frontBuffer.buf.outerWidth = 0;
|
|
#endif
|
|
|
|
#ifdef _MCD_
|
|
if (gengc->pMcdState)
|
|
{
|
|
(gpMcdTable->pMCDUnlock)(&gengc->pMcdState->McdContext);
|
|
}
|
|
#endif
|
|
|
|
MyDCIEndAccess(pwnd);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvGrabLock
|
|
*
|
|
* Grab the display lock and tear down the cursor as needed. Also, initialize
|
|
* the tickers and such that help determine when the thread should give up
|
|
* the lock.
|
|
*
|
|
* Note that for contexts that draw only to the generic back buffer do not
|
|
* need to grab the display lock or tear down the cursor. However, to prevent
|
|
* another thread of a multithreaded app from resizing the drawable while
|
|
* this thread is using it, a per-drawable semaphore will be grabbed via
|
|
* DEVLOCKOBJ_WNDOBJ_bLock().
|
|
*
|
|
* Note: while the return value indicates whether the function succeeded,
|
|
* some APIs that might call this (like the dispatch function for glCallList
|
|
* and glCallLists) may not be able to return failure. So, an error code
|
|
* of GLGEN_DEVLOCK_FAILED is posted to the GLGENcontext if the lock fails.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 12-Apr-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY glsrvGrabLock(__GLGENcontext *gengc)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
BOOL bBackBufferOnly = GENERIC_BACKBUFFER_ONLY((__GLcontext *) gengc);
|
|
GLGENwindow *pwnd;
|
|
|
|
// Mostly ignore attempts to lock IC's
|
|
if (gengc->iDCType == DCTYPE_INFO)
|
|
{
|
|
// If we're running with a real WNDOBJ then we need to look it
|
|
// up to detect whether it's died or not
|
|
if (gengc->ipfdCurrent != 0)
|
|
{
|
|
pwnd = pwndGetFromDC(gengc->CurrentDC);
|
|
if (pwnd == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (pwnd != (GLGENwindow *)gengc->pwo)
|
|
{
|
|
WARNING("glsrvGrabLock: mismatched WNDOBJs (info DC)\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
UpdateWindowInfo(gengc);
|
|
return TRUE;
|
|
}
|
|
|
|
// Get the WNDOBJ from the DC. This has the side effect of locking it
|
|
// against deletion.
|
|
|
|
pwnd = pwndGetFromDC(gengc->CurrentDC);
|
|
if (pwnd == NULL)
|
|
{
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
if (pwnd != (GLGENwindow *)gengc->pwo)
|
|
{
|
|
// One way an app could cause this is if the current HDC is released
|
|
// without releasing (wglMakeCurrent(0, 0)) the corresponding HGLRC.
|
|
// If GetDC returns this same HDC but for a different window, then
|
|
// pwndGetFromDC will return the pwnd associated with the new window.
|
|
// However, the HGLRC is still bound to the original window. In
|
|
// such a situation we must fail the lock.
|
|
|
|
WARNING("glsrvGrabLock: mismatched WNDOBJs\n");
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
|
|
// Save the lock type. We need to do this because the drawing buffer
|
|
// may change before glsrvReleaseLock is called (either because of a
|
|
// glDrawBuffer in a display list or a glDrawBuffer as the last function
|
|
// in a batch). Therefore, inside glsrvReleaseLock we cannot trust the
|
|
// GENERIC_BACKBUFFER_ONLY macro to determine the type of lock that needs
|
|
// to be released.
|
|
//
|
|
// DISPLAY_LOCK -- drawable buffers and display surface are protected;
|
|
// cursor is torn down
|
|
//
|
|
// DRAWABLE_LOCK -- only the drawable buffers are protected; cursor is not
|
|
// torn down
|
|
|
|
gengc->ulLockType = ((!bBackBufferOnly) &&
|
|
GLDCIENABLED &&
|
|
pwnd->hwnd) ? DISPLAY_LOCK : DRAWABLE_LOCK;
|
|
|
|
// Either way, we to lock the GLGENwindow structure.
|
|
|
|
EnterCriticalSection(&pwnd->sem);
|
|
|
|
// If the current window is out-of-process then we haven't
|
|
// been receiving any updates on its status. Manually
|
|
// check its position, size and palette information
|
|
if (pwnd->ulFlags & GLGENWIN_OTHERPROCESS)
|
|
{
|
|
RECT rct;
|
|
POINT pt;
|
|
BOOL bPosChanged, bSizeChanged;
|
|
|
|
if (!IsWindow(pwnd->hwnd))
|
|
{
|
|
// Window was destroyed
|
|
pwndCleanup(pwnd);
|
|
pwnd = NULL;
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
|
|
if (!GetClientRect(pwnd->hwnd, &rct))
|
|
{
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
pt.x = rct.left;
|
|
pt.y = rct.top;
|
|
if (!ClientToScreen(pwnd->hwnd, &pt))
|
|
{
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
|
|
bPosChanged =
|
|
GLDCIENABLED &&
|
|
(pt.x != pwnd->wo.rclClient.left ||
|
|
pt.y != pwnd->wo.rclClient.top);
|
|
bSizeChanged =
|
|
rct.right != (pwnd->wo.rclClient.right-pwnd->wo.rclClient.left) ||
|
|
rct.bottom != (pwnd->wo.rclClient.bottom-pwnd->wo.rclClient.top);
|
|
|
|
if (bPosChanged || bSizeChanged)
|
|
{
|
|
__GLdrawablePrivate *dp;
|
|
__GLGENbuffers *buffers = NULL;
|
|
|
|
pwnd->wo.rclClient.left = pt.x;
|
|
pwnd->wo.rclClient.top = pt.y;
|
|
pwnd->wo.rclClient.right = pt.x+rct.right;
|
|
pwnd->wo.rclClient.bottom = pt.y+rct.bottom;
|
|
pwnd->wo.coClient.rclBounds = pwnd->wo.rclClient;
|
|
|
|
dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer;
|
|
if (dp != NULL)
|
|
{
|
|
buffers = (__GLGENbuffers *)dp->data;
|
|
}
|
|
|
|
if (buffers != NULL)
|
|
{
|
|
// Don't let it hit -1. -1 is special and is used by
|
|
// MakeCurrent to signal that an update is required
|
|
|
|
if (++buffers->WndUniq == -1)
|
|
{
|
|
buffers->WndUniq = 0;
|
|
}
|
|
if (bSizeChanged &&
|
|
++buffers->WndSizeUniq == -1)
|
|
{
|
|
buffers->WndSizeUniq = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The palette watcher should be active since we
|
|
// are going to use its count.
|
|
if (tidPaletteWatcherThread == 0)
|
|
{
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
pwnd->ulPaletteUniq = ulPaletteWatcherCount;
|
|
}
|
|
|
|
// The display lock, if required, means calling DCIBeginAccess.
|
|
// Update drawables.
|
|
|
|
if ( gengc->ulLockType == DISPLAY_LOCK )
|
|
{
|
|
if (!glsrvGrabDci(gengc, pwnd))
|
|
{
|
|
goto glsrvGrabLock_exit;
|
|
}
|
|
|
|
// Record the approximate time the lock was grabbed. That way we
|
|
// can compute the time the lock is held and release it if necessary.
|
|
|
|
gcmsOpenGLTimer = GetTickCount();
|
|
|
|
gengc->dwLockTick = gcmsOpenGLTimer;
|
|
gengc->dwLastTick = gcmsOpenGLTimer;
|
|
gengc->dwCalls = 0;
|
|
gengc->dwCallsPerTick = 16;
|
|
}
|
|
else
|
|
{
|
|
UpdateWindowInfo(gengc);
|
|
|
|
#ifdef _MCD_
|
|
// Update MCD buffer state for MCD drivers w/o DCI support.
|
|
|
|
if (gengc->pMcdState)
|
|
{
|
|
GenMcdUpdateBufferInfo(gengc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
glsrvGrabLock_exit:
|
|
|
|
if (!bRet)
|
|
{
|
|
gengc->ulLockType = NO_LOCK;
|
|
gengc->errorcode = GLGEN_DEVLOCK_FAILED;
|
|
__glSetError(GL_OUT_OF_MEMORY); // not really an out-of-mem err, but
|
|
// this code is an indication that
|
|
// the OpenGL state is now
|
|
// indeterminate
|
|
if (pwnd)
|
|
{
|
|
pwndUnlock(pwnd);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvReleaseLock
|
|
*
|
|
* Releases display or drawable semaphore as appropriate.
|
|
*
|
|
* Returns:
|
|
* No return value.
|
|
*
|
|
* History:
|
|
* 12-Apr-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY glsrvReleaseLock(__GLGENcontext *gengc)
|
|
{
|
|
GLGENwindow *pwnd = (GLGENwindow *) gengc->pwo;
|
|
|
|
// Mostly ignore attempts to lock IC's
|
|
if (gengc->iDCType == DCTYPE_INFO)
|
|
{
|
|
// If we have a real WNDOBJ we need to release it
|
|
if (gengc->ipfdCurrent != 0)
|
|
{
|
|
pwndRelease(pwnd);
|
|
}
|
|
return;
|
|
}
|
|
ASSERTOPENGL(gengc->pwo != NULL, "glsrvReleaseLock: No wndobj\n");
|
|
|
|
// Release lock.
|
|
|
|
if ( gengc->ulLockType == DISPLAY_LOCK )
|
|
{
|
|
glsrvReleaseDci(gengc, pwnd);
|
|
}
|
|
|
|
gengc->ulLockType = NO_LOCK;
|
|
|
|
pwndUnlock(pwnd);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvAttention
|
|
*
|
|
* Dispatches each of the OpenGL API calls in the shared memory window.
|
|
*
|
|
* So that a single complex or long batch does not starve the rest of the
|
|
* system, the lock is released periodically based on the number of ticks
|
|
* that have elapsed since the lock was acquired.
|
|
*
|
|
* The user Raw Input Thread (RIT) and OpenGL share the gcmsOpenGLTimer
|
|
* value. Because the RIT may be blocked, it does not always service
|
|
* the gcmsOpenGLTimer. To compensate, glsrvAttention (as well as the
|
|
* display list dispatchers for glCallList and glCallLists) update
|
|
* gcmsOpenGLTimer explicitly with NtGetTickCount (a relatively expensive
|
|
* call) every N calls.
|
|
*
|
|
* The value N, or the number of APIs dispatched per call to NtGetTickCount,
|
|
* is variable. glsrvAttention and its display list equivalents attempt
|
|
* to adjust N so that NtGetTickCount is called approximately every
|
|
* TICK_RANGE_LO to TICK_RANGE_HI ticks.
|
|
*
|
|
* Returns:
|
|
* TRUE if entire batch is processed, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 12-Apr-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY glsrvAttention(PVOID pdlo, PVOID pdco, PVOID pdxo, HANDLE hdev)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG *pOffset;
|
|
SERVERPROC Proc;
|
|
GLMSGBATCHINFO *pMsgBatchInfo = GLTEB_SHAREDMEMORYSECTION();
|
|
__GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
|
|
#ifdef CHAIN_DRAWPOLYARRAY_MSG
|
|
POLYARRAY *paBegin = (POLYARRAY *) NULL;
|
|
POLYARRAY *paEnd, *pa;
|
|
GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray = NULL;
|
|
#endif
|
|
UINT old_fp;
|
|
GDISAVESTATE GdiState;
|
|
|
|
#ifdef DETECT_FPE
|
|
old_fp = _controlfp(0, 0);
|
|
_controlfp(_EM_INEXACT, _MCW_EM);
|
|
#endif
|
|
vSaveGdiState(gengc->CurrentDC, &GdiState);
|
|
|
|
DBGENTRY("glsrvAttention\n");
|
|
|
|
DBGLEVEL1(LEVEL_INFO, "glsrvAttention: pMsgBatchInfo=0x%lx\n",
|
|
pMsgBatchInfo);
|
|
|
|
STATS_INC_SERVERTRIPS();
|
|
|
|
// Need these so that glsrvGrabLock/ReleaseLock can call the private
|
|
// DEVLOCKOBJ/DEVEXCLUDEOBJ interface.
|
|
|
|
gengc->pdco = pdco;
|
|
//!!!XXX -- not needed for client-side?
|
|
#if 0
|
|
gengc->pdlo = pdlo;
|
|
gengc->pdxo = pdxo;
|
|
gengc->hdev = hdev;
|
|
#endif
|
|
|
|
// Grab the lock.
|
|
|
|
if (!glsrvGrabLock(gengc))
|
|
{
|
|
//!!! mcd/dma too?
|
|
PolyArrayResetBuffer((__GLcontext *) gengc);
|
|
goto glsrvAttention_exit;
|
|
}
|
|
|
|
// Dispatch the calls in the batch.
|
|
|
|
pOffset = (ULONG *)(((BYTE *)pMsgBatchInfo) + pMsgBatchInfo->FirstOffset);
|
|
|
|
// Generic back buffer drawing does not require the lock. Yay!
|
|
|
|
if (gengc->ulLockType != DISPLAY_LOCK)
|
|
{
|
|
while (*pOffset)
|
|
{
|
|
ASSERTOPENGL(*pOffset <= LASTPROCOFFSET(glSrvSbProcTable),
|
|
"Bad ProcOffset: memory corruption - we are hosed!\n");
|
|
|
|
STATS_INC_SERVERCALLS();
|
|
|
|
DBGLEVEL1(LEVEL_ENTRY, "%s\n",
|
|
glSrvSbStringTable[*pOffset / sizeof(SERVERPROC *)]);
|
|
|
|
#ifdef CHAIN_DRAWPOLYARRAY_MSG
|
|
if (*pOffset == offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray))
|
|
pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *) pOffset;
|
|
#endif
|
|
|
|
// Dispatch the call. The return value is the offset of the next
|
|
// message in the batch.
|
|
|
|
Proc = (*((SERVERPROC *)( ((BYTE *)(&glSrvSbProcTable)) +
|
|
*pOffset )));
|
|
pOffset = (*Proc)((__GLcontext *) gengc, pOffset);
|
|
|
|
#ifdef CHAIN_DRAWPOLYARRAY_MSG
|
|
// If we are processing DrawPolyArray, we need to update the pointers
|
|
// that indicate the beginning and end of the POLYARRAY data for
|
|
// the current range of DrawPolyArray chain.
|
|
|
|
if (pMsgDrawPolyArray)
|
|
{
|
|
pa = (POLYARRAY *) pMsgDrawPolyArray->pa;
|
|
pMsgDrawPolyArray = NULL; // get ready for next iteration
|
|
|
|
// Skip this primitive if no rendering is needed.
|
|
if (!(pa->flags & POLYARRAY_RENDER_PRIMITIVE))
|
|
{
|
|
PolyArrayRestoreColorPointer(pa);
|
|
}
|
|
else
|
|
{
|
|
// Add to DrawPolyArray chain
|
|
pa->paNext = NULL;
|
|
if (!paBegin)
|
|
paBegin = pa;
|
|
else
|
|
paEnd->paNext = pa;
|
|
paEnd = pa;
|
|
}
|
|
|
|
// If the next message is not a DrawPolyArray, then we need to
|
|
// flush the primitive drawing.
|
|
if (*pOffset != offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray)
|
|
&& paBegin)
|
|
{
|
|
// Draw all the POLYARRAY primitives between paBegin
|
|
// and paEnd
|
|
glsrvFlushDrawPolyArray((void *) paBegin);
|
|
paBegin = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (*pOffset)
|
|
{
|
|
ASSERTOPENGL(*pOffset <= LASTPROCOFFSET(glSrvSbProcTable),
|
|
"Bad ProcOffset: memory corruption - we are hosed!\n");
|
|
|
|
STATS_INC_SERVERCALLS();
|
|
|
|
DBGLEVEL1(LEVEL_ENTRY, "%s\n",
|
|
glSrvSbStringTable[*pOffset / sizeof(SERVERPROC *)]);
|
|
|
|
#ifdef CHAIN_DRAWPOLYARRAY_MSG
|
|
if (*pOffset == offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray))
|
|
pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *) pOffset;
|
|
#endif
|
|
|
|
// Dispatch the call. The return value is the offset of the next
|
|
// message in the batch.
|
|
|
|
Proc = (*((SERVERPROC *)( ((BYTE *)(&glSrvSbProcTable)) +
|
|
*pOffset )));
|
|
pOffset = (*Proc)((__GLcontext *) gengc, pOffset);
|
|
|
|
#ifdef CHAIN_DRAWPOLYARRAY_MSG
|
|
// If we are processing DrawPolyArray, we need to update the pointers
|
|
// that indicate the beginning and end of the POLYARRAY data for
|
|
// the current range of DrawPolyArray chain.
|
|
|
|
if (pMsgDrawPolyArray)
|
|
{
|
|
pa = (POLYARRAY *) pMsgDrawPolyArray->pa;
|
|
pMsgDrawPolyArray = NULL; // get ready for next iteration
|
|
|
|
// Skip this primitive if no rendering is needed.
|
|
if (!(pa->flags & POLYARRAY_RENDER_PRIMITIVE))
|
|
{
|
|
PolyArrayRestoreColorPointer(pa);
|
|
}
|
|
else
|
|
{
|
|
// Add to DrawPolyArray chain
|
|
pa->paNext = NULL;
|
|
if (!paBegin)
|
|
paBegin = pa;
|
|
else
|
|
paEnd->paNext = pa;
|
|
paEnd = pa;
|
|
}
|
|
|
|
// If the next message is not a DrawPolyArray, then we need to
|
|
// flush the primitive drawing.
|
|
if (*pOffset != offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray)
|
|
&& paBegin)
|
|
{
|
|
// Draw all the POLYARRAY primitives between paBegin
|
|
// and paEnd
|
|
glsrvFlushDrawPolyArray((void *) paBegin);
|
|
paBegin = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef NT_DEADCODE_DISPATCH
|
|
// Some calls (specifically glCallList and glCallLists) may try
|
|
// to release and regrab the lock. We must check the errorcode
|
|
// for a lock failure.
|
|
|
|
if (gengc->errorcode == GLGEN_DEVLOCK_FAILED)
|
|
{
|
|
gengc->errorcode = 0; // reset error code
|
|
goto glsrvAttention_exit;
|
|
}
|
|
#endif // NT_DEADCODE_DISPATCH
|
|
|
|
// Force a check of the current tick count every N calls.
|
|
|
|
gengc->dwCalls++;
|
|
|
|
if (gengc->dwCalls >= gengc->dwCallsPerTick)
|
|
{
|
|
gcmsOpenGLTimer = GetTickCount();
|
|
|
|
// If the tick delta is out of range, then increase or decrease
|
|
// N as appropriate. Be careful not to let it grow out of
|
|
// bounds or to shrink to zero.
|
|
|
|
if ((gcmsOpenGLTimer - gengc->dwLastTick) < TICK_RANGE_LO)
|
|
if (gengc->dwCallsPerTick < 64)
|
|
gengc->dwCallsPerTick *= 2;
|
|
else if ((gcmsOpenGLTimer - gengc->dwLastTick) > TICK_RANGE_HI)
|
|
// The + 1 is to keep it from hitting 0
|
|
gengc->dwCallsPerTick = (gengc->dwCallsPerTick + 1) / 2;
|
|
|
|
gengc->dwLastTick = gcmsOpenGLTimer;
|
|
gengc->dwCalls = 0;
|
|
}
|
|
|
|
// Check if time slice has expired. If so, relinquish the lock.
|
|
|
|
if ((gcmsOpenGLTimer - gengc->dwLockTick) > BATCH_LOCK_TICKMAX)
|
|
{
|
|
#ifdef CHAIN_DRAWPOLYARRAY_MSG
|
|
//!!! Before we release the lock, we may need to flush the
|
|
//!!! DrawPolyArray chain. For now, just flush it although
|
|
//!!! it is probably unnecessary.
|
|
if (paBegin)
|
|
{
|
|
// Draw all the POLYARRAY primitives between paBegin
|
|
// and paEnd
|
|
glsrvFlushDrawPolyArray((void *) paBegin);
|
|
paBegin = NULL;
|
|
}
|
|
#endif
|
|
|
|
// Release and regrab lock. This will allow the cursor to
|
|
// redraw as well as reset the cursor timer.
|
|
|
|
glsrvReleaseLock(gengc);
|
|
if (!glsrvGrabLock(gengc))
|
|
{
|
|
//!!! mcd/dma too?
|
|
PolyArrayResetBuffer((__GLcontext *) gengc);
|
|
goto glsrvAttention_exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Release the lock.
|
|
|
|
glsrvReleaseLock(gengc);
|
|
|
|
// Success.
|
|
|
|
bRet = TRUE;
|
|
|
|
glsrvAttention_exit:
|
|
|
|
vRestoreGdiState(gengc->CurrentDC, &GdiState);
|
|
#ifdef DETECT_FPE
|
|
_controlfp(old_fp, _MCW_EM);
|
|
#endif
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// GDI server doesn't have access to __assert in CRT
|
|
#if DBG
|
|
void __glassert(char *ex, char *file, int line)
|
|
{
|
|
DbgPrint("OpenGL assertion failed: %s ", ex);
|
|
DbgPrint(file);
|
|
DbgPrint(" line %d\n", line);
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|