From 36e20cd06998d2ef18f9ccd7b296a89fec8a135e Mon Sep 17 00:00:00 2001 From: icculus Date: Thu, 27 Mar 2008 22:35:19 -0400 Subject: [PATCH] [svn] Lots and lots of work on the public API. --HG-- branch : trunk --- mojoshader.c | 409 +++++++++++++++++++++++++++++---------------------- mojoshader.h | 147 ++++++++++++++++-- testparse.c | 67 ++++++++- 3 files changed, 433 insertions(+), 190 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index 961cb56b..7367b136 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -112,17 +112,7 @@ typedef struct emit_comment comment_emitter; } Profile; - -// These are enum values, but they also can be used in bitmasks, so we can -// test if an opcode is acceptable: if (op->shader_types & ourtype) {} ... -typedef enum -{ - SHADER_TYPE_UNKNOWN = 0, - SHADER_TYPE_PIXEL = (1 << 0), - SHADER_TYPE_VERTEX = (1 << 1), - SHADER_TYPE_GEOMETRY = (1 << 2), - SHADER_TYPE_ANY = 0xFFFFFFFF -} ShaderType; +typedef MOJOSHADER_shaderType ShaderType; typedef enum { @@ -280,12 +270,12 @@ struct Context int profileid; const Profile *profile; ShaderType shader_type; - uint32 major_ver; - uint32 minor_ver; + uint8 major_ver; + uint8 minor_ver; DestArgInfo dest_args[1]; SourceArgInfo source_args[4]; uint32 dwords[4]; - uint32 instruction_count; + int instruction_count; uint32 instruction_controls; }; @@ -326,11 +316,15 @@ static inline isfail(const Context *ctx) } // isfail -static const char *out_of_mem_string = "Out of memory"; +static MOJOSHADER_parseData out_of_mem_data = { + "Out of memory", 0, 0, 0, MOJOSHADER_TYPE_UNKNOWN, 0, 0, 0, 0 +}; + +static const char *out_of_mem_str = "Out of memory"; static inline int out_of_memory(Context *ctx) { if (ctx->failstr == NULL) - ctx->failstr = out_of_mem_string; // fail() would call malloc(). + ctx->failstr = out_of_mem_str; // fail() would call malloc(). return FAIL; } // out_of_memory @@ -497,7 +491,7 @@ static const char *get_D3D_register_string(Context *ctx, break; case REGISTER_TYPE_ADDR: // (or REGISTER_TYPE_TEXTURE, same value.) - retval = (ctx->shader_type == SHADER_TYPE_VERTEX) ? "a" : "t"; + retval = (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) ? "a" : "t"; break; case REGISTER_TYPE_RASTOUT: @@ -515,7 +509,7 @@ static const char *get_D3D_register_string(Context *ctx, break; case REGISTER_TYPE_TEXCRDOUT: // (or REGISTER_TYPE_OUTPUT, same value.) - if ((ctx->shader_type==SHADER_TYPE_VERTEX) && (ctx->major_ver>=3)) + if ((ctx->shader_type==MOJOSHADER_TYPE_VERTEX) && (ctx->major_ver>=3)) retval = "o"; else retval = "oT"; @@ -750,9 +744,9 @@ static void emit_D3D_start(Context *ctx) else snprintf(minor_str, sizeof (minor_str), "%u", (uint) minor); - if (ctx->shader_type == SHADER_TYPE_PIXEL) + if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL) shadertype_str = "ps"; - else if (ctx->shader_type == SHADER_TYPE_VERTEX) + else if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) shadertype_str = "vs"; else { @@ -1052,7 +1046,7 @@ static void emit_D3D_DCL(Context *ctx) const char *usage_str = ""; char index_str[16] = { '\0' }; - if (ctx->shader_type == SHADER_TYPE_VERTEX) + if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) { static const char *usagestrs[] = { "_position", "_blendweight", "_blendindices", "_normal", @@ -1182,9 +1176,9 @@ static void emit_GLSL_start(Context *ctx) { const uint major = (uint) ctx->major_ver; const uint minor = (uint) ctx->minor_ver; - if (ctx->shader_type == SHADER_TYPE_PIXEL) + if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL) output_line(ctx, "// Pixel shader, version %u.%u", major, minor); - else if (ctx->shader_type == SHADER_TYPE_VERTEX) + else if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) output_line(ctx, "// Vertex shader, version %u.%u", major, minor); else { @@ -1719,10 +1713,10 @@ static void emit_GLSL_RESERVED(Context *ctx) static const Profile profiles[] = { #if SUPPORT_PROFILE_D3D - { "d3d", emit_D3D_start, emit_D3D_end, emit_D3D_comment }, + { MOJOSHADER_PROFILE_D3D, emit_D3D_start, emit_D3D_end, emit_D3D_comment }, #endif #if SUPPORT_PROFILE_GLSL - { "glsl", emit_GLSL_start, emit_GLSL_end, emit_GLSL_comment }, + { MOJOSHADER_PROFILE_GLSL, emit_GLSL_start, emit_GLSL_end, emit_GLSL_comment }, #endif }; @@ -1770,7 +1764,7 @@ static int parse_destination_token(Context *ctx, DestArgInfo *info) if (info->relative) { - if (ctx->shader_type != SHADER_TYPE_VERTEX) + if (ctx->shader_type != MOJOSHADER_TYPE_VERTEX) return fail(ctx, "Relative addressing in non-vertex shader"); else if (ctx->major_ver < 3) return fail(ctx, "Relative addressing in vertex shader version < 3.0"); @@ -1780,7 +1774,7 @@ static int parse_destination_token(Context *ctx, DestArgInfo *info) const int s = info->result_shift; if (s != 0) { - if (ctx->shader_type != SHADER_TYPE_PIXEL) + if (ctx->shader_type != MOJOSHADER_TYPE_PIXEL) return fail(ctx, "Result shift scale in non-pixel shader"); else if (ctx->major_ver >= 2) return fail(ctx, "Result shift scale in pixel shader version >= 2.0"); @@ -1790,19 +1784,19 @@ static int parse_destination_token(Context *ctx, DestArgInfo *info) if (info->result_mod & MOD_SATURATE) // Saturate (vertex shaders only) { - if (ctx->shader_type != SHADER_TYPE_VERTEX) + if (ctx->shader_type != MOJOSHADER_TYPE_VERTEX) return fail(ctx, "Saturate result mod in non-vertex shader"); } // if if (info->result_mod & MOD_PP) // Partial precision (pixel shaders only) { - if (ctx->shader_type != SHADER_TYPE_PIXEL) + if (ctx->shader_type != MOJOSHADER_TYPE_PIXEL) return fail(ctx, "Partial precision result mod in non-pixel shader"); } // if if (info->result_mod & MOD_CENTROID) // Centroid (pixel shaders only) { - if (ctx->shader_type != SHADER_TYPE_PIXEL) + if (ctx->shader_type != MOJOSHADER_TYPE_PIXEL) return fail(ctx, "Centroid result mod in non-pixel shader"); } // if @@ -1847,7 +1841,7 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) if (info->relative) { - if ((ctx->shader_type == SHADER_TYPE_PIXEL) && (ctx->major_ver < 3)) + if ((ctx->shader_type == MOJOSHADER_TYPE_PIXEL) && (ctx->major_ver < 3)) return fail(ctx, "Relative addressing in pixel shader version < 3.0"); return fail(ctx, "Relative addressing is unsupported"); // !!! FIXME } // if @@ -1940,7 +1934,7 @@ static int parse_args_DCL(Context *ctx) return FAIL; const RegisterType regtype = (RegisterType) ctx->dest_args[0].regtype; - if ((ctx->shader_type == SHADER_TYPE_PIXEL) && (ctx->major_ver >= 3)) + if ((ctx->shader_type == MOJOSHADER_TYPE_PIXEL) && (ctx->major_ver >= 3)) { if (regtype == REGISTER_TYPE_INPUT) reserved_mask = 0x7FFFFFFF; @@ -2002,7 +1996,7 @@ static int parse_args_DCL(Context *ctx) } // else } // if - else if ((ctx->shader_type == SHADER_TYPE_PIXEL) && (ctx->major_ver >= 2)) + else if ((ctx->shader_type == MOJOSHADER_TYPE_PIXEL) && (ctx->major_ver >= 2)) { if (regtype == REGISTER_TYPE_INPUT) reserved_mask = 0x7FFFFFFF; @@ -2019,7 +2013,7 @@ static int parse_args_DCL(Context *ctx) } // else } // if - else if ((ctx->shader_type == SHADER_TYPE_VERTEX) && (ctx->major_ver >= 3)) + else if ((ctx->shader_type == MOJOSHADER_TYPE_VERTEX) && (ctx->major_ver >= 3)) { if ((regtype==REGISTER_TYPE_INPUT) || (regtype==REGISTER_TYPE_OUTPUT)) { @@ -2035,7 +2029,7 @@ static int parse_args_DCL(Context *ctx) } // else } // else if - else if ((ctx->shader_type == SHADER_TYPE_VERTEX) && (ctx->major_ver >= 2)) + else if ((ctx->shader_type == MOJOSHADER_TYPE_VERTEX) && (ctx->major_ver >= 2)) { if (regtype == REGISTER_TYPE_INPUT) { @@ -2173,106 +2167,106 @@ static const Instruction instructions[] = #op, t, args, parse_args_##argsseq, 0, PROFILE_EMITTERS(op) \ } - // !!! FIXME: Some of these SHADER_TYPE_ANYs need to have their scope + // !!! FIXME: Some of these MOJOSHADER_TYPE_ANYs need to have their scope // !!! FIXME: reduced to just PIXEL or VERTEX. - INSTRUCTION(NOP, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(MOV, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(ADD, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(SUB, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(MAD, 4, DSSS, SHADER_TYPE_ANY), - INSTRUCTION(MUL, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(RCP, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(RSQ, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(DP3, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(DP4, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(MIN, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(MAX, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(SLT, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(SGE, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(EXP, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(LOG, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(LIT, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(DST, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(LRP, 4, DSSS, SHADER_TYPE_ANY), - INSTRUCTION(FRC, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(M4X4, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(M4X3, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(M3X4, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(M3X3, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(M3X2, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(CALL, 1, S, SHADER_TYPE_ANY), - INSTRUCTION(CALLNZ, 2, SS, SHADER_TYPE_ANY), - INSTRUCTION(LOOP, 2, SS, SHADER_TYPE_ANY), - INSTRUCTION(RET, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(ENDLOOP, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(LABEL, 1, S, SHADER_TYPE_ANY), - INSTRUCTION(DCL, 2, DCL, SHADER_TYPE_ANY), - INSTRUCTION(POW, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(CRS, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(SGN, 4, DSSS, SHADER_TYPE_ANY), - INSTRUCTION(ABS, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(NRM, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(SINCOS, 4, NULL, SHADER_TYPE_ANY), - INSTRUCTION(REP, 1, S, SHADER_TYPE_ANY), - INSTRUCTION(ENDREP, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(IF, 1, S, SHADER_TYPE_ANY), - INSTRUCTION(IFC, 2, SS, SHADER_TYPE_ANY), - INSTRUCTION(ELSE, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(ENDIF, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(BREAK, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(BREAKC, 2, SS, SHADER_TYPE_ANY), - INSTRUCTION(MOVA, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(DEFB, 2, DEFB, SHADER_TYPE_ANY), - INSTRUCTION(DEFI, 5, DEFI, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(TEXCOORD, -1, TEXCOORD, SHADER_TYPE_PIXEL), - INSTRUCTION(TEXKILL, 1, D, SHADER_TYPE_PIXEL), - INSTRUCTION(TEX, -1, TEXCOORD, SHADER_TYPE_PIXEL), // same parse_args logic as TEXCOORD - INSTRUCTION(TEXBEM, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXBEML, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXREG2AR, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXREG2GB, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X2PAD, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X2TEX, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X3PAD, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X3TEX, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION_STATE(RESERVED, 0, NULL, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X3SPEC, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X3VSPEC, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(EXPP, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(LOGP, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(CND, 4, DSSS, SHADER_TYPE_ANY), - INSTRUCTION(DEF, 5, DEF, SHADER_TYPE_ANY), - INSTRUCTION(TEXREG2RGB, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXDP3TEX, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X2DEPTH, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXDP3, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXM3X3, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXDEPTH, 1, D, SHADER_TYPE_ANY), - INSTRUCTION(CMP, 4, DSSS, SHADER_TYPE_ANY), - INSTRUCTION(BEM, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(DP2ADD, 4, DSSS, SHADER_TYPE_ANY), - INSTRUCTION(DSX, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(DSY, 2, DS, SHADER_TYPE_ANY), - INSTRUCTION(TEXLDD, 5, DSSSS, SHADER_TYPE_ANY), - INSTRUCTION(SETP, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(TEXLDL, 3, DSS, SHADER_TYPE_ANY), - INSTRUCTION(BREAKP, 1, S, SHADER_TYPE_ANY), // src + INSTRUCTION(NOP, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(MOV, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(ADD, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(SUB, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(MAD, 4, DSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(MUL, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(RCP, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(RSQ, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DP3, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DP4, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(MIN, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(MAX, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(SLT, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(SGE, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(EXP, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(LOG, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(LIT, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DST, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(LRP, 4, DSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(FRC, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(M4X4, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(M4X3, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(M3X4, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(M3X3, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(M3X2, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(CALL, 1, S, MOJOSHADER_TYPE_ANY), + INSTRUCTION(CALLNZ, 2, SS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(LOOP, 2, SS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(RET, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(ENDLOOP, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(LABEL, 1, S, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DCL, 2, DCL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(POW, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(CRS, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(SGN, 4, DSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(ABS, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(NRM, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(SINCOS, 4, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(REP, 1, S, MOJOSHADER_TYPE_ANY), + INSTRUCTION(ENDREP, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(IF, 1, S, MOJOSHADER_TYPE_ANY), + INSTRUCTION(IFC, 2, SS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(ELSE, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(ENDIF, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(BREAK, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(BREAKC, 2, SS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(MOVA, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DEFB, 2, DEFB, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DEFI, 5, DEFI, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXCOORD, -1, TEXCOORD, MOJOSHADER_TYPE_PIXEL), + INSTRUCTION(TEXKILL, 1, D, MOJOSHADER_TYPE_PIXEL), + INSTRUCTION(TEX, -1, TEXCOORD, MOJOSHADER_TYPE_PIXEL), // same parse_args logic as TEXCOORD + INSTRUCTION(TEXBEM, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXBEML, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXREG2AR, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXREG2GB, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X2PAD, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X2TEX, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X3PAD, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X3TEX, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION_STATE(RESERVED, 0, NULL, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X3SPEC, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X3VSPEC, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(EXPP, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(LOGP, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(CND, 4, DSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DEF, 5, DEF, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXREG2RGB, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXDP3TEX, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X2DEPTH, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXDP3, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXM3X3, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXDEPTH, 1, D, MOJOSHADER_TYPE_ANY), + INSTRUCTION(CMP, 4, DSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(BEM, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DP2ADD, 4, DSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DSX, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(DSY, 2, DS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXLDD, 5, DSSSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(SETP, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(TEXLDL, 3, DSS, MOJOSHADER_TYPE_ANY), + INSTRUCTION(BREAKP, 1, S, MOJOSHADER_TYPE_ANY), // src #undef INSTRUCTION #undef INSTRUCTION_STATE @@ -2368,14 +2362,14 @@ static int parse_version_token(Context *ctx) const uint32 token = SWAP32(*(ctx->tokens)); const uint32 shadertype = ((token >> 16) & 0xFFFF); - const uint32 major = (uint32) ((token >> 8) & 0xFF); - const uint32 minor = (uint32) (token & 0xFF); + const uint8 major = (uint8) ((token >> 8) & 0xFF); + const uint8 minor = (uint8) (token & 0xFF); // 0xFFFF == pixel shader, 0xFFFE == vertex shader if (shadertype == 0xFFFF) - ctx->shader_type = SHADER_TYPE_PIXEL; + ctx->shader_type = MOJOSHADER_TYPE_PIXEL; else if (shadertype == 0xFFFE) - ctx->shader_type = SHADER_TYPE_VERTEX; + ctx->shader_type = MOJOSHADER_TYPE_VERTEX; else // geometry shader? Bogus data? return fail(ctx, "Unsupported shader type or not a shader at all"); @@ -2405,11 +2399,21 @@ static int parse_comment_token(Context *ctx) const uint32 commenttoks = ((token >> 16) & 0xFFFF); const uint32 len = commenttoks * sizeof (uint32); const int needmalloc = (len >= SCRATCH_BUFFER_SIZE); - char *str = ((needmalloc) ? (char *) ctx->malloc(len + 1) : - get_scratch_buffer(ctx)); + char *str = NULL; + + if (!needmalloc) + str = get_scratch_buffer(ctx); + else + { + str = (char *) ctx->malloc(len + 1); + if (str == NULL) + return out_of_memory(ctx); + } // else + memcpy(str, (const char *) (ctx->tokens+1), len); str[len] = '\0'; ctx->profile->comment_emitter(ctx, str); + if (needmalloc) ctx->free(str); @@ -2487,9 +2491,9 @@ static int find_profile_id(const char *profile) static Context *build_context(const char *profile, - const unsigned char *tokenbuf, - const unsigned int bufsize, - MOJOSHADER_malloc m, MOJOSHADER_free f) + const unsigned char *tokenbuf, + const unsigned int bufsize, + MOJOSHADER_malloc m, MOJOSHADER_free f) { if (m == NULL) m = internal_malloc; if (f == NULL) f = internal_free; @@ -2511,27 +2515,32 @@ static Context *build_context(const char *profile, const int profileid = find_profile_id(profile); ctx->profileid = profileid; - if (profileid >= 0) // we'll fail later, but we still need the context! + if (profileid >= 0) ctx->profile = &profiles[profileid]; - - return ctx; + else + failf(ctx, "Profile '%s' is unknown or unsupported", profile); } // build_context static void destroy_context(Context *ctx) { - OutputList *item = ctx->output.next; - while (item != NULL) + if (ctx != NULL) { - OutputList *next = item->next; - ctx->free(item->str); - ctx->free(item); - item = next; - } // for + MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : internal_free); + OutputList *item = ctx->output.next; + while (item != NULL) + { + OutputList *next = item->next; + if (item->str != NULL) + f(item->str); + f(item); + item = next; + } // while - if (ctx->failstr != out_of_mem_string) - ctx->free((void *) ctx->failstr); - ctx->free(ctx); + if ((ctx->failstr != NULL) && (ctx->failstr != out_of_mem_str)) + f((void *) ctx->failstr); + f(ctx); + } // if } // destroy_context @@ -2562,20 +2571,61 @@ static char *build_output(Context *ctx) } // build_output +static MOJOSHADER_parseData *build_parsedata(Context *ctx) +{ + char *output = NULL; + int len = 0; + MOJOSHADER_parseData *retval; + + if ((retval = ctx->malloc(sizeof (MOJOSHADER_parseData))) == NULL) + return &out_of_mem_data; + + memset(retval, '\0', sizeof (MOJOSHADER_parseData)); + + if (!isfail(ctx)) + output = build_output(ctx); + + // check again, in case build_output ran out of memory. + if (isfail(ctx)) + { + if (output != NULL) + ctx->free(output); // just in case. + retval->error = ctx->failstr; // we recycle. :) + ctx->failstr = NULL; // don't let this get free()'d too soon. + } // if + else + { + retval->output = output; + retval->output_len = ctx->output_len; + retval->instruction_count = ctx->instruction_count; + retval->shader_type = ctx->shader_type; + retval->major_ver = (int) ctx->major_ver; + retval->minor_ver = (int) ctx->minor_ver; + retval->malloc = (ctx->malloc == internal_malloc) ? NULL : ctx->malloc; + retval->free = (ctx->free == internal_free) ? NULL : ctx->free; + } // else + + return retval; +} // build_parsedata + + // API entry point... -int MOJOSHADER_parse(const char *profile, const unsigned char *tokenbuf, - const unsigned int bufsize, MOJOSHADER_malloc m, - MOJOSHADER_free f) +const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile, + const unsigned char *tokenbuf, + const unsigned int bufsize, + MOJOSHADER_malloc m, + MOJOSHADER_free f) { + MOJOSHADER_parseData *retval = NULL; + Context *ctx = NULL; int rc = FAIL; - Context *ctx = build_context(profile, tokenbuf, bufsize, m, f); - if (ctx == NULL) - return 0; // !!! FIXME: error string? + if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) ) + return &out_of_mem_data; // supply both or neither. - if (ctx->profile == NULL) - failf(ctx, "Profile '%s' is unknown or unsupported", profile); + if ((ctx = build_context(profile, tokenbuf, bufsize, m, f)) == NULL) + return &out_of_mem_data; if (!isfail(ctx)) { @@ -2591,25 +2641,28 @@ int MOJOSHADER_parse(const char *profile, const unsigned char *tokenbuf, } // while } // if -// if (!isfail(ctx)) - { - char *str = build_output(ctx); - if (str != NULL) - { - printf("OUTPUT:\n%s\n", str); // !!! FIXME: report to caller. - ctx->free(str); - } // if + retval = build_parsedata(ctx); + destroy_context(ctx); + return retval; +} // MOJOSHADER_parse - printf("INSTRUCTION COUNT: %u\n", (uint) ctx->instruction_count); - } // if - if (ctx->failstr != NULL) - printf("FAIL: %s\n", ctx->failstr); +void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *_data) +{ + MOJOSHADER_parseData *data = (MOJOSHADER_parseData *) _data; + if ((data == NULL) || (data == &out_of_mem_data)) + return; // no-op. - destroy_context(ctx); + MOJOSHADER_free f = (data->free == NULL) ? internal_free : data->free; - return (rc == END_OF_STREAM); -} // MOJOSHADER_parse + if (data->output != NULL) // check for NULL in case of dumb free() impl. + f((void *) data->output); + + if ((data->error != NULL) && (data->error != out_of_mem_str)) + f((void *) data->error); + + f(data); +} // MOJOSHADER_freeParseData int MOJOSHADER_version(void) diff --git a/mojoshader.h b/mojoshader.h index 901fb60c..de1b042f 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -15,25 +15,154 @@ extern "C" { #endif /* - * const int compiled_against = MOJOSHADER_VERSION; - * const int linked_against = MOJOSHADER_version(); + * For determining the version of MojoShader you are using: + * const int compiled_against = MOJOSHADER_VERSION; + * const int linked_against = MOJOSHADER_version(); + * + * The version is a single integer that increments, not a major/minor value. */ #define MOJOSHADER_VERSION 1 int MOJOSHADER_version(void); /* * These allocators work just like the C runtime's malloc() and free() - * (in fact, they use malloc() and free() internally if you don't - * specify your own allocator). + * (in fact, they probably use malloc() and free() internally if you don't + * specify your own allocator, but don't rely on that behaviour). */ typedef void *(*MOJOSHADER_malloc)(int bytes); typedef void (*MOJOSHADER_free)(void *ptr); -/* !!! FIXME: documentation. */ -/* !!! FIXME: this needs to change to return a buffer of GLSL code. */ -int MOJOSHADER_parse(const char *profile, const unsigned char *tokenbuf, - const unsigned int bufsize, MOJOSHADER_malloc m, - MOJOSHADER_free f); + +/* + * These are enum values, but they also can be used in bitmasks, so we can + * test if an opcode is acceptable: if (op->shader_types & ourtype) {} ... + */ +typedef enum +{ + MOJOSHADER_TYPE_UNKNOWN = 0, + MOJOSHADER_TYPE_PIXEL = (1 << 0), + MOJOSHADER_TYPE_VERTEX = (1 << 1), + MOJOSHADER_TYPE_GEOMETRY = (1 << 2), /* (not supported yet.) */ + MOJOSHADER_TYPE_ANY = 0xFFFFFFFF /* used for bitmasks */ +} MOJOSHADER_shaderType; + + +/* + * Structure used to return data from parsing of a shader... + */ +typedef struct +{ + /* + * Human-readable error, if there is one. Will be NULL if there was no + * error. The string will be UTF-8 encoded, and English only. Most of + * these shouldn't be shown to the end-user anyhow. + */ + const char *error; + + /* + * Bytes of output from parsing. Most profiles produce a string of source + * code, but profiles that do binary output may not be text at all. + * Will be NULL on error. + */ + const char *output; + + /* + * Byte count for output, not counting any null terminator. Most profiles + * produce an ASCII string of source code, but profiles that do binary + * output may not be text at all. Will be 0 on error. + */ + int output_len; + + /* + * Count of Direct3D instructions we parsed. This is meaningless in terms + * of the actual output, as the profile will probably grow or reduce + * the count (or for high-level languages, not have that information at + * all), but it can give you a rough idea of the size of your shader. + * Will be zero on error. + */ + int instruction_count; + + /* + * The type of shader we parsed. Will be MOJOSHADER_TYPE_UNKNOWN on error. + */ + MOJOSHADER_shaderType shader_type; + + /* + * The shader's major version. If this was a "vs_3_0", this would be 3. + */ + int major_ver; + + /* + * The shader's minor version. If this was a "ps_1_4", this would be 4. + * Two notes: for "vs_2_x", this is 1, and for "vs_3_sw", this is 255. + */ + int minor_ver; + + /* + * This is the malloc implementation you passed to MOJOSHADER_parse(). + */ + MOJOSHADER_malloc malloc; + + /* + * This is the free implementation you passed to MOJOSHADER_parse(). + */ + MOJOSHADER_free free; +} MOJOSHADER_parseData; + + +/* + * Profile string for Direct3D assembly language output. + */ +#define MOJOSHADER_PROFILE_D3D "d3d" + +/* + * Profile string for GLSL: OpenGL high-level shader language output. + */ +#define MOJOSHADER_PROFILE_GLSL "glsl" + +/* + * Parse a compiled Direct3D shader's bytecode. + * + * This is your primary entry point into MojoShader. You need to pass it + * a compiled D3D shader and tell it which "profile" you want to use to + * convert it into useful data. + * + * The available profiles are the set of MOJOSHADER_PROFILE_* defines. + * Note that MojoShader may be built without support for all listed + * profiles (in which case using one here will return with an error). + * + * As parsing requires some memory to be allocated, you may provide a custom + * allocator to this function, which will be used to allocate/free memory. + * They function just like malloc() and free(). We do not use realloc(). + * If you don't care, pass NULL in for the allocator functions. + * + * This function returns a MOJOSHADER_parseData + * + * This function will never return NULL, even if the system is completely + * out of memory upon entry (in which case, this function returns a static + * MOJOSHADER_parseData object, which is still safe to pass to + * MOJOSHADER_freeParseData()). + * + * This function is thread safe, so long (m) and (f) are too, and that + * (tokenbuf) remains intact for the duration of the call. This allows you + * to parse several shaders on separate CPU cores at the same time. + */ +const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile, + const unsigned char *tokenbuf, + const unsigned int bufsize, + MOJOSHADER_malloc m, + MOJOSHADER_free f); + +/* + * Call this to dispose of parsing results when you are done with them. + * This will call the MOJOSHADER_free function you provided to + * MOJOSHADER_parse multiple times, if you provided one. + * Passing a NULL here is a safe no-op. + * + * This function is thread safe, so long as any allocator you passed into + * MOJOSHADER_parse() is, too. + */ +void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *data); #ifdef __cplusplus } diff --git a/testparse.c b/testparse.c index a79569cb..7c7c8318 100644 --- a/testparse.c +++ b/testparse.c @@ -2,20 +2,81 @@ #include #include "mojoshader.h" + +#if DEBUG_MALLOC +static void *Malloc(int len) +{ + void *ptr = malloc(len + sizeof (int)); + int *store = (int *) ptr; + printf("malloc() %d bytes (%p)\n", len, ptr); + if (ptr == NULL) return NULL; + *store = len; + return (void *) (store + 1); +} // Malloc + + +static void Free(void *_ptr) +{ + int *ptr = (((int *) ptr) - 1); + int *store = (int *) ptr; + int len = *store; + printf("free() %d bytes (%p)\n", len, ptr); + free(ptr); +} // Free +#else +#define Malloc NULL +#define Free NULL +#endif + +static const char *shader_type(MOJOSHADER_shaderType s) +{ + switch (s) + { + case MOJOSHADER_TYPE_UNKNOWN: return "unknown"; + case MOJOSHADER_TYPE_PIXEL: return "pixel"; + case MOJOSHADER_TYPE_VERTEX: return "vertex"; + case MOJOSHADER_TYPE_GEOMETRY: return "geometry"; + } // switch + + return "(bogus value?)"; +} // shader_type + + +static void do_parse(unsigned char *buf, int len, const char *prof) +{ + const MOJOSHADER_parseData *pd; + + pd = MOJOSHADER_parse(prof, buf, len, Malloc, Free); + printf("PROFILE: %s\n", prof); + printf("SHADER TYPE: %s\n", shader_type(pd->shader_type)); + printf("VERSION: %d.%d\n", pd->major_ver, pd->minor_ver); + printf("INSTRUCTION COUNT: %d\n", (int) pd->instruction_count); + if (pd->error != NULL) + printf("ERROR: %s\n", pd->error); + if (pd->output != NULL) + printf("OUTPUT:\n%s\n", pd->output); + printf("\n\n"); + MOJOSHADER_freeParseData(pd); +} // do_parse + + int main(int argc, char **argv) { + int i; + printf("Compiled against version %d\n", MOJOSHADER_VERSION); printf("Linked against version %d\n", MOJOSHADER_version()); - if (argv[1] != NULL) + for (i = 1; i < argc; i++) { - FILE *io = fopen(argv[1], "rb"); + FILE *io = fopen(argv[i], "rb"); if (io != NULL) { unsigned char *buf = (unsigned char *) malloc(1000000); int rc = fread(buf, 1, 1000000, io); fclose(io); - MOJOSHADER_parse("d3d", buf, rc, NULL, NULL); + do_parse(buf, rc, MOJOSHADER_PROFILE_D3D); + do_parse(buf, rc, MOJOSHADER_PROFILE_GLSL); free(buf); } // if } // if