/* Copyright (c) 2006-2007, H. Andres Lagar-Cavilla, University of Toronto
	In the context of the vmgl project

	See the file LICENSE.txt for information on redistributing this software. */
	

#include <stdio.h>
#include "cr_server.h"
#include "cr_packfunctions.h"
#include "packspu.h"
#include "packspu_proto.h"

/* Andres: DLM code inserted for vmgl state resume. 
   GenLists not anymore generated by packspu_get.py */

GLuint PACKSPU_APIENTRY
packspu_GenLists( GLsizei range )
{
        GET_THREAD(thread);
        int writeback = 1;
        GLuint return_val = (GLuint) 0;
        if (!(pack_spu.thread[0].netServer.conn->actual_network))
        {
            crError( "packspu_GenLists doesn't work when there's no actual network involved!\nTry using the simplequery SPU in your chain!");
        }
	crDLMGenLists(range);
        if (pack_spu.swap)
        {
                crPackGenListsSWAP( range, &return_val, &writeback );
        }
        else
        {
                crPackGenLists( range, &return_val, &writeback );
        }
        packspuFlush( (void *) thread );
        while (writeback)
    		crNetRecv();
        if (pack_spu.swap)
        {
                return_val = (GLuint) SWAP32(return_val);
        }
        return return_val;
}


void PACKSPU_APIENTRY packspu_NewList(GLuint listIdentifier, GLenum mode)
{
	GET_THREAD(thread);

	if (listIdentifier == 0) {
	    crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, 
		"NewList with zero list identifier");
	    return;
	}
	if (mode != GL_COMPILE && mode != GL_COMPILE_AND_EXECUTE) {
	    crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, 
		"NewList with bad mode (0x%x)", mode);
	    return;
	}
	if (IN_DL(thread)) {
	    crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, 
		"NewList called while list %d was open",
		thread->currentContext->DL_ID);
	    return;
	}

	/* All okay.  Tell the state tracker and the DLM that we've
	 * started a new display list.
	 */
	crStateNewList(listIdentifier, mode);
	crDLMNewList(listIdentifier, mode);

	/* Remember ourselves, too, so we don't have to waste a function
	 * call to figure out whether we're in a list or not.
	 */
	thread->currentContext->DL_mode = mode;
	thread->currentContext->DL_ID = listIdentifier;

	if (pack_spu.swap)
	{
		crPackNewListSWAP(listIdentifier, mode);
	}
	else
	{
		crPackNewList(listIdentifier, mode);
	}
}

void PACKSPU_APIENTRY packspu_EndList(void)
{
	GET_THREAD(thread);
	
	if (!(IN_DL(thread))) {
	    crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, 
		"EndList called without a preceding NewList");
	    return;
	}

	/* All okay.  Tell the state tracker and the DLM that we've
	 * finished a new display list.
	 */
	crStateEndList();
	crDLMEndList();

	/* Remember ourselves, too, so we don't have to waste a function
	 * call to figure out whether we're in a list or not.
	 */
	thread->currentContext->DL_mode = GL_FALSE;
	thread->currentContext->DL_ID = 0;

	if (pack_spu.swap)
	{
		crPackEndListSWAP();
	}
	else
	{
		crPackEndList();
	}
}

void PACKSPU_APIENTRY packspu_DeleteLists(GLuint listIdentifier, GLsizei range)
{
	if (range < 0) {
	    crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, 
		"DeleteLists with negative range (%d)",
		range);
	    return;
	}

	crStateDeleteLists(listIdentifier, range);
	crDLMDeleteLists(listIdentifier, range);

	if (pack_spu.swap)
	{
		crPackDeleteListsSWAP(listIdentifier, range);
	}
	else
	{
		crPackDeleteLists(listIdentifier, range);
	}
}

/* When we call a remote list, we'll duplicate any state effects
 * caused by the list in the local state records.
 */
void PACKSPU_APIENTRY packspu_CallList( GLuint list )
{
	GET_THREAD(thread);

	/* Compile if we're supposed to do so. */
	if (IN_DL(thread))
		crDLMCompileCallList(list);
	if (pack_spu.swap)
	{
		crPackCallListSWAP(list);
	}
	else
	{
		crPackCallList(list);
	}

	/* If we've just packed a call that is going to immediately be
	 * executed (i.e. one that isn't just being compiled), make
	 * the appropriate state change on our end, so we're aware of it.
	 */
	if (NOT_COMPILE_DL(thread)) 
	    crDLMReplayListState(list, &pack_spu.state_DT);
}

void PACKSPU_APIENTRY packspu_CallLists( GLsizei n, GLenum type, const GLvoid * lists )
{
	GET_THREAD(thread);
	if (IN_DL(thread))
		crDLMCompileCallLists(n, type, lists);
	if (pack_spu.swap)
	{
		crPackCallListsSWAP(n, type, lists);
	}
	else
	{
		crPackCallLists(n, type, lists);
	}
	/* If we've just packed a call that is going to immediately be
	 * executed (i.e. one that isn't just being compiled), make
	 * the appropriate state change on our end, so we're aware of it.
	 */
	if (NOT_COMPILE_DL(thread))
	    crDLMReplayListsState(n, type, lists, &pack_spu.state_DT);
}

/* The DLM has to be told of the ListBase function, so it can correctly
 * manage CallLists invocations.
 */
void PACKSPU_APIENTRY packspu_ListBase( GLuint base )
{
	GET_THREAD(thread);
	if (IN_DL(thread)) 
		crDLMCompileListBase(base);
	if (pack_spu.swap)
	{
		crPackListBaseSWAP(base);
	}
	else
	{
		crPackListBase(base);
	}
	if (NOT_COMPILE_DL(thread)) {
		crStateListBase( base );
		crDLMListBase(base);
	}
}
