From 30b5186597590df6e5bcc130e745c9c0578a74df Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 5 Apr 2008 12:39:02 -0400 Subject: [PATCH] First shot at DCL emitter for GLSL profile. Incomplete. This touched a LOT of code and has a lot of scary implications that I haven't fully explored. This is going to be one of those areas where OpenGL and Direct3D don't have a perfect one-to-one mapping, I think. --HG-- branch : trunk --- mojoshader.c | 286 +++++++++++++++++++++++++++++++++++++-------------- mojoshader.h | 3 +- 2 files changed, 209 insertions(+), 80 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index 0ab8227d..506a0f3b 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -172,24 +172,6 @@ typedef enum MISCTYPE_TYPE_MAX = 1 } MiscTypeType; -typedef enum -{ - DECLUSAGE_POSITION = 0, - DECLUSAGE_BLENDWEIGHT = 1, - DECLUSAGE_BLENDINDICES = 2, - DECLUSAGE_NORMAL = 3, - DECLUSAGE_PSIZE = 4, - DECLUSAGE_TEXCOORD = 5, - DECLUSAGE_TANGENT = 6, - DECLUSAGE_BINORMAL = 7, - DECLUSAGE_TESSFACTOR = 8, - DECLUSAGE_POSITIONT = 9, - DECLUSAGE_COLOR = 10, - DECLUSAGE_FOG = 11, - DECLUSAGE_DEPTH = 12, - DECLUSAGE_SAMPLE = 13 -} DeclUsageType; - typedef enum { TEXTURE_TYPE_2D = 2, @@ -1291,6 +1273,7 @@ static void emit_D3D_DCL(Context *ctx) const DestArgInfo *arg = &ctx->dest_args[0]; const char *usage_str = ""; char index_str[16] = { '\0' }; + const uint32 usage = ctx->dwords[0]; if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) { @@ -1300,30 +1283,26 @@ static void emit_D3D_DCL(Context *ctx) "_positiont", "_color", "_fog", "_depth", "_sample" }; - const uint32 usage = ctx->dwords[0]; const uint32 index = ctx->dwords[1]; - if (usage >= STATICARRAYLEN(usagestrs)) - { - fail(ctx, "unknown DCL usage"); - return; - } // if - usage_str = usagestrs[usage]; if (index != 0) snprintf(index_str, sizeof (index_str), "%u", (uint) index); } // if - else if (arg->regtype == REG_TYPE_SAMPLER) + else if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL) { - switch ((const TextureType) ctx->dwords[0]) + if (arg->regtype == REG_TYPE_SAMPLER) { - case TEXTURE_TYPE_2D: usage_str = "_2d"; break; - case TEXTURE_TYPE_CUBE: usage_str = "_cube"; break; - case TEXTURE_TYPE_VOLUME: usage_str = "_volume"; break; - default: fail(ctx, "unknown sampler texture type"); return; - } // switch + switch ((const TextureType) usage) + { + case TEXTURE_TYPE_2D: usage_str = "_2d"; break; + case TEXTURE_TYPE_CUBE: usage_str = "_cube"; break; + case TEXTURE_TYPE_VOLUME: usage_str = "_volume"; break; + default: fail(ctx, "unknown sampler texture type"); return; + } // switch + } // if } // else if output_line(ctx, "dcl%s%s%s", usage_str, index_str, dst0); @@ -1639,21 +1618,49 @@ static void emit_GLSL_finalize(Context *ctx) pop_output(ctx); } // emit_GLSL_finalize +static void emit_GLSL_DCL(Context *ctx); static void emit_GLSL_global(Context *ctx, RegisterType regtype, int regnum) { push_output(ctx, &ctx->globals); - if (regtype == REG_TYPE_ADDRESS) - output_line(ctx, "ivec4 a%d;", regnum); - else if (regtype == REG_TYPE_PREDICATE) - output_line(ctx, "bvec4 p%d;", regnum); - else if (regtype == REG_TYPE_TEMP) - output_line(ctx, "vec4 r%d;", regnum); - else if (regtype == REG_TYPE_LOOP) - output_line(ctx, "ivec4 aL;"); - else if (regtype == REG_TYPE_LABEL) - ; /* no-op. If we see it here, it means we optimized it out. */ - else - fail(ctx, "BUG: we used a register we don't know how to define."); + switch (regtype) + { + case REG_TYPE_RASTOUT: + case REG_TYPE_ATTROUT: + case REG_TYPE_TEXCRDOUT: + case REG_TYPE_COLOROUT: + case REG_TYPE_DEPTHOUT: + // this happens on shaders which don't have to declare output + // registers before using them. We fake a DCL emit for them now. + assert(!shader_version_atleast(ctx, 3, 0)); + memset(&ctx->dest_args[0], '\0', sizeof (DestArgInfo)); + ctx->dest_args[0].regnum = regnum; + ctx->dest_args[0].writemask = 0xF; + ctx->dest_args[0].writemask0 = 1; + ctx->dest_args[0].writemask1 = 1; + ctx->dest_args[0].writemask2 = 1; + ctx->dest_args[0].writemask3 = 1; + ctx->dest_args[0].regtype = regtype; + emit_GLSL_DCL(ctx); // force a DCL declaration for this register. + break; + + case REG_TYPE_ADDRESS: + output_line(ctx, "ivec4 a%d;", regnum); + break; + case REG_TYPE_PREDICATE: + output_line(ctx, "bvec4 p%d;", regnum); + break; + case REG_TYPE_TEMP: + output_line(ctx, "vec4 r%d;", regnum); + break; + case REG_TYPE_LOOP: + output_line(ctx, "ivec4 aL;"); + break; + case REG_TYPE_LABEL: + break; // no-op. If we see it here, it means we optimized it out. + default: + fail(ctx, "BUG: we used a register we don't know how to define."); + break; + } // switch pop_output(ctx); } // emit_GLSL_global @@ -2039,53 +2046,120 @@ static void emit_GLSL_LABEL(Context *ctx) static void emit_GLSL_DCL(Context *ctx) { -// fail(ctx, "unimplemented."); // !!! FIXME -// !!! FIXME -push_output(ctx, &ctx->globals); -output_line(ctx, "DCL GOES HERE"); -pop_output(ctx); -#if 0 - const char *dst0 = make_GLSL_destarg_string(ctx, 0); + // !!! FIXME: this function doesn't deal with write masks at all yet! + const char *varname = get_GLSL_destarg_varname(ctx, 0); const DestArgInfo *arg = &ctx->dest_args[0]; - const char *usage_str = ""; - char index_str[16] = { '\0' }; + uint32 usage = ctx->dwords[0]; + RegisterType regtype = arg->regtype; if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) { - static const char *usagestrs[] = { - "_position", "_blendweight", "_blendindices", "_normal", - "_psize", "_texcoord", "_tangent", "_binormal", "_tessfactor", - "_positiont", "_color", "_fog", "_depth", "_sample" - }; + // pre-vs3 output registers. + // these don't ever happen in DCL opcodes, I think, but we reuse this + // function from emit_GLSL_global(). Map to vs3 output registers. + if (!shader_version_atleast(ctx, 3, 0)) + { + if (regtype == REG_TYPE_RASTOUT) + { + regtype = REG_TYPE_OUTPUT; + switch ((const RastOutType) arg->regnum) + { + case RASTOUT_TYPE_POSITION: + usage = (uint32) MOJOSHADER_USAGE_POSITION; + break; + case RASTOUT_TYPE_FOG: + usage = (uint32) MOJOSHADER_USAGE_FOG; + break; + case RASTOUT_TYPE_POINT_SIZE: + usage = (uint32) MOJOSHADER_USAGE_POINTSIZE; + break; + } // switch + } // if - const uint32 usage = ctx->dwords[0]; - const uint32 index = ctx->dwords[1]; + else if (regtype == REG_TYPE_ATTROUT) + { + regtype = REG_TYPE_OUTPUT; + usage = MOJOSHADER_USAGE_COLOR; + } // else if - if (usage >= STATICARRAYLEN(usagestrs)) - { - fail(ctx, "unknown DCL usage"); - return; + else if (regtype == REG_TYPE_TEXCRDOUT) + { + regtype = REG_TYPE_OUTPUT; + usage = MOJOSHADER_USAGE_TEXCOORD; + } // else if } // if - usage_str = usagestrs[usage]; + // to avoid limitations of various GL entry points for input + // attributes (glSecondaryColorPointer() can only take 3 component + // items, glVertexPointer() can't do GL_UNSIGNED_BYTE, many other + // issues), we set up all inputs as generic vertex attributes, so we + // can pass data in just about any form, and ignore the built-in GLSL + // attributes like gl_SecondaryColor. Output needs to use the the + // built-ins, though, but we don't have to worry about the GL entry + // point limitations there. - if (index != 0) - snprintf(index_str, sizeof (index_str), "%u", (uint) index); + if (regtype == REG_TYPE_INPUT) + output_line(ctx, "attribute vec4 %s;", varname); + else if (regtype == REG_TYPE_OUTPUT) + { + const uint32 index = ctx->dwords[1]; + const char *usage_str = NULL; + char index_str[16] = { '\0' }; + if (index != 0) // !!! FIXME: a lot of these MUST be zero. + snprintf(index_str, sizeof (index_str), "%u", (uint) index); + + switch (usage) + { + case MOJOSHADER_USAGE_POSITION: + // !!! FIXME: make sure this is index == 0 in state machine. + usage_str = "gl_Position"; + break; + case MOJOSHADER_USAGE_POINTSIZE: + usage_str = "gl_PointSize"; + break; + // !!! FIXME: we need to deal with some built-in varyings here. + default: + fail(ctx, "Don't know how to handle this output register."); + } // switch + + // !!! FIXME: the #define is a little hacky, but it means we don't + // !!! FIXME: have to track these separately if this works. + push_output(ctx, &ctx->globals); + output_line(ctx, "#define %s %s;", varname, usage_str); + pop_output(ctx); + } // else } // if - else if (arg->regtype == REG_TYPE_SAMPLER) +#if 0 // !!! FIXME: write me. + else if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL) { - switch ((const TextureType) ctx->dwords[0]) + if (regtype == REG_TYPE_SAMPLER) { - case TEXTURE_TYPE_2D: usage_str = "_2d"; break; - case TEXTURE_TYPE_CUBE: usage_str = "_cube"; break; - case TEXTURE_TYPE_VOLUME: usage_str = "_volume"; break; - default: fail(ctx, "unknown sampler texture type"); return; - } // switch - } // else if + switch ((const TextureType) usage) + { + case TEXTURE_TYPE_2D: usage_str = "_2d"; break; + case TEXTURE_TYPE_CUBE: usage_str = "_cube"; break; + case TEXTURE_TYPE_VOLUME: usage_str = "_volume"; break; + default: fail(ctx, "unknown sampler texture type"); return; + } // switch + } // if - output_line(ctx, "dcl%s%s%s", usage_str, index_str, dst0); + else if (regtype == REG_TYPE_COLOROUT) + { + retval = "oC"; + } // else if + + else if (regtype == REG_TYPE_DEPTHOUT) + { + retval = "oDepth"; + } // else if + } // else if #endif + + else + { + fail(ctx, "Unknown shader type"); // state machine should catch this. + } // else } // emit_GLSL_DCL static void emit_GLSL_POW(Context *ctx) @@ -2653,12 +2727,12 @@ static int parse_args_DCL(Context *ctx) { const uint32 usage = (token & 0xF); const uint32 index = ((token >> 16) & 0xF); - if (usage == DECLUSAGE_TEXCOORD) + if (usage == MOJOSHADER_USAGE_TEXCOORD) { if (index > 7) return fail(ctx, "DCL texcoord usage must have 0-7 index"); } // if - else if (usage == DECLUSAGE_COLOR) + else if (usage == MOJOSHADER_USAGE_COLOR) { if (index != 0) return fail(ctx, "DCL color usage must have 0 index"); @@ -2704,7 +2778,7 @@ static int parse_args_DCL(Context *ctx) else if ((ctx->shader_type == MOJOSHADER_TYPE_VERTEX) && (ctx->major_ver >= 3)) { - if ((regtype==REG_TYPE_INPUT) || (regtype==REG_TYPE_OUTPUT)) + if ((regtype == REG_TYPE_INPUT) || (regtype == REG_TYPE_OUTPUT)) { const uint32 usage = (token & 0xF); const uint32 index = ((token >> 16) & 0xF); @@ -2867,6 +2941,41 @@ static void state_DCL(Context *ctx) { const RegisterType regtype = ctx->dest_args[0].regtype; const int regnum = ctx->dest_args[0].regnum; + const uint32 usage = ctx->dwords[0]; + + if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) + { + //const uint32 index = ctx->dwords[1]; + if (usage >= ((const uint32) MOJOSHADER_USAGE_TOTAL)) + { + fail(ctx, "unknown DCL usage"); + return; + } // if + } // if + + else if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL) + { + if (regtype == REG_TYPE_SAMPLER) + { + switch ((const TextureType) usage) + { + case TEXTURE_TYPE_2D: + case TEXTURE_TYPE_CUBE: + case TEXTURE_TYPE_VOLUME: + break; // it's okay. + default: + fail(ctx, "unknown sampler texture type"); + return; + } // switch + } // if + + } // else if + + else + { + assert(0 && "Unsupported shader type."); // should be caught elsewhere. + } // else + set_defined_register(ctx, regtype, regnum); } // state_DCL @@ -3649,6 +3758,25 @@ static void process_definitions(Context *ctx) // haven't already dealt with this one. switch (regtype) { + // !!! FIXME: I'm not entirely sure this is right... + case REG_TYPE_RASTOUT: + case REG_TYPE_ATTROUT: + case REG_TYPE_TEXCRDOUT: + case REG_TYPE_COLOROUT: + case REG_TYPE_DEPTHOUT: + if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX) + { + if (shader_version_atleast(ctx, 3, 0)) + { + fail(ctx, "vs_3 can't use output registers" + " without declaring them first."); + return; + } // if + } // if + + // profiles need to deal with older shader models. + // intentional fallthrough to next case statements! + case REG_TYPE_ADDRESS: case REG_TYPE_PREDICATE: case REG_TYPE_TEMP: diff --git a/mojoshader.h b/mojoshader.h index c16894d1..17221450 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -82,7 +82,7 @@ typedef enum MOJOSHADER_USAGE_BLENDWEIGHT = 1, MOJOSHADER_USAGE_BLENDINDICES = 2, MOJOSHADER_USAGE_NORMAL = 3, - MOJOSHADER_USAGE_PSIZE = 4, + MOJOSHADER_USAGE_POINTSIZE = 4, MOJOSHADER_USAGE_TEXCOORD = 5, MOJOSHADER_USAGE_TANGENT = 6, MOJOSHADER_USAGE_BINORMAL = 7, @@ -92,6 +92,7 @@ typedef enum MOJOSHADER_USAGE_FOG = 11, MOJOSHADER_USAGE_DEPTH = 12, MOJOSHADER_USAGE_SAMPLE = 13, + MOJOSHADER_USAGE_TOTAL, /* housekeeping value; not ever returned. */ } MOJOSHADER_usage; /*