| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- /**
- * MojoShader; generate shader programs from bytecode of compiled
- * Direct3D shaders.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
- #define __MOJOSHADER_INTERNAL__ 1
- #include "mojoshader_internal.h"
- #include <math.h>
- #if SUPPORT_PRESHADERS
- void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
- const float *inregs, float *outregs)
- {
- // this is fairly straightforward, as there aren't any branching
- // opcodes in the preshader instruction set (at the moment, at least).
- const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
- double *temps = NULL;
- if (preshader->temp_count > 0)
- {
- temps = (double *) alloca(sizeof (double) * preshader->temp_count);
- memset(temps, '\0', sizeof (double) * preshader->temp_count);
- } // if
- double dst[4] = { 0, 0, 0, 0 };
- double src[3][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
- const double *src0 = &src[0][0];
- const double *src1 = &src[1][0];
- const double *src2 = &src[2][0];
- MOJOSHADER_preshaderInstruction *inst = preshader->instructions;
- int instit;
- for (instit = 0; instit < preshader->instruction_count; instit++, inst++)
- {
- const MOJOSHADER_preshaderOperand *operand = inst->operands;
- const int elems = inst->element_count;
- const int elemsbytes = sizeof (double) * elems;
- const int isscalarop = (inst->opcode >= scalarstart);
- assert(elems >= 0);
- assert(elems <= 4);
- // load up our operands...
- int opiter, elemiter;
- for (opiter = 0; opiter < inst->operand_count-1; opiter++, operand++)
- {
- const int isscalar = ((isscalarop) && (opiter == 0));
- const unsigned int index = operand->index;
- switch (operand->type)
- {
- case MOJOSHADER_PRESHADEROPERAND_LITERAL:
- {
- const double *lit = &preshader->literals[index];
- assert((index + elems) <= preshader->literal_count);
- if (!isscalar)
- memcpy(&src[opiter][0], lit, elemsbytes);
- else
- {
- const double val = *lit;
- for (elemiter = 0; elemiter < elems; elemiter++)
- src[opiter][elemiter] = val;
- } // else
- break;
- } // case
- case MOJOSHADER_PRESHADEROPERAND_INPUT:
- if (isscalar)
- src[opiter][0] = inregs[index];
- else
- {
- int cpy;
- for (cpy = 0; cpy < elems; cpy++)
- src[opiter][cpy] = inregs[index+cpy];
- } // else
- break;
- case MOJOSHADER_PRESHADEROPERAND_OUTPUT:
- if (isscalar)
- src[opiter][0] = outregs[index];
- else
- {
- int cpy;
- for (cpy = 0; cpy < elems; cpy++)
- src[opiter][cpy] = outregs[index+cpy];
- } // else
- break;
- case MOJOSHADER_PRESHADEROPERAND_TEMP:
- if (temps != NULL)
- {
- if (isscalar)
- src[opiter][0] = temps[index];
- else
- memcpy(src[opiter], temps + index, elemsbytes);
- } // if
- break;
- default:
- assert(0 && "unexpected preshader operand type.");
- return;
- } // switch
- } // for
- // run the actual instruction, store result to dst.
- int i;
- switch (inst->opcode)
- {
- #define OPCODE_CASE(op, val) \
- case MOJOSHADER_PRESHADEROP_##op: \
- for (i = 0; i < elems; i++) { dst[i] = val; } \
- break;
- //OPCODE_CASE(NOP, 0.0) // not a real instruction.
- OPCODE_CASE(MOV, src0[i])
- OPCODE_CASE(NEG, -src0[i])
- OPCODE_CASE(RCP, 1.0 / src0[i])
- OPCODE_CASE(FRC, src0[i] - floor(src0[i]))
- OPCODE_CASE(EXP, exp(src0[i]))
- OPCODE_CASE(LOG, log(src0[i]))
- OPCODE_CASE(RSQ, 1.0 / sqrt(src0[i]))
- OPCODE_CASE(SIN, sin(src0[i]))
- OPCODE_CASE(COS, cos(src0[i]))
- OPCODE_CASE(ASIN, asin(src0[i]))
- OPCODE_CASE(ACOS, acos(src0[i]))
- OPCODE_CASE(ATAN, atan(src0[i]))
- OPCODE_CASE(MIN, (src0[i] < src1[i]) ? src0[i] : src1[i])
- OPCODE_CASE(MAX, (src0[i] > src1[i]) ? src0[i] : src1[i])
- OPCODE_CASE(LT, (src0[i] < src1[i]) ? 1.0 : 0.0)
- OPCODE_CASE(GE, (src0[i] >= src1[i]) ? 1.0 : 0.0)
- OPCODE_CASE(ADD, src0[i] + src1[i])
- OPCODE_CASE(MUL, src0[i] * src1[i])
- OPCODE_CASE(ATAN2, atan2(src0[i], src1[i]))
- OPCODE_CASE(DIV, src0[i] / src1[i])
- OPCODE_CASE(CMP, (src0[i] >= 0.0) ? src1[i] : src2[i])
- //OPCODE_CASE(NOISE, ???) // !!! FIXME: don't know what this does
- //OPCODE_CASE(MOVC, ???) // !!! FIXME: don't know what this does
- OPCODE_CASE(MIN_SCALAR, (src0[0] < src1[i]) ? src0[0] : src1[i])
- OPCODE_CASE(MAX_SCALAR, (src0[0] > src1[i]) ? src0[0] : src1[i])
- OPCODE_CASE(LT_SCALAR, (src0[0] < src1[i]) ? 1.0 : 0.0)
- OPCODE_CASE(GE_SCALAR, (src0[0] >= src1[i]) ? 1.0 : 0.0)
- OPCODE_CASE(ADD_SCALAR, src0[0] + src1[i])
- OPCODE_CASE(MUL_SCALAR, src0[0] * src1[i])
- OPCODE_CASE(ATAN2_SCALAR, atan2(src0[0], src1[i]))
- OPCODE_CASE(DIV_SCALAR, src0[0] / src1[i])
- //OPCODE_CASE(DOT_SCALAR) // !!! FIXME: isn't this just a MUL?
- //OPCODE_CASE(NOISE_SCALAR, ???) // !!! FIXME: ?
- #undef OPCODE_CASE
- case MOJOSHADER_PRESHADEROP_DOT:
- {
- double final = 0.0;
- for (i = 0; i < elems; i++)
- final += src0[i] * src1[i];
- for (i = 0; i < elems; i++)
- dst[i] = final; // !!! FIXME: is this right?
- } // case
- default:
- assert(0 && "Unhandled preshader opcode!");
- break;
- } // switch
- // Figure out where dst wants to be stored.
- if (operand->type == MOJOSHADER_PRESHADEROPERAND_TEMP)
- {
- assert(preshader->temp_count >=
- operand->index + (elemsbytes / sizeof (double)));
- memcpy(temps + operand->index, dst, elemsbytes);
- } // if
- else
- {
- assert(operand->type == MOJOSHADER_PRESHADEROPERAND_OUTPUT);
- for (i = 0; i < elems; i++)
- outregs[operand->index + i] = (float) dst[i];
- } // else
- } // for
- } // MOJOSHADER_runPreshader
- #endif
- static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
- 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- static uint32 readui32(const uint8 **_ptr, uint32 *_len)
- {
- uint32 retval = 0;
- if (*_len < sizeof (retval))
- *_len = 0;
- else
- {
- const uint32 *ptr = (const uint32 *) *_ptr;
- retval = SWAP32(*ptr);
- *_ptr += sizeof (retval);
- *_len -= sizeof (retval);
- } // else
- return retval;
- } // readui32
- // !!! FIXME: this is sort of a big, ugly function.
- const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
- const unsigned char *buf,
- const unsigned int _len,
- const MOJOSHADER_swizzle *swiz,
- const unsigned int swizcount,
- const MOJOSHADER_samplerMap *smap,
- const unsigned int smapcount,
- MOJOSHADER_malloc m,
- MOJOSHADER_free f,
- void *d)
- {
- if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
- return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
- if (m == NULL) m = MOJOSHADER_internal_malloc;
- if (f == NULL) f = MOJOSHADER_internal_free;
- MOJOSHADER_effect *retval = (MOJOSHADER_effect *)m(sizeof (MOJOSHADER_effect), d);
- if (retval == NULL)
- return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
- memset(retval, '\0', sizeof (*retval));
- retval->malloc = m;
- retval->free = f;
- retval->malloc_data = d;
- const uint8 *ptr = (const uint8 *) buf;
- uint32 len = (uint32) _len;
- size_t siz = 0;
- int i, j, k;
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- const uint8 *base = NULL;
- if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic?
- goto parseEffect_notAnEffectsFile;
- else
- {
- const uint32 offset = readui32(&ptr, &len);
- base = ptr;
- //printf("base offset == %u\n", offset);
- if (offset > len)
- goto parseEffect_unexpectedEOF;
- ptr += offset;
- len -= offset;
- } // else
- // params...
- if (len < 16)
- goto parseEffect_unexpectedEOF;
- const uint32 numparams = readui32(&ptr, &len);
- const uint32 numtechniques = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here. Annotations?
- /*const uint32 numobjects = */ readui32(&ptr, &len);
- if (numparams > 0)
- {
- siz = sizeof (MOJOSHADER_effectParam) * numparams;
- retval->params = (MOJOSHADER_effectParam *) m(siz, d);
- if (retval->params == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->params, '\0', siz);
- retval->param_count = numparams;
- for (i = 0; i < numparams; i++)
- {
- if (len < 16)
- goto parseEffect_unexpectedEOF;
- const uint32 typeoffset = readui32(&ptr, &len);
- /*const uint32 valoffset =*/ readui32(&ptr, &len);
- /*const uint32 flags =*/ readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- for (j = 0; j < numannos; j++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: parse annotations.
- readui32(&ptr, &len);
- readui32(&ptr, &len);
- } // for
- const uint8 *typeptr = base + typeoffset;
- unsigned int typelen = 9999999; // !!! FIXME
- /*const uint32 paramtype =*/ readui32(&typeptr, &typelen);
- /*const uint32 paramclass =*/ readui32(&typeptr, &typelen);
- const uint32 paramname = readui32(&typeptr, &typelen);
- const uint32 paramsemantic = readui32(&typeptr, &typelen);
- // !!! FIXME: sanity checks!
- const char *namestr = ((const char *) base) + paramname;
- const char *semstr = ((const char *) base) + paramsemantic;
- uint32 len;
- char *strptr;
- len = *((const uint32 *) namestr);
- strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- retval->params[i].name = strptr;
- len = *((const uint32 *) semstr);
- strptr = (char *) m(len + 1, d);
- memcpy(strptr, semstr + 4, len);
- strptr[len] = '\0';
- retval->params[i].semantic = strptr;
- } // for
- } // if
- uint32 numshaders = 0; // we'll calculate this later.
- // techniques...
- if (numtechniques > 0)
- {
- siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
- retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
- if (retval->techniques == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->techniques, '\0', siz);
- retval->technique_count = numtechniques;
- for (i = 0; i < numtechniques; i++)
- {
- if (len < 12)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectTechnique *technique = &retval->techniques[i];
- const uint32 nameoffset = readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- const uint32 numpasses = readui32(&ptr, &len);
- if (nameoffset >= _len)
- goto parseEffect_unexpectedEOF;
- if (numannos > 0)
- {
- // !!! FIXME: expose these to the caller?
- for (j = 0; j < numannos; j++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- readui32(&ptr, &len); // typedef offset
- readui32(&ptr, &len); // value offset
- } // for
- } // if
- // !!! FIXME: verify this doesn't go past EOF looking for a null.
- {
- const char *namestr = ((char *) base) + nameoffset;
- uint32 len = *((const uint32 *) namestr);
- char *strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- technique->name = strptr;
- }
- if (numpasses > 0)
- {
- technique->pass_count = numpasses;
- siz = sizeof (MOJOSHADER_effectPass) * numpasses;
- technique->passes = (MOJOSHADER_effectPass *) m(siz, d);
- if (technique->passes == NULL)
- goto parseEffect_outOfMemory;
- memset(technique->passes, '\0', siz);
- for (j = 0; j < numpasses; j++)
- {
- if (len < 12)
- goto parseEffect_unexpectedEOF;
- MOJOSHADER_effectPass *pass = &technique->passes[j];
- const uint32 passnameoffset = readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- const uint32 numstates = readui32(&ptr, &len);
- if (passnameoffset >= _len)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: verify this doesn't go past EOF looking for a null.
- {
- const char *namestr = ((char *) base) + passnameoffset;
- uint32 len = *((const uint32 *) namestr);
- char *strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- pass->name = strptr;
- }
- if (numannos > 0)
- {
- for (k = 0; k < numannos; k++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: do something with this.
- readui32(&ptr, &len);
- readui32(&ptr, &len);
- } // for
- } // if
- if (numstates > 0)
- {
- pass->state_count = numstates;
- siz = sizeof (MOJOSHADER_effectState) * numstates;
- pass->states = (MOJOSHADER_effectState *) m(siz, d);
- if (pass->states == NULL)
- goto parseEffect_outOfMemory;
- memset(pass->states, '\0', siz);
- for (k = 0; k < numstates; k++)
- {
- if (len < 16)
- goto parseEffect_unexpectedEOF;
- MOJOSHADER_effectState *state = &pass->states[k];
- const uint32 type = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: don't know what this field does.
- /*const uint32 offsetend = */ readui32(&ptr, &len);
- /*const uint32 offsetstart = */ readui32(&ptr, &len);
- state->type = type;
- if ((type == 0x92) || (type == 0x93))
- numshaders++;
- } // for
- } // if
- } // for
- } // if
- } // for
- } // if
- // textures...
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- const int numtextures = readui32(&ptr, &len);
- const int numobjects = readui32(&ptr, &len); // !!! FIXME: "objects" for lack of a better word.
- if (numtextures > 0)
- {
- siz = sizeof (MOJOSHADER_effectTexture) * numtextures;
- retval->textures = (MOJOSHADER_effectTexture *)m(siz, d);
- if (retval->textures == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->textures, '\0', siz);
- for (i = 0; i < numtextures; i++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- MOJOSHADER_effectTexture *texture = &retval->textures[i];
- const uint32 texparam = readui32(&ptr, &len);
- const uint32 texsize = readui32(&ptr, &len);
- // apparently texsize will pad out to 32 bits.
- const uint32 readsize = (((texsize + 3) / 4) * 4);
- if (len < readsize)
- goto parseEffect_unexpectedEOF;
- texture->param = texparam;
- char *str = (char *)m(texsize + 1, d);
- if (str == NULL)
- goto parseEffect_outOfMemory;
- memcpy(str, ptr, texsize);
- str[texsize] = '\0';
- texture->name = str;
- ptr += readsize;
- len -= readsize;
- } // for
- } // if
- // shaders...
- if (numshaders > 0)
- {
- siz = sizeof (MOJOSHADER_effectShader) * numshaders;
- retval->shaders = (MOJOSHADER_effectShader *) m(siz, d);
- if (retval->shaders == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->shaders, '\0', siz);
- retval->shader_count = numshaders;
- // !!! FIXME: I wonder if we should pull these from offsets and not
- // !!! FIXME: count on them all being in a line like this.
- for (i = 0; i < numshaders; i++)
- {
- if (len < 24)
- goto parseEffect_unexpectedEOF;
- MOJOSHADER_effectShader *shader = &retval->shaders[i];
- const uint32 technique = readui32(&ptr, &len);
- const uint32 pass = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: don't know what this does.
- readui32(&ptr, &len); // !!! FIXME: don't know what this does (vertex/pixel/geometry?)
- readui32(&ptr, &len); // !!! FIXME: don't know what this does.
- const uint32 shadersize = readui32(&ptr, &len);
- if (len < shadersize)
- goto parseEffect_unexpectedEOF;
- shader->technique = technique;
- shader->pass = pass;
- shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
- swiz, swizcount, smap, smapcount,
- m, f, d);
- // !!! FIXME: check for errors.
- ptr += shadersize;
- len -= shadersize;
- } // for
- } // if
- // !!! FIXME: we parse this, but don't expose the data, yet.
- // mappings ...
- assert(numshaders <= numobjects);
- const uint32 nummappings = numobjects - numshaders;
- if (nummappings > 0)
- {
- for (i = 0; i < nummappings; i++)
- {
- if (len < 24)
- goto parseEffect_unexpectedEOF;
- /*const uint32 magic = */ readui32(&ptr, &len);
- /*const uint32 index = */ readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: what is this field?
- readui32(&ptr, &len); // !!! FIXME: what is this field?
- /*const uint32 type = */ readui32(&ptr, &len);
- const uint32 mapsize = readui32(&ptr, &len);
- if (mapsize > 0)
- {
- const uint32 readsize = (((mapsize + 3) / 4) * 4);
- if (len < readsize)
- goto parseEffect_unexpectedEOF;
- } // if
- } // for
- } // if
- retval->profile = (char *) m(strlen(profile) + 1, d);
- if (retval->profile == NULL)
- goto parseEffect_outOfMemory;
- strcpy((char *) retval->profile, profile);
- return retval;
- // !!! FIXME: do something with this.
- parseEffect_notAnEffectsFile:
- parseEffect_unexpectedEOF:
- parseEffect_outOfMemory:
- MOJOSHADER_freeEffect(retval);
- return &MOJOSHADER_out_of_mem_effect;
- } // MOJOSHADER_parseEffect
- void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
- {
- MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
- if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
- return; // no-op.
- MOJOSHADER_free f = effect->free;
- void *d = effect->malloc_data;
- int i, j;
- for (i = 0; i < effect->error_count; i++)
- {
- f((void *) effect->errors[i].error, d);
- f((void *) effect->errors[i].filename, d);
- } // for
- f((void *) effect->errors, d);
- f((void *) effect->profile, d);
- for (i = 0; i < effect->param_count; i++)
- {
- f((void *) effect->params[i].name, d);
- f((void *) effect->params[i].semantic, d);
- } // for
- f(effect->params, d);
- for (i = 0; i < effect->technique_count; i++)
- {
- MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
- f((void *) technique->name, d);
- for (j = 0; j < technique->pass_count; j++)
- {
- f((void *) technique->passes[j].name, d);
- f(technique->passes[j].states, d);
- } // for
- f(technique->passes, d);
- } // for
- f(effect->techniques, d);
- for (i = 0; i < effect->texture_count; i++)
- f((void *) effect->textures[i].name, d);
- f(effect->textures, d);
- for (i = 0; i < effect->shader_count; i++)
- MOJOSHADER_freeParseData(effect->shaders[i].shader);
- f(effect->shaders, d);
- f(effect, d);
- } // MOJOSHADER_freeEffect
- // end of mojoshader_effects.c ...
|