[v3 PATCH] d3d10/effect: Add initial support for indexing expressions.

Nikolay Sivov nsivov at codeweavers.com
Mon Nov 8 06:30:19 CST 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

v3: some rework based on received feedback

For now for simplicity I removed destination index from property update, with additional
test for property type when parsing.

 dlls/d3d10/effect.c       | 577 +++++++++++++++++++++++++++++++++++++-
 dlls/d3d10/tests/effect.c | 114 ++++++++
 2 files changed, 683 insertions(+), 8 deletions(-)

diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c
index 78a3d0c386a..1be16771921 100644
--- a/dlls/d3d10/effect.c
+++ b/dlls/d3d10/effect.c
@@ -30,6 +30,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d10);
     ((DWORD)(ch2) << 16) | ((DWORD)(ch3) << 24 ))
 #define TAG_DXBC MAKE_TAG('D', 'X', 'B', 'C')
 #define TAG_FX10 MAKE_TAG('F', 'X', '1', '0')
+#define TAG_FXLC MAKE_TAG('F', 'X', 'L', 'C')
+#define TAG_CLI4 MAKE_TAG('C', 'L', 'I', '4')
+#define TAG_CTAB MAKE_TAG('C', 'T', 'A', 'B')
 
 #define D3D10_FX10_TYPE_COLUMN_SHIFT    11
 #define D3D10_FX10_TYPE_COLUMN_MASK     (0x7 << D3D10_FX10_TYPE_COLUMN_SHIFT)
@@ -180,6 +183,96 @@ static enum d3d10_effect_container_type get_var_container_type(const struct d3d1
     }
 }
 
+struct preshader_instr
+{
+    unsigned int comp_count : 16;
+    unsigned int reserved   :  4;
+    unsigned int opcode     : 11;
+    unsigned int scalar     :  1;
+};
+
+typedef float (*pres_op_func)(float **args, unsigned int n);
+
+static float pres_ftou(float **args, unsigned int n)
+{
+    unsigned int u = *args[0];
+    return *(float *)&u;
+}
+
+static float pres_add(float **args, unsigned int n)
+{
+    return *args[0] + *args[1];
+}
+
+struct preshader_op_info
+{
+    int opcode;
+    char name[8];
+    pres_op_func func;
+};
+
+static const struct preshader_op_info preshader_ops[] =
+{
+    { 0x133, "ftou", pres_ftou },
+    { 0x204, "add",  pres_add  },
+};
+
+static int __cdecl preshader_op_compare(const void *a, const void *b)
+{
+    int opcode = *(int *)a;
+    const struct preshader_op_info *op_info = b;
+    return opcode - op_info->opcode;
+}
+
+static const struct preshader_op_info * d3d10_effect_get_op_info(int opcode)
+{
+    return bsearch(&opcode, preshader_ops, ARRAY_SIZE(preshader_ops), sizeof(*preshader_ops),
+            preshader_op_compare);
+}
+
+struct d3d10_ctab_var
+{
+    struct d3d10_effect_variable *v;
+    unsigned int offset;
+    unsigned int length;
+};
+
+struct d3d10_reg_table
+{
+    union
+    {
+        float *f;
+        DWORD *dword;
+    };
+    unsigned int count;
+};
+
+enum d3d10_reg_table_type
+{
+    D3D10_REG_TABLE_CONSTANTS = 1,
+    D3D10_REG_TABLE_CB = 2,
+    D3D10_REG_TABLE_RESULT = 4,
+    D3D10_REG_TABLE_TEMP = 7,
+    D3D10_REG_TABLE_COUNT,
+};
+
+struct d3d10_effect_preshader
+{
+    struct d3d10_reg_table reg_tables[D3D10_REG_TABLE_COUNT];
+    ID3D10Blob *code;
+
+    struct d3d10_ctab_var *vars;
+    unsigned int vars_count;
+};
+
+struct d3d10_preshader_parse_context
+{
+    struct d3d10_effect_preshader *preshader;
+    struct d3d10_effect *effect;
+    unsigned int result_count;
+    unsigned int temp_count;
+};
+
 struct d3d10_effect_prop_dependency
 {
     unsigned int id;
@@ -192,11 +285,115 @@ struct d3d10_effect_prop_dependency
             struct d3d10_effect_variable *v;
             unsigned int offset;
         } var;
