dlm.c revision 072f0b86f23a38efb7454da3144cbce76805be76
/* $Id$ */
#include <float.h>
#include "cr_dlm.h"
#include "cr_mem.h"
#include "dlm.h"
/**
* \mainpage Dlm
*
* \section DlmIntroduction Introduction
*
* Chromium consists of all the top-level files in the cr
* directory. The dlm module basically takes care of API dispatch,
* and OpenGL state management.
*
*/
/**
* Module globals: the current DLM state, bound either to each thread, or
* to a global.
*/
#ifdef CHROMIUM_THREADSAFE
#else
#endif
#define MIN(a,b) ((a)<(b)?(a):(b))
/*************************************************************************/
#ifdef CHROMIUM_THREADSAFE
/**
* This is the thread-specific destructor function for the
* data used in the DLM. It's very simple: if a thread exits
* that has DLM-specific data, the data represents the listState
* for the thread. All data and buffers associated with the list
* can be deleted, and the structure itself can be freed.
*
* Most Chromium threads don't have such things; but then,
* if a thread dies elsewhere in Chromium, huge buffers
* of information won't still be floating around in
* unrecoverable allocated areas, either.
*/
static void threadDestructor(void *tsd)
{
if (listState) {
if (listState->currentListInfo) {
}
}
}
#endif
/**
* This function creates and initializes a new display list
* manager. It returns a pointer to the manager, or NULL in
* the case of insufficient memory. The dispatch table pointer
* is passed in to allow the utilities to muck with the table
* to gain functional control when GL calls are made.
*/
{
/* This is the default configuration. We'll overwrite it later
* with user-supplied configuration information.
*/
CRDLMConfig config = {
};
if (!dlm) {
return NULL;
}
/* Start off by initializing all entries that require further
* memory allocation, so we can free up all the memory if there's
* a problem.
*/
return NULL;
}
/* The creator counts as the first user. */
#ifdef CHROMIUM_THREADSAFE
/* This mutex ensures that only one thread is changing the displayLists
* hash at a time. Note that we may also need a mutex to guarantee that
* the hash is not changed by one thread while another thread is
* traversing it; this issue has not yet been resolved.
*/
/* Although the thread-specific data (TSD) functions will initialize
* the thread key themselves when needed, those functions do not allow
* us to specify a thread destructor. Since a thread could potentially
* exit with considerable memory allocated (e.g. if a thread exits
* after it has issued NewList but before EndList, and while there
* are considerable content buffers allocated), I do the initialization
* myself, in order to be able to reclaim those resources if a thread
* exits.
*/
#endif
/* Copy over any appropriate configuration values */
if (userConfig != NULL) {
/* Copy over as much configuration information as is provided.
* Note that if the CRDLMConfig structure strictly grows, this
* allows forward compatability - routines compiled with
* older versions of the structure will only initialize that
* section of the structure that they know about.
*/
}
/* Return the pointer to the newly-allocated display list manager */
return dlm;
}
{
}
/**
* This routine is called when a context or thread is done with a DLM.
* It maintains an internal count of users, and will only actually destroy
* itself when no one is still using the DLM.
*/
{
/* We're about to change the displayLists hash; lock it first */
/* Decrement the user count. If the user count has gone to
* 0, then free the rest of the DLM. Otherwise, other
* contexts or threads are still using this DLM; keep
* it around.
*/
/* Free the set of display lists. As each one is freed, the
* crdlm_free_list function will be called to free up its
* internal resources. The crdlm_free_list() routine is
* cast to a (void *) to avoid warnings about being an
*/
/* Must unlock before freeing the mutex */
#ifdef CHROMIUM_THREADSAFE
/* We release the mutex here; we really should delete the
* thread data key, but there's no utility in Chromium to
* do this.
*
* Note that, should one thread release the entire DLM
* while other threads still believe they are using it,
* any other threads that have current display lists (i.e.
* have issued glNewList more recently than glEndList)
* will be unable to reclaim their (likely very large)
* content buffers, as there will be no way to reclaim
* the thread-specific data.
*
* On the other hand, if one thread really does release
* the DLM while other threads still believe they are
* using it, unreclaimed memory is the least of the
* application's problems...
*/
/* We free the TSD key here as well. Note that this will
* strand any threads that still have thread-specific data
* tied to this key; but as stated above, if any threads
* still do have thread-specific data attached to this DLM,
* they're in big trouble anyway.
*/
//crFreeTSD(&CRDLMTSDKey);
#endif
/* Free the master record, and we're all done. */
}
else {
/* We're keeping the DLM around for other users. Unlock it,
* but retain its memory and display lists.
*/
}
}
/**
* The actual run-time state of a DLM is bound to a context
* (because each context can be used by at most one thread at
* a time, and a thread can only use one context at a time,
* while multiple contexts can use the same DLM).
* This creates the structure required to hold the state, and
* returns it to the caller, who should store it with any other
* context-specific information.
*/
{
/* Get a record for our own internal state structure */
if (!state) {
return NULL;
}
state->currentListIdentifier = 0;
/* Increment the use count of the DLM provided. This guarantees that
* the DLM won't be released until all the contexts have released it.
*/
return state;
}
/**
* This routine should be called when a MakeCurrent changes the current
* context. It sets the thread data (or global data, in an unthreaded
* environment) appropriately; this in turn changes the behavior of
* the installed DLM API functions.
*/
{
if (currentState != state) {
}
}
{
return CURRENT_STATE();
}
/**
* This routine, of course, is used to release a DLM context when it
* is no longer going to be used.
*/
{
/* If we're currently using this context, release it first */
}
/* Try to free the DLM. This will either decrement the use count,
* or will actually free the DLM, if we were the last user.
*/
/* If any buffers still remain (e.g. because there was an open
* display list), remove those as well.
*/
if (state->currentListInfo) {
}
state->currentListIdentifier = 0;
/* Free the state record itself */
}
/**
* This function can be used if the caller wishes to free up the
* potentially considerable resources used to store the display list
* content, without losing the rest of the display list management.
* For one example, consider an SPU that conditionally sends its
* input stream to multiple servers. It could broadcast all display
* lists to all servers, or it could only send display lists to servers
* that need them. After all servers have the display list, the SPU
* may wish to release the resources used to manage the content.
*/
{
while (instance) {
}
}
return GL_NO_ERROR;
}
/* Return whether the current thread is involved in playback.
* This is useful for some routines to selectively choose their
* unpack state, for example (as replayed DLM functions must be
* unpacked with crStateNativePixelPacking instead of the
* normal unpack state, for example.
*/
{
if (listState) {
return listState->replayState;
}
else {
return CRDLM_IMMEDIATE;
}
}
/**
*
* dlm - the display list manager context
* listIdentifier - the display list ID (as specified by app) to playback
* dispatchTable - the GL dispatch table to jump through as we execute commands
*/
void DLM_APIENTRY crDLMReplayDLMList(CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
{
if (listInfo) {
while (instance) {
/* mutex, to make sure another thread doesn't change the list? */
/* For now, leave it alone. */
}
}
}
{
if (listState) {
}
}
/*
* dlm - the display list manager context
* listIdentifier - the display list ID (as specified by app) to playback
* dispatchTable - the GL dispatch table to jump through as we execute commands
*/
void DLM_APIENTRY crDLMReplayDLMListState(CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
{
if (listInfo) {
while (instance) {
/* mutex, to make sure another thread doesn't change the list? */
/* For now, leave it alone. */
}
}
}
void DLM_APIENTRY crDLMReplayListState(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
{
if (listState) {
}
}
/* This is a switch statement that lists every "type" value valid for a
* glCallLists() function call, with code for decoding the subsequent
* values correctly. It uses the current value of the EXPAND() macro,
* which must expand into an appropriate action to be taken.
* Its codification here allows for multiple uses.
*/
switch (type) {\
default:\
}
void DLM_APIENTRY crDLMReplayDLMLists(CRDLM *dlm, GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
{
unsigned long listId;
case TYPENAME: {\
while (n--) {\
}\
break;\
}
CALL_LISTS_SWITCH(type, break)
}
void DLM_APIENTRY crDLMReplayLists(GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
{
if (listState) {
}
}
void DLM_APIENTRY crDLMReplayDLMListsState(CRDLM *dlm, GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
{
unsigned long listId;
case TYPENAME: {\
while (n--) {\
}\
break;\
}
CALL_LISTS_SWITCH(type, break)
}
void DLM_APIENTRY crDLMReplayListsState(GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
{
if (listState) {
}
}
/* When we compiled the display list, we packed all pixel data
* tightly. When we execute the display list, we have to make
* sure that the client state reflects that the pixel data is
* tightly packed, or it will be interpreted incorrectly.
*/
{
}
void DLM_APIENTRY crDLMRestoreClientState(CRClientState *clientState, SPUDispatchTable *dispatchTable)
{
if (clientState) {
}
}
{
dispatchTable->EndList();
}
{
if (listState) {
}
}
struct sendListsCallbackParms {
};
{
}
{
struct sendListsCallbackParms parms;
/* This is how we pass our parameter information to the callback routine -
* through a pointer to this local structure.
*/
}
{
if (listState) {
}
}
/** Another clever callback arrangement to get the desired data. */
struct getRefsCallbackParms {
int remainingOffset;
int remainingCount;
unsigned int *buffer;
int totalCount;
};
{
struct getRefsCallbackParms *cbParms =
(struct getRefsCallbackParms *)dataPtr2;
/* Count the total number of references */
cbParms->totalCount++;
/* If we haven't yet reached the desired offset, decrement it */
if (cbParms->remainingOffset > 0) {
}
else if (cbParms->remainingCount > 0) {
/* Store data until we've stored all we can.
*/
}
}
{
if (listInfo) {
struct getRefsCallbackParms cbParms;
cbParms.totalCount = 0;
return cbParms.totalCount;
}
else {
/* No list exists; it therefore has no references */
return 0;
}
}
CRDLMError DLM_APIENTRY crDLMGetDLMBounds(CRDLM *dlm, unsigned long listIdentifier, CRDLMBounds *bounds)
{
if (listInfo) {
return GL_NO_ERROR;
}
else {
return GL_INVALID_OPERATION;
}
}
{
if (listState) {
}
else {
return CRDLM_ERROR_STATE;
}
}
/**
* Set the bounding box for a display list.
*/
{
if (!listInfo) {
/* allocate a list info now */
}
if (listInfo) {
}
}
{
if (listState) {
}
}
/**
* Return GL_TRUE if the given list has a valid bounding box
*/
{
if (listInfo)
else
return GL_FALSE;
}
{
if (listState) {
}
return 0;
}
/*
* Return id of list currently being compiled. Returns 0 of there's no
* current DLM state, or if no list is being compiled.
*/
{
}
/*
* Return mode of list currently being compiled. Should be
* GL_FALSE if no list is being compiled, or GL_COMPILE if a
* list is being compiled but not executed, or GL_COMPILE_AND_EXECUTE
* if a list is being compiled and executed.
*/
{
}
{
}
{
if (ErrorCallback)
}