|
|
/******************************Module*Header*******************************\
* Module Name: dl_list.c * * Display list management rountines. * * Copyright (c) 1995-96 Microsoft Corporation \**************************************************************************/ /*
** Copyright 1991-1993, 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. ** ** Basic display list routines. ** */ #include "precomp.h"
#pragma hdrstop
extern GLCLTPROCTABLE ListCompCltProcTable; extern GLEXTPROCTABLE ListCompExtProcTable;
__GLdlist *__glShrinkDlist(__GLcontext *gc, __GLdlist *dlist);
// #define DL_HEAP_VERBOSE
#ifdef DL_HEAP_VERBOSE
int cbDlistTotal = 0; extern ULONG glSize;
#ifdef DBG
#define GL_MSIZE(pv) _msize((BYTE *)(pv)-16)
#else
#define GL_MSIZE(pv) _msize(pv)
#endif
#endif
#if defined(DL_BLOCK_VERBOSE) || defined(DL_HEAP_VERBOSE)
#include "malloc.h"
#endif
/*
** Arbitrary limit for looking up multiple display lists at once ** (with glCallLists()). Any number from 128 to 1024 should work well. ** This value doesn't change the functionality of OpenGL at all, but ** will make minor variations to the performance characteristics. */ #define MAX_LISTS_CACHE 256
const GLubyte __GLdlsize_tab[] = { /* GL_BYTE */ 1, /* GL_UNSIGNED_BYTE */ 1, /* GL_SHORT */ 2, /* GL_UNSIGNED_SHORT */ 2, /* GL_INT */ 4, /* GL_UNSIGNED_INT */ 4, /* GL_FLOAT */ 4, /* GL_2_BYTES */ 2, /* GL_3_BYTES */ 3, /* GL_4_BYTES */ 4, };
#define __glCallListsSize(type) \
((type) >= GL_BYTE && (type) <= GL_4_BYTES ? \ __GLdlsize_tab[(type)-GL_BYTE] : -1)
#define DL_LINK_SIZE (sizeof(__GLlistExecFunc *)+sizeof(GLubyte *))
#define DL_TERMINATOR_SIZE sizeof(GLubyte *)
#define DL_OVERHEAD (offsetof(__GLdlist, head)+DL_LINK_SIZE+\
DL_TERMINATOR_SIZE)
// This value should be a power of two
#define DL_BLOCK_SIZE (256 * 1024)
// This value is chosen specifically to give the initial total size
// of the dlist an even block size
#define DL_INITIAL_SIZE (DL_BLOCK_SIZE-DL_OVERHEAD)
// Skip to the next block in the display list block chain
const GLubyte * FASTCALL __glle_NextBlock(__GLcontext *gc, const GLubyte *PC) { #ifdef DL_BLOCK_VERBOSE
DbgPrint("NextBlock: %08lX\n", *(const GLubyte * UNALIGNED64 *)PC); #endif
return *(const GLubyte * UNALIGNED64 *)PC; }
/*
** Used to pad display list entries to double word boundaries where needed ** (for those few OpenGL commands which take double precision values). */ const GLubyte * FASTCALL __glle_Nop(__GLcontext *gc, const GLubyte *PC) { return PC; }
void APIENTRY glcltNewList ( IN GLuint list, IN GLenum mode ) { __GLdlistMachine *dlstate; __GL_SETUP();
// Must use the client side begin state
if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; }
dlstate = &gc->dlist;
/* Valid mode? */ switch(mode) { case GL_COMPILE: case GL_COMPILE_AND_EXECUTE: break; default: GLSETERROR(GL_INVALID_ENUM); return; }
if (dlstate->currentList) { /* Must call EndList before calling NewList again! */ GLSETERROR(GL_INVALID_OPERATION); return; }
if (list == 0) { GLSETERROR(GL_INVALID_VALUE); return; }
// If we are in COMPILE mode, we need to clear the command buffer,
// the poly array buffer, and the poly material buffer so that we
// can use them to compile poly array. Otherwise, previously batched
// commands may be lost.
if (mode == GL_COMPILE) glsbAttention();
ASSERTOPENGL((DL_BLOCK_SIZE & (DL_BLOCK_SIZE-1)) == 0, "DL_BLOCK_SIZE is not a power of two\n"); ASSERTOPENGL(dlstate->listData == NULL, "listData non-NULL in NewList\n"); dlstate->listData = __glAllocDlist(gc, DL_INITIAL_SIZE); if (dlstate->listData == NULL) { GLSETERROR(GL_OUT_OF_MEMORY); return; } /*
** Save current client dispatch pointers into saved state in context. Then ** switch to the list tables. */ gc->savedCltProcTable.cEntries = ListCompCltProcTable.cEntries; gc->savedExtProcTable.cEntries = ListCompExtProcTable.cEntries; GetCltProcTable(&gc->savedCltProcTable, &gc->savedExtProcTable, FALSE); SetCltProcTable(&ListCompCltProcTable, &ListCompExtProcTable, FALSE);
dlstate->currentList = list; dlstate->mode = mode; dlstate->nesting = 0; #if 0
dlstate->drawBuffer = GL_FALSE; #endif
dlstate->beginRec = NULL;
(*dlstate->initState)(gc); }
void APIENTRY glcltEndList ( void ) { __GLdlistMachine *dlstate; __GLdlist *dlist; __GLdlist *newDlist; __GLdlist *prevDlist; GLubyte *allEnd; GLubyte *data; GLuint totalSize; GLuint currentList; POLYARRAY *pa; __GL_SETUP();
pa = gc->paTeb;
dlstate = &gc->dlist;
/* Must call NewList() first! */ if (dlstate->currentList == 0) { GLSETERROR(GL_INVALID_OPERATION); return; }
// In COMPILE_AND_EXECUTE mode, EndList must not be called in Begin.
// In COMPILE mode, however, this flag should be clear (enforced in NewList)
// unless it was set in the poly array compilation code.
if (dlstate->mode == GL_COMPILE_AND_EXECUTE && pa->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; }
// If we are in the middle of compiling poly array, end the poly array
// compilation.
if (gc->dlist.beginRec) { ASSERTOPENGL(pa->flags & POLYARRAY_IN_BEGIN, "not in begin!\n");
gc->dlist.beginRec->flags |= DLIST_BEGIN_NO_MATCHING_END;
// Record the last POLYDATA since it may contain attribute changes.
__glDlistCompilePolyData(gc, GL_TRUE);
// Terminate poly array compilation
gc->dlist.beginRec = NULL; }
// If we are in COMPILE mode, we need to reset the command buffer,
// the poly array buffer, and the poly material buffer.
if (gc->dlist.mode == GL_COMPILE) { glsbResetBuffers(gc->dlist.beginRec ? TRUE : FALSE);
// Clear begin flag too
pa->flags &= ~POLYARRAY_IN_BEGIN; }
dlist = dlstate->listData; #if 0
// Copy over the DrawBuffer flag
dlist->drawBuffer = dlstate->drawBuffer; #endif
// Shrink this block to remove wasted space
dlist = __glShrinkDlist(gc, dlist);
// Remember the true end of the list
allEnd = dlist->head+dlist->used; // Reverse the order of the list
prevDlist = NULL; while (dlist->nextBlock != NULL) { newDlist = dlist->nextBlock; dlist->nextBlock = prevDlist; prevDlist = dlist; dlist = newDlist; } dlist->nextBlock = prevDlist; // Set the end pointer correctly
dlist->end = allEnd; // Mark the end of the display list data with 0:
*((DWORD *)dlist->end) = 0;
dlstate->listData = NULL;
currentList = dlstate->currentList; dlstate->currentList = 0; #ifdef DL_HEAP_VERBOSE
DbgPrint("Dlists using %8d, total %8d\n", cbDlistTotal, glSize); #endif
#ifdef DL_BLOCK_VERBOSE
DbgPrint("List %d: start %08lX, end %08lX\n", currentList, dlist->head, dlist->end); DbgPrint("Blocks at:"); newDlist = dlist; while (newDlist != NULL) { DbgPrint(" %08lX:%d", newDlist, GL_MSIZE(newDlist)); newDlist = newDlist->nextBlock; } DbgPrint("\n"); #endif
// __glNamesNewData sets dlist refcount to 1.
if (!__glNamesNewData(gc, gc->dlist.namesArray, currentList, dlist)) { /*
** No memory! ** Nuke the list! */ __glFreeDlist(gc, dlist); } /* Switch back to saved dispatch state */ SetCltProcTable(&gc->savedCltProcTable, &gc->savedExtProcTable, FALSE); }
#ifdef NT_SERVER_SHARE_LISTS
/******************************Public*Routine******************************\
* * DlLockLists * * Remember the locked lists for possible later cleanup * * History: * Mon Dec 12 18:58:32 1994 -by- Drew Bliss [drewb] * Created * \**************************************************************************/
// Number of locks to allocate when the lock list needs to grow
// Must be a power of two
#define DL_LOCK_LIST_BLOCK 32
GLboolean DlLockLists(__GLcontext *gc, GLsizei n, __GLdlist **dlists) { DlLockArray *pdla; DlLockEntry *pdle; GLsizei nNewSize;
pdla = &gc->dla; // Extend current lock array if needed
if (pdla->nAllocated-pdla->nFilled < n) { // Round the needed size up to the block size
nNewSize = (pdla->nAllocated+n+DL_LOCK_LIST_BLOCK-1) & ~(DL_LOCK_LIST_BLOCK-1); pdle = GCREALLOC(gc, pdla->pdleEntries, sizeof(DlLockEntry)*nNewSize); if (pdle == NULL) { return 0; }
pdla->nAllocated = nNewSize; pdla->pdleEntries = pdle; }
// We must have enough space now
ASSERTOPENGL(pdla->nAllocated-pdla->nFilled >= n, "no enough space!\n");
// Lock down dlists and remember them
pdle = pdla->pdleEntries+pdla->nFilled; pdla->nFilled += n; while (n-- > 0) { pdle->dlist = *dlists;
DBGLEVEL3(LEVEL_INFO, "Locked %p for %p, ref %d\n", *dlists, gc, (*dlists)->refcount); dlists++; pdle++; } return (GLboolean) (pdla->nFilled != 0); // return high water mark
}
/******************************Public*Routine******************************\
* * DlUnlockLists * * Remove list lock entries. * * History: * Mon Dec 12 18:58:54 1994 -by- Drew Bliss [drewb] * Created * \**************************************************************************/
void DlUnlockLists(__GLcontext *gc, GLsizei n) { DlLockArray *pdla; DlLockEntry *pdle; GLsizei i; __GLdlist *dlist;
// Since DlLockLists and DlUnlockLists are called in a recursive manner,
// we can simply decrement the filled count.
pdla = &gc->dla; pdla->nFilled -= n;
// Lock list doesn't shrink. This would be fairly easy since realloc
// is guaranteed not to fail when the memory block shrinks
// Is this important?
}
/******************************Public*Routine******************************\
* * DlReleaseLocks * * Releases any locks in the lock list and frees the lock list * * Must be executed under the dlist semaphore * * History: * Tue Dec 13 11:45:26 1994 -by- Drew Bliss [drewb] * Created * \**************************************************************************/
void DlReleaseLocks(__GLcontext *gc) { DlLockArray *pdla; DlLockEntry *pdle;
__GL_NAMES_ASSERT_LOCKED(gc->dlist.namesArray); pdla = &gc->dla;
DBGLEVEL3(LEVEL_INFO, "Cleaning up %p, locks %d (%d)\n", gc, pdla->nFilled, pdla->nAllocated);
// Sanity check the counts
ASSERTOPENGL(pdla->nFilled <= pdla->nAllocated, "bad nFilled!\n"); pdle = pdla->pdleEntries; while (pdla->nFilled) { pdla->nFilled--;
// This function is called to clean up display list locks held by
// glCallList or glCallLists when it dies. We need to release the
// locks here and free the dlists if their refcounts reach 0.
// The refcounts will reach 0 here only when the dlists were deleted
// by another thread while this thread was also holding the locks.
__glDisposeDlist(gc, pdle->dlist); pdle++; }
pdla->nAllocated = 0; if (pdla->pdleEntries) { GCFREE(gc, pdla->pdleEntries); } }
#endif // NT_SERVER_SIDE
// If the a dlist was deleted by another thread while we have it locked,
// we need to free the dlist here.
void FASTCALL DlCleanup(__GLcontext *gc, void *pData) { __glFreeDlist(gc, (__GLdlist *)pData); }
void FASTCALL DoCallList(GLuint list) { __GLdlist *dlist; __GLdlistMachine *dlstate; const GLubyte *end, *PC; __GLlistExecFunc *fp; __GL_SETUP();
dlstate = &gc->dlist;
if (dlstate->nesting >= __GL_MAX_LIST_NESTING) { /* Force unwinding of the display list */ dlstate->nesting = __GL_MAX_LIST_NESTING*2; return; }
/* Increment dlist refcount */ dlist = __glNamesLockData(gc, gc->dlist.namesArray, list);
/* No list, no action! */ if (!dlist) { return; }
#ifdef NT_SERVER_SHARE_LISTS
if (!DlLockLists(gc, 1, &dlist)) { /* Decrement dlist refcount */ __glNamesUnlockData(gc, (void *)dlist, DlCleanup); GLSETERROR(GL_OUT_OF_MEMORY); return; } #endif
dlstate->nesting++;
end = dlist->end; PC = dlist->head;
while (PC != end) { // Get the current function pointer.
fp = *((__GLlistExecFunc * const UNALIGNED64 *) PC);
// Execute the current function. Return value is pointer to
// next function/parameter block in the display list.
PC = (*fp)(gc, PC+sizeof(__GLlistExecFunc * const *)); }
dlstate->nesting--;
/* Decrement dlist refcount */ // Will perform cleanup if necessary
__glNamesUnlockData(gc, (void *)dlist, DlCleanup); #ifdef NT_SERVER_SHARE_LISTS
DlUnlockLists(gc, 1); #endif
}
/*
** Display list compilation and execution versions of CallList and CallLists ** are maintained here for the sake of sanity. Note that __glle_CallList ** may not call glcltCallList or it will break the infinite recursive ** display list prevention code. */ void APIENTRY __gllc_CallList ( IN GLuint list ) { struct __gllc_CallList_Rec *data; __GL_SETUP();
if (list == 0) { __gllc_InvalidValue(); return; }
// It is extremely difficult to make CallList(s) work with poly array
// compilation. For example, in the call sequence in COMPILE_AND_EXECUTE
// mode [Begin, TexCoord, CallList, Vertex, ...], it is difficult to record
// the partial POLYDATA in both COMPILE and COMPILE_AND_EXECUTE modes.
// That is, we may end up recording and playing back TexCoord twice in the
// above example. As a result, we may have to stop building poly array in
// some cases. Fortunately, this situation is rare.
if (gc->dlist.beginRec) { gc->dlist.beginRec->flags |= DLIST_BEGIN_HAS_CALLLIST;
// Record the last POLYDATA since it may contain attribute changes.
__glDlistCompilePolyData(gc, GL_TRUE); }
data = (struct __gllc_CallList_Rec *) __glDlistAddOpUnaligned(gc, DLIST_SIZE(sizeof(struct __gllc_CallList_Rec)), DLIST_GENERIC_OP(CallList)); if (data == NULL) return; data->list = list; __glDlistAppendOp(gc, data, __glle_CallList);
if (gc->dlist.beginRec) { POLYARRAY *pa;
pa = gc->paTeb;
// In COMPILE_AND_EXECUTE mode, we can actually get out of the Begin mode.
// Although it is an application error, we need to terminate poly array
// compilation!
if (!(pa->flags & POLYARRAY_IN_BEGIN)) gc->dlist.beginRec = NULL; else { // If there is a partial vertex record after CallList(s), we will terminate
// the poly array compilation. Otherwise, it is safe to continue the
// processing.
if (pa->pdNextVertex->flags) { // Terminate poly array compilation
gc->dlist.beginRec = NULL;
if (gc->dlist.mode == GL_COMPILE) { glsbResetBuffers(TRUE);
// Clear begin flag too
pa->flags &= ~POLYARRAY_IN_BEGIN; }
} } } }
const GLubyte * FASTCALL __glle_CallList(__GLcontext *gc, const GLubyte *PC) { struct __gllc_CallList_Rec *data;
data = (struct __gllc_CallList_Rec *) PC; DoCallList(data->list); return PC + sizeof(struct __gllc_CallList_Rec); }
void APIENTRY glcltCallList ( IN GLuint list ) { __GL_SETUP(); if (list == 0) { GLSETERROR(GL_INVALID_VALUE); return; }
gc->dlist.nesting = 0; DoCallList(list); }
void FASTCALL DoCallLists(GLsizei n, GLenum type, const GLvoid *lists) { __GLdlist *dlists[MAX_LISTS_CACHE]; __GLdlist *dlist; __GLdlistMachine *dlstate; GLint i, dlcount, datasize; const GLubyte *listiter; const GLubyte *end, *PC; __GLlistExecFunc *fp; __GL_SETUP();
dlstate = &gc->dlist;
datasize = __glCallListsSize(type);
if (dlstate->nesting >= __GL_MAX_LIST_NESTING) { /* Force unwinding of the display list */ dlstate->nesting = __GL_MAX_LIST_NESTING*2; return; } dlstate->nesting++;
listiter = (const GLubyte *) lists; while (n) { dlcount = n; if (dlcount > MAX_LISTS_CACHE) dlcount = MAX_LISTS_CACHE;
#ifdef NT_SERVER_SHARE_LISTS
// Is there anything we can do here in the failure case besides
// just skip the lists? This is more or less consistent
// with the behavior for not-found lists
/* Increment dlist refcount */ __glNamesLockDataList(gc, gc->dlist.namesArray, dlcount, type, gc->state.list.listBase, (const GLvoid *) listiter, (void **)dlists);
if (!DlLockLists(gc, dlcount, dlists)) { /* Decrement dlist refcount */ __glNamesUnlockDataList(gc, dlcount, (void **)dlists, DlCleanup); GLSETERROR(GL_OUT_OF_MEMORY); } else { #else
__glNamesLockDataList(gc, gc->dlist.namesArray, dlcount, type, gc->state.list.listBase, (const GLvoid *) listiter, (void **)dlists); #endif
i = 0; while (i < dlcount) { dlist = dlists[i]; end = dlist->end; PC = dlist->head; while (PC != end) { // Get the current function pointer.
fp = *((__GLlistExecFunc * const UNALIGNED64 *) PC);
// Execute the current function. Return value is pointer to
// next function/parameter block in the display list.
PC = (*fp)(gc, PC+sizeof(__GLlistExecFunc * const *)); } i++; }
/* Decrement dlist refcount */ // Will perform cleanup if necessary
__glNamesUnlockDataList(gc, dlcount, (void **)dlists, DlCleanup);
#ifdef NT_SERVER_SHARE_LISTS
DlUnlockLists(gc, dlcount); } #endif
listiter += dlcount * datasize; n -= dlcount; }
dlstate->nesting--; }
/*
** Display list compilation and execution versions of CallList and CallLists ** are maintained here for the sake of sanity. Note that __glle_CallLists ** may not call glcltCallLists or it will break the infinite recursive ** display list prevention code. */ void APIENTRY __gllc_CallLists ( IN GLsizei n, IN GLenum type, IN const GLvoid *lists ) { GLuint size; GLint arraySize; struct __gllc_CallLists_Rec *data; __GL_SETUP();
if (n < 0) { __gllc_InvalidValue(); return; } else if (n == 0) { return; }
// It is extremely difficult to make CallList(s) work with poly array
// compilation. For example, in the call sequence in COMPILE_AND_EXECUTE
// mode [Begin, TexCoord, CallList, Vertex, ...], it is difficult to record
// the partial POLYDATA in both COMPILE and COMPILE_AND_EXECUTE modes.
// That is, we may end up recording and playing back TexCoord twice in the
// above example. As a result, we may have to stop building poly array in
// some cases. Fortunately, this situation is rare.
if (gc->dlist.beginRec) { gc->dlist.beginRec->flags |= DLIST_BEGIN_HAS_CALLLIST;
// Record the last POLYDATA since it may contain attribute changes.
__glDlistCompilePolyData(gc, GL_TRUE); }
arraySize = __glCallListsSize(type)*n; if (arraySize < 0) { __gllc_InvalidEnum(); return; } #ifdef NT
size = sizeof(struct __gllc_CallLists_Rec) + __GL_PAD(arraySize); #else
arraySize = __GL_PAD(arraySize); size = sizeof(struct __gllc_CallLists_Rec) + arraySize; #endif
data = (struct __gllc_CallLists_Rec *) __glDlistAddOpUnaligned(gc, DLIST_SIZE(size), DLIST_GENERIC_OP(CallLists)); if (data == NULL) return; data->n = n; data->type = type; __GL_MEMCOPY((GLubyte *)data + sizeof(struct __gllc_CallLists_Rec), lists, arraySize); __glDlistAppendOp(gc, data, __glle_CallLists);
if (gc->dlist.beginRec) { POLYARRAY *pa;
pa = gc->paTeb;
// In COMPILE_AND_EXECUTE mode, we can actually get out of the Begin mode.
// Although it is an application error, we need to terminate poly array
// compilation!
if (!(pa->flags & POLYARRAY_IN_BEGIN)) gc->dlist.beginRec = NULL; else { // If there is a partial vertex record after CallList(s), we will terminate
// the poly array compilation. Otherwise, it is safe to continue the
// processing.
if (pa->pdNextVertex->flags) { // Terminate poly array compilation
gc->dlist.beginRec = NULL;
if (gc->dlist.mode == GL_COMPILE) { glsbResetBuffers(TRUE);
// Clear begin flag too
pa->flags &= ~POLYARRAY_IN_BEGIN; }
} } } }
const GLubyte * FASTCALL __glle_CallLists(__GLcontext *gc, const GLubyte *PC) { GLuint size; GLuint arraySize; struct __gllc_CallLists_Rec *data;
data = (struct __gllc_CallLists_Rec *) PC; DoCallLists(data->n, data->type, (GLvoid *) (data+1)); arraySize = __GL_PAD(__glCallListsSize(data->type)*data->n); size = sizeof(struct __gllc_CallLists_Rec) + arraySize; return PC + size; }
void APIENTRY glcltCallLists ( IN GLsizei n, IN GLenum type, IN const GLvoid *lists ) { __GL_SETUP();
if (n < 0) { GLSETERROR(GL_INVALID_VALUE); return; } else if (n == 0) { return; }
if ((GLint) __glCallListsSize(type) < 0) { GLSETERROR(GL_INVALID_ENUM); return; }
gc->dlist.nesting = 0; DoCallLists(n, type, lists); }
/************************************************************************/
// Expand a dlist
__GLdlist *__glDlistGrow(GLuint size) { __GLdlist *dlist, *newDlist; GLubyte * UNALIGNED64 *op; __GL_SETUP(); newDlist = __glAllocDlist(gc, size); if (newDlist == NULL) { GLSETERROR(GL_OUT_OF_MEMORY); return NULL; }
// Add on record to link old block to new block
dlist = gc->dlist.listData;
op = (GLubyte **)(dlist->head+dlist->used); *(__GLlistExecFunc * UNALIGNED64 *)op = __glle_NextBlock; *(op+1) = newDlist->head;
// Shrink old block down to remove any wasted space at the end of it
dlist = __glShrinkDlist(gc, dlist); // Link new block into chain
newDlist->nextBlock = dlist; gc->dlist.listData = newDlist;
return newDlist; }
// Shrink a dlist block down to the minimum size
// Guaranteed not to fail since we can always just use the overly
// large block if the realloc fails
// NOTE: This function should only be used during build time
// where the nextBlock links are in the opposite direction of
// the __glle_NextBlock link record links
__GLdlist *__glShrinkDlist(__GLcontext *gc, __GLdlist *dlist) { __GLdlist *newDlist, *prevDlist; // If the amount of unused space is small, don't bother shrinking the block.
if (dlist->size - dlist->used < 4096) return dlist;
// If it is in COMPILE_AND_EXECUTE mode, flush the command buffer before
// reallocating listData. Shrinking listData may invalidate the memory
// pointers placed in the command buffer by the the display list execution
// code. When we are in the middle of building POLYARRAY, glsbAttention
// will not flush commands batched before the Begin call. As a result,
// we also need to flush the command buffer before compiling the Begin call.
if (gc->dlist.mode == GL_COMPILE_AND_EXECUTE) glsbAttention();
#ifdef DL_HEAP_VERBOSE
cbDlistTotal -= GL_MSIZE(dlist); #endif
newDlist = (__GLdlist *)GCREALLOC(gc, dlist, dlist->used+DL_OVERHEAD);
// If the realloc fails, just use the original list
if (newDlist != NULL) { // If the realloc moved the block, fix up the link from the
// previous block. This should be relatively rare
if (newDlist != dlist && newDlist->nextBlock != NULL) { prevDlist = newDlist->nextBlock;
ASSERTOPENGL(*(__GLlistExecFunc * UNALIGNED64 *) (prevDlist->head+prevDlist->used) == __glle_NextBlock, "Link not found where expected\n"); *(GLubyte * UNALIGNED64 *)(prevDlist->head+prevDlist->used+ sizeof(__GLlistExecFunc *)) = newDlist->head; }
// If we are compiling the poly array record, we need to fix up
// the Begin pointer! Note that if beginRec is not in the moved
// block, the pointer does not change!
if (newDlist != dlist && gc->dlist.beginRec && (GLubyte *) gc->dlist.beginRec >= dlist->head && (GLubyte *) gc->dlist.beginRec <= dlist->head + dlist->used) { gc->dlist.beginRec += newDlist->head - dlist->head; } dlist = newDlist; dlist->size = dlist->used; }
#ifdef DL_HEAP_VERBOSE
cbDlistTotal += GL_MSIZE(dlist); #endif
return dlist; }
__GLdlist *__glAllocDlist(__GLcontext *gc, GLuint size) { __GLdlist *dlist; __GLdlist temp; GLuint memsize;
// Add on overhead and round size to an even block
memsize = (size+DL_OVERHEAD+DL_BLOCK_SIZE-1) & ~(DL_BLOCK_SIZE-1); // Check overflow
if (memsize < size) return NULL; size = memsize-DL_OVERHEAD;
dlist = (__GLdlist *)GCALLOC(gc, memsize); if (dlist == NULL) return NULL; #if 0 // NT_SERVER_SHARE_LISTS
dlist->refcount = 1; #else
// refcount is set to 1 in __glNamesNewData.
dlist->refcount = 0; #endif
dlist->size = size; dlist->used = 0; dlist->nextBlock = NULL; #ifdef DL_HEAP_VERBOSE
cbDlistTotal += GL_MSIZE(dlist); #endif
return dlist; }
void FASTCALL __glFreeDlist(__GLcontext *gc, __GLdlist *dlist) { __GLdlist *dlistNext; #ifdef NT_SERVER_SHARE_LISTS
if (dlist->refcount != 0) { WARNING2("dlist %p refcount on free is %d\n", dlist, dlist->refcount); } #endif
while (dlist != NULL) { dlistNext = dlist->nextBlock;
#ifdef DL_HEAP_VERBOSE
cbDlistTotal -= GL_MSIZE(dlist); #endif
GCFREE(gc, dlist); dlist = dlistNext; }
#ifdef DL_HEAP_VERBOSE
DbgPrint("Dlists using %8d, total %8d\n", cbDlistTotal, glSize); #endif
}
|