546 lines
12 KiB
C
546 lines
12 KiB
C
/*
|
|
** 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
|
|
|
|
#if DBG
|
|
|
|
// Set glRandomMallocFail to a positive value, say 40, to enable random
|
|
// allocation failures. The failure will occur every glRandomMallocFail
|
|
// times.
|
|
long glRandomMallocFail = 0;
|
|
static long glRandomFailCount;
|
|
|
|
// glSize is the size of memory in use.
|
|
ULONG glSize = 0;
|
|
ULONG glHighWater = 0;
|
|
ULONG glReal = 0;
|
|
|
|
static void AdjustSizes(LONG delta, void *mem)
|
|
{
|
|
ULONG nbytes;
|
|
|
|
#ifdef GL_REAL_SIZE
|
|
nbytes = HeapSize(GetProcessHeap(), 0, mem);
|
|
#else
|
|
nbytes = 0;
|
|
#endif
|
|
|
|
if (delta < 0)
|
|
{
|
|
glSize -= (ULONG)(-delta);
|
|
glReal -= nbytes;
|
|
|
|
if ((int) glSize < 0)
|
|
{
|
|
DBGPRINT("glSize underflows\n");
|
|
}
|
|
}
|
|
else if (delta > 0)
|
|
{
|
|
glSize += delta;
|
|
glReal += nbytes;
|
|
|
|
if ((int) glSize < 0)
|
|
{
|
|
DBGPRINT("glSize overflows\n");
|
|
}
|
|
|
|
if (glSize > glHighWater)
|
|
{
|
|
#ifdef GL_SHOW_HIGH_WATER
|
|
DbgPrint("glSize high %8d (%8d)\n", glSize, glReal);
|
|
#endif
|
|
glHighWater = glSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef struct _MEM_HDR
|
|
{
|
|
ULONG nbytes;
|
|
ULONG signature[3];
|
|
} MEM_HDR;
|
|
|
|
// 'GLal' in byte order
|
|
#define MEM_ALLOC_SIG 0x6C614C47
|
|
// 'GLfr' in byte order
|
|
#define MEM_FREE_SIG 0x72664C47
|
|
|
|
#define MEM_HDR_SIZE sizeof(MEM_HDR)
|
|
#define MEM_HDR_PTR(mem) ((MEM_HDR *)((BYTE *)(mem)-MEM_HDR_SIZE))
|
|
|
|
// XXX We may want to protect these debug allocation functions with a
|
|
// critical section.
|
|
void * FASTCALL
|
|
dbgAlloc(UINT nbytes, DWORD flags)
|
|
{
|
|
PVOID mem;
|
|
|
|
// If random failure is enabled, fail this call randomly.
|
|
|
|
if (glRandomMallocFail)
|
|
{
|
|
if (++glRandomFailCount >= glRandomMallocFail)
|
|
{
|
|
DBGPRINT("dbgAlloc random failing\n");
|
|
glRandomFailCount = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (nbytes == 0)
|
|
{
|
|
DBGERROR("nbytes == 0\n");
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate extra bytes for debug house keeping.
|
|
|
|
mem = HeapAlloc(GetProcessHeap(), flags, nbytes+MEM_HDR_SIZE);
|
|
|
|
// Do house keeping and add allocation size so far.
|
|
|
|
if (mem)
|
|
{
|
|
MEM_HDR *pmh = (MEM_HDR *)mem;
|
|
|
|
pmh->nbytes = nbytes;
|
|
pmh->signature[0] = MEM_ALLOC_SIG;
|
|
pmh->signature[1] = MEM_ALLOC_SIG;
|
|
pmh->signature[2] = MEM_ALLOC_SIG;
|
|
AdjustSizes((LONG)nbytes, mem);
|
|
mem = (PVOID) (pmh+1);
|
|
}
|
|
else
|
|
{
|
|
DBGLEVEL1(LEVEL_ERROR, "dbgAlloc could not allocate %u bytes\n",
|
|
nbytes);
|
|
}
|
|
|
|
DBGLEVEL2(LEVEL_ALLOC, "dbgAlloc of %u returned 0x%x\n", nbytes, mem);
|
|
|
|
return mem;
|
|
}
|
|
|
|
void FASTCALL
|
|
dbgFree(void *mem)
|
|
{
|
|
MEM_HDR *pmh;
|
|
|
|
if (!mem)
|
|
{
|
|
#ifdef FREE_OF_NULL_ERR
|
|
// Freeing NULL happens currently so this error results
|
|
// in a little too much spew.
|
|
DBGERROR("mem is NULL\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// Verify that the signature is not corrupted.
|
|
|
|
pmh = MEM_HDR_PTR(mem);
|
|
if (pmh->signature[0] != MEM_ALLOC_SIG ||
|
|
pmh->signature[1] != MEM_ALLOC_SIG ||
|
|
pmh->signature[2] != MEM_ALLOC_SIG)
|
|
{
|
|
WARNING("Possible memory corruption\n");
|
|
}
|
|
|
|
// Make sure it is freed once only.
|
|
|
|
pmh->signature[0] = MEM_FREE_SIG;
|
|
pmh->signature[1] = MEM_FREE_SIG;
|
|
pmh->signature[2] = MEM_FREE_SIG;
|
|
|
|
// Subtract the allocation size.
|
|
|
|
AdjustSizes(-(LONG)pmh->nbytes, pmh);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pmh);
|
|
|
|
DBGLEVEL1(LEVEL_ALLOC, "dbgFree of 0x%x\n", mem);
|
|
}
|
|
|
|
void * FASTCALL
|
|
dbgRealloc(void *mem, UINT nbytes)
|
|
{
|
|
PVOID memNew;
|
|
MEM_HDR *pmh;
|
|
|
|
// If random failure is enabled, fail this call randomly.
|
|
|
|
if (glRandomMallocFail)
|
|
{
|
|
if (++glRandomFailCount >= glRandomMallocFail)
|
|
{
|
|
DBGPRINT("dbgRealloc random failing\n");
|
|
glRandomFailCount = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (mem != NULL)
|
|
{
|
|
// Verify that the signature is not corrupted.
|
|
|
|
pmh = MEM_HDR_PTR(mem);
|
|
if (pmh->signature[0] != MEM_ALLOC_SIG ||
|
|
pmh->signature[1] != MEM_ALLOC_SIG ||
|
|
pmh->signature[2] != MEM_ALLOC_SIG)
|
|
{
|
|
WARNING("Possible memory corruption\n");
|
|
}
|
|
|
|
AdjustSizes(-(LONG)pmh->nbytes, pmh);
|
|
|
|
// Reallocate nbytes+extra bytes.
|
|
memNew = HeapReAlloc(GetProcessHeap(), 0, pmh, nbytes+MEM_HDR_SIZE);
|
|
}
|
|
else
|
|
{
|
|
// Old memory pointer is NULL, so allocate a new chunk.
|
|
memNew = HeapAlloc(GetProcessHeap(), 0, nbytes+MEM_HDR_SIZE);
|
|
|
|
// We've allocated new memory so initialize its signature.
|
|
if (memNew != NULL)
|
|
{
|
|
pmh = (MEM_HDR *)memNew;
|
|
pmh->signature[0] = MEM_ALLOC_SIG;
|
|
pmh->signature[1] = MEM_ALLOC_SIG;
|
|
pmh->signature[2] = MEM_ALLOC_SIG;
|
|
}
|
|
}
|
|
|
|
if (memNew != NULL)
|
|
{
|
|
// Do house keeping and update allocation size so far.
|
|
|
|
AdjustSizes(nbytes, memNew);
|
|
pmh = (MEM_HDR *)memNew;
|
|
pmh->nbytes = nbytes;
|
|
memNew = (PVOID) (pmh+1);
|
|
}
|
|
else
|
|
{
|
|
if (mem != NULL)
|
|
{
|
|
AdjustSizes((LONG)pmh->nbytes, pmh);
|
|
}
|
|
|
|
DBGLEVEL1(LEVEL_ERROR, "dbgRealloc could not allocate %u bytes\n",
|
|
nbytes);
|
|
}
|
|
|
|
DBGLEVEL3(LEVEL_ALLOC, "dbgRealloc of 0x%X:%u returned 0x%x\n",
|
|
mem, nbytes, memNew);
|
|
|
|
return memNew;
|
|
}
|
|
|
|
int FASTCALL
|
|
dbgMemSize(void *mem)
|
|
{
|
|
MEM_HDR *pmh;
|
|
|
|
pmh = MEM_HDR_PTR(mem);
|
|
|
|
if (pmh->signature[0] != MEM_ALLOC_SIG ||
|
|
pmh->signature[1] != MEM_ALLOC_SIG ||
|
|
pmh->signature[2] != MEM_ALLOC_SIG)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return (int)pmh->nbytes;
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ULONG APIENTRY glDebugEntry(int param, void *data)
|
|
{
|
|
#if DBG
|
|
switch(param)
|
|
{
|
|
case 0:
|
|
return glSize;
|
|
case 1:
|
|
return glHighWater;
|
|
case 2:
|
|
return glReal;
|
|
case 3:
|
|
return dbgMemSize(data);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#define MEM_ALIGN 32
|
|
|
|
void * FASTCALL
|
|
AllocAlign32(UINT nbytes)
|
|
{
|
|
void *mem;
|
|
void **aligned;
|
|
|
|
// We allocate enough extra memory for the alignment and our header
|
|
// which just consists of a pointer:
|
|
|
|
mem = ALLOC(nbytes + MEM_ALIGN + sizeof(void *));
|
|
if (!mem)
|
|
{
|
|
DBGLEVEL1(LEVEL_ERROR, "AllocAlign32 could not allocate %u bytes\n",
|
|
nbytes);
|
|
return NULL;
|
|
}
|
|
|
|
aligned = (void **)(((ULONG_PTR)mem + sizeof(void *) +
|
|
(MEM_ALIGN - 1)) & ~(MEM_ALIGN - 1));
|
|
*(aligned-1) = mem;
|
|
|
|
return aligned;
|
|
}
|
|
|
|
void FASTCALL
|
|
FreeAlign32(void *mem)
|
|
{
|
|
if ( NULL == mem )
|
|
{
|
|
DBGERROR("NULL pointer passed to FreeAlign32\n");
|
|
return;
|
|
}
|
|
|
|
FREE(*((void **)mem-1));
|
|
}
|
|
|
|
void * FASTCALL
|
|
gcAlloc( __GLcontext *gc, UINT nbytes, DWORD flags )
|
|
{
|
|
void *mem;
|
|
|
|
#if DBG
|
|
mem = dbgAlloc(nbytes, flags);
|
|
#else
|
|
mem = HeapAlloc(GetProcessHeap(), flags, nbytes);
|
|
#endif
|
|
if (NULL == mem)
|
|
{
|
|
((__GLGENcontext *)gc)->errorcode = GLGEN_OUT_OF_MEMORY;
|
|
__glSetErrorEarly(gc, GL_OUT_OF_MEMORY);
|
|
}
|
|
return mem;
|
|
}
|
|
|
|
void * FASTCALL
|
|
GCREALLOC( __GLcontext *gc, void *mem, UINT nbytes )
|
|
{
|
|
void *newMem;
|
|
|
|
// The Win32 realloc functions do not have free-on-zero behavior,
|
|
// so fake it.
|
|
if (nbytes == 0)
|
|
{
|
|
if (mem != NULL)
|
|
{
|
|
FREE(mem);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// The Win32 realloc functions don't handle a NULL old pointer,
|
|
// so explicitly turn such calls into allocs.
|
|
if (mem == NULL)
|
|
{
|
|
newMem = ALLOC(nbytes);
|
|
}
|
|
else
|
|
{
|
|
newMem = REALLOC(mem, nbytes);
|
|
}
|
|
|
|
if (NULL == newMem)
|
|
{
|
|
((__GLGENcontext *)gc)->errorcode = GLGEN_OUT_OF_MEMORY;
|
|
__glSetErrorEarly(gc, GL_OUT_OF_MEMORY);
|
|
}
|
|
|
|
return newMem;
|
|
}
|
|
|
|
void * FASTCALL
|
|
GCALLOCALIGN32( __GLcontext *gc, UINT nbytes )
|
|
{
|
|
void *mem;
|
|
|
|
mem = AllocAlign32(nbytes);
|
|
if (NULL == mem)
|
|
{
|
|
((__GLGENcontext *)gc)->errorcode = GLGEN_OUT_OF_MEMORY;
|
|
__glSetErrorEarly(gc, GL_OUT_OF_MEMORY);
|
|
}
|
|
return mem;
|
|
}
|
|
|
|
// Tunable parameters for temporary memory allocation
|
|
|
|
#define MAX_TEMP_BUFFERS 4
|
|
#define TEMP_BUFFER_SIZE 4096
|
|
|
|
struct MemHeaderRec
|
|
{
|
|
LONG inUse;
|
|
ULONG nbytes;
|
|
void *mem;
|
|
};
|
|
|
|
typedef struct MemHeaderRec MemHeader;
|
|
|
|
MemHeader TempMemHeader[MAX_TEMP_BUFFERS];
|
|
|
|
// InitTempAlloc
|
|
// Initializes the temporary memory allocation header and allocates the
|
|
// temporary memory buffers.
|
|
//
|
|
// Synopsis:
|
|
// BOOL InitTempAlloc()
|
|
//
|
|
// History:
|
|
// 02-DEC-93 Eddie Robinson [v-eddier] Wrote it.
|
|
//
|
|
BOOL FASTCALL
|
|
InitTempAlloc(void)
|
|
{
|
|
int i;
|
|
PBYTE buffers;
|
|
static LONG initCount = -1;
|
|
|
|
if (initCount >= 0)
|
|
return TRUE;
|
|
|
|
if (InterlockedIncrement(&initCount) != 0)
|
|
return TRUE;
|
|
|
|
// Allocate buffers for the first time.
|
|
|
|
buffers = ALLOC(MAX_TEMP_BUFFERS*TEMP_BUFFER_SIZE);
|
|
if (!buffers)
|
|
{
|
|
InterlockedDecrement(&initCount); // try again later
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < MAX_TEMP_BUFFERS; i++)
|
|
{
|
|
TempMemHeader[i].nbytes = TEMP_BUFFER_SIZE;
|
|
TempMemHeader[i].mem = (void *) buffers;
|
|
TempMemHeader[i].inUse = -1; // must be last
|
|
buffers += TEMP_BUFFER_SIZE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// gcTempAlloc
|
|
// Allocates temporary memory from a static array, if possible. Otherwise
|
|
// it calls ALLOC
|
|
//
|
|
// Synopsis:
|
|
// void * gcTempAlloc(__GLcontext *gc, UINT nbytes)
|
|
// gc points to the OpenGL context structure
|
|
// nbytes specifies the number of bytes to allocate
|
|
//
|
|
// History:
|
|
// 02-DEC-93 Eddie Robinson [v-eddier] Wrote it.
|
|
//
|
|
void * FASTCALL
|
|
gcTempAlloc(__GLcontext *gc, UINT nbytes)
|
|
{
|
|
int i;
|
|
void *mem;
|
|
|
|
if (nbytes == 0)
|
|
{
|
|
// Zero-byte allocations do occur so don't make this a warning
|
|
// to avoid excessive debug spew.
|
|
DBGLEVEL(LEVEL_ALLOC, "gcTempAlloc: failing zero byte alloc\n");
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < MAX_TEMP_BUFFERS; i++)
|
|
{
|
|
if (nbytes <= TempMemHeader[i].nbytes)
|
|
{
|
|
if (InterlockedIncrement(&TempMemHeader[i].inUse))
|
|
{
|
|
InterlockedDecrement(&TempMemHeader[i].inUse);
|
|
}
|
|
else
|
|
{
|
|
DBGLEVEL2(LEVEL_ALLOC, "gcTempAlloc of %u returned 0x%x\n",
|
|
nbytes, TempMemHeader[i].mem);
|
|
GC_TEMP_BUFFER_ALLOC(gc, TempMemHeader[i].mem);
|
|
return(TempMemHeader[i].mem);
|
|
}
|
|
}
|
|
}
|
|
|
|
mem = ALLOC(nbytes);
|
|
if (!mem)
|
|
{
|
|
WARNING1("gcTempAlloc: memory allocation error size %d\n", nbytes);
|
|
((__GLGENcontext *)gc)->errorcode = GLGEN_OUT_OF_MEMORY;
|
|
__glSetErrorEarly(gc, GL_OUT_OF_MEMORY);
|
|
}
|
|
|
|
DBGLEVEL2(LEVEL_ALLOC, "gcTempAlloc of %u returned 0x%x\n", nbytes, mem);
|
|
GC_TEMP_BUFFER_ALLOC(gc, mem);
|
|
|
|
return mem;
|
|
}
|
|
|
|
// gcTempFree
|
|
// Marks allocated static buffer as unused or calls FREE.
|
|
//
|
|
// Synopsis:
|
|
// void gcTempFree(__GLcontext *gc, void *mem)
|
|
// mem specifies the adress of the memory to free
|
|
//
|
|
// History:
|
|
// 02-DEC-93 Eddie Robinson [v-eddier] Wrote it.
|
|
//
|
|
void FASTCALL
|
|
gcTempFree(__GLcontext *gc, void *mem)
|
|
{
|
|
int i;
|
|
|
|
DBGLEVEL1(LEVEL_ALLOC, "gcTempFree of 0x%x\n", mem);
|
|
|
|
GC_TEMP_BUFFER_FREE(gc, mem);
|
|
for (i = 0; i < MAX_TEMP_BUFFERS; i++)
|
|
{
|
|
if (mem == TempMemHeader[i].mem)
|
|
{
|
|
InterlockedDecrement(&TempMemHeader[i].inUse);
|
|
return;
|
|
}
|
|
}
|
|
|
|
FREE( mem );
|
|
}
|