////////////////////////////////////////////////////////////////////// // // Pixie // // Copyright © 1999 - 2003, Okan Arikan // // Contact: okan@cs.berkeley.edu // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // // File : execute.cpp // Classes : - // Description : This file implements the main shader execution // //////////////////////////////////////////////////////////////////////// #include #include #include "common/global.h" #include "memory.h" #include "output.h" #include "renderer.h" #include "shader.h" #include "slcode.h" #include "shading.h" #include "noise.h" #include "stats.h" #include "photonMap.h" #include "irradiance.h" #include "bundles.h" #include "error.h" #include "executeMisc.h" // This function is defined in shader.cpp for debugging purposes void debugFunction(float *); // These functions are defined in init.cpp void convertColorFrom(float *,const float *,ECoordinateSystem); void convertColorTo(float *,const float *,ECoordinateSystem); #define saveLighting(__L) \ if (numActive != 0) { \ CShadedLight *cLight = NULL; \ int numGlobals = cInstance->parent->numGlobals; \ if (*freeLights != NULL) { \ cLight = *freeLights; \ *freeLights = (*freeLights)->next; \ float** savedState = (float**) ralloc((2+numGlobals)*sizeof(float*)); \ savedState[0] = cLight->savedState[0]; \ savedState[1] = cLight->savedState[1]; \ cLight->savedState = savedState; \ } else { \ cLight = (CShadedLight*) ralloc(sizeof(CShadedLight)); \ cLight->lightTags = (int*) ralloc(sizeof(int)*numVertices); \ cLight->savedState = (float**) ralloc((2+numGlobals)*sizeof(float*)); \ cLight->savedState[0] = (float*) ralloc(3*sizeof(float)*numVertices); \ cLight->savedState[1] = (float*) ralloc(3*sizeof(float)*numVertices); \ cLight->instance = cInstance; \ } \ cLight->next = *lights; \ *lights = cLight; \ memcpy(cLight->lightTags,tagStart,sizeof(int)*numVertices); \ memcpy(cLight->savedState[1],varying[VARIABLE_CL],3*sizeof(float)*numVertices); \ __L = cLight->savedState[0]; \ /*save extra variables if needed*/ \ if (numGlobals != 0) { \ CShader *cShader = cInstance->parent; \ int globNum = 0; \ for (int i=0;inumParameters;i++) { \ if (cShader->parameters[i].global != NULL) { \ CVariable *cVar = cShader->parameters[i].global; \ if ((cVar->container == CONTAINER_UNIFORM) || (cVar->container == CONTAINER_CONSTANT)) { \ cLight->savedState[2+globNum] = (float*) ralloc(sizeof(float)*cVar->numFloats); \ memcpy(cLight->savedState[2+globNum],varying[cVar->entry],sizeof(float)*cVar->numFloats); \ } else { \ cLight->savedState[2+globNum] = (float*) ralloc(sizeof(float)*cVar->numFloats*numVertices); \ memcpy(cLight->savedState[2+globNum],varying[cVar->entry],sizeof(float)*cVar->numFloats*numVertices); \ } \ globNum++; \ } \ } \ } \ } #define clearLighting() { \ currentShadingState->lightsExecuted = FALSE; \ *freeLights = *lights; \ *lights = NULL; \ } #define enterLightingConditional() { \ int tmpTag; \ int *lightTags = (*currentLight)->lightTags; \ tags = tagStart; \ for (i=numVertices;i>0;i--,tags++,lightTags++) { \ tmpTag = (*tags == 0); \ *tags += *lightTags; \ if (tmpTag && *tags) { \ numActive--; \ numPassive++; \ } \ } \ tags = tagStart; \ } #define exitLightingConditional() { \ int tmpTag; \ int *lightTags = (*currentLight)->lightTags; \ tags = tagStart; \ for (i=numVertices;i>0;i--,tags++,lightTags++) { \ tmpTag = *tags; \ *tags -= *lightTags; \ if (tmpTag && (*tags == 0)) { \ numActive++; \ numPassive--; \ } \ } \ tags = tagStart; \ } #define enterFastLightingConditional() { \ int *lightTags = (*currentLight)->lightTags; \ tags = tagStart; \ for (i=numVertices;i>0;i--) { \ (*tags++) += (*lightTags++); \ } \ tags = tagStart; \ } #define exitFastLightingConditional() { \ int *lightTags = (*currentLight)->lightTags; \ tags = tagStart; \ for (i=numVertices;i>0;i--) { \ (*tags++) -= (*lightTags++); \ } \ tags = tagStart; \ } /////////////////////////////////////////////////////////////////////// // Class : CShadingContext // Method : execute // Description : Execute a shader // Return Value : - // Comments : // Date last edited : 11/28/2001 void CShadingContext::execute(CProgrammableShaderInstance *cInstance) { // At this point, the shader sends us the arrays for parameters/constants/variables/uniforms for the shader // The maximum allowed string size that can be handled #define MAX_SCRIPT_STRING_SIZE 256 #define scripterror(mes) { \ error(CODE_SCRIPT,"\"%s\", (nullified)\n",mes); \ cInstance->parent->codeEntryPoint = -1; \ cInstance->parent->initEntryPoint = -1; \ goto execEnd; \ } // Allocate temporary memory for the string and save it #define savestring(r,n) { \ int strLen = strlen(n) + 1; \ int strSize = (strLen & ~3) + 4; \ char *strmem = (char *) ralloc(strSize); \ strcpy(strmem,n); \ r = strmem; \ } // Begin a conditional block execution #define beginConditional() if (conditionals == NULL) { \ conditionals = (CConditional *) frameMemory->alloc(sizeof(CConditional)); \ conditionals->next = NULL; \ conditionals->prev = NULL; \ } \ \ conditionals->prev = lastConditional; \ lastConditional = conditionals; \ conditionals = lastConditional->next; // End a conditional block execution #define endConditional() lastConditional->next = conditionals; \ conditionals = lastConditional; \ lastConditional = lastConditional->prev; // Retrieve a pointer to an operand and obtain it's size #define operand(i,n) { \ const TCode ref = code[IP+i+2]; \ n = stuff[ref.reference.accessor][ref.reference.index]; \ } // Retrieve an operand's size #define operandSize(i,n,s) { \ const TCode ref = code[IP+i+2]; \ n = stuff[ref.reference.accessor][ref.reference.index]; \ s = ref.reference.numItems; \ } // Retrieve the parameterlist #define parameterlist cInstance->parameterLists[code[IP+1].arguments.plNumber] #define dirty() if (cInstance->dirty == FALSE) { \ cInstance->dirty = TRUE; \ if (dirtyInstances == NULL) \ dirtyInstances = new CArray; \ cInstance->attach(); \ dirtyInstances->push(cInstance); \ } // Retrieve an integer operand (label references are integer) #define argument(i) code[IP+i+2].integer; // Retrieve an integer operand (label references are integer) #define argumentCode(i) code[IP+i+2] // Retrieve the number of arguments #define argumentcount(n) n = code[IP+1].arguments.numArguments; // Control transfer #define jmp(n) { \ IP = n; \ goto execStart; \ } #define hashLookupNegative(__dest) // Run the ambient light source shaders for the lP #define runAmbientLights() if (!currentShadingState->ambientLightsExecuted) { \ const CAttributes *currentAttributes = currentShadingState->currentObject->attributes; \ float *Clsave; \ int i; \ \ assert((numActive+numPassive) == numVertices); \ assert(numVertices == currentShadingState->numVertices); \ currentShadingState->numActive = numActive; \ currentShadingState->numPassive = numPassive; \ currentShadingState->ambientLightsExecuted = TRUE; \ \ if (*alights == NULL) { \ *alights = (CShadedLight*) ralloc(sizeof(CShadedLight)); \ (*alights)->savedState = (float**) ralloc(2*sizeof(CShadedLight)); \ (*alights)->savedState[1] = (float*) ralloc(3*sizeof(float)*numVertices); \ (*alights)->savedState[0] = NULL; /* ambient lights do not use tags or save L */ \ (*alights)->lightTags = NULL; \ (*alights)->instance = NULL; \ (*alights)->next = NULL; \ \ Clsave = (*alights)->savedState[1]; \ for (i=0;ilightSources;cLight!=NULL;cLight=cLight->next) { \ CProgrammableShaderInstance *light = cLight->light; \ if (!(light->flags & SHADERFLAGS_NONAMBIENT)) { \ currentShadingState->currentLightInstance = light; \ currentAttributes->initLightDefaults(numVertices,varying,cLight); \ light->illuminate(this); \ } \ } \ } \ assert(currentShadingState->numActive == numActive); \ assert(currentShadingState->numPassive == numPassive); \ \ currentShadingState->currentShaderInstance = cInstance; \ } // Run the light source shaders for the lP #define runLightsTemplate(lP,lN,lT,lightCategoryPre,lightCategoryCheck) \ int curLightingValid = currentShadingState->lightsExecuted; \ lightCategoryPre; \ if (curLightingValid) { \ const int *aTag = tagStart; \ const int *lTag = currentShadingState->lightingTags; \ int i; \ curLightingValid = curLightingValid && \ (currentShadingState->lightCategory == saveCat); \ /* memcmp is faster than a T32/xor/compare loop here */ \ /* note: we should really only need to compare active */ \ /* shading points, but it's faster to compare all */ \ curLightingValid = curLightingValid && \ !memcmp(lN,currentShadingState->Ns,sizeof(float)*3*numVertices) && \ !memcmp(lP,varying[VARIABLE_PS],sizeof(float)*3*numVertices) && \ !memcmp(lT,currentShadingState->costheta,sizeof(float)*numVertices); \ /* we must still compare active tags, note this isn't */ \ /* the same as tags being numerically equal */ \ for (i=numVertices; curLightingValid && (i>0); i--) { \ curLightingValid = curLightingValid && (!*aTag++ & !*lTag++); \ } \ } \ if (!curLightingValid) { \ const CAttributes *currentAttributes = currentShadingState->currentObject->attributes; \ assert((numActive+numPassive) == numVertices); \ assert(numVertices == currentShadingState->numVertices); \ currentShadingState->numActive = numActive; \ currentShadingState->numPassive = numPassive; \ currentShadingState->lightsExecuted = TRUE; \ currentShadingState->costheta = lT; \ currentShadingState->lightCategory = saveCat; \ /* memcpy is faster than a loop here */ \ memcpy(varying[VARIABLE_PS],lP,numVertices*3*sizeof(float)); \ memcpy(currentShadingState->Ns,lN,numVertices*3*sizeof(float)); \ memcpy(currentShadingState->lightingTags,tagStart,numVertices*sizeof(int)); \ \ /* clear all lights */ \ *freeLights = *lights; \ *lights = NULL; \ \ if (inShadow == FALSE) { \ CActiveLight *cLight; \ \ for (cLight=currentAttributes->lightSources;cLight!=NULL;cLight=cLight->next) { \ CProgrammableShaderInstance *light = cLight->light; \ lightCategoryCheck; \ if (light->flags & SHADERFLAGS_NONAMBIENT) { \ currentShadingState->currentLightInstance = light; \ currentAttributes->initLightDefaults(numVertices,varying,cLight); \ light->illuminate(this); \ } \ } \ } \ assert(currentShadingState->numActive == numActive); \ assert(currentShadingState->numPassive == numPassive); \ \ currentShadingState->currentShaderInstance = cInstance; \ } #define CATEGORYLIGHT_PRE(lC) int runCat = 0,saveCat = 0; \ int invertCatMatch = FALSE; \ if (*(lC->string) != '\0') { \ if (*(lC->string) == '-') { \ saveCat = -(runCat = currentRenderer->getGlobalID(lC->string+1)); \ invertCatMatch = TRUE; \ } else { \ saveCat = runCat = currentRenderer->getGlobalID(lC->string); \ } \ } #define CATEGORYLIGHT_CHECK if (light->categories != NULL) { \ int validLight = FALSE; \ int *cCat; \ for (cCat=light->categories;(*cCat!=0);cCat++) { \ if (*cCat == runCat) { \ validLight = TRUE; \ break; \ } \ } \ if (invertCatMatch) { \ if (validLight) continue; \ } else { \ if (!validLight) continue; \ } \ } else if (!invertCatMatch) { \ continue; \ } #define runCategoryLights(lP,lN,lT,lC) runLightsTemplate(lP,lN,lT,CATEGORYLIGHT_PRE(lC),CATEGORYLIGHT_CHECK) #define NORMALLIGHT_PRE int saveCat = 0; #define runLights(lP,lN,lT) runLightsTemplate(lP,lN,lT,NORMALLIGHT_PRE,NULL_EXPR) // The misc macros #define DEFLINKOPCODE(name,text,nargs) case OPCODE_##name: #define DEFLINKFUNC(name,text,prototype,par) case FUNCTION_##name: // Break the shader execution #define BREAK goto execEnd; // The shading variables and junk TCode **stuff[6]; // Where we keep pointers to the variables int IP; // Isn't it obvious ? ESlCode opcode; // :) CConditional *lastConditional; // The last conditional int numActive; // The number of active points being shaded int numPassive; // The number of passive points being not shaded (numPassive+numActive = numVertices) int *tags; // Execution tags int *tagStart; int currentVertex; // The current vertex being executed CShader *currentShader = cInstance->parent; TCode *code; int numVertices; float **varying; CShadedLight **lights; CShadedLight **alights; CShadedLight **currentLight; CShadedLight **freeLights; CShaderCache *cCache; CGatherBundle *lastGather; // Pointer to the last gather bundle assert((currentShadingState->numActive+currentShadingState->numPassive) == currentShadingState->numVertices); currentShadingState->currentShaderInstance = cInstance; code = currentShader->codeArea; IP = currentShader->codeEntryPoint; tagStart = currentShadingState->tags; // Allocate the shader variables cCache = currentShader->cache; if (cCache == NULL) cCache = newCache(currentShader); currentShader->cache = cCache->shaderNext; // Save this stuff for fast access numVertices = currentShadingState->numVertices; varying = currentShadingState->varying; lights = ¤tShadingState->lights; alights = ¤tShadingState->alights; currentLight = ¤tShadingState->currentLight; freeLights = ¤tShadingState->freeLights; // Set the access arrays stuff[SL_IMMEDIATE_OPERAND] = currentShader->constantEntries; // Immediate operands stuff[SL_PARAMETER_OPERAND] = cInstance->parameterEntries; // Parameters stuff[SL_GLOBAL_OPERAND] = (TCode **) varying; // Varying globals stuff[SL_UNIFORM_OPERAND] = cCache->uniforms; // Shader uniform local variables stuff[SL_VARYING_OPERAND] = cCache->varyings; // Shader varying local variables numActive = currentShadingState->numActive; numPassive = currentShadingState->numPassive; lastConditional = NULL; // The last conditional block // Execute execStart: opcode = (ESlCode) code[IP].integer; // Get the opcode tags = tagStart; // Set the tags to the start if (code[IP+1].arguments.uniform) { // If the opcode is uniform , execute once #define DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params) \ case OPCODE_##name: \ { \ expr_pre; \ expr; \ expr_post; \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params) \ case OPCODE_##name: \ { \ expr_pre; \ expr; \ expr_post; \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ expr; \ expr_post; \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ scripterror("invalid uniform lighting call"); \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ expr; \ expr_post; \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } switch(opcode) { #include "scriptOpcodes.h" #include "scriptFunctions.h" default: error(CODE_BUG,"Opcode conflict"); goto execEnd; } // Resume executing instructions IP += code[IP+1].arguments.numCodes; goto execStart; #undef DEFOPCODE #undef DEFSHORTOPCODE #undef DEFFUNC #undef DEFLIGHTFUNC #undef DEFSHORTFUNC } else { if (numPassive != 0) { // If we have some vertices that are passive, be more careful #define DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params) \ case OPCODE_##name: \ { \ expr_pre; \ for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) { \ if (*tags == 0) { \ expr; \ } \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params) \ case OPCODE_##name: \ { \ expr_pre; \ for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--,tags++) { \ if (*tags == 0) { \ expr; \ } \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) { \ if (*tags == 0) { \ expr; \ } \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) { \ if (*tags == 0) { \ expr; \ } \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--,tags++) { \ if (*tags == 0) { \ expr; \ } \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } switch(opcode) { #include "scriptOpcodes.h" #include "scriptFunctions.h" default: error(CODE_BUG,"Opcode conflict"); goto execEnd; } IP += code[IP+1].arguments.numCodes; goto execStart; } else { #undef DEFOPCODE #undef DEFSHORTOPCODE #undef DEFFUNC #undef DEFLIGHTFUNC #undef DEFSHORTFUNC #define DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params) \ case OPCODE_##name: \ { \ expr_pre; \ for (currentVertex=numVertices;currentVertex>0;currentVertex--) { \ expr; \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params) \ case OPCODE_##name: \ { \ expr_pre; \ for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--) { \ expr; \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ for (currentVertex=numVertices;currentVertex>0;currentVertex--) { \ expr; \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) { \ if (*tags == 0) { \ expr; \ } \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } #define DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par) \ case FUNCTION_##name: \ { \ expr_pre; \ for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--) { \ expr; \ expr_update; \ } \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } switch(opcode) { #include "scriptOpcodes.h" #include "scriptFunctions.h" default: error(CODE_BUG,"Opcode conflict"); goto execEnd; } IP += code[IP+1].arguments.numCodes; goto execStart; } #undef DEFOPCODE #undef DEFSHORTOPCODE #undef DEFFUNC #undef DEFLIGHTFUNC #undef DEFSHORTFUNC } goto execStart; execEnd: // Restore the cache for the shader cCache->shaderNext = currentShader->cache; currentShader->cache = cCache; // Make sure we save the ambient contribution if there has been no illuminate/solar executed if (currentShader->type == SL_LIGHTSOURCE) { if (!(currentShader->usedParameters & PARAMETER_NONAMBIENT)) { float *Cl = varying[VARIABLE_CL]; float *Ol = varying[VARIABLE_OL]; float *Clsave; // Save the ambient junk Clsave = (*alights)->savedState[1]; tags = tagStart; for (int i=0;i