mojoshader.c
changeset 1164 006194daea99
parent 1163 c73c39a59dd4
child 1169 68e644e677fd
equal deleted inserted replaced
1163:c73c39a59dd4 1164:006194daea99
 10628 //  up. There are cases where the preshaders are 3+ times as many instructions
 10628 //  up. There are cases where the preshaders are 3+ times as many instructions
 10629 //  as the shader itself, so this can be a big performance win.
 10629 //  as the shader itself, so this can be a big performance win.
 10630 // My presumption is that Microsoft's Effects framework runs the preshaders on
 10630 // My presumption is that Microsoft's Effects framework runs the preshaders on
 10631 //  the CPU, then loads the constant register file appropriately before handing
 10631 //  the CPU, then loads the constant register file appropriately before handing
 10632 //  off to the GPU. As such, we do the same.
 10632 //  off to the GPU. As such, we do the same.
 10633 static void parse_preshader(Context *ctx, uint32 tokcount)
 10633 static void parse_preshader(Context *ctx, const uint32 *tokens, uint32 tokcount)
 10634 {
 10634 {
 10635     const uint32 *tokens = ctx->tokens;
       
 10636     if ((tokcount < 2) || (SWAP32(tokens[1]) != PRES_ID))
       
 10637         return;  // not a preshader.
       
 10638 
       
 10639 #ifndef MOJOSHADER_EFFECT_SUPPORT
 10635 #ifndef MOJOSHADER_EFFECT_SUPPORT
 10640     fail(ctx, "Preshader found, but effect support is disabled!");
 10636     fail(ctx, "Preshader found, but effect support is disabled!");
 10641 #else
 10637 #else
       
 10638     uint32 i;
 10642 
 10639 
 10643     assert(ctx->have_preshader == 0);  // !!! FIXME: can you have more than one?
 10640     assert(ctx->have_preshader == 0);  // !!! FIXME: can you have more than one?
 10644     ctx->have_preshader = 1;
 10641     ctx->have_preshader = 1;
 10645 
 10642 
 10646     // !!! FIXME: I don't know what specific versions signify, but we need to
 10643     // !!! FIXME: I don't know what specific versions signify, but we need to
 10647     // !!! FIXME:  save this to test against the CTAB version field, if
 10644     // !!! FIXME:  save this to test against the CTAB version field, if
 10648     // !!! FIXME:  nothing else.
 10645     // !!! FIXME:  nothing else.
 10649     // !!! FIXME: 0x02 0x0? is probably the version (fx_2_?),
 10646     // !!! FIXME: 0x02 0x0? is probably the version (fx_2_?),
 10650     // !!! FIXME:  and 0x4658 is the magic, like a real shader's version token.
 10647     // !!! FIXME:  and 0x4658 is the magic, like a real shader's version token.
 10651     const uint32 min_version = 0x46580200;
 10648     const uint32 version_magic = 0x46580000;
 10652     const uint32 max_version = 0x46580201;
 10649     const uint32 min_version = 0x00000200 | version_magic;
 10653     const uint32 version = SWAP32(tokens[2]);
 10650     const uint32 max_version = 0x00000201 | version_magic;
       
 10651     const uint32 version = SWAP32(tokens[0]);
 10654     if (version < min_version || version > max_version)
 10652     if (version < min_version || version > max_version)
 10655     {
 10653     {
 10656         fail(ctx, "Unsupported preshader version.");
 10654         fail(ctx, "Unsupported preshader version.");
 10657         return;  // fail because the shader will malfunction w/o this.
 10655         return;  // fail because the shader will malfunction w/o this.
 10658     } // if
 10656     } // if
 10659 
 10657 
 10660     tokens += 3;
 10658     tokens++;
 10661     tokcount -= 3;
 10659     tokcount--;
 10662 
 10660 
 10663     // All sections of a preshader are packed into separate comment tokens,
 10661     // All sections of a preshader are packed into separate comment tokens,
 10664     //  inside the containing comment token block. Find them all before
 10662     //  inside the containing comment token block. Find them all before
 10665     //  we start, so we don't care about the order they appear in the file.
 10663     //  we start, so we don't care about the order they appear in the file.
 10666     PreshaderBlockInfo ctab = { 0, 0, 0 };
 10664     PreshaderBlockInfo ctab = { 0, 0, 0 };
 10711         tokens = nexttokens;
 10709         tokens = nexttokens;
 10712         tokcount = nexttokcount;
 10710         tokcount = nexttokcount;
 10713     } // while
 10711     } // while
 10714 
 10712 
 10715     if (!ctab.seen) { fail(ctx, "No CTAB block in preshader."); return; }
 10713     if (!ctab.seen) { fail(ctx, "No CTAB block in preshader."); return; }
 10716     if (!prsi.seen) { fail(ctx, "No PRSI block in preshader."); return; }
       
 10717     if (!fxlc.seen) { fail(ctx, "No FXLC block in preshader."); return; }
 10714     if (!fxlc.seen) { fail(ctx, "No FXLC block in preshader."); return; }
 10718     if (!clit.seen) { fail(ctx, "No CLIT block in preshader."); return; }
 10715     if (!clit.seen) { fail(ctx, "No CLIT block in preshader."); return; }
       
 10716     // prsi.seen is optional, apparently.
 10719 
 10717 
 10720     MOJOSHADER_preshader *preshader = (MOJOSHADER_preshader *)
 10718     MOJOSHADER_preshader *preshader = (MOJOSHADER_preshader *)
 10721                                     Malloc(ctx, sizeof (MOJOSHADER_preshader));
 10719                                     Malloc(ctx, sizeof (MOJOSHADER_preshader));
 10722     if (preshader == NULL)
 10720     if (preshader == NULL)
 10723         return;
 10721         return;
       
 10722 
 10724     memset(preshader, '\0', sizeof (MOJOSHADER_preshader));
 10723     memset(preshader, '\0', sizeof (MOJOSHADER_preshader));
       
 10724     preshader->malloc = ctx->malloc;
       
 10725     preshader->free = ctx->free;
       
 10726     preshader->malloc_data = ctx->malloc_data;
       
 10727 
 10725     ctx->preshader = preshader;
 10728     ctx->preshader = preshader;
 10726 
 10729 
 10727     // Let's set up the constant literals first...
 10730     // Let's set up the constant literals first...
 10728     if (clit.tokcount == 0)
 10731     if (clit.tokcount == 0)
 10729         fail(ctx, "Bogus CLIT block in preshader.");
 10732         fail(ctx, "Bogus CLIT block in preshader.");
 10742             const size_t len = sizeof (double) * lit_count;
 10745             const size_t len = sizeof (double) * lit_count;
 10743             preshader->literals = (double *) Malloc(ctx, len);
 10746             preshader->literals = (double *) Malloc(ctx, len);
 10744             if (preshader->literals == NULL)
 10747             if (preshader->literals == NULL)
 10745                 return;  // oh well.
 10748                 return;  // oh well.
 10746             const double *litptr = (const double *) (clit.tokens + 2);
 10749             const double *litptr = (const double *) (clit.tokens + 2);
 10747             int i;
       
 10748             for (i = 0; i < lit_count; i++)
 10750             for (i = 0; i < lit_count; i++)
 10749                 preshader->literals[i] = SWAPDBL(litptr[i]);
 10751                 preshader->literals[i] = SWAPDBL(litptr[i]);
 10750         } // else if
 10752         } // else if
 10751     } // else
 10753     } // else
 10752 
 10754 
 10753     // Parse out the PRSI block. This is used to map the output registers.
 10755     // Parse out the PRSI block. This is used to map the output registers.
 10754     if (prsi.tokcount < 8)
 10756     uint32 output_map_count = 0;
 10755     {
 10757     const uint32 *output_map = NULL;
 10756         fail(ctx, "Bogus preshader PRSI data");
 10758     if (prsi.seen)
 10757         return;
 10759     {
 10758     } // if
 10760         if (prsi.tokcount < 8)
 10759 
 10761         {
 10760     //const uint32 first_output_reg = SWAP32(prsi.tokens[1]);
 10762             fail(ctx, "Bogus preshader PRSI data");
 10761     // !!! FIXME: there are a lot of fields here I don't know about.
 10763             return;
 10762     // !!! FIXME:  maybe [2] and [3] are for int4 and bool registers?
 10764         } // if
 10763     //const uint32 output_reg_count = SWAP32(prsi.tokens[4]);
 10765 
 10764     // !!! FIXME:  maybe [5] and [6] are for int4 and bool registers?
 10766         //const uint32 first_output_reg = SWAP32(prsi.tokens[1]);
 10765     const uint32 output_map_count = SWAP32(prsi.tokens[7]);
 10767         // !!! FIXME: there are a lot of fields here I don't know about.
 10766 
 10768         // !!! FIXME:  maybe [2] and [3] are for int4 and bool registers?
 10767     prsi.tokcount -= 8;
 10769         //const uint32 output_reg_count = SWAP32(prsi.tokens[4]);
 10768     prsi.tokens += 8;
 10770         // !!! FIXME:  maybe [5] and [6] are for int4 and bool registers?
 10769 
 10771         output_map_count = SWAP32(prsi.tokens[7]);
 10770     if (prsi.tokcount < ((output_map_count + 1) * 2))
 10772 
 10771     {
 10773         prsi.tokcount -= 8;
 10772         fail(ctx, "Bogus preshader PRSI data");
 10774         prsi.tokens += 8;
 10773         return;
 10775 
 10774     } // if
 10776         if (prsi.tokcount < ((output_map_count + 1) * 2))
 10775 
 10777         {
 10776     const uint32 *output_map = prsi.tokens;
 10778             fail(ctx, "Bogus preshader PRSI data");
       
 10779             return;
       
 10780         } // if
       
 10781 
       
 10782         output_map = prsi.tokens;
       
 10783     } // if
 10777 
 10784 
 10778     // Now we'll figure out the CTAB...
 10785     // Now we'll figure out the CTAB...
 10779     CtabData ctabdata = { 0, 0, 0 };
 10786     CtabData ctabdata = { 0, 0, 0 };
 10780     parse_constant_table(ctx, ctab.tokens - 1, ctab.tokcount * 4,
 10787     parse_constant_table(ctx, ctab.tokens - 1, ctab.tokcount * 4,
 10781                          version, 0, &ctabdata);
 10788                          version, 0, &ctabdata);
 10791     } // if
 10798     } // if
 10792 
 10799 
 10793     // The FXLC block has the actual instructions...
 10800     // The FXLC block has the actual instructions...
 10794     uint32 opcode_count = SWAP32(fxlc.tokens[1]);
 10801     uint32 opcode_count = SWAP32(fxlc.tokens[1]);
 10795 
 10802 
 10796     size_t len = sizeof (MOJOSHADER_preshaderInstruction) * opcode_count;
 10803     const size_t len = sizeof (MOJOSHADER_preshaderInstruction) * opcode_count;
 10797     preshader->instruction_count = (unsigned int) opcode_count;
 10804     preshader->instruction_count = (unsigned int) opcode_count;
 10798     preshader->instructions = (MOJOSHADER_preshaderInstruction *)
 10805     preshader->instructions = (MOJOSHADER_preshaderInstruction *) Malloc(ctx, len);
 10799                                 Malloc(ctx, len);
       
 10800     if (preshader->instructions == NULL)
 10806     if (preshader->instructions == NULL)
 10801         return;
 10807         return;
 10802     memset(preshader->instructions, '\0', len);
 10808     memset(preshader->instructions, '\0', len);
 10803 
 10809 
 10804     fxlc.tokens += 2;
 10810     fxlc.tokens += 2;
 10870         MOJOSHADER_preshaderOperand *operand = inst->operands;
 10876         MOJOSHADER_preshaderOperand *operand = inst->operands;
 10871         while (operand_count--)
 10877         while (operand_count--)
 10872         {
 10878         {
 10873             const unsigned int item = (unsigned int) SWAP32(fxlc.tokens[2]);
 10879             const unsigned int item = (unsigned int) SWAP32(fxlc.tokens[2]);
 10874 
 10880 
 10875             // !!! FIXME: don't know what first token does.
 10881             // !!! FIXME: Is this used anywhere other than INPUT? -flibit
       
 10882             const uint32 numarrays = SWAP32(fxlc.tokens[0]);
 10876             switch (SWAP32(fxlc.tokens[1]))
 10883             switch (SWAP32(fxlc.tokens[1]))
 10877             {
 10884             {
 10878                 case 1:  // literal from CLIT block.
 10885                 case 1:  // literal from CLIT block.
 10879                 {
 10886                 {
 10880                     if (item > preshader->literal_count)
 10887                     if ((item + inst->element_count) >= preshader->literal_count)
 10881                     {
 10888                     {
 10882                         fail(ctx, "Bogus preshader literal index.");
 10889                         fail(ctx, "Bogus preshader literal index.");
 10883                         break;
 10890                         break;
 10884                     } // if
 10891                     } // if
 10885                     operand->type = MOJOSHADER_PRESHADEROPERAND_LITERAL;
 10892                     operand->type = MOJOSHADER_PRESHADEROPERAND_LITERAL;
 10886                     break;
 10893                     break;
 10887                 } // case
 10894                 } // case
 10888 
 10895 
 10889                 case 2:  // item from ctabdata.
 10896                 case 2:  // item from ctabdata.
 10890                 {
 10897                 {
 10891                     int i;
       
 10892                     MOJOSHADER_symbol *sym = ctabdata.symbols;
 10898                     MOJOSHADER_symbol *sym = ctabdata.symbols;
 10893                     for (i = 0; i < ctabdata.symbol_count; i++, sym++)
 10899                     const uint32 symcount = (uint32) ctabdata.symbol_count;
       
 10900                     for (i = 0; i < symcount; i++, sym++)
 10894                     {
 10901                     {
 10895                         const uint32 base = sym->register_index * 4;
 10902                         const uint32 base = sym->register_index * 4;
 10896                         const uint32 count = sym->register_count * 4;
 10903                         const uint32 count = sym->register_count * 4;
 10897                         assert(sym->register_set==MOJOSHADER_SYMREGSET_FLOAT4);
 10904                         assert(sym->register_set==MOJOSHADER_SYMREGSET_FLOAT4);
 10898                         if ( (base <= item) && ((base + count) > item) )
 10905                         if ( (base <= item) && ((base + count) >= (item + inst->element_count)) )
 10899                             break;
 10906                             break;
 10900                     } // for
 10907                     } // for
 10901                     if (i == ctabdata.symbol_count)
 10908                     if (i == ctabdata.symbol_count)
 10902                     {
 10909                     {
 10903                         fail(ctx, "Bogus preshader input index.");
 10910                         fail(ctx, "Bogus preshader input index.");
 10904                         break;
 10911                         break;
 10905                     } // if
 10912                     } // if
 10906                     operand->type = MOJOSHADER_PRESHADEROPERAND_INPUT;
 10913                     operand->type = MOJOSHADER_PRESHADEROPERAND_INPUT;
       
 10914                     if (numarrays > 0)
       
 10915                     {
       
 10916                         // malloc the array symbol name array
       
 10917                         const uint32 siz = numarrays * sizeof (uint32);
       
 10918                         operand->array_register_count = numarrays;
       
 10919                         operand->array_registers = (uint32 *) Malloc(ctx, siz);
       
 10920                         memset(operand->array_registers, '\0', siz);
       
 10921                         // Get each register base, indicating the arrays used.
       
 10922                         // !!! FIXME: fail if fxlc.tokcount*2 > numarrays ?
       
 10923                         for (i = 0; i < numarrays; i++)
       
 10924                         {
       
 10925                             const uint32 jmp = SWAP32(fxlc.tokens[4]);
       
 10926                             const uint32 bigjmp = (jmp >> 4) * 4;
       
 10927                             const uint32 ltljmp = (jmp >> 2) & 3;
       
 10928                             operand->array_registers[i] = bigjmp + ltljmp;
       
 10929                             fxlc.tokens += 2;
       
 10930                             fxlc.tokcount -= 2;
       
 10931                         } // for
       
 10932                     } // if
 10907                     break;
 10933                     break;
 10908                 } // case
 10934                 } // case
 10909 
 10935 
 10910                 case 4:
 10936                 case 4:
 10911                 {
 10937                 {
 10912                     int i;
 10938                     operand->type = MOJOSHADER_PRESHADEROPERAND_OUTPUT;
       
 10939 
 10913                     for (i = 0; i < output_map_count; i++)
 10940                     for (i = 0; i < output_map_count; i++)
 10914                     {
 10941                     {
 10915                         const uint32 base = output_map[(i*2)] * 4;
 10942                         const uint32 base = output_map[(i*2)] * 4;
 10916                         const uint32 count = output_map[(i*2)+1] * 4;
 10943                         const uint32 count = output_map[(i*2)+1] * 4;
 10917                         if ( (base <= item) && ((base + count) > item) )
 10944                         if ( (base <= item) && ((base + count) >= (item + inst->element_count)) )
 10918                             break;
 10945                             break;
 10919                     } // for
 10946                     } // for
       
 10947 
 10920                     if (i == output_map_count)
 10948                     if (i == output_map_count)
 10921                     {
 10949                     {
 10922                         fail(ctx, "Bogus preshader output index.");
 10950                         if (prsi.seen)  // No PRSI tokens, no output map.
 10923                         break;
 10951                             fail(ctx, "Bogus preshader output index.");
 10924                     } // if
 10952                     } // if
 10925 
 10953 
 10926                     operand->type = MOJOSHADER_PRESHADEROPERAND_OUTPUT;
       
 10927                     break;
 10954                     break;
 10928                 } // case
 10955                 } // case
 10929 
 10956 
 10930                 case 7:
 10957                 case 7:
 10931                 {
 10958                 {
 10932                     operand->type = MOJOSHADER_PRESHADEROPERAND_TEMP;
 10959                     operand->type = MOJOSHADER_PRESHADEROPERAND_TEMP;
 10933                     if (item >= preshader->temp_count)
 10960                     if (item >= preshader->temp_count)
 10934                         preshader->temp_count = item + 1;
 10961                         preshader->temp_count = item + inst->element_count;
 10935                     break;
 10962                     break;
 10936                 } // case
 10963                 } // case
 10937             } // switch
 10964             } // switch
 10938 
 10965 
 10939             operand->index = item;
 10966             operand->index = item;
 10949     // Registers need to be vec4, round up to nearest 4
 10976     // Registers need to be vec4, round up to nearest 4
 10950     preshader->temp_count = (preshader->temp_count + 3) & ~3;
 10977     preshader->temp_count = (preshader->temp_count + 3) & ~3;
 10951 
 10978 
 10952     unsigned int largest = 0;
 10979     unsigned int largest = 0;
 10953     const MOJOSHADER_symbol *sym = preshader->symbols;
 10980     const MOJOSHADER_symbol *sym = preshader->symbols;
 10954     int i;
 10981     const uint32 symcount = (uint32) preshader->symbol_count;
 10955     for (i = 0; i < preshader->symbol_count; i++, sym++)
 10982     for (i = 0; i < symcount; i++, sym++)
 10956     {
 10983     {
 10957         const unsigned int val = sym->register_index + sym->register_count;
 10984         const unsigned int val = sym->register_index + sym->register_count;
 10958         if (val > largest)
 10985         if (val > largest)
 10959             largest = val;
 10986             largest = val;
 10960     } // for
 10987     } // for
 10967         preshader->register_count = largest;
 10994         preshader->register_count = largest;
 10968     } // if
 10995     } // if
 10969 #endif
 10996 #endif
 10970 } // parse_preshader
 10997 } // parse_preshader
 10971 
 10998 
 10972 
       
 10973 static int parse_comment_token(Context *ctx)
 10999 static int parse_comment_token(Context *ctx)
 10974 {
 11000 {
 10975     uint32 commenttoks = 0;
 11001     uint32 commenttoks = 0;
 10976     if (is_comment_token(ctx, *ctx->tokens, &commenttoks))
 11002     if (is_comment_token(ctx, *ctx->tokens, &commenttoks))
 10977     {
 11003     {
 10978         if ((commenttoks >= 1) && (commenttoks < ctx->tokencount))
 11004         if ((commenttoks >= 2) && (commenttoks < ctx->tokencount))
 10979         {
 11005         {
 10980             const uint32 id = SWAP32(ctx->tokens[1]);
 11006             const uint32 id = SWAP32(ctx->tokens[1]);
 10981             if (id == PRES_ID)
 11007             if (id == PRES_ID)
 10982                 parse_preshader(ctx, commenttoks);
 11008                 parse_preshader(ctx, ctx->tokens + 2, commenttoks - 2);
 10983             else if (id == CTAB_ID)
 11009             else if (id == CTAB_ID)
 10984             {
 11010             {
 10985                 parse_constant_table(ctx, ctx->tokens, commenttoks * 4,
 11011                 parse_constant_table(ctx, ctx->tokens, commenttoks * 4,
 10986                                      ctx->version_token, 1, &ctx->ctab);
 11012                                      ctx->version_token, 1, &ctx->ctab);
 10987             } // else if
 11013             } // else if
 11133     } // if
 11159     } // if
 11134 
 11160 
 11135     if (mainfn)
 11161     if (mainfn)
 11136         ctx->mainfn = StrDup(ctx, mainfn);
 11162         ctx->mainfn = StrDup(ctx, mainfn);
 11137 
 11163 
 11138     const int profileid = find_profile_id(profile);
 11164     if (profile != NULL)
 11139     ctx->profileid = profileid;
 11165     {
 11140     if (profileid >= 0)
 11166         const int profileid = find_profile_id(profile);
 11141         ctx->profile = &profiles[profileid];
 11167         ctx->profileid = profileid;
 11142     else
 11168         if (profileid >= 0)
 11143         failf(ctx, "Profile '%s' is unknown or unsupported", profile);
 11169             ctx->profile = &profiles[profileid];
       
 11170         else
       
 11171             failf(ctx, "Profile '%s' is unknown or unsupported", profile);
       
 11172     } // if
 11144 
 11173 
 11145     return ctx;
 11174     return ctx;
 11146 } // build_context
 11175 } // build_context
 11147 
 11176 
 11148 
 11177 
 11219         free_reglist(f, d, ctx->attributes.next);
 11248         free_reglist(f, d, ctx->attributes.next);
 11220         free_reglist(f, d, ctx->samplers.next);
 11249         free_reglist(f, d, ctx->samplers.next);
 11221         free_variable_list(f, d, ctx->variables);
 11250         free_variable_list(f, d, ctx->variables);
 11222         errorlist_destroy(ctx->errors);
 11251         errorlist_destroy(ctx->errors);
 11223         free_symbols(f, d, ctx->ctab.symbols, ctx->ctab.symbol_count);
 11252         free_symbols(f, d, ctx->ctab.symbols, ctx->ctab.symbol_count);
 11224         MOJOSHADER_freePreshader(ctx->preshader, f, d);
 11253         MOJOSHADER_freePreshader(ctx->preshader);
 11225         f((void *) ctx->mainfn, d);
 11254         f((void *) ctx->mainfn, d);
 11226         f(ctx, d);
 11255         f(ctx, d);
 11227     } // if
 11256     } // if
 11228 } // destroy_context
 11257 } // destroy_context
 11229 
 11258 
 11880 
 11909 
 11881     ctx = build_context(profile, mainfn, tokenbuf, bufsize, swiz, swizcount,
 11910     ctx = build_context(profile, mainfn, tokenbuf, bufsize, swiz, swizcount,
 11882                         smap, smapcount, m, f, d);
 11911                         smap, smapcount, m, f, d);
 11883     if (ctx == NULL)
 11912     if (ctx == NULL)
 11884         return &MOJOSHADER_out_of_mem_data;
 11913         return &MOJOSHADER_out_of_mem_data;
 11885 	
 11914 
       
 11915     if (profile == NULL)  // build_context allows NULL; check this ourselves.
       
 11916         fail(ctx, "Profile name is NULL");
       
 11917 
 11886     if (isfail(ctx))
 11918     if (isfail(ctx))
 11887     {
 11919     {
 11888         retval = build_parsedata(ctx);
 11920         retval = build_parsedata(ctx);
 11889         destroy_context(ctx);
 11921         destroy_context(ctx);
 11890         return retval;
 11922         return retval;
 12005     for (i = 0; i < data->sampler_count; i++)
 12037     for (i = 0; i < data->sampler_count; i++)
 12006         f((void *) data->samplers[i].name, d);
 12038         f((void *) data->samplers[i].name, d);
 12007     f((void *) data->samplers, d);
 12039     f((void *) data->samplers, d);
 12008 
 12040 
 12009     free_symbols(f, d, data->symbols, data->symbol_count);
 12041     free_symbols(f, d, data->symbols, data->symbol_count);
 12010     MOJOSHADER_freePreshader(data->preshader, f, d);
 12042     MOJOSHADER_freePreshader(data->preshader);
 12011 
 12043 
 12012     f(data, d);
 12044     f(data, d);
 12013 } // MOJOSHADER_freeParseData
 12045 } // MOJOSHADER_freeParseData
 12014 
 12046 
 12015 
 12047 
 12042     return -1;  // unknown profile?
 12074     return -1;  // unknown profile?
 12043 } // MOJOSHADER_maxShaderModel
 12075 } // MOJOSHADER_maxShaderModel
 12044 
 12076 
 12045 
 12077 
 12046 const MOJOSHADER_preshader *MOJOSHADER_parsePreshader(const unsigned char *buf,
 12078 const MOJOSHADER_preshader *MOJOSHADER_parsePreshader(const unsigned char *buf,
 12047                                                       const unsigned int _len,
 12079                                                       const unsigned int buflen,
 12048                                                       MOJOSHADER_malloc m,
 12080                                                       MOJOSHADER_malloc m,
 12049                                                       MOJOSHADER_free f,
 12081                                                       MOJOSHADER_free f,
 12050                                                       void *d)
 12082                                                       void *d)
 12051 {
 12083 {
 12052     // !!! FIXME: This is copypasta ripped from parse_preshader -flibit
 12084     MOJOSHADER_preshader *retval = NULL;
 12053     unsigned int i;
 12085 
 12054 
 12086     // We need just enough Context for allocators and error state.
 12055     // All sections of a preshader are packed into separate comment tokens,
 12087     Context *ctx = build_context(NULL, NULL, buf, buflen, NULL, 0, NULL, 0, m, f, d);
 12056     //  inside the containing comment token block. Find them all before
 12088     parse_preshader(ctx, ctx->tokens, ctx->tokencount);
 12057     //  we start, so we don't care about the order they appear in the file.
 12089     if (!isfail(ctx))
 12058     PreshaderBlockInfo ctab = { 0, 0, 0 };
 12090     {
 12059     PreshaderBlockInfo prsi = { 0, 0, 0 };
 12091         retval = ctx->preshader;
 12060     PreshaderBlockInfo fxlc = { 0, 0, 0 };
 12092         ctx->preshader = NULL;  // don't let destroy_context() eat the retval.
 12061     PreshaderBlockInfo clit = { 0, 0, 0 };
 12093     } // if
 12062 
 12094 
 12063     CtabData ctabdata = { 0, 0, 0 };
 12095     destroy_context(ctx);
 12064 
 12096     return retval;
 12065     const uint32 *tokens = (const uint32 *) buf;
       
 12066     uint32 tokcount = _len / 4;
       
 12067 
       
 12068     // !!! FIXME: This is stupid. -flibit
       
 12069     Context fillerContext;
       
 12070     fillerContext.malloc = m;
       
 12071     fillerContext.free = f;
       
 12072     fillerContext.malloc_data = d;
       
 12073     fillerContext.out_of_memory = 0;
       
 12074 
       
 12075     MOJOSHADER_preshader *preshader = NULL;
       
 12076 
       
 12077     const uint32 version_magic = 0x46580000;
       
 12078     const uint32 min_version = 0x00000200 | version_magic;
       
 12079     const uint32 max_version = 0x00000201 | version_magic;
       
 12080     const uint32 version = SWAP32(tokens[0]);
       
 12081     if (version < min_version || version > max_version)
       
 12082     {
       
 12083         // fail because the shader will malfunction w/o this.
       
 12084         goto parsePreshader_notAPreshader;
       
 12085     } // if
       
 12086 
       
 12087     tokens++;
       
 12088     tokcount++;
       
 12089 
       
 12090     while (tokcount > 0)
       
 12091     {
       
 12092         uint32 subtokcount = 0;
       
 12093         // !!! FIXME: Passing a NULL ctx! -flibit
       
 12094         if ( (!is_comment_token(&fillerContext, *tokens, &subtokcount)) ||
       
 12095              (subtokcount > tokcount) )
       
 12096         {
       
 12097             goto parsePreshader_notAPreshader;
       
 12098         } // if
       
 12099 
       
 12100         tokens++;
       
 12101         tokcount--;
       
 12102 
       
 12103         const uint32 *nexttokens = tokens + subtokcount;
       
 12104         const uint32 nexttokcount = tokcount - subtokcount;
       
 12105 
       
 12106         if (subtokcount > 0)
       
 12107         {
       
 12108             switch (SWAP32(*tokens))
       
 12109             {
       
 12110                 #define PRESHADER_BLOCK_CASE(id, var) \
       
 12111                     case id##_ID: { \
       
 12112                         if (var.seen) \
       
 12113                             goto parsePreshader_notAPreshader; \
       
 12114                         var.tokens = tokens; \
       
 12115                         var.tokcount = subtokcount; \
       
 12116                         var.seen = 1; \
       
 12117                         break; \
       
 12118                     }
       
 12119                 PRESHADER_BLOCK_CASE(CTAB, ctab);
       
 12120                 PRESHADER_BLOCK_CASE(PRSI, prsi);
       
 12121                 PRESHADER_BLOCK_CASE(FXLC, fxlc);
       
 12122                 PRESHADER_BLOCK_CASE(CLIT, clit);
       
 12123                 default:
       
 12124                     // Bogus preshader section
       
 12125                     goto parsePreshader_notAPreshader;
       
 12126                 #undef PRESHADER_BLOCK_CASE
       
 12127             } // switch
       
 12128         } // if
       
 12129 
       
 12130         tokens = nexttokens;
       
 12131         tokcount = nexttokcount;
       
 12132     } // while
       
 12133 
       
 12134     if (!ctab.seen) // No CTAB block in preshader
       
 12135         goto parsePreshader_notAPreshader;
       
 12136     if (!fxlc.seen) // No FXLC block in preshader
       
 12137         goto parsePreshader_notAPreshader;
       
 12138     if (!clit.seen) // No CLIT block in preshader
       
 12139         goto parsePreshader_notAPreshader;
       
 12140 
       
 12141     preshader = (MOJOSHADER_preshader *) m(sizeof (MOJOSHADER_preshader), d);
       
 12142     if (preshader == NULL)
       
 12143         goto parsePreshader_outOfMemory;
       
 12144     memset(preshader, '\0', sizeof (MOJOSHADER_preshader));
       
 12145 
       
 12146     // Let's set up the constant literals first...
       
 12147     if (clit.tokcount == 0) // Bogus CLIT block in preshader
       
 12148         goto parsePreshader_notAPreshader;
       
 12149     else
       
 12150     {
       
 12151         const uint32 lit_count = SWAP32(clit.tokens[1]);
       
 12152         if (lit_count > ((clit.tokcount - 2) / 2))
       
 12153             // Bogus CLIT block in preshader
       
 12154             goto parsePreshader_notAPreshader;
       
 12155         else if (lit_count > 0)
       
 12156         {
       
 12157             preshader->literal_count = (unsigned int) lit_count;
       
 12158             assert(sizeof (double) == 8);  // just in case.
       
 12159             const size_t len = sizeof (double) * lit_count;
       
 12160             preshader->literals = (double *) m(len, d);
       
 12161             if (preshader->literals == NULL)
       
 12162                 goto parsePreshader_notAPreshader;  // oh well.
       
 12163             const double *litptr = (const double *) (clit.tokens + 2);
       
 12164             for (i = 0; i < lit_count; i++)
       
 12165                 preshader->literals[i] = SWAPDBL(litptr[i]);
       
 12166         } // else if
       
 12167     } // else
       
 12168 
       
 12169     // Parse out the PRSI block. This is used to map the output registers.
       
 12170     uint32 output_map_count = 0;
       
 12171     const uint32 *output_map = NULL;
       
 12172     if (prsi.seen)
       
 12173     {
       
 12174         if (prsi.tokcount < 8) // Bogus preshader PRSI data
       
 12175             goto parsePreshader_notAPreshader;
       
 12176 
       
 12177         //const uint32 first_output_reg = SWAP32(prsi.tokens[1]);
       
 12178         // !!! FIXME: there are a lot of fields here I don't know about.
       
 12179         // !!! FIXME:  maybe [2] and [3] are for int4 and bool registers?
       
 12180         //const uint32 output_reg_count = SWAP32(prsi.tokens[4]);
       
 12181         // !!! FIXME:  maybe [5] and [6] are for int4 and bool registers?
       
 12182         output_map_count = SWAP32(prsi.tokens[7]);
       
 12183 
       
 12184         prsi.tokcount -= 8;
       
 12185         prsi.tokens += 8;
       
 12186 
       
 12187         if (prsi.tokcount < ((output_map_count + 1) * 2))
       
 12188             // Bogus preshader PRSI data
       
 12189             goto parsePreshader_notAPreshader;
       
 12190 
       
 12191         output_map = prsi.tokens;
       
 12192     }
       
 12193 
       
 12194     // Now we'll figure out the CTAB...
       
 12195     parse_constant_table(&fillerContext, ctab.tokens - 1, ctab.tokcount * 4,
       
 12196                          version, 0, &ctabdata);
       
 12197 
       
 12198     // preshader owns this now. Don't free it in this function.
       
 12199     preshader->symbol_count = ctabdata.symbol_count;
       
 12200     preshader->symbols = ctabdata.symbols;
       
 12201 
       
 12202     if (!ctabdata.have_ctab) // Bogus preshader CTAB data
       
 12203         goto parsePreshader_notAPreshader;
       
 12204 
       
 12205     // The FXLC block has the actual instructions...
       
 12206     uint32 opcode_count = SWAP32(fxlc.tokens[1]);
       
 12207 
       
 12208     size_t len = sizeof (MOJOSHADER_preshaderInstruction) * opcode_count;
       
 12209     preshader->instruction_count = (unsigned int) opcode_count;
       
 12210     preshader->instructions = (MOJOSHADER_preshaderInstruction *)
       
 12211                                 m(len, d);
       
 12212     if (preshader->instructions == NULL)
       
 12213         goto parsePreshader_outOfMemory;
       
 12214     memset(preshader->instructions, '\0', len);
       
 12215 
       
 12216     fxlc.tokens += 2;
       
 12217     fxlc.tokcount -= 2;
       
 12218     if (opcode_count > (fxlc.tokcount / 2)) // Bogus preshader FXLC block
       
 12219         goto parsePreshader_notAPreshader;
       
 12220 
       
 12221     MOJOSHADER_preshaderInstruction *inst = preshader->instructions;
       
 12222     while (opcode_count--)
       
 12223     {
       
 12224         const uint32 opcodetok = SWAP32(fxlc.tokens[0]);
       
 12225         MOJOSHADER_preshaderOpcode opcode = MOJOSHADER_PRESHADEROP_NOP;
       
 12226         switch ((opcodetok >> 16) & 0xFFFF)
       
 12227         {
       
 12228             case 0x1000: opcode = MOJOSHADER_PRESHADEROP_MOV; break;
       
 12229             case 0x1010: opcode = MOJOSHADER_PRESHADEROP_NEG; break;
       
 12230             case 0x1030: opcode = MOJOSHADER_PRESHADEROP_RCP; break;
       
 12231             case 0x1040: opcode = MOJOSHADER_PRESHADEROP_FRC; break;
       
 12232             case 0x1050: opcode = MOJOSHADER_PRESHADEROP_EXP; break;
       
 12233             case 0x1060: opcode = MOJOSHADER_PRESHADEROP_LOG; break;
       
 12234             case 0x1070: opcode = MOJOSHADER_PRESHADEROP_RSQ; break;
       
 12235             case 0x1080: opcode = MOJOSHADER_PRESHADEROP_SIN; break;
       
 12236             case 0x1090: opcode = MOJOSHADER_PRESHADEROP_COS; break;
       
 12237             case 0x10A0: opcode = MOJOSHADER_PRESHADEROP_ASIN; break;
       
 12238             case 0x10B0: opcode = MOJOSHADER_PRESHADEROP_ACOS; break;
       
 12239             case 0x10C0: opcode = MOJOSHADER_PRESHADEROP_ATAN; break;
       
 12240             case 0x2000: opcode = MOJOSHADER_PRESHADEROP_MIN; break;
       
 12241             case 0x2010: opcode = MOJOSHADER_PRESHADEROP_MAX; break;
       
 12242             case 0x2020: opcode = MOJOSHADER_PRESHADEROP_LT; break;
       
 12243             case 0x2030: opcode = MOJOSHADER_PRESHADEROP_GE; break;
       
 12244             case 0x2040: opcode = MOJOSHADER_PRESHADEROP_ADD; break;
       
 12245             case 0x2050: opcode = MOJOSHADER_PRESHADEROP_MUL; break;
       
 12246             case 0x2060: opcode = MOJOSHADER_PRESHADEROP_ATAN2; break;
       
 12247             case 0x2080: opcode = MOJOSHADER_PRESHADEROP_DIV; break;
       
 12248             case 0x3000: opcode = MOJOSHADER_PRESHADEROP_CMP; break;
       
 12249             case 0x3010: opcode = MOJOSHADER_PRESHADEROP_MOVC; break;
       
 12250             case 0x5000: opcode = MOJOSHADER_PRESHADEROP_DOT; break;
       
 12251             case 0x5020: opcode = MOJOSHADER_PRESHADEROP_NOISE; break;
       
 12252             case 0xA000: opcode = MOJOSHADER_PRESHADEROP_MIN_SCALAR; break;
       
 12253             case 0xA010: opcode = MOJOSHADER_PRESHADEROP_MAX_SCALAR; break;
       
 12254             case 0xA020: opcode = MOJOSHADER_PRESHADEROP_LT_SCALAR; break;
       
 12255             case 0xA030: opcode = MOJOSHADER_PRESHADEROP_GE_SCALAR; break;
       
 12256             case 0xA040: opcode = MOJOSHADER_PRESHADEROP_ADD_SCALAR; break;
       
 12257             case 0xA050: opcode = MOJOSHADER_PRESHADEROP_MUL_SCALAR; break;
       
 12258             case 0xA060: opcode = MOJOSHADER_PRESHADEROP_ATAN2_SCALAR; break;
       
 12259             case 0xA080: opcode = MOJOSHADER_PRESHADEROP_DIV_SCALAR; break;
       
 12260             case 0xD000: opcode = MOJOSHADER_PRESHADEROP_DOT_SCALAR; break;
       
 12261             case 0xD020: opcode = MOJOSHADER_PRESHADEROP_NOISE_SCALAR; break;
       
 12262             default:
       
 12263                 // Unknown preshader opcode
       
 12264                 goto parsePreshader_notAPreshader;
       
 12265         } // switch
       
 12266 
       
 12267         uint32 operand_count = SWAP32(fxlc.tokens[1]) + 1;  // +1 for dest.
       
 12268 
       
 12269         inst->opcode = opcode;
       
 12270         inst->element_count = (unsigned int) (opcodetok & 0xFF);
       
 12271         inst->operand_count = (unsigned int) operand_count;
       
 12272 
       
 12273         fxlc.tokens += 2;
       
 12274         fxlc.tokcount -= 2;
       
 12275         if ((operand_count * 3) > fxlc.tokcount)
       
 12276             // Bogus preshader FXLC block
       
 12277             goto parsePreshader_notAPreshader;
       
 12278 
       
 12279         MOJOSHADER_preshaderOperand *operand = inst->operands;
       
 12280         while (operand_count--)
       
 12281         {
       
 12282             const unsigned int item = (unsigned int) SWAP32(fxlc.tokens[2]);
       
 12283 
       
 12284             // !!! FIXME: Is this used anywhere other than INPUT? -flibit
       
 12285             const uint32 numArrays = SWAP32(fxlc.tokens[0]);
       
 12286 
       
 12287             switch (SWAP32(fxlc.tokens[1]))
       
 12288             {
       
 12289                 case 1:  // literal from CLIT block.
       
 12290                 {
       
 12291                     if ((item + inst->element_count) >= preshader->literal_count)
       
 12292                         // Bogus preshader literal index
       
 12293                         goto parsePreshader_notAPreshader;
       
 12294                     operand->type = MOJOSHADER_PRESHADEROPERAND_LITERAL;
       
 12295                     break;
       
 12296                 } // case
       
 12297 
       
 12298                 case 2:  // item from ctabdata.
       
 12299                 {
       
 12300                     MOJOSHADER_symbol *sym = ctabdata.symbols;
       
 12301                     for (i = 0; i < (unsigned int) ctabdata.symbol_count; i++, sym++)
       
 12302                     {
       
 12303                         const uint32 base = sym->register_index * 4;
       
 12304                         const uint32 count = sym->register_count * 4;
       
 12305                         assert(sym->register_set==MOJOSHADER_SYMREGSET_FLOAT4);
       
 12306                         if ( (base <= item) && ((base + count) >= (item + inst->element_count)) )
       
 12307                             break;
       
 12308                     } // for
       
 12309                     if (i == ctabdata.symbol_count)
       
 12310                         // Bogus preshader input index
       
 12311                         goto parsePreshader_notAPreshader;
       
 12312                     operand->type = MOJOSHADER_PRESHADEROPERAND_INPUT;
       
 12313                     if (numArrays > 0)
       
 12314                     {
       
 12315                         // malloc the array symbol name array
       
 12316                         const uint32 siz = numArrays * sizeof (uint32);
       
 12317                         operand->array_register_count = numArrays;
       
 12318                         operand->array_registers = (uint32 *) m(siz, d);
       
 12319                         memset(operand->array_registers, '\0', siz);
       
 12320                         // Get each register base, indicating the arrays used.
       
 12321                         for (i = 0; i < numArrays; i++)
       
 12322                         {
       
 12323                             const uint32 jmp = SWAP32(fxlc.tokens[4]);
       
 12324                             const uint32 bigjmp = (jmp >> 4) * 4;
       
 12325                             const uint32 ltljmp = (jmp >> 2) & 3;
       
 12326                             operand->array_registers[i] = bigjmp + ltljmp;
       
 12327                             fxlc.tokens += 2;
       
 12328                             fxlc.tokcount -= 2;
       
 12329                         } // for
       
 12330                     } // if
       
 12331                     break;
       
 12332                 } // case
       
 12333 
       
 12334                 case 4:
       
 12335                 {
       
 12336                     operand->type = MOJOSHADER_PRESHADEROPERAND_OUTPUT;
       
 12337                     if (!prsi.seen)
       
 12338                         // No PRSI tokens, no output map.
       
 12339                         continue;
       
 12340                     for (i = 0; i < output_map_count; i++)
       
 12341                     {
       
 12342                         const uint32 base = output_map[(i*2)] * 4;
       
 12343                         const uint32 count = output_map[(i*2)+1] * 4;
       
 12344                         if ( (base <= item) && ((base + count) >= (item + inst->element_count)) )
       
 12345                             break;
       
 12346                     } // for
       
 12347                     if (i == output_map_count)
       
 12348                         // Bogus preshader output index
       
 12349                         goto parsePreshader_notAPreshader;
       
 12350                     break;
       
 12351                 } // case
       
 12352 
       
 12353                 case 7:
       
 12354                 {
       
 12355                     operand->type = MOJOSHADER_PRESHADEROPERAND_TEMP;
       
 12356                     if (item >= preshader->temp_count)
       
 12357                         preshader->temp_count = item + inst->element_count;
       
 12358                     break;
       
 12359                 } // case
       
 12360             } // switch
       
 12361 
       
 12362             operand->index = item;
       
 12363 
       
 12364             fxlc.tokens += 3;
       
 12365             fxlc.tokcount -= 3;
       
 12366             operand++;
       
 12367         } // while
       
 12368 
       
 12369         inst++;
       
 12370     } // while
       
 12371 
       
 12372     // Registers need to be vec4, round up to nearest 4
       
 12373     preshader->temp_count = (preshader->temp_count + 3) & ~3;
       
 12374 
       
 12375     unsigned int largest = 0;
       
 12376     const MOJOSHADER_symbol *sym = preshader->symbols;
       
 12377     for (i = 0; i < preshader->symbol_count; i++, sym++)
       
 12378     {
       
 12379         const unsigned int val = sym->register_index + sym->register_count;
       
 12380         if (val > largest)
       
 12381             largest = val;
       
 12382     } // for
       
 12383 
       
 12384     if (largest > 0)
       
 12385     {
       
 12386         const size_t len = largest * sizeof (float) * 4;
       
 12387         preshader->registers = (float *) m(len, d);
       
 12388         memset(preshader->registers, '\0', len);
       
 12389         preshader->register_count = largest;
       
 12390     } // if
       
 12391 
       
 12392     return preshader;
       
 12393 
       
 12394 parsePreshader_notAPreshader:
       
 12395 parsePreshader_outOfMemory:
       
 12396     MOJOSHADER_freePreshader(preshader, f, d);
       
 12397     return NULL;
       
 12398 } // MOJOSHADER_parsePreshader
 12097 } // MOJOSHADER_parsePreshader
 12399 
 12098 
 12400 
 12099 void MOJOSHADER_freePreshader(const MOJOSHADER_preshader *preshader)
 12401 void MOJOSHADER_freePreshader(const MOJOSHADER_preshader *preshader,
 12100 {
 12402                               MOJOSHADER_free f,
       
 12403                               void *d)
       
 12404 {
       
 12405     unsigned int i, j;
       
 12406     if (preshader != NULL)
 12101     if (preshader != NULL)
 12407     {
 12102     {
       
 12103         unsigned int i, j;
       
 12104         void *d = preshader->malloc_data;
       
 12105         MOJOSHADER_free f = preshader->free;
       
 12106         if (f == NULL) f = MOJOSHADER_internal_free;
       
 12107 
 12408         f((void *) preshader->literals, d);
 12108         f((void *) preshader->literals, d);
 12409         for (i = 0; i < preshader->instruction_count; i++)
 12109         for (i = 0; i < preshader->instruction_count; i++)
 12410         {
 12110         {
 12411             for (j = 0; j < preshader->instructions[i].operand_count; j++)
 12111             for (j = 0; j < preshader->instructions[i].operand_count; j++)
 12412                 f((void *) preshader->instructions[i].operands[j].array_registers, d);
 12112                 f((void *) preshader->instructions[i].operands[j].array_registers, d);