-    } u;
+        struct
+        {
+            struct d3d10_effect_variable *v;
+            struct d3d10_effect_preshader index;
+        } index_expr;
+    };
 };
 
+static HRESULT d3d10_reg_table_allocate(struct d3d10_reg_table *table, unsigned int count)
+{
+    if (!(table->f = heap_calloc(count, sizeof(*table->f))))
+        return E_OUTOFMEMORY;
+    table->count = count;
+    return S_OK;
+}
+
+static void d3d10_effect_preshader_clear(struct d3d10_effect_preshader *p)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(p->reg_tables); ++i)
+        heap_free(&p->reg_tables[i].f);
+    if (p->code)
+        ID3D10Blob_Release(p->code);
+    heap_free(p->vars);
+    memset(p, 0, sizeof(*p));
+}
+
+static float * d3d10_effect_preshader_get_reg_ptr(const struct d3d10_effect_preshader *p,
+        enum d3d10_reg_table_type regt, unsigned int offset)
+{
+    switch (regt)
+    {
+        case D3D10_REG_TABLE_CONSTANTS:
+        case D3D10_REG_TABLE_CB:
+        case D3D10_REG_TABLE_RESULT:
+        case D3D10_REG_TABLE_TEMP:
+            return p->reg_tables[regt].f + offset;
+        default:
+            return NULL;
+    }
+}
+
+static HRESULT d3d10_effect_preshader_eval(struct d3d10_effect_preshader *p)
+{
+    unsigned int i, j, regt, offset, instr_count, input_count;
+    const DWORD *ip = ID3D10Blob_GetBufferPointer(p->code);
+    float *dst, *args[4], *retval;
+    struct preshader_instr ins;
+
+    dst = d3d10_effect_preshader_get_reg_ptr(p, D3D10_REG_TABLE_RESULT, 0);
+    memset(dst, 0, sizeof(float) * p->reg_tables[D3D10_REG_TABLE_RESULT].count);
+
+    /* Update constant buffer */
+    dst = d3d10_effect_preshader_get_reg_ptr(p, D3D10_REG_TABLE_CB, 0);
+    for (i = 0; i < p->vars_count; ++i)
+    {
+        struct d3d10_ctab_var *v = &p->vars[i];
+        memcpy(dst + v->offset, v->v->buffer->u.buffer.local_buffer, v->length * sizeof(*dst));
+    }
+
+    instr_count = *ip++;
+
+    for (i = 0; i < instr_count; ++i)
+    {
+        *(DWORD *)&ins = *ip++;
+        input_count = *ip++;
+
+        if (input_count > ARRAY_SIZE(args))
+        {
+            FIXME("Unexpected argument count %u.\n", input_count);
+            return E_FAIL;
+        }
+
+        /* Arguments */
+        for (j = 0; j < input_count; ++j)
+        {
+            ip++; /* TODO: argument register flags are currently ignored */
+            regt = *ip++;
+            offset = *ip++;
+
+            args[j] = d3d10_effect_preshader_get_reg_ptr(p, regt, offset);
+        }
+
+        ip++; /* TODO: result register flags are currently ignored */
+        regt = *ip++;
+        offset = *ip++;
+        retval = d3d10_effect_preshader_get_reg_ptr(p, regt, offset);
+
+        *retval = d3d10_effect_get_op_info(ins.opcode)->func(args, input_count);
+    }
+
+    return S_OK;
+}
+
 static void d3d10_effect_clear_prop_dependencies(struct d3d10_effect_prop_dependencies *d)
 {
+    unsigned int i;
+
+    for (i = 0; i < d->count; ++i)
+    {
+        struct d3d10_effect_prop_dependency *dep = &d->entries[i];
+        switch (dep->operation)
+        {
+            case D3D10_EOO_INDEX_EXPRESSION:
+                d3d10_effect_preshader_clear(&dep->index_expr.index);
+                break;
+        }
+    }
     heap_free(d->entries);
     memset(d, 0, sizeof(*d));
 }
