diff options
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/expando')
8 files changed, 703 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expando.py b/src/VBox/HostServices/SharedOpenGL/expando/expando.py new file mode 100644 index 00000000..86c45950 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expando.py @@ -0,0 +1,91 @@ +# $Id: expando.py $ +# This script generates calls for display list compilation +# and state management. +import sys + +sys.path.append( "../../glapi_parser" ) +import apiutil + +apiutil.CopyrightC() + +print """ +/* DO NOT EDIT - THIS FILE AUTOMATICALLY GENERATED BY expando.py SCRIPT */ +#include <stdio.h> +#include "cr_error.h" +#include "cr_spu.h" +#include "cr_dlm.h" +#include "expandospu.h" +""" + +allFunctions = [] +generatedFunctions = [] + +for func_name in apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt"): + if apiutil.FindSpecial("expando", func_name): + allFunctions.append(func_name) + elif apiutil.CanCompile(func_name) or apiutil.SetsClientState(func_name): + generatedFunctions.append(func_name) + allFunctions.append(func_name) + +for func_name in generatedFunctions: + params = apiutil.Parameters(func_name) + return_type = apiutil.ReturnType(func_name) + basicCallString = apiutil.MakeCallString(params) + declarationString = apiutil.MakeDeclarationString(params) + dlmCallString = basicCallString + chromiumProps = apiutil.ChromiumProps(func_name) + + needClientState = 0 + if apiutil.UsesClientState(func_name): + dlmCallString = basicCallString + ", clientState" + needClientState = 1 + + needDL = 0 + if apiutil.CanCompile(func_name): + needDL = 1 + + print 'static %s EXPANDOSPU_APIENTRY expando%s(%s)' % ( return_type, func_name, declarationString) + print '{' + if needDL: + print '\tGLenum dlMode = crDLMGetCurrentMode();' + if needClientState: + print '\tCRContext *stateContext = crStateGetCurrent();' + print '\tCRClientState *clientState = NULL;' + print '\tif (stateContext != NULL) {' + print '\t\tclientState = &(stateContext->client);' + print '\t}' + + if needDL: + if "checklist" in chromiumProps: + print '\tif (dlMode != GL_FALSE && crDLMCheckList%s(%s)) {' % (func_name, basicCallString) + else: + print '\tif (dlMode != GL_FALSE) {' + print '\t\tcrDLMCompile%s(%s);' % (func_name, dlmCallString) + # If we're only compiling, return now. + print '\t\tif (dlMode == GL_COMPILE) return %s;' % '0' if return_type != "void" else "" + print '\t}' + + # If it gets this far, we're either just executing, or executing + # and compiling. Either way, pass the call to the super SPU, + # and to the state tracker (if appropriate; note that we only + # track client-side state, not all state). + if return_type != "void": + print '\t%s rc = expando_spu.super.%s(%s);' % (return_type, func_name, basicCallString) + else: + print '\texpando_spu.super.%s(%s);' % (func_name, basicCallString) + if apiutil.SetsClientState(func_name): + print '\tcrState%s(%s);' % (func_name, basicCallString) + + if return_type != "void": + print "\treturn rc;" + + print '}' + print '' + +# Generate the table of named functions. including all the static generated +# functions as well as the special functions. +print 'SPUNamedFunctionTable _cr_expando_table[] = {' +for func_name in allFunctions: + print '\t{ "%s", (SPUGenericFunction) expando%s },' % (func_name, func_name ) +print '\t{ NULL, NULL }' +print '};' diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expando_special b/src/VBox/HostServices/SharedOpenGL/expando/expando_special new file mode 100644 index 00000000..9a8cd569 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expando_special @@ -0,0 +1,18 @@ +CreateContext +DestroyContext +MakeCurrent +NewList +EndList +DeleteLists +GenLists +ListBase +IsList +CallList +CallLists + +# Calls to be ignored. +#VBoxConCreate +#VBoxCreateContext +#VBoxPackSetInjectThread +#VBoxPresentComposition +#VBoxWindowCreate diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu.c b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.c new file mode 100644 index 00000000..8db885a5 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.c @@ -0,0 +1,182 @@ +/* $Id: expandospu.c $ */ +/** @file + * Implementation of routines which Expando SPU explicitly overrides. + */ + +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + + +/* + * Copyright (C) 2015-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include <stdio.h> +#include "cr_spu.h" +#include "cr_dlm.h" +#include "cr_mem.h" +#include "expandospu.h" + +extern GLint EXPANDOSPU_APIENTRY +expandoCreateContext(const char *displayName, GLint visBits, GLint shareCtx) +{ + ExpandoContextState *contextState; + + /* Allocate our own per-context record */ + contextState = crCalloc(sizeof(ExpandoContextState)); + if (contextState) + { + GLint contextId; + + /* Get an official context ID from our super */ + contextId = expando_spu.super.CreateContext(displayName, visBits, shareCtx); + + /* Supplement that with our DLM. In a more correct situation, we should + * see if we've been called through glXCreateContext, which has a parameter + * for sharing DLMs. We don't currently get that information, so for now + * give each context its own DLM. + */ + contextState->dlm = crDLMNewDLM(0, NULL); + if (contextState->dlm) + { + contextState->dlmContext = crDLMNewContext(contextState->dlm); + if (contextState->dlmContext) + { + /* The DLM needs us to use the state tracker to track client + * state, so we can compile client-state-using functions correctly. + */ + contextState->State = crStateCreateContext(NULL, visBits, NULL); + + /* Associate the Expando context with the user context. */ + crHashtableAdd(expando_spu.contextTable, contextId, (void *)contextState); + + crDebug("Expando SPU: created context %d (contextState=%p, contextState->dlm=%p, " + "contextState->dlmContext=%p, contextState->State=%p).", + contextId, contextState, contextState->dlm, contextState->dlmContext, contextState->State); + + return contextId; + } + else + crError("Expando SPU: can't allocate new DLM context."); + + crDLMFreeDLM(contextState->dlm, &expando_spu.super); + } + else + crError("Expando SPU: can't allocate new DLM."); + + crFree(contextState); + } + else + crError("Expando SPU: couldn't allocate per-context state"); + + return 0; +} + +void expando_free_context_state(void *data) +{ + ExpandoContextState *contextState = (ExpandoContextState *)data; + + crDebug("Expando SPU: destroying context internals: " + "contextState=%p, contextState->dlm=%p, contextState->dlmContext=%p, contextState->State=%p", + contextState, contextState->dlm, contextState->dlmContext, contextState->State); + + crDLMFreeContext(contextState->dlmContext, &expando_spu.super); + crDLMFreeDLM(contextState->dlm, &expando_spu.super); + crStateDestroyContext(contextState->State); + crFree(contextState); +} + +void EXPANDOSPU_APIENTRY +expandoDestroyContext(GLint contextId) +{ + crDebug("Expando SPU: destroy context %d.", contextId); + + /* Destroy our context information */ + crHashtableDelete(expando_spu.contextTable, contextId, expando_free_context_state); + + /* Pass along the destruction to our super. */ + expando_spu.super.DestroyContext(contextId); +} + +void EXPANDOSPU_APIENTRY +expandoMakeCurrent(GLint crWindow, GLint nativeWindow, GLint contextId) +{ + ExpandoContextState *expandoContextState; + + expando_spu.super.MakeCurrent(crWindow, nativeWindow, contextId); + + expandoContextState = crHashtableSearch(expando_spu.contextTable, contextId); + if (expandoContextState) + { + crDebug("Expando SPU: switch to context %d.", contextId); + + crDLMSetCurrentState(expandoContextState->dlmContext); + crStateMakeCurrent(expandoContextState->State); + } + else + { + crDebug("Expando SPU: can't switch to context %d: not found.", contextId); + + crDLMSetCurrentState(NULL); + crStateMakeCurrent(NULL); + } +} + +extern void EXPANDOSPU_APIENTRY +expandoNewList(GLuint list, GLenum mode) +{ + crDLMNewList(list, mode, &expando_spu.super); +} + +extern void EXPANDOSPU_APIENTRY +expandoEndList(void) +{ + crDLMEndList(&expando_spu.super); +} + +extern void EXPANDOSPU_APIENTRY +expandoDeleteLists(GLuint first, GLsizei range) +{ + crDLMDeleteLists(first, range, &expando_spu.super); +} + +extern GLuint EXPANDOSPU_APIENTRY +expandoGenLists(GLsizei range) +{ + return crDLMGenLists(range, &expando_spu.super); +} + +void EXPANDOSPU_APIENTRY +expandoListBase(GLuint base) +{ + crDLMListBase(base, &expando_spu.super); +} + +extern GLboolean EXPANDOSPU_APIENTRY +expandoIsList(GLuint list) +{ + return crDLMIsList(list, &expando_spu.super); +} + +extern void EXPANDOSPU_APIENTRY +expandoCallList(GLuint list) +{ + crDLMCallList(list, &expando_spu.super); +} + +extern void EXPANDOSPU_APIENTRY +expandoCallLists(GLsizei n, GLenum type, const GLvoid *lists) +{ + crDLMCallLists(n, type, lists, &expando_spu.super); +} diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu.def b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.def new file mode 100644 index 00000000..9edc7163 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.def @@ -0,0 +1,6 @@ +; Copyright (c) 2001, Stanford University +; All rights reserved. +; +; See the file LICENSE.txt for information on redistributing this software. +EXPORTS +SPULoad diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu.h b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.h new file mode 100644 index 00000000..dad5e120 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.h @@ -0,0 +1,69 @@ +/* $Id: expandospu.h $ */ +/* Copyright (c) 2001, Stanford University + * All rights reserved. + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#ifndef EXPANDO_SPU_H +#define EXPANDO_SPU_H + +#ifdef WINDOWS +#define EXPANDOSPU_APIENTRY __stdcall +#else +#define EXPANDOSPU_APIENTRY +#endif + +#include "cr_glstate.h" +#include "cr_spu.h" +#include "cr_server.h" +#include "cr_dlm.h" + +typedef struct { + int id; + int has_child; + SPUDispatchTable self, child, super; + CRServer *server; + + /* Expando-specific variables */ + CRHashTable *contextTable; +} ExpandoSPU; + +typedef struct { + /* Local copy of state, needed by DLM to compile client-side stuff. + * We only collect client-side state; we ignore all server-side + * state (we just don't need it). + */ + CRContext *State; + + /* The DLM, and the per-context state for a DLM. Right now, every + * context will have its own DLM; it's possible in OpenGL to share + * DLMs, but the Chromium interface doesn't allow it yet. + */ + CRDLM *dlm; + CRDLMContextState *dlmContext; +} ExpandoContextState; + +extern ExpandoSPU expando_spu; + +extern SPUNamedFunctionTable _cr_expando_table[]; + +extern SPUOptions expandoSPUOptions[]; + +extern void expandospuGatherConfiguration( void ); + +extern void expando_free_context_state(void *data); + +extern GLint EXPANDOSPU_APIENTRY expandoCreateContext(const char *displayName, GLint visBits, GLint shareCtx); +extern void EXPANDOSPU_APIENTRY expandoDestroyContext(GLint contextId); +extern void EXPANDOSPU_APIENTRY expandoMakeCurrent(GLint crWindow, GLint nativeWindow, GLint contextId); +extern void EXPANDOSPU_APIENTRY expandoNewList(GLuint list, GLenum mode); +extern void EXPANDOSPU_APIENTRY expandoEndList(void); +extern void EXPANDOSPU_APIENTRY expandoDeleteLists(GLuint first, GLsizei range); +extern GLuint EXPANDOSPU_APIENTRY expandoGenLists(GLsizei range); +extern void EXPANDOSPU_APIENTRY expandoListBase(GLuint base); +extern GLboolean EXPANDOSPU_APIENTRY expandoIsList(GLuint list); +extern void EXPANDOSPU_APIENTRY expandoCallList(GLuint list); +extern void EXPANDOSPU_APIENTRY expandoCallLists(GLsizei n, GLenum type, const GLvoid *lists); + +#endif /* EXPANDO_SPU_H */ diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c new file mode 100644 index 00000000..9843f486 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c @@ -0,0 +1,48 @@ +/* $Id: expandospu_config.c $ */ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#include "expandospu.h" + +//#include "cr_mothership.h" +#include "cr_string.h" + +#include <stdio.h> + +static void __setDefaults( void ) +{ +} + +/* option, type, nr, default, min, max, title, callback + */ +SPUOptions expandoSPUOptions[] = { + { NULL, CR_BOOL, 0, NULL, NULL, NULL, NULL, NULL }, +}; + + +void expandospuGatherConfiguration( void ) +{ + CRConnection *conn; + + __setDefaults(); +#if 0 + /* Connect to the mothership and identify ourselves. */ + + conn = crMothershipConnect( ); + if (!conn) + { + /* The mothership isn't running. Some SPU's can recover gracefully, some + * should issue an error here. */ + crSPUSetDefaultParams( &expando_spu, expandoSPUOptions ); + return; + } + crMothershipIdentifySPU( conn, expando_spu.id ); + + crSPUGetMothershipParams( conn, &expando_spu, expandoSPUOptions ); + + crMothershipDisconnect( conn ); +#endif +} diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c new file mode 100644 index 00000000..f49dffbb --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c @@ -0,0 +1,289 @@ +/* $Id: expandospu_init.c $ */ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#include <stdio.h> +#include "cr_spu.h" +#include "cr_dlm.h" +#include "cr_hash.h" +#include "cr_mem.h" +#include "expandospu.h" + +/* This magic number is used for SSM data consistency check. */ +#define VBOX_EXPANDOSPU_SSM_MAGIC 0x3d3d3d3d +/* Modify VBox Expando SPU SSM version if SSM data structure changed. */ +#define VBOX_EXPANDOSPU_SSM_VERSION_ONE 1 +#define VBOX_EXPANDOSPU_SSM_VERSION VBOX_EXPANDOSPU_SSM_VERSION_ONE + +ExpandoSPU expando_spu; + +static SPUFunctions expando_functions = { + NULL, /* CHILD COPY */ + NULL, /* DATA */ + _cr_expando_table /* THE ACTUAL FUNCTIONS */ +}; + +/* + * Structure of SSM data: + * + * <VBOX_EXPANDOSPU_SSM_MAGIC> + * <VBOX_EXPANDOSPU_SSM_VERSION> + * <Number of Expando SPU contexts> + * + * <Context ID> + * <CRDLMContextState structure> + * <DLM module data> + * + * <Next context...> + * + * <VBOX_EXPANDOSPU_SSM_MAGIC> + */ + +static void +expandoSPUSaveContextCb(unsigned long id, void *pData1, void *pData2) +{ + uint32_t ui32 = (uint32_t)id; + PSSMHANDLE pSSM = (PSSMHANDLE)pData2; + int32_t rc; + + ExpandoContextState *pExpandoContextState = (ExpandoContextState *)pData1; + CRDLMContextState dlmContextState; + + /* Save context ID. */ + rc = SSMR3PutU32(pSSM, ui32); AssertRCReturnVoid(rc); + + /* Save DLM context state. Clean fields which will not be valid on restore (->dlm and ->currentListInfo). + * We interested only in fields: currentListIdentifier, currentListMode and listBase. */ + crMemcpy(&dlmContextState, pExpandoContextState->dlmContext, sizeof(CRDLMContextState)); + dlmContextState.dlm = NULL; + dlmContextState.currentListInfo = NULL; + rc = SSMR3PutMem(pSSM, &dlmContextState, sizeof(CRDLMContextState)); AssertRCReturnVoid(rc); + + /* Delegate the rest of work to DLM module. */ + crDLMSaveState(pExpandoContextState->dlmContext->dlm, pSSM); +} + +static int +expandoSPUSaveState(void *pData) +{ + uint32_t magic = VBOX_EXPANDOSPU_SSM_MAGIC; + uint32_t version = VBOX_EXPANDOSPU_SSM_VERSION; + PSSMHANDLE pSSM = (PSSMHANDLE)pData; + int32_t rc; + uint32_t cStates; + + crDebug("Saving state of Expando SPU."); + + AssertReturn(pSSM, 1); + + /* Magic & version first. */ + rc = SSMR3PutU32(pSSM, magic); AssertRCReturn(rc, rc); + rc = SSMR3PutU32(pSSM, version); AssertRCReturn(rc, rc); + + /* Store number of Expando SPU contexts. */ + cStates = (uint32_t)crHashtableNumElements(expando_spu.contextTable); + rc = SSMR3PutU32(pSSM, cStates); AssertRCReturn(rc, rc); + + /* Walk over context table and store required data. */ + crHashtableWalk(expando_spu.contextTable, expandoSPUSaveContextCb, pSSM); + + /* Expando SPU and DLM data should end with magic (consistency check). */ + rc = SSMR3PutU32(pSSM, magic); AssertRCReturn(rc, rc); + + return 0; +} + +static int +expandoSPULoadState(void *pData) +{ + uint32_t magic = 0; + uint32_t version = 0; + PSSMHANDLE pSSM = (PSSMHANDLE)pData; + int32_t rc; + + crDebug("Loading state of Expando SPU."); + + AssertReturn(pSSM, 1); + + /* Check magic and version. */ + rc = SSMR3GetU32(pSSM, &magic); + AssertRCReturn(rc, rc); + + if (magic == VBOX_EXPANDOSPU_SSM_MAGIC) + { + rc = SSMR3GetU32(pSSM, &version); + AssertRCReturn(rc, rc); + + if (version >= VBOX_EXPANDOSPU_SSM_VERSION_ONE) + { + uint32_t cStates = 0; + uint32_t i; + bool fSuccess = false; + + CRDLMContextState *pCurrentDLMState; + CRContext *pCurrentCRState; + + /* Remember current state. */ + pCurrentDLMState = crDLMGetCurrentState(); + pCurrentCRState = crStateGetCurrent(); + + /* Restore number of Expando SPU contexts. */ + rc = SSMR3GetU32(pSSM, &cStates); + AssertRCReturn(rc, rc); + + /* Restore and update Expando SPU contexts one by one. */ + for (i = 0; i < cStates; i++) + { + uint32_t idContext = 0; + ExpandoContextState *pExpandoContextState; + + rc = SSMR3GetU32(pSSM, &idContext); + AssertRCReturn(rc, rc); + + /* Find context which was previously created by CR Server. */ + pExpandoContextState = crHashtableSearch(expando_spu.contextTable, idContext); + if (pExpandoContextState) + { + CRDLMContextState dlmContextState; + + /* Restore and update DLM context state. */ + rc = SSMR3GetMem(pSSM, &dlmContextState, sizeof(CRDLMContextState)); + if (RT_SUCCESS(rc)) + { + pExpandoContextState->dlmContext->currentListIdentifier = dlmContextState.currentListIdentifier; + pExpandoContextState->dlmContext->currentListMode = dlmContextState.currentListMode; + pExpandoContextState->dlmContext->listBase = dlmContextState.listBase; + + crDLMSetCurrentState(pExpandoContextState->dlmContext); + crStateMakeCurrent(pExpandoContextState->State); + + /* Delegate the rest of work to DLM module. */ + fSuccess = crDLMLoadState(pExpandoContextState->dlmContext->dlm, pSSM, &expando_spu.server->dispatch); + if (fSuccess) + { + continue; + } + else + { + crError("Expando SPU: stop restoring Display Lists."); + break; + } + } + else + { + crError("Expando SPU: unable to load state: state file structure error (1)."); + break; + } + } + else + { + crError("Expando SPU: unable to load state: no context ID %u found.", idContext); + break; + } + } + + /* Restore original state. */ + crDLMSetCurrentState(pCurrentDLMState); + crStateMakeCurrent(pCurrentCRState); + + if (fSuccess) + { + /* Expando SPU and DLM data should end with magic (consistency check). */ + magic = 0; + rc = SSMR3GetU32(pSSM, &magic); + if (RT_SUCCESS(rc)) + { + if (magic == VBOX_EXPANDOSPU_SSM_MAGIC) + { + crInfo("Expando SPU state loaded."); + return 0; + } + else + crError("Expando SPU: unable to load state: SSM data corrupted."); + } + else + crError("Expando SPU: unable to load state: state file structure error (2): no magic."); + } + else + crError("Expando SPU: unable to load state: some list(s) could not be restored."); + } + else + crError("Expando SPU: unable to load state: unexpected SSM version (0x%x).", version); + } + else + crError("Expando SPU: unable to load state: SSM data possibly corrupted."); + + return VERR_SSM_UNEXPECTED_DATA; +} + +static SPUFunctions * +expandoSPUInit(int id, SPU *child, SPU *self, unsigned int context_id, unsigned int num_contexts) +{ + + (void)self; + (void)context_id; + (void)num_contexts; + + expando_spu.id = id; + expando_spu.has_child = 0; + expando_spu.server = NULL; + + if (child) + { + crSPUInitDispatchTable(&(expando_spu.child)); + crSPUCopyDispatchTable(&(expando_spu.child), &(child->dispatch_table)); + expando_spu.has_child = 1; + } + + crSPUInitDispatchTable(&(expando_spu.super)); + crSPUCopyDispatchTable(&(expando_spu.super), &(self->superSPU->dispatch_table)); + expandospuGatherConfiguration(); + + /* Expando-specific initialization */ + expando_spu.contextTable = crAllocHashtable(); + + /* We'll be using the state tracker for each context */ + crStateInit(); + + /* Export optional interfaces for SPU save/restore. */ + self->dispatch_table.spu_save_state = expandoSPUSaveState; + self->dispatch_table.spu_load_state = expandoSPULoadState; + + return &expando_functions; +} + +static void +expandoSPUSelfDispatch(SPUDispatchTable *self) +{ + crSPUInitDispatchTable(&(expando_spu.self)); + crSPUCopyDispatchTable(&(expando_spu.self), self); + + expando_spu.server = (CRServer *)(self->server); +} + + +static int +expandoSPUCleanup(void) +{ + crFreeHashtable(expando_spu.contextTable, expando_free_context_state); + crStateDestroy(); + return 1; +} + +int +SPULoad(char **name, char **super, SPUInitFuncPtr *init, SPUSelfDispatchFuncPtr *self, + SPUCleanupFuncPtr *cleanup, SPUOptionsPtr *options, int *flags) +{ + *name = "expando"; + *super = "render"; + *init = expandoSPUInit; + *self = expandoSPUSelfDispatch; + *cleanup = expandoSPUCleanup; + *options = expandoSPUOptions; + *flags = (SPU_NO_PACKER|SPU_NOT_TERMINAL|SPU_MAX_SERVERS_ZERO); + + return 1; +} |