mojoshader_effects.c
changeset 1019 e8988ca01c6d
child 1021 cad933999680
equal deleted inserted replaced
1018:ad6c6286df61 1019:e8988ca01c6d
       
     1 /**
       
     2  * MojoShader; generate shader programs from bytecode of compiled
       
     3  *  Direct3D shaders.
       
     4  *
       
     5  * Please see the file LICENSE.txt in the source's root directory.
       
     6  *
       
     7  *  This file written by Ryan C. Gordon.
       
     8  */
       
     9 
       
    10 #define __MOJOSHADER_INTERNAL__ 1
       
    11 #include "mojoshader_internal.h"
       
    12 
       
    13 
       
    14 static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
       
    15     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
       
    16 };
       
    17 
       
    18 static uint32 readui32(const uint8 **_ptr, uint32 *_len)
       
    19 {
       
    20     uint32 retval = 0;
       
    21     if (*_len < sizeof (retval))
       
    22         *_len = 0;
       
    23     else
       
    24     {
       
    25         const uint32 *ptr = (const uint32 *) *_ptr;
       
    26         retval = SWAP32(*ptr);
       
    27         *_ptr += sizeof (retval);
       
    28         *_len -= sizeof (retval);
       
    29     } // else
       
    30     return retval;
       
    31 } // readui32
       
    32 
       
    33 // !!! FIXME: this is sort of a big, ugly function.
       
    34 const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
       
    35                                                 const unsigned char *buf,
       
    36                                                 const unsigned int _len,
       
    37                                                 const MOJOSHADER_swizzle *swiz,
       
    38                                                 const unsigned int swizcount,
       
    39                                                 MOJOSHADER_malloc m,
       
    40                                                 MOJOSHADER_free f,
       
    41                                                 void *d)
       
    42 {
       
    43     if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
       
    44         return &MOJOSHADER_out_of_mem_effect;  // supply both or neither.
       
    45 
       
    46     if (m == NULL) m = MOJOSHADER_internal_malloc;
       
    47     if (f == NULL) f = MOJOSHADER_internal_free;
       
    48 
       
    49     MOJOSHADER_effect *retval = m(sizeof (MOJOSHADER_effect), d);
       
    50     if (retval == NULL)
       
    51         return &MOJOSHADER_out_of_mem_effect;  // supply both or neither.
       
    52     memset(retval, '\0', sizeof (*retval));
       
    53 
       
    54     retval->malloc = m;
       
    55     retval->free = f;
       
    56     retval->malloc_data = d;
       
    57 
       
    58     const uint8 *ptr = (const uint8 *) buf;
       
    59     uint32 len = (uint32) _len;
       
    60     size_t siz = 0;
       
    61     int i, j, k;
       
    62 
       
    63     if (len < 8)
       
    64         goto parseEffect_unexpectedEOF;
       
    65 
       
    66     if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic?
       
    67         goto parseEffect_notAnEffectsFile;
       
    68     else
       
    69     {
       
    70         const uint32 offset = readui32(&ptr, &len);
       
    71         if (offset > len)
       
    72             goto parseEffect_unexpectedEOF;
       
    73         ptr += offset;
       
    74         len -= offset;
       
    75     } // else
       
    76 
       
    77     // params...
       
    78 
       
    79     if (len < 16)
       
    80         goto parseEffect_unexpectedEOF;
       
    81 
       
    82     const uint32 numparams = readui32(&ptr, &len);
       
    83     const uint32 numtechniques = readui32(&ptr, &len);
       
    84 
       
    85     readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here.
       
    86     readui32(&ptr, &len);
       
    87 
       
    88     for (i = 0; i < numparams; i++)
       
    89     {
       
    90         if (len < 16)
       
    91             goto parseEffect_unexpectedEOF;
       
    92 
       
    93         /*const uint32 startoffset = */ readui32(&ptr, &len);
       
    94         /*const uint32 endoffset = */ readui32(&ptr, &len);
       
    95         readui32(&ptr, &len);  // !!! FIXME: don't know what this is.
       
    96         const uint32 numannos = readui32(&ptr, &len);
       
    97         for (j = 0; j < numannos; j++)
       
    98         {
       
    99             if (len < 8)
       
   100                 goto parseEffect_unexpectedEOF;
       
   101             // !!! FIXME: parse annotations.
       
   102             readui32(&ptr, &len);
       
   103             readui32(&ptr, &len);
       
   104         } // for
       
   105     } // for
       
   106 
       
   107     uint32 numshaders = 0;  // we'll calculate this later.
       
   108 
       
   109     // techniques...
       
   110 
       
   111     if (numtechniques > 0)
       
   112     {
       
   113         siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
       
   114         retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
       
   115         if (retval->techniques == NULL)
       
   116             goto parseEffect_outOfMemory;
       
   117         memset(retval->techniques, '\0', siz);
       
   118 
       
   119         retval->technique_count = numtechniques;
       
   120 
       
   121         for (i = 0; i < numtechniques; i++)
       
   122         {
       
   123             if (len < 12)
       
   124                 goto parseEffect_unexpectedEOF;
       
   125             
       
   126             MOJOSHADER_effectTechnique *technique = &retval->techniques[i];
       
   127 
       
   128             // !!! FIXME: is this always 12?
       
   129             const uint32 nameoffset = readui32(&ptr, &len) + 12;
       
   130             readui32(&ptr, &len);  // !!! FIXME: don't know what this field does.
       
   131             const uint32 numpasses = readui32(&ptr, &len);
       
   132 
       
   133             if (nameoffset >= _len)
       
   134                 goto parseEffect_unexpectedEOF;
       
   135 
       
   136             if (numpasses > 0)
       
   137             {
       
   138                 // !!! FIXME: verify this doesn't go past EOF looking for a null.
       
   139                 siz = strlen(((const char *) buf) + nameoffset) + 1;
       
   140                 technique->name = (char *) m(siz, d);
       
   141                 if (technique->name == NULL)
       
   142                     goto parseEffect_outOfMemory;
       
   143                 strcpy((char *) technique->name, ((const char *) buf) + nameoffset);
       
   144 
       
   145                 technique->pass_count = numpasses;
       
   146 
       
   147                 siz = sizeof (MOJOSHADER_effectPass) * numpasses;
       
   148                 technique->passes = (MOJOSHADER_effectPass *) m(siz, d);
       
   149                 if (technique->passes == NULL)
       
   150                     goto parseEffect_outOfMemory;
       
   151                 memset(technique->passes, '\0', siz);
       
   152 
       
   153                 for (j = 0; j < numpasses; j++)
       
   154                 {
       
   155                     if (len < 12)
       
   156                         goto parseEffect_unexpectedEOF;
       
   157 
       
   158                     MOJOSHADER_effectPass *pass = &technique->passes[j];
       
   159 
       
   160                     // !!! FIXME: is this always 12?
       
   161                     const uint32 passnameoffset = readui32(&ptr, &len) + 12;
       
   162                     readui32(&ptr, &len);  // !!! FIXME: don't know what this field does.
       
   163                     const uint32 numstates = readui32(&ptr, &len);
       
   164 
       
   165                     if (passnameoffset >= _len)
       
   166                         goto parseEffect_unexpectedEOF;
       
   167 
       
   168                     // !!! FIXME: verify this doesn't go past EOF looking for a null.
       
   169                     siz = strlen(((const char *) buf) + passnameoffset) + 1;
       
   170                     pass->name = (char *) m(siz, d);
       
   171                     if (pass->name == NULL)
       
   172                         goto parseEffect_outOfMemory;
       
   173                     strcpy((char *) pass->name, ((const char *) buf) + passnameoffset);
       
   174 
       
   175                     if (numstates > 0)
       
   176                     {
       
   177                         pass->state_count = numstates;
       
   178 
       
   179                         siz = sizeof (MOJOSHADER_effectState) * numstates;
       
   180                         pass->states = (MOJOSHADER_effectState *) m(siz, d);
       
   181                         if (pass->states == NULL)
       
   182                             goto parseEffect_outOfMemory;
       
   183                         memset(pass->states, '\0', siz);
       
   184 
       
   185                         for (k = 0; k < numstates; k++)
       
   186                         {
       
   187                             if (len < 16)
       
   188                                 goto parseEffect_unexpectedEOF;
       
   189 
       
   190                             MOJOSHADER_effectState *state = &pass->states[k];
       
   191                             const uint32 type = readui32(&ptr, &len);
       
   192                             readui32(&ptr, &len);  // !!! FIXME: don't know what this field does.
       
   193                             /*const uint32 offsetend = */ readui32(&ptr, &len);
       
   194                             /*const uint32 offsetstart = */ readui32(&ptr, &len);
       
   195                             state->type = type;
       
   196 
       
   197                             if ((type == 0x92) || (type == 0x93))
       
   198                                 numshaders++;
       
   199                         } // for
       
   200                     } // if
       
   201                 } // for
       
   202             } // if
       
   203         } // for
       
   204     } // if
       
   205 
       
   206     // textures...
       
   207 
       
   208     if (len < 8)
       
   209         goto parseEffect_unexpectedEOF;
       
   210 
       
   211     const int numtextures = readui32(&ptr, &len);
       
   212     const int numobjects = readui32(&ptr, &len);  // !!! FIXME: "objects" for lack of a better word.
       
   213 
       
   214     if (numtextures > 0)
       
   215     {
       
   216         siz = sizeof (MOJOSHADER_effectTexture) * numtextures;
       
   217         retval->textures = m(siz, d);
       
   218         if (retval->textures == NULL)
       
   219             goto parseEffect_outOfMemory;
       
   220         memset(retval->textures, '\0', siz);
       
   221 
       
   222         for (i = 0; i < numtextures; i++)
       
   223         {
       
   224             if (len < 8)
       
   225                 goto parseEffect_unexpectedEOF;
       
   226 
       
   227             MOJOSHADER_effectTexture *texture = &retval->textures[i];
       
   228             const uint32 texparam = readui32(&ptr, &len);
       
   229             const uint32 texsize = readui32(&ptr, &len);
       
   230             // apparently texsize will pad out to 32 bits.
       
   231             const uint32 readsize = (((texsize + 3) / 4) * 4);
       
   232             if (len < readsize)
       
   233                 goto parseEffect_unexpectedEOF;
       
   234 
       
   235             texture->param = texparam;
       
   236             char *str = m(texsize + 1, d);
       
   237             if (str == NULL)
       
   238                 goto parseEffect_outOfMemory;
       
   239             memcpy(str, ptr, texsize);
       
   240             str[texsize] = '\0';
       
   241             texture->name = str;
       
   242 
       
   243             ptr += readsize;
       
   244             len -= readsize;
       
   245         } // for
       
   246     } // if
       
   247 
       
   248     // shaders...
       
   249 
       
   250     if (numshaders > 0)
       
   251     {
       
   252         siz = sizeof (MOJOSHADER_effectShader) * numshaders;
       
   253         retval->shaders = (MOJOSHADER_effectShader *) m(siz, d);
       
   254         if (retval->shaders == NULL)
       
   255             goto parseEffect_outOfMemory;
       
   256         memset(retval->shaders, '\0', siz);
       
   257 
       
   258         retval->shader_count = numshaders;
       
   259 
       
   260         // !!! FIXME: I wonder if we should pull these from offsets and not
       
   261         // !!! FIXME:  count on them all being in a line like this.
       
   262         for (i = 0; i < numshaders; i++)
       
   263         {
       
   264             if (len < 24)
       
   265                 goto parseEffect_unexpectedEOF;
       
   266 
       
   267             MOJOSHADER_effectShader *shader = &retval->shaders[i];
       
   268             const uint32 technique = readui32(&ptr, &len);
       
   269             const uint32 pass = readui32(&ptr, &len);
       
   270             readui32(&ptr, &len);  // !!! FIXME: don't know what this does.
       
   271             readui32(&ptr, &len);  // !!! FIXME: don't know what this does (vertex/pixel/geometry?)
       
   272             readui32(&ptr, &len);  // !!! FIXME: don't know what this does.
       
   273             const uint32 shadersize = readui32(&ptr, &len);
       
   274 
       
   275             if (len < shadersize)
       
   276                 goto parseEffect_unexpectedEOF;
       
   277 
       
   278             shader->technique = technique;
       
   279             shader->pass = pass;
       
   280             shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
       
   281                                               swiz, swizcount, m, f, d);
       
   282 
       
   283             // !!! FIXME: check for errors.
       
   284 
       
   285             ptr += shadersize;
       
   286             len -= shadersize;
       
   287         } // for
       
   288     } // if
       
   289 
       
   290     // !!! FIXME: we parse this, but don't expose the data, yet.
       
   291     // mappings ...
       
   292     assert(numshaders <= numobjects);
       
   293     const uint32 nummappings = numobjects - numshaders;
       
   294     if (nummappings > 0)
       
   295     {
       
   296         for (i = 0; i < nummappings; i++)
       
   297         {
       
   298             if (len < 24)
       
   299                 goto parseEffect_unexpectedEOF;
       
   300 
       
   301             /*const uint32 magic = */ readui32(&ptr, &len);
       
   302             /*const uint32 index = */ readui32(&ptr, &len);
       
   303             readui32(&ptr, &len);  // !!! FIXME: what is this field?
       
   304             readui32(&ptr, &len);  // !!! FIXME: what is this field?
       
   305             /*const uint32 type = */ readui32(&ptr, &len);
       
   306             const uint32 mapsize = readui32(&ptr, &len);
       
   307             if (mapsize > 0)
       
   308             {
       
   309                 const uint32 readsize = (((mapsize + 3) / 4) * 4);
       
   310                 if (len < readsize)
       
   311                     goto parseEffect_unexpectedEOF;
       
   312             } // if
       
   313         } // for
       
   314     } // if
       
   315 
       
   316     retval->profile = (char *) m(strlen(profile) + 1, d);
       
   317     if (retval->profile == NULL)
       
   318         goto parseEffect_outOfMemory;
       
   319     strcpy((char *) retval->profile, profile);
       
   320 
       
   321     return retval;
       
   322 
       
   323 
       
   324 // !!! FIXME: do something with this.
       
   325 parseEffect_notAnEffectsFile:
       
   326 parseEffect_unexpectedEOF:
       
   327 parseEffect_outOfMemory:
       
   328     MOJOSHADER_freeEffect(retval);
       
   329     return &MOJOSHADER_out_of_mem_effect;
       
   330 } // MOJOSHADER_parseEffect
       
   331 
       
   332 
       
   333 void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
       
   334 {
       
   335     MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
       
   336     if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
       
   337         return;  // no-op.
       
   338 
       
   339     MOJOSHADER_free f = effect->free;
       
   340     void *d = effect->malloc_data;
       
   341     int i, j;
       
   342 
       
   343     for (i = 0; i < effect->error_count; i++)
       
   344     {
       
   345         f((void *) effect->errors[i].error, d);
       
   346         f((void *) effect->errors[i].filename, d);
       
   347     } // for
       
   348     f((void *) effect->errors, d);
       
   349 
       
   350     f((void *) effect->profile, d);
       
   351 
       
   352     for (i = 0; i < effect->technique_count; i++)
       
   353     {
       
   354         MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
       
   355         for (j = 0; j < technique->pass_count; j++)
       
   356             f(technique->passes[j].states, d);
       
   357         f(technique->passes, d);
       
   358     } // for
       
   359 
       
   360     f(effect->techniques, d);
       
   361 
       
   362     for (i = 0; i < effect->texture_count; i++)
       
   363         f((void *) effect->textures[i].name, d);
       
   364     f(effect->textures, d);
       
   365 
       
   366     for (i = 0; i < effect->shader_count; i++)
       
   367         MOJOSHADER_freeParseData(effect->shaders[i].shader);
       
   368     f(effect->shaders, d);
       
   369 
       
   370     f(effect, d);
       
   371 } // MOJOSHADER_freeEffect
       
   372 
       
   373 // end of mojoshader_effects.c ...
       
   374