@@ -516,9 +713,11 @@ static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_depende
 {
     const struct d3d10_effect_state_property_info *property_info;
     struct d3d10_effect_prop_dependency *d;
+    unsigned int i, j, count, variable_idx;
     struct d3d10_effect_variable *v;
-    unsigned int i, j, count;
+    unsigned int *dst_index;
     uint32_t value;
+    HRESULT hr;
     void *dst;
 
     for (i = 0; i < deps->count; ++i)
@@ -528,24 +727,58 @@ static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_depende
         property_info = &property_infos[d->id];
 
         dst = (char *)container + property_info->offset;
+        dst_index = (unsigned int *)((char *)container + property_info->index_offset);
 
         switch (d->operation)
         {
             case D3D10_EOO_VAR:
             case D3D10_EOO_CONST_INDEX:
 
-                v = d->u.var.v;
+                v = d->var.v;
 
                 count = v->type->type_class == D3D10_SVC_VECTOR ? 4 : 1;
 
                 for (j = 0; j < count; ++j)
                 {
-                    d3d10_effect_variable_get_raw_value(v, &value, d->u.var.offset + j * sizeof(value), sizeof(value));
+                    d3d10_effect_variable_get_raw_value(v, &value, d->var.offset + j * sizeof(value), sizeof(value));
                     d3d10_effect_read_numeric_value(value, v->type->basetype, property_info->type, dst, j);
                 }
 
                 break;
 
+            case D3D10_EOO_INDEX_EXPRESSION:
+
+                v = d->index_expr.v;
+
+                if (FAILED(hr = d3d10_effect_preshader_eval(&d->index_expr.index)))
+                {
+                    WARN("Failed to evaluate index expression, hr %#x.\n", hr);
+                    return;
+                }
+
+                variable_idx = *d->index_expr.index.reg_tables[D3D10_REG_TABLE_RESULT].dword;
+
+                if (variable_idx >= v->type->element_count)
+                {
+                    WARN("Expression evaluated to invalid index value %u, array %s of size %u.\n",
+                            variable_idx, debugstr_a(v->name), v->type->element_count);
+                    return;
+                }
+
+                /* Ignoring destination index here, there are no object typed array properties. */
+                switch (property_info->type)
+                {
+                    case D3D10_SVT_VERTEXSHADER:
+                    case D3D10_SVT_PIXELSHADER:
+                    case D3D10_SVT_GEOMETRYSHADER:
+                        *(void **)dst = v;
+                        *dst_index = variable_idx;
+                        break;
+                    default:
+                        *(void **)dst = &v->elements[variable_idx];
+                }
+                break;
+
             default:
                 FIXME("Unsupported property update for %u.\n", d->operation);
         }
@@ -1856,6 +2089,266 @@ static BOOL is_object_property_type_matching(const struct d3d10_effect_state_pro
     }
 }
 
