profiles/mojoshader_profile_common.c
changeset 1199 b8ece252a201
child 1200 eb1e5280a5a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/mojoshader_profile_common.c	Tue Apr 23 14:43:10 2019 -0400
@@ -0,0 +1,504 @@
+/**
+ * MojoShader; generate shader programs from bytecode of compiled
+ *  Direct3D shaders.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#pragma GCC visibility push(hidden)
+
+#define __MOJOSHADER_INTERNAL__ 1
+#include "mojoshader_profile.h"
+
+// Common Utilities
+
+void out_of_memory(Context *ctx)
+{
+    ctx->isfail = ctx->out_of_memory = 1;
+} // out_of_memory
+
+void *Malloc(Context *ctx, const size_t len)
+{
+    void *retval = ctx->malloc((int) len, ctx->malloc_data);
+    if (retval == NULL)
+        out_of_memory(ctx);
+    return retval;
+} // Malloc
+
+char *StrDup(Context *ctx, const char *str)
+{
+    char *retval = (char *) Malloc(ctx, strlen(str) + 1);
+    if (retval != NULL)
+        strcpy(retval, str);
+    return retval;
+} // StrDup
+
+void Free(Context *ctx, void *ptr)
+{
+    ctx->free(ptr, ctx->malloc_data);
+} // Free
+
+void * MOJOSHADERCALL MallocBridge(int bytes, void *data)
+{
+    return Malloc((Context *) data, (size_t) bytes);
+} // MallocBridge
+
+void MOJOSHADERCALL FreeBridge(void *ptr, void *data)
+{
+    Free((Context *) data, ptr);
+} // FreeBridge
+
+// Jump between output sections in the context...
+
+int set_output(Context *ctx, Buffer **section)
+{
+    // only create output sections on first use.
+    if (*section == NULL)
+    {
+        *section = buffer_create(256, MallocBridge, FreeBridge, ctx);
+        if (*section == NULL)
+            return 0;
+    } // if
+
+    ctx->output = *section;
+    return 1;
+} // set_output
+
+void push_output(Context *ctx, Buffer **section)
+{
+    assert(ctx->output_stack_len < (int) (STATICARRAYLEN(ctx->output_stack)));
+    ctx->output_stack[ctx->output_stack_len] = ctx->output;
+    ctx->indent_stack[ctx->output_stack_len] = ctx->indent;
+    ctx->output_stack_len++;
+    if (!set_output(ctx, section))
+        return;
+    ctx->indent = 0;
+} // push_output
+
+void pop_output(Context *ctx)
+{
+    assert(ctx->output_stack_len > 0);
+    ctx->output_stack_len--;
+    ctx->output = ctx->output_stack[ctx->output_stack_len];
+    ctx->indent = ctx->indent_stack[ctx->output_stack_len];
+} // pop_output
+
+// Shader model version magic...
+
+uint32 ver_ui32(const uint8 major, const uint8 minor)
+{
+    return ( (((uint32) major) << 16) | (((minor) == 0xFF) ? 1 : (minor)) );
+} // version_ui32
+
+int shader_version_supported(const uint8 maj, const uint8 min)
+{
+    return (ver_ui32(maj,min) <= ver_ui32(MAX_SHADER_MAJOR, MAX_SHADER_MINOR));
+} // shader_version_supported
+
+int shader_version_atleast(const Context *ctx, const uint8 maj,
+                                         const uint8 min)
+{
+    return (ver_ui32(ctx->major_ver, ctx->minor_ver) >= ver_ui32(maj, min));
+} // shader_version_atleast
+
+int shader_version_exactly(const Context *ctx, const uint8 maj,
+                           const uint8 min)
+{
+    return ((ctx->major_ver == maj) && (ctx->minor_ver == min));
+} // shader_version_exactly
+
+int shader_is_pixel(const Context *ctx)
+{
+    return (ctx->shader_type == MOJOSHADER_TYPE_PIXEL);
+} // shader_is_pixel
+
+int shader_is_vertex(const Context *ctx)
+{
+    return (ctx->shader_type == MOJOSHADER_TYPE_VERTEX);
+} // shader_is_vertex
+
+// Fail...
+
+int isfail(const Context *ctx)
+{
+    return ctx->isfail;
+} // isfail
+
+void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
+void failf(Context *ctx, const char *fmt, ...)
+{
+    ctx->isfail = 1;
+    if (ctx->out_of_memory)
+        return;
+
+    // no filename at this level (we pass a NULL to errorlist_add_va()...)
+    va_list ap;
+    va_start(ap, fmt);
+    errorlist_add_va(ctx->errors, NULL, ctx->current_position, fmt, ap);
+    va_end(ap);
+} // failf
+
+void fail(Context *ctx, const char *reason)
+{
+    failf(ctx, "%s", reason);
+} // fail
+
+// Output Lines...
+
+void output_line(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
+void output_line(Context *ctx, const char *fmt, ...)
+{
+    assert(ctx->output != NULL);
+    if (isfail(ctx))
+        return;  // we failed previously, don't go on...
+
+    const int indent = ctx->indent;
+    if (indent > 0)
+    {
+        char *indentbuf = (char *) alloca(indent);
+        memset(indentbuf, '\t', indent);
+        buffer_append(ctx->output, indentbuf, indent);
+    } // if
+
+    va_list ap;
+    va_start(ap, fmt);
+    buffer_append_va(ctx->output, fmt, ap);
+    va_end(ap);
+
+    buffer_append(ctx->output, ctx->endline, ctx->endline_len);
+} // output_line
+
+void output_blank_line(Context *ctx)
+{
+    assert(ctx->output != NULL);
+    if (!isfail(ctx))
+        buffer_append(ctx->output, ctx->endline, ctx->endline_len);
+} // output_blank_line
+
+// !!! FIXME: this is sort of nasty.
+void floatstr(Context *ctx, char *buf, size_t bufsize, float f,
+              int leavedecimal)
+{
+    const size_t len = MOJOSHADER_printFloat(buf, bufsize, f);
+    if ((len+2) >= bufsize)
+        fail(ctx, "BUG: internal buffer is too small");
+    else
+    {
+        char *end = buf + len;
+        char *ptr = strchr(buf, '.');
+        if (ptr == NULL)
+        {
+            if (leavedecimal)
+                strcat(buf, ".0");
+            return;  // done.
+        } // if
+
+        while (--end != ptr)
+        {
+            if (*end != '0')
+            {
+                end++;
+                break;
+            } // if
+        } // while
+        if ((leavedecimal) && (end == ptr))
+            end += 2;
+        *end = '\0';  // chop extra '0' or all decimal places off.
+    } // else
+} // floatstr
+
+// Deal with register lists...
+
+static inline uint32 reg_to_ui32(const RegisterType regtype, const int regnum)
+{
+    return ( ((uint32) regnum) | (((uint32) regtype) << 16) );
+} // reg_to_uint32
+
+// !!! FIXME: ditch this for a hash table.
+RegisterList *reglist_insert(Context *ctx, RegisterList *prev,
+                             const RegisterType regtype,
+                             const int regnum)
+{
+    const uint32 newval = reg_to_ui32(regtype, regnum);
+    RegisterList *item = prev->next;
+    while (item != NULL)
+    {
+        const uint32 val = reg_to_ui32(item->regtype, item->regnum);
+        if (newval == val)
+            return item;  // already set, so we're done.
+        else if (newval < val)  // insert it here.
+            break;
+        else // if (newval > val)
+        {
+            // keep going, we're not to the insertion point yet.
+            prev = item;
+            item = item->next;
+        } // else
+    } // while
+
+    // we need to insert an entry after (prev).
+    item = (RegisterList *) Malloc(ctx, sizeof (RegisterList));
+    if (item != NULL)
+    {
+        item->regtype = regtype;
+        item->regnum = regnum;
+        item->usage = MOJOSHADER_USAGE_UNKNOWN;
+        item->index = 0;
+        item->writemask = 0;
+        item->misc = 0;
+        item->written = 0;
+        item->array = NULL;
+        item->next = prev->next;
+        prev->next = item;
+    } // if
+
+    return item;
+} // reglist_insert
+
+RegisterList *reglist_find(const RegisterList *prev,
+                           const RegisterType rtype,
+                           const int regnum)
+{
+    const uint32 newval = reg_to_ui32(rtype, regnum);
+    RegisterList *item = prev->next;
+    while (item != NULL)
+    {
+        const uint32 val = reg_to_ui32(item->regtype, item->regnum);
+        if (newval == val)
+            return item;  // here it is.
+        else if (newval < val)  // should have been here if it existed.
+            return NULL;
+        else // if (newval > val)
+            item = item->next;
+    } // while
+
+    return NULL;  // wasn't in the list.
+} // reglist_find
+
+RegisterList *set_used_register(Context *ctx,
+                                const RegisterType regtype,
+                                const int regnum,
+                                const int written)
+{
+    RegisterList *reg = NULL;
+    if ((regtype == REG_TYPE_COLOROUT) && (regnum > 0))
+        ctx->have_multi_color_outputs = 1;
+
+    reg = reglist_insert(ctx, &ctx->used_registers, regtype, regnum);
+    if (reg && written)
+        reg->written = 1;
+    return reg;
+} // set_used_register
+
+void set_defined_register(Context *ctx, const RegisterType rtype,
+                          const int regnum)
+{
+    reglist_insert(ctx, &ctx->defined_registers, rtype, regnum);
+} // set_defined_register
+
+// Writemasks
+
+int writemask_xyzw(const int writemask)
+{
+    return (writemask == 0xF);  // 0xF == 1111. No explicit mask (full!).
+} // writemask_xyzw
+
+int writemask_xyz(const int writemask)
+{
+    return (writemask == 0x7);  // 0x7 == 0111. (that is: xyz)
+} // writemask_xyz
+
+int writemask_xy(const int writemask)
+{
+    return (writemask == 0x3);  // 0x3 == 0011. (that is: xy)
+} // writemask_xy
+
+int writemask_x(const int writemask)
+{
+    return (writemask == 0x1);  // 0x1 == 0001. (that is: x)
+} // writemask_x
+
+int writemask_y(const int writemask)
+{
+    return (writemask == 0x2);  // 0x2 == 0010. (that is: y)
+} // writemask_y
+
+int replicate_swizzle(const int swizzle)
+{
+    return ( (((swizzle >> 0) & 0x3) == ((swizzle >> 2) & 0x3)) &&
+             (((swizzle >> 2) & 0x3) == ((swizzle >> 4) & 0x3)) &&
+             (((swizzle >> 4) & 0x3) == ((swizzle >> 6) & 0x3)) );
+} // replicate_swizzle
+
+int no_swizzle(const int swizzle)
+{
+    return (swizzle == 0xE4);  // 0xE4 == 11100100 ... 0 1 2 3. No swizzle.
+} // no_swizzle
+
+int vecsize_from_writemask(const int m)
+{
+    return (m & 1) + ((m >> 1) & 1) + ((m >> 2) & 1) + ((m >> 3) & 1);
+} // vecsize_from_writemask
+
+void set_dstarg_writemask(DestArgInfo *dst, const int mask)
+{
+    dst->writemask = mask;
+    dst->writemask0 = ((mask >> 0) & 1);
+    dst->writemask1 = ((mask >> 1) & 1);
+    dst->writemask2 = ((mask >> 2) & 1);
+    dst->writemask3 = ((mask >> 3) & 1);
+} // set_dstarg_writemask
+
+// D3D stuff that's used in more than just the d3d profile...
+
+int isscalar(Context *ctx, const MOJOSHADER_shaderType shader_type,
+             const RegisterType rtype, const int rnum)
+{
+    const int uses_psize = ctx->uses_pointsize;
+    const int uses_fog = ctx->uses_fog;
+    if ( (rtype == REG_TYPE_OUTPUT) && ((uses_psize) || (uses_fog)) )
+    {
+        const RegisterList *reg = reglist_find(&ctx->attributes, rtype, rnum);
+        if (reg != NULL)
+        {
+            const MOJOSHADER_usage usage = reg->usage;
+            return ( (uses_psize && (usage == MOJOSHADER_USAGE_POINTSIZE)) ||
+                     (uses_fog && (usage == MOJOSHADER_USAGE_FOG)) );
+        } // if
+    } // if
+
+    return scalar_register(shader_type, rtype, rnum);
+} // isscalar
+
+const char *get_D3D_register_string(Context *ctx,
+                                    RegisterType regtype,
+                                    int regnum, char *regnum_str,
+                                    size_t regnum_size)
+{
+    const char *retval = NULL;
+    int has_number = 1;
+
+    switch (regtype)
+    {
+        case REG_TYPE_TEMP:
+            retval = "r";
+            break;
+
+        case REG_TYPE_INPUT:
+            retval = "v";
+            break;
+
+        case REG_TYPE_CONST:
+            retval = "c";
+            break;
+
+        case REG_TYPE_ADDRESS:  // (or REG_TYPE_TEXTURE, same value.)
+            retval = shader_is_vertex(ctx) ? "a" : "t";
+            break;
+
+        case REG_TYPE_RASTOUT:
+            switch ((RastOutType) regnum)
+            {
+                case RASTOUT_TYPE_POSITION: retval = "oPos"; break;
+                case RASTOUT_TYPE_FOG: retval = "oFog"; break;
+                case RASTOUT_TYPE_POINT_SIZE: retval = "oPts"; break;
+            } // switch
+            has_number = 0;
+            break;
+
+        case REG_TYPE_ATTROUT:
+            retval = "oD";
+            break;
+
+        case REG_TYPE_OUTPUT: // (or REG_TYPE_TEXCRDOUT, same value.)
+            if (shader_is_vertex(ctx) && shader_version_atleast(ctx, 3, 0))
+                retval = "o";
+            else
+                retval = "oT";
+            break;
+
+        case REG_TYPE_CONSTINT:
+            retval = "i";
+            break;
+
+        case REG_TYPE_COLOROUT:
+            retval = "oC";
+            break;
+
+        case REG_TYPE_DEPTHOUT:
+            retval = "oDepth";
+            has_number = 0;
+            break;
+
+        case REG_TYPE_SAMPLER:
+            retval = "s";
+            break;
+
+        case REG_TYPE_CONSTBOOL:
+            retval = "b";
+            break;
+
+        case REG_TYPE_LOOP:
+            retval = "aL";
+            has_number = 0;
+            break;
+
+        case REG_TYPE_MISCTYPE:
+            switch ((const MiscTypeType) regnum)
+            {
+                case MISCTYPE_TYPE_POSITION: retval = "vPos"; break;
+                case MISCTYPE_TYPE_FACE: retval = "vFace"; break;
+            } // switch
+            has_number = 0;
+            break;
+
+        case REG_TYPE_LABEL:
+            retval = "l";
+            break;
+
+        case REG_TYPE_PREDICATE:
+            retval = "p";
+            break;
+
+        //case REG_TYPE_TEMPFLOAT16:  // !!! FIXME: don't know this asm string
+        default:
+            fail(ctx, "unknown register type");
+            retval = "???";
+            has_number = 0;
+            break;
+    } // switch
+
+    if (has_number)
+        snprintf(regnum_str, regnum_size, "%u", (uint) regnum);
+    else
+        regnum_str[0] = '\0';
+
+    return retval;
+} // get_D3D_register_string
+
+// !!! FIXME: These should stay in the mojoshader_profile_d3d file
+// !!! FIXME: but ARB1 relies on them, so we have to move them here.
+// !!! FIXME: If/when we kill off ARB1, we can move these back.
+
+const char *get_D3D_varname_in_buf(Context *ctx, RegisterType rt,
+                                   int regnum, char *buf,
+                                   const size_t len)
+{
+    char regnum_str[16];
+    const char *regtype_str = get_D3D_register_string(ctx, rt, regnum,
+                                              regnum_str, sizeof (regnum_str));
+    snprintf(buf,len,"%s%s", regtype_str, regnum_str);
+    return buf;
+} // get_D3D_varname_in_buf
+
+
+const char *get_D3D_varname(Context *ctx, RegisterType rt, int regnum)
+{
+    char buf[64];
+    get_D3D_varname_in_buf(ctx, rt, regnum, buf, sizeof (buf));
+    return StrDup(ctx, buf);
+} // get_D3D_varname
+
+#pragma GCC visibility pop
\ No newline at end of file