+static HRESULT parse_fx10_preshader_instr(struct d3d10_preshader_parse_context *context,
+        unsigned int *offset, const char **ptr, unsigned int data_size)
+{
+    const struct preshader_op_info *op_info;
+    unsigned int i, param_count;
+    struct preshader_instr ins;
+    uint32_t input_count;
+
+    if (!require_space(*offset, 2, sizeof(uint32_t), data_size))
+    {
+        WARN("Malformed FXLC table, size %u.\n", data_size);
+        return E_FAIL;
+    }
+
+    read_dword(ptr, (uint32_t *)&ins);
+    read_dword(ptr, &input_count);
+    *offset += 2 * sizeof(uint32_t);
+
+    if (!(op_info = d3d10_effect_get_op_info(ins.opcode)))
+    {
+        FIXME("Unrecognized opcode %#x.\n", ins.opcode);
+        return E_FAIL;
+    }
+
+    TRACE("Opcode %#x (%s), input count %u.\n", ins.opcode, op_info->name, input_count);
+
+    /* Inputs + one output */
+    param_count = input_count + 1;
+
+    if (!require_space(*offset, 3 * param_count, sizeof(uint32_t), data_size))
+    {
+        WARN("Malformed FXLC table, opcode %#x.\n", ins.opcode);
+        return E_FAIL;
+    }
+    *offset += 3 * param_count * sizeof(uint32_t);
+
+    for (i = 0; i < param_count; ++i)
+    {
+        uint32_t flags, regt, param_offset;
+
+        read_dword(ptr, &flags);
+        if (flags)
+        {
+            FIXME("Arguments flags are not supported %#x.\n", flags);
+            return E_UNEXPECTED;
+        }
+
+        read_dword(ptr, &regt);
+        read_dword(ptr, &param_offset);
+
+        switch (regt)
+        {
+            case D3D10_REG_TABLE_RESULT:
+                context->result_count = max(context->result_count, param_offset + 1);
+                break;
+            case D3D10_REG_TABLE_TEMP:
+                context->temp_count = max(context->temp_count, param_offset + 1);
+                break;
+            default:
+                break;
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT parse_fx10_fxlc(void *ctx, const char *data, unsigned int data_size)
+{
+    struct d3d10_preshader_parse_context *context = ctx;
+    struct d3d10_effect_preshader *p = context->preshader;
+    unsigned int i, offset = 4;
+    uint32_t ins_count;
+    const char *ptr;
+    HRESULT hr;
+
+    if (data_size % sizeof(uint32_t))
+    {
+        WARN("FXLC size misaligned %u.\n", data_size);
+        return E_FAIL;
+    }
+
+    /* Parse through bytecode copy, so we can patch opcodes. */
+    if (FAILED(hr = D3DCreateBlob(data_size, &p->code)))
+        return hr;
+    memcpy(ID3D10Blob_GetBufferPointer(p->code), data, data_size);
+
+    ptr = data;
+    read_dword(&ptr, &ins_count);
+    TRACE("%u instructions.\n", ins_count);
+
+    for (i = 0; i < ins_count; ++i)
+    {
+        if (FAILED(hr = parse_fx10_preshader_instr(context, &offset, &ptr, data_size)))
+        {
+            WARN("Failed to parse instruction %u.\n", i);
+            return hr;
+        }
+    }
+
+    if (FAILED(hr = d3d10_reg_table_allocate(&p->reg_tables[D3D10_REG_TABLE_RESULT],
+            context->result_count))) return hr;
+    if (FAILED(hr = d3d10_reg_table_allocate(&p->reg_tables[D3D10_REG_TABLE_TEMP],
+            context->temp_count))) return hr;
+
+    return S_OK;
+}
+
+static HRESULT parse_fx10_cli4(void *ctx, const char *data, unsigned int data_size)
+{
+    struct d3d10_preshader_parse_context *context = ctx;
+    struct d3d10_effect_preshader *p = context->preshader;
+    struct d3d10_reg_table *table = &p->reg_tables[D3D10_REG_TABLE_CONSTANTS];
+    const char *ptr = data;
+    uint32_t count;
+    HRESULT hr;
+
+    if (data_size < sizeof(DWORD))
+    {
+        WARN("Invalid CLI4 chunk size %u.\n", data_size);
+        return E_FAIL;
+    }
+
+    read_dword(&ptr, &count);
+
+    TRACE("%u literal constants.\n", count);
+
+    if (!require_space(4, count, sizeof(float), data_size))
+    {
+        WARN("Invalid constant table size %u.\n", data_size);
+        return E_FAIL;
+    }
+
+    if (FAILED(hr = d3d10_reg_table_allocate(table, count)))
+        return hr;
+
+    memcpy(table->f, ptr, table->count * sizeof(*table->f));
+
+    return S_OK;
+}
+
+static HRESULT parse_fx10_ctab(void *ctx, const char *data, unsigned int data_size)
+{
+    struct d3d10_preshader_parse_context *context = ctx;
+    struct d3d10_effect_preshader *p = context->preshader;
+    struct ctab_header
+    {
+        DWORD size;
+        DWORD creator;
+        DWORD version;
+        DWORD constants;
+        DWORD constantinfo;
+        DWORD flags;
+        DWORD target;
+    } header;
+    struct ctab_const_info
+    {
+        DWORD name;
+        WORD register_set;
+        WORD register_index;
+        WORD register_count;
+        WORD reserved;
+        DWORD typeinfo;
+        DWORD default_value;
+    } *info;
+    unsigned int i, cb_reg_count = 0;
+    const char *ptr = data;
+    const char *name;
+    size_t name_len;
+    HRESULT hr;
+
+    if (data_size < sizeof(header))
+    {
+        WARN("Invalid constant table size %u.\n", data_size);
+        return E_FAIL;
+    }
+
+    read_dword(&ptr, &header.size);
+    read_dword(&ptr, &header.creator);
+    read_dword(&ptr, &header.version);
+    read_dword(&ptr, &header.constants);
+    read_dword(&ptr, &header.constantinfo);
+    read_dword(&ptr, &header.flags);
+    read_dword(&ptr, &header.target);
+
+    if (!require_space(header.constantinfo, header.constants, sizeof(*info), data_size))
+    {
+        WARN("Invalid constant info section offset %#x.\n", header.constantinfo);
+        return E_FAIL;
+    }
+
+    p->vars_count = header.constants;
+
+    TRACE("Variable count %u.\n", p->vars_count);
+
+    if (!(p->vars = heap_calloc(p->vars_count, sizeof(*p->vars))))
+        return E_OUTOFMEMORY;
+
+    /* Collect variables used in expression. */
+    info = (struct ctab_const_info *)(data + header.constantinfo);
+    for (i = 0; i < p->vars_count; ++i, ++info)
+    {
+        if (!fx10_get_string(data, data_size, info->name, &name, &name_len))
+            return E_FAIL;
+
+        if (!(p->vars[i].v = d3d10_effect_get_variable_by_name(context->effect, name)))
+        {
+            WARN("Couldn't find variable %s.\n", debugstr_a(name));
+            return E_FAIL;
+        }
+
+        /* 4 components per register */
+        p->vars[i].offset = info->register_index * 4;
+        p->vars[i].length = info->register_count * 4;
+
+        cb_reg_count = max(cb_reg_count, info->register_index + info->register_count);
+    }
+
+    /* Allocate contiguous "constant buffer" for all referenced variables. */
+    if (FAILED(hr = d3d10_reg_table_allocate(&p->reg_tables[D3D10_REG_TABLE_CB], cb_reg_count * 4)))
+    {
+        WARN("Failed to allocate variables buffer.\n");
+        return hr;
+    }
+
+    return S_OK;
+}
+
+static HRESULT fxlvm_chunk_handler(const char *data, DWORD data_size, DWORD tag, void *ctx)
+{
+    TRACE("Chunk tag: %s, size: %u.\n", debugstr_an((const char *)&tag, 4), data_size);
+
+    switch (tag)
+    {
+        case TAG_FXLC:
+            return parse_fx10_fxlc(ctx, data, data_size);
+
+        case TAG_CLI4:
+            return parse_fx10_cli4(ctx, data, data_size);
+
+        case TAG_CTAB:
+            return parse_fx10_ctab(ctx, data, data_size);
+
+        default:
+            FIXME("Unhandled chunk %s.\n", debugstr_an((const char *)&tag, 4));
+            return S_OK;
+    }
+}
+
+static HRESULT parse_fx10_preshader(const char *data, size_t data_size,
+        struct d3d10_effect *effect, struct d3d10_effect_preshader *preshader)
+{
+    struct d3d10_preshader_parse_context context;
+
+    memset(preshader, 0, sizeof(*preshader));
+    context.preshader = preshader;
+    context.effect = effect;
+
+    return parse_dxbc(data, data_size, fxlvm_chunk_handler, &context);
+}
+
 static HRESULT d3d10_effect_add_prop_dependency(struct d3d10_effect_prop_dependencies *d,
         const struct d3d10_effect_prop_dependency *dep)
 {
@@ -1875,6 +2368,7 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size
     const struct d3d10_effect_state_property_info *property_info;
     struct d3d10_effect_prop_dependency dep;
     struct d3d10_effect_variable *variable;
+    uint32_t code_offset, blob_size;
     const char *data_ptr, *name;
     unsigned int *dst_index;
     size_t name_len;
@@ -1974,8 +2468,8 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size
                 dep.id = id;
                 dep.idx = idx;
                 dep.operation = operation;
-                dep.u.var.v = variable;
-                dep.u.var.offset = 0;
+                dep.var.v = variable;
+                dep.var.offset = 0;
 
                 return d3d10_effect_add_prop_dependency(d, &dep);
             }
@@ -2051,14 +2545,75 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size
                 dep.id = id;
                 dep.idx = idx;
                 dep.operation = operation;
-                dep.u.var.v = variable;
-                dep.u.var.offset = offset;
+                dep.var.v = variable;
+                dep.var.offset = offset;
 
                 return d3d10_effect_add_prop_dependency(d, &dep);
             }
 
             break;
 
+        case D3D10_EOO_INDEX_EXPRESSION:
+
+            /* Variable, and an expression for its index. */
+            if (value_offset >= data_size || !require_space(value_offset, 2, sizeof(DWORD), data_size))
+            {
+                WARN("Invalid offset %#x (data size %#lx).\n", value_offset, (long)data_size);
+                return E_FAIL;
+            }
+
+            data_ptr = data + value_offset;
+            read_dword(&data_ptr, &value_offset);
+            read_dword(&data_ptr, &code_offset);
+
+            if (!fx10_get_string(data, data_size, value_offset, &name, &name_len))
+            {
+                WARN("Failed to get variable name.\n");
+                return E_FAIL;
+            }
+
+            TRACE("Variable name %s[<expr>].\n", debugstr_a(name));
+
+            if (!(variable = d3d10_effect_get_variable_by_name(effect, name)))
+            {
+                WARN("Couldn't find variable %s.\n", debugstr_a(name));
+                return E_FAIL;
+            }
+
+            /* Has to be an array */
+            if (!variable->type->element_count)
+            {
+                WARN("Expected array variable.\n");
+                return E_FAIL;
+            }
+
+            if (!is_object_property(property_info))
+            {
+                WARN("Expected object type property used with indexed expression.\n");
+                return E_FAIL;
+            }
+
+            if (code_offset >= data_size || !require_space(code_offset, 1, sizeof(DWORD), data_size))
+            {
+                WARN("Invalid offset %#x (data size %#lx).\n", value_offset, (long)data_size);
+                return E_FAIL;
+            }
+
+            data_ptr = data + code_offset;
+            read_dword(&data_ptr, &blob_size);
+
+            dep.id = id;
+            dep.idx = idx;
+            dep.operation = operation;
+            dep.index_expr.v = variable;
+            if (FAILED(hr = parse_fx10_preshader(data_ptr, blob_size, effect, &dep.index_expr.index)))
+            {
+                WARN("Failed to parse preshader, hr %#x.\n", hr);
+                return hr;
+            }
+
+            return d3d10_effect_add_prop_dependency(d, &dep);
+
         case D3D10_EOO_ANONYMOUS_SHADER:
 
             /* Anonymous shader */
@@ -4004,6 +4559,8 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_pass_GetVertexShaderDesc(ID3D10Eff
         return E_INVALIDARG;
     }
 
+    d3d10_effect_update_dependent_props(&pass->dependencies, pass);
+
     desc->pShaderVariable = (ID3D10EffectShaderVariable *)&pass->vs.shader->ID3D10EffectVariable_iface;
     desc->ShaderIndex = pass->vs.index;
 
@@ -4029,6 +4586,8 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_pass_GetGeometryShaderDesc(ID3D10E
         return E_INVALIDARG;
     }
 
+    d3d10_effect_update_dependent_props(&pass->dependencies, pass);
+
     desc->pShaderVariable = (ID3D10EffectShaderVariable *)&pass->gs.shader->ID3D10EffectVariable_iface;
     desc->ShaderIndex = pass->gs.index;
 
@@ -4054,6 +4613,8 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_pass_GetPixelShaderDesc(ID3D10Effe
         return E_INVALIDARG;
     }
 
+    d3d10_effect_update_dependent_props(&pass->dependencies, pass);
+
     desc->pShaderVariable = (ID3D10EffectShaderVariable *)&pass->ps.shader->ID3D10EffectVariable_iface;
     desc->ShaderIndex = pass->ps.index;
 
diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c
index da644d8d9db..f3e93fe34f4 100644
--- a/dlls/d3d10/tests/effect.c
+++ b/dlls/d3d10/tests/effect.c
@@ -7801,6 +7801,119 @@ static void test_effect_dynamic_numeric_field(void)
     ok(!refcount, "Device has %u references left.\n", refcount);
 }
 
+#if 0
+float4 g_var;
+PixelShader ps_array[2];
+VertexShader vs_array[2];
+technique10 tech
+{
+    pass p0
+    {
+        SetPixelShader( ps_array[g_var.z] );
+        SetVertexShader( vs_array[g_var.x + 0.1f] );
+    }
+}
+#endif
+static DWORD fx_test_index_expression[] =
+{
+    0x43425844, 0x83787296, 0xf866b7a9, 0x7b56930c, 0xdc9d061a, 0x00000001, 0x000003e9, 0x00000001,
+    0x00000024, 0x30315846, 0x000003bd, 0xfeff1001, 0x00000001, 0x00000001, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x000002cd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 0x6f6c4724,
+    0x736c6162, 0x6f6c6600, 0x00347461, 0x0000000d, 0x00000001, 0x00000000, 0x00000010, 0x00000010,
+    0x00000010, 0x0000210a, 0x61765f67, 0x69500072, 0x536c6578, 0x65646168, 0x00360072, 0x00020000,
+    0x00020000, 0x00000000, 0x00000000, 0x00000000, 0x00050000, 0x73700000, 0x7272615f, 0x56007961,
+    0x65747265, 0x61685378, 0x00726564, 0x00000067, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
+    0x00000000, 0x00000006, 0x615f7376, 0x79617272, 0x63657400, 0x30700068, 0x0000ec00, 0x42584400,
+    0x990a9743, 0xd17834e6, 0x40de477e, 0xf476a79f, 0x00000101, 0x0000ec00, 0x00000300, 0x00002c00,
+    0x0000a800, 0x0000b400, 0x41544300, 0x00007442, 0x00001c00, 0x00004b00, 0x58040000, 0x00000146,
+    0x00001c00, 0x00010000, 0x00004800, 0x00003000, 0x00000200, 0x00000100, 0x00003800, 0x00000000,
+    0x765f6700, 0xab007261, 0x030001ab, 0x04000100, 0x00000100, 0x00000000, 0x00787400, 0x7263694d,
+    0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, 0x6c69706d, 0x31207265,
+    0x00312e30, 0x494c43ab, 0x00000434, 0x00000000, 0x4c584600, 0x00003043, 0x00000100, 0x30000100,
+    0x00000113, 0x00000000, 0x00000200, 0x00000200, 0x00000000, 0x00000400, 0x00000000, 0xf0f0f000,
+    0x0f0f0ff0, 0x00ffff0f, 0x00005e00, 0x0000a100, 0x00012800, 0x42584400, 0x78de2e43, 0x31414e7a,
+    0xf69158cd, 0x416c97b6, 0x00000192, 0x00012800, 0x00000300, 0x00002c00, 0x0000a800, 0x0000c400,
+    0x41544300, 0x00007442, 0x00001c00, 0x00004b00, 0x58040000, 0x00000146, 0x00001c00, 0x00010000,
+    0x00004800, 0x00003000, 0x00000200, 0x00000100, 0x00003800, 0x00000000, 0x765f6700, 0xab007261,
+    0x030001ab, 0x04000100, 0x00000100, 0x00000000, 0x00787400, 0x7263694d, 0x666f736f, 0x52282074,
+    0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, 0x6c69706d, 0x31207265, 0x00312e30, 0x494c43ab,
+    0x00001434, 0x00000400, 0xcccccd00, 0x0000003d, 0x00000000, 0x00000000, 0x4c584600, 0x00005c43,
+    0x00000200, 0x40000100, 0x00000220, 0x00000000, 0x00000200, 0x00000000, 0x00000000, 0x00000100,
+    0x00000000, 0x00000000, 0x00000700, 0x00000000, 0x30000100, 0x00000113, 0x00000000, 0x00000700,
+    0x00000000, 0x00000000, 0x00000400, 0x00000000, 0xf0f0f000, 0x0f0f0ff0, 0x00ffff0f, 0x00009000,
+    0x00019900, 0x00000400, 0x00001000, 0x00000000, 0x00000100, 0xffffff00, 0x000000ff, 0x00003000,
+    0x00001400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00005e00, 0x00004200,
+    0x00000000, 0xffffff00, 0x000000ff, 0x00000000, 0x00000000, 0x00009000, 0x00007400, 0x00000000,
+    0xffffff00, 0x000000ff, 0x00000000, 0x00000000, 0x00009900, 0x00000100, 0x00000000, 0x00009e00,
+    0x00000200, 0x00000000, 0x00000700, 0x00000000, 0x00000500, 0x00019100, 0x00000600, 0x00000000,
+    0x00000500, 0x0002c500, 0x00000000,
+};
+
+static void test_effect_index_expression(void)
+{
+    D3D10_PASS_SHADER_DESC shader_desc;
+    ID3D10EffectVectorVariable *vector;
+    ID3D10EffectTechnique *tech;
+    ID3D10EffectVariable *v;
+    ID3D10EffectPass *pass;
+    ID3D10Effect *effect;
+    ID3D10Device *device;
+    ULONG refcount;
+    float val[4];
+    HRESULT hr;
+
+    if (!(device = create_device()))
+    {
+        skip("Failed to create device, skipping tests.\n");
+        return;
+    }
+
+    hr = create_effect(fx_test_index_expression, 0, device, NULL, &effect);
+    ok(SUCCEEDED(hr), "Failed to create an effect, hr %#x.\n", hr);
+
+    /* Initial index */
+    tech = effect->lpVtbl->GetTechniqueByIndex(effect, 0);
+    pass = tech->lpVtbl->GetPassByIndex(tech, 0);
+    hr = pass->lpVtbl->GetPixelShaderDesc(pass, &shader_desc);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(!shader_desc.ShaderIndex, "Unexpected shader index.\n");
+
+    v = effect->lpVtbl->GetVariableByName(effect, "g_var");
+    vector = v->lpVtbl->AsVector(v);
+
+    val[0] = 0.0f;
+    val[1] = 0.0f;
+    val[2] = 1.0f;
+    val[3] = 0.0f;
+    hr = vector->lpVtbl->SetFloatVector(vector, val);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = pass->lpVtbl->GetPixelShaderDesc(pass, &shader_desc);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(shader_desc.ShaderIndex == 1, "Unexpected shader index %#x.\n", shader_desc.ShaderIndex);
+
+    hr = pass->lpVtbl->GetVertexShaderDesc(pass, &shader_desc);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(!shader_desc.ShaderIndex, "Unexpected shader index %#x.\n", shader_desc.ShaderIndex);
+
+    val[0] = 0.9f;
+    val[1] = 0.0f;
+    val[2] = 1.0f;
+    val[3] = 0.0f;
+    hr = vector->lpVtbl->SetFloatVector(vector, val);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = pass->lpVtbl->GetVertexShaderDesc(pass, &shader_desc);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(shader_desc.ShaderIndex == 1, "Unexpected shader index %#x.\n", shader_desc.ShaderIndex);
+
+    effect->lpVtbl->Release(effect);
+
+    refcount = ID3D10Device_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+}
+
 START_TEST(effect)
 {
     test_effect_constant_buffer_type();
@@ -7825,4 +7938,5 @@ START_TEST(effect)
     test_effect_default_variable_value();
     test_effect_raw_value();
     test_effect_dynamic_numeric_field();
+    test_effect_index_expression();
 }
-- 
2.33.0




More information about the wine-devel mailing list