Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/effect.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 22a09f45e14..23374fdb48f 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -6411,9 +6411,11 @@ static inline struct d3d10_effect_variable *impl_from_ID3D10EffectShaderResource
static BOOL STDMETHODCALLTYPE d3d10_effect_shader_resource_variable_IsValid(ID3D10EffectShaderResourceVariable *iface) { - TRACE("iface %p\n", iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectShaderResourceVariable(iface); + + TRACE("iface %p.\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_shader_resource_variable; + return v != &null_shader_resource_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_shader_resource_variable_GetType(
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/d3d10_private.h | 9 + dlls/d3d10/effect.c | 341 ++++++++++++++++++++++++++----------- dlls/d3d10/tests/effect.c | 207 ++++++++++++++++++---- 3 files changed, 420 insertions(+), 137 deletions(-)
diff --git a/dlls/d3d10/d3d10_private.h b/dlls/d3d10/d3d10_private.h index 11b3b4e9482..f8e415f860b 100644 --- a/dlls/d3d10/d3d10_private.h +++ b/dlls/d3d10/d3d10_private.h @@ -95,6 +95,13 @@ struct d3d10_effect_shader_variable unsigned int isinline : 1; };
+struct d3d10_effect_prop_dependencies +{ + struct d3d10_effect_prop_dependency *entries; + SIZE_T count; + SIZE_T capacity; +}; + struct d3d10_effect_sampler_desc { D3D10_SAMPLER_DESC desc; @@ -118,6 +125,7 @@ struct d3d10_effect_state_object_variable ID3D10SamplerState *sampler; IUnknown *object; } object; + struct d3d10_effect_prop_dependencies dependencies; };
struct d3d10_effect_resource_variable @@ -217,6 +225,7 @@ struct d3d10_effect_pass char *name; struct d3d10_effect_annotations annotations;
+ struct d3d10_effect_prop_dependencies dependencies; struct d3d10_effect_pass_shader_desc vs; struct d3d10_effect_pass_shader_desc ps; struct d3d10_effect_pass_shader_desc gs; diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 23374fdb48f..34a5eb1b701 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -168,6 +168,27 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+struct d3d10_effect_prop_dependency +{ + unsigned int id; + unsigned int idx; + unsigned int operation; + union + { + struct + { + struct d3d10_effect_variable *v; + unsigned int offset; + } var; + } u; +}; + +static void d3d10_effect_clear_prop_dependencies(struct d3d10_effect_prop_dependencies *d) +{ + heap_free(d->entries); + memset(d, 0, sizeof(*d)); +} + static enum d3d10_effect_container_type get_var_container_type(const struct d3d10_effect_variable *v) { switch (v->type->basetype) @@ -386,6 +407,148 @@ static const char *debug_d3d10_shader_variable_type(D3D10_SHADER_VARIABLE_TYPE t
#undef WINE_D3D10_TO_STR
+static HRESULT d3d10_effect_variable_get_raw_value(struct d3d10_effect_variable *v, + void *data, unsigned int offset, unsigned int count) +{ + BOOL is_buffer; + + is_buffer = v->type->basetype == D3D10_SVT_CBUFFER || v->type->basetype == D3D10_SVT_TBUFFER; + + if (v->type->type_class == D3D10_SVC_OBJECT && !is_buffer) + { + WARN("Not supported on object variables of type %s.\n", + debug_d3d10_shader_variable_type(v->type->basetype)); + return D3DERR_INVALIDCALL; + } + + if (!is_buffer) + { + offset += v->buffer_offset; + v = v->buffer; + } + + memcpy(data, v->u.buffer.local_buffer + offset, count); + + return S_OK; +} + +static BOOL read_float_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, float *out_data, UINT idx) +{ + switch (in_type) + { + case D3D10_SVT_FLOAT: + out_data[idx] = *(float *)&value; + return TRUE; + + case D3D10_SVT_INT: + out_data[idx] = (INT)value; + return TRUE; + + case D3D10_SVT_UINT: + out_data[idx] = value; + return TRUE; + + default: + FIXME("Unhandled in_type %#x.\n", in_type); + return FALSE; + } +} + +static BOOL read_int32_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, INT *out_data, UINT idx) +{ + switch (in_type) + { + case D3D10_SVT_FLOAT: + out_data[idx] = *(float *)&value; + return TRUE; + + case D3D10_SVT_INT: + case D3D10_SVT_UINT: + case D3D10_SVT_BOOL: + out_data[idx] = value; + return TRUE; + + default: + FIXME("Unhandled in_type %#x.\n", in_type); + return FALSE; + } +} + +static BOOL read_int8_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, INT8 *out_data, UINT idx) +{ + switch (in_type) + { + case D3D10_SVT_INT: + case D3D10_SVT_UINT: + out_data[idx] = value; + return TRUE; + + default: + FIXME("Unhandled in_type %#x.\n", in_type); + return FALSE; + } +} + +static BOOL d3d10_effect_read_numeric_value(uint32_t value, D3D_SHADER_VARIABLE_TYPE in_type, + D3D_SHADER_VARIABLE_TYPE out_type, void *out_data, unsigned int out_idx) +{ + switch (out_type) + { + case D3D10_SVT_FLOAT: + return read_float_value(value, in_type, out_data, out_idx); + case D3D10_SVT_INT: + case D3D10_SVT_UINT: + case D3D10_SVT_BOOL: + return read_int32_value(value, in_type, out_data, out_idx); + case D3D10_SVT_UINT8: + return read_int8_value(value, in_type, out_data, out_idx); + default: + FIXME("Unsupported property type %u.\n", out_type); + return FALSE; + } +} + +static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_dependencies *deps, + void *container) +{ + const struct d3d10_effect_state_property_info *property_info; + struct d3d10_effect_prop_dependency *d; + struct d3d10_effect_variable *v; + unsigned int i, j, count; + uint32_t value; + void *dst; + + for (i = 0; i < deps->count; ++i) + { + d = &deps->entries[i]; + + property_info = &property_infos[d->id]; + + dst = (char *)container + property_info->offset; + + switch (d->operation) + { + case D3D10_EOO_VAR: + case D3D10_EOO_CONST_INDEX: + + v = d->u.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_read_numeric_value(value, v->type->basetype, property_info->type, dst, j); + } + + break; + + default: + FIXME("Unsupported property update for %u.\n", d->operation); + } + } +} + static BOOL d3d_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size) { SIZE_T max_capacity, new_capacity; @@ -1567,63 +1730,6 @@ static const struct d3d10_effect_state_storage_info *get_storage_info(D3D_SHADER return NULL; }
-static BOOL read_float_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, float *out_data, UINT idx) -{ - switch (in_type) - { - case D3D10_SVT_FLOAT: - out_data[idx] = *(float *)&value; - return TRUE; - - case D3D10_SVT_INT: - out_data[idx] = (INT)value; - return TRUE; - - case D3D10_SVT_UINT: - out_data[idx] = value; - return TRUE; - - default: - FIXME("Unhandled in_type %#x.\n", in_type); - return FALSE; - } -} - -static BOOL read_int32_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, INT *out_data, UINT idx) -{ - switch (in_type) - { - case D3D10_SVT_FLOAT: - out_data[idx] = *(float *)&value; - return TRUE; - - case D3D10_SVT_INT: - case D3D10_SVT_UINT: - case D3D10_SVT_BOOL: - out_data[idx] = value; - return TRUE; - - default: - FIXME("Unhandled in_type %#x.\n", in_type); - return FALSE; - } -} - -static BOOL read_int8_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, INT8 *out_data, UINT idx) -{ - switch (in_type) - { - case D3D10_SVT_INT: - case D3D10_SVT_UINT: - out_data[idx] = value; - return TRUE; - - default: - FIXME("Unhandled in_type %#x.\n", in_type); - return FALSE; - } -} - static BOOL read_value_list(const char *data, size_t data_size, DWORD offset, D3D_SHADER_VARIABLE_TYPE out_type, UINT out_base, UINT out_size, void *out_data) { @@ -1663,19 +1769,11 @@ static BOOL read_value_list(const char *data, size_t data_size, DWORD offset, switch (out_type) { case D3D10_SVT_FLOAT: - if (!read_float_value(value, in_type, out_data, out_idx)) - return FALSE; - break; - case D3D10_SVT_INT: case D3D10_SVT_UINT: case D3D10_SVT_BOOL: - if (!read_int32_value(value, in_type, out_data, out_idx)) - return FALSE; - break; - case D3D10_SVT_UINT8: - if (!read_int8_value(value, in_type, out_data, out_idx)) + if (!d3d10_effect_read_numeric_value(value, in_type, out_type, out_data, out_idx)) return FALSE; break;
@@ -1695,6 +1793,14 @@ static BOOL read_value_list(const char *data, size_t data_size, DWORD offset, *(void **)out_data = &null_shader_resource_variable; break;
+ case D3D10_SVT_DEPTHSTENCIL: + *(void **)out_data = &null_depth_stencil_variable; + break; + + case D3D10_SVT_BLEND: + *(void **)out_data = &null_blend_variable; + break; + default: FIXME("Unhandled out_type %#x.\n", out_type); return FALSE; @@ -1745,21 +1851,31 @@ static BOOL is_object_property_type_matching(const struct d3d10_effect_state_pro } }
+static HRESULT d3d10_effect_add_prop_dependency(struct d3d10_effect_prop_dependencies *d, + const struct d3d10_effect_prop_dependency *dep) +{ + if (!d3d_array_reserve((void **)&d->entries, &d->capacity, d->count + 1, sizeof(*d->entries))) + return E_OUTOFMEMORY; + + d->entries[d->count++] = *dep; + + return S_OK; +} + static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size, const char **ptr, enum d3d10_effect_container_type container_type, - struct d3d10_effect *effect, void *container) + struct d3d10_effect *effect, void *container, struct d3d10_effect_prop_dependencies *d) { const struct d3d10_effect_state_property_info *property_info; + unsigned int variable_idx, *dst_index, offset, idx, id; UINT value_offset, sodecl_offset, operation; + struct d3d10_effect_prop_dependency dep; struct d3d10_effect_variable *variable; - unsigned int variable_idx, *dst_index; const char *data_ptr; const char *name; size_t name_len; HRESULT hr; void *dst; - UINT idx; - UINT id;
read_dword(ptr, &id); read_dword(ptr, &idx); @@ -1844,8 +1960,20 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size } else { - FIXME("Assigning variables to numeric fields is not supported.\n"); - return E_FAIL; + if (property_info->size * sizeof(float) > variable->type->size_unpacked) + { + WARN("Mismatching variable size %u, property size %u.\n", + variable->type->size_unpacked, property_info->size); + return E_FAIL; + } + + dep.id = id; + dep.idx = idx; + dep.operation = operation; + dep.u.var.v = variable; + dep.u.var.offset = 0; + + return d3d10_effect_add_prop_dependency(d, &dep); }
break; @@ -1868,7 +1996,8 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size return E_FAIL; }
- TRACE("Variable name %s[%u].\n", debugstr_a(name), variable_idx); + TRACE("Variable name %s[%s%u].\n", debugstr_a(name), is_object_property(property_info) ? + "" : "offset ", variable_idx);
if (!(variable = d3d10_effect_get_variable_by_name(effect, name))) { @@ -1876,15 +2005,14 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size return E_FAIL; }
- /* Has to be an array */ - if (!variable->type->element_count || variable_idx >= variable->type->element_count) - { - WARN("Invalid array size %u.\n", variable->type->element_count); - return E_FAIL; - } - if (is_object_property(property_info)) { + if (!variable->type->element_count || variable_idx >= variable->type->element_count) + { + WARN("Invalid array size %u.\n", variable->type->element_count); + return E_FAIL; + } + if (!is_object_property_type_matching(property_info, variable)) { WARN("Object type mismatch. Variable type %#x, property type %#x.\n", @@ -1907,8 +2035,22 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size } else { - FIXME("Assigning indexed variables to numeric fields is not supported.\n"); - return E_FAIL; + offset = variable_idx * sizeof(float); + + if (offset >= variable->type->size_unpacked || + variable->type->size_unpacked - offset < property_info->size * sizeof(float)) + { + WARN("Invalid numeric variable data offset %u.\n", variable_idx); + return E_FAIL; + } + + dep.id = id; + dep.idx = idx; + dep.operation = operation; + dep.u.var.v = variable; + dep.u.var.offset = offset; + + return d3d10_effect_add_prop_dependency(d, &dep); }
break; @@ -2016,7 +2158,7 @@ static HRESULT parse_fx10_pass(const char *data, size_t data_size, for (i = 0; i < object_count; ++i) { if (FAILED(hr = parse_fx10_property_assignment(data, data_size, ptr, - D3D10_C_PASS, p->technique->effect, p))) + D3D10_C_PASS, p->technique->effect, p, &p->dependencies))) { WARN("Failed to parse pass assignment %u, hr %#x.\n", i, hr); return hr; @@ -2385,7 +2527,8 @@ static HRESULT parse_fx10_object_variable(const char *data, size_t data_size, for (j = 0; j < prop_count; ++j) { if (FAILED(hr = parse_fx10_property_assignment(data, data_size, ptr, - get_var_container_type(var), var->effect, &var->u.state.desc))) + get_var_container_type(var), var->effect, &var->u.state.desc, + &var->u.state.dependencies))) { ERR("Failed to read property list.\n"); return hr; @@ -3063,6 +3206,7 @@ static void d3d10_effect_variable_destroy(struct d3d10_effect_variable *v) case D3D10_SVT_SAMPLER: if (v->u.state.object.object) IUnknown_Release(v->u.state.object.object); + d3d10_effect_clear_prop_dependencies(&v->u.state.dependencies); break;
case D3D10_SVT_TEXTURE1D: @@ -3106,6 +3250,7 @@ static void d3d10_effect_pass_destroy(struct d3d10_effect_pass *p)
heap_free(p->name); d3d10_effect_annotations_destroy(&p->annotations); + d3d10_effect_clear_prop_dependencies(&p->dependencies); }
static void d3d10_effect_technique_destroy(struct d3d10_effect_technique *t) @@ -3820,6 +3965,8 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_pass_GetDesc(ID3D10EffectPass *ifa return E_INVALIDARG; }
+ d3d10_effect_update_dependent_props(&pass->dependencies, pass); + vs = d3d10_array_get_element(pass->vs.shader, pass->vs.index); input_signature = vs->u.shader.input_signature;
@@ -4105,6 +4252,8 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_pass_Apply(ID3D10EffectPass *iface
if (flags) FIXME("Ignoring flags (%#x)\n", flags);
+ d3d10_effect_update_dependent_props(&pass->dependencies, pass); + if (pass->vs.shader != &null_shader_variable) d3d10_effect_pass_set_shader(pass, &pass->vs); if (pass->gs.shader != &null_shader_variable) @@ -4550,7 +4699,6 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_variable_GetRawValue(ID3D10EffectV void *data, UINT offset, UINT count) { struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable(iface); - BOOL is_buffer;
TRACE("iface %p, data %p, offset %u, count %u.\n", iface, data, offset, count);
@@ -4560,24 +4708,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_variable_GetRawValue(ID3D10EffectV return E_FAIL; }
- is_buffer = v->type->basetype == D3D10_SVT_CBUFFER || v->type->basetype == D3D10_SVT_TBUFFER; - - if (v->type->type_class == D3D10_SVC_OBJECT && !is_buffer) - { - WARN("Not supported on object variables of type %s.\n", - debug_d3d10_shader_variable_type(v->type->basetype)); - return D3DERR_INVALIDCALL; - } - - if (!is_buffer) - { - offset += v->buffer_offset; - v = v->buffer; - } - - memcpy(data, v->u.buffer.local_buffer + offset, count); - - return S_OK; + return d3d10_effect_variable_get_raw_value(v, data, offset, count); }
static const struct ID3D10EffectVariableVtbl d3d10_effect_variable_vtbl = @@ -4873,6 +5004,7 @@ static BOOL get_value_as_bool(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_typ { case D3D10_SVT_FLOAT: case D3D10_SVT_INT: + case D3D10_SVT_UINT: case D3D10_SVT_BOOL: if (*(DWORD *)src_data) return -1; @@ -4893,6 +5025,7 @@ static int get_value_as_int(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_type) return (int)(*(float *)src_data);
case D3D10_SVT_INT: + case D3D10_SVT_UINT: return *(int *)src_data;
case D3D10_SVT_BOOL: @@ -4911,6 +5044,7 @@ static float get_value_as_float(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_t return *(float *)src_data;
case D3D10_SVT_INT: + case D3D10_SVT_UINT: return (float)(*(int *)src_data);
case D3D10_SVT_BOOL: @@ -4941,6 +5075,7 @@ static void get_vector_as_type(BYTE *dst_data, D3D_SHADER_VARIABLE_TYPE dst_type break;
case D3D10_SVT_INT: + case D3D10_SVT_UINT: *(int *)dst_data_dword = get_value_as_int(src_data_dword, src_type); break;
diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index a8a64a6ed0d..b379fc7bddc 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -4843,43 +4843,32 @@ cbuffer cb float f0, f_a[2]; int i0, i_a[2]; bool b0, b_a[2]; + uint i1, i1_a[2]; }; #endif static DWORD fx_test_scalar_variable[] = { - 0x43425844, 0xe4da4aa6, 0x1380ddc5, 0x445edad5, - 0x08581666, 0x00000001, 0x0000020b, 0x00000001, - 0x00000024, 0x30315846, 0x000001df, 0xfeff1001, - 0x00000001, 0x00000006, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x000000d3, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x66006263, - 0x74616f6c, 0x00000700, 0x00000100, 0x00000000, - 0x00000400, 0x00001000, 0x00000400, 0x00090900, - 0x00306600, 0x00000007, 0x00000001, 0x00000002, - 0x00000014, 0x00000010, 0x00000008, 0x00000909, - 0x00615f66, 0x00746e69, 0x0000004c, 0x00000001, - 0x00000000, 0x00000004, 0x00000010, 0x00000004, - 0x00000911, 0x4c003069, 0x01000000, 0x02000000, - 0x14000000, 0x10000000, 0x08000000, 0x11000000, - 0x69000009, 0x6200615f, 0x006c6f6f, 0x0000008f, - 0x00000001, 0x00000000, 0x00000004, 0x00000010, - 0x00000004, 0x00000921, 0x8f003062, 0x01000000, - 0x02000000, 0x14000000, 0x10000000, 0x08000000, - 0x21000000, 0x62000009, 0x0400615f, 0x70000000, - 0x00000000, 0x06000000, 0xff000000, 0x00ffffff, - 0x29000000, 0x0d000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x48000000, - 0x2c000000, 0x00000000, 0x10000000, 0x00000000, - 0x00000000, 0x00000000, 0x6c000000, 0x50000000, - 0x00000000, 0x24000000, 0x00000000, 0x00000000, - 0x00000000, 0x8b000000, 0x6f000000, 0x00000000, - 0x30000000, 0x00000000, 0x00000000, 0x00000000, - 0xb0000000, 0x94000000, 0x00000000, 0x44000000, - 0x00000000, 0x00000000, 0x00000000, 0xcf000000, - 0xb3000000, 0x00000000, 0x50000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, + 0x43425844, 0x7d97f44c, 0x1da4b110, 0xb710407e, 0x26750c1c, 0x00000001, 0x00000288, 0x00000001, + 0x00000024, 0x30315846, 0x0000025c, 0xfeff1001, 0x00000001, 0x00000008, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000118, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66006263, + 0x74616f6c, 0x00000700, 0x00000100, 0x00000000, 0x00000400, 0x00001000, 0x00000400, 0x00090900, + 0x00306600, 0x00000007, 0x00000001, 0x00000002, 0x00000014, 0x00000010, 0x00000008, 0x00000909, + 0x00615f66, 0x00746e69, 0x0000004c, 0x00000001, 0x00000000, 0x00000004, 0x00000010, 0x00000004, + 0x00000911, 0x4c003069, 0x01000000, 0x02000000, 0x14000000, 0x10000000, 0x08000000, 0x11000000, + 0x69000009, 0x6200615f, 0x006c6f6f, 0x0000008f, 0x00000001, 0x00000000, 0x00000004, 0x00000010, + 0x00000004, 0x00000921, 0x8f003062, 0x01000000, 0x02000000, 0x14000000, 0x10000000, 0x08000000, + 0x21000000, 0x62000009, 0x7500615f, 0x00746e69, 0x000000d3, 0x00000001, 0x00000000, 0x00000004, + 0x00000010, 0x00000004, 0x00000919, 0xd3003169, 0x01000000, 0x02000000, 0x14000000, 0x10000000, + 0x08000000, 0x19000000, 0x69000009, 0x00615f31, 0x00000004, 0x00000090, 0x00000000, 0x00000008, + 0xffffffff, 0x00000000, 0x00000029, 0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000048, 0x0000002c, 0x00000000, 0x00000010, 0x00000000, 0x00000000, 0x00000000, + 0x0000006c, 0x00000050, 0x00000000, 0x00000024, 0x00000000, 0x00000000, 0x00000000, 0x0000008b, + 0x0000006f, 0x00000000, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x000000b0, 0x00000094, + 0x00000000, 0x00000044, 0x00000000, 0x00000000, 0x00000000, 0x000000cf, 0x000000b3, 0x00000000, + 0x00000050, 0x00000000, 0x00000000, 0x00000000, 0x000000f4, 0x000000d8, 0x00000000, 0x00000064, + 0x00000000, 0x00000000, 0x00000000, 0x00000113, 0x000000f7, 0x00000000, 0x00000070, 0x00000000, + 0x00000000, 0x00000000, };
static void test_scalar_methods(ID3D10EffectScalarVariable *var, D3D10_SHADER_VARIABLE_TYPE type, @@ -5146,6 +5135,7 @@ static void test_effect_scalar_variable(void) {"f0", D3D10_SVT_FLOAT}, {"i0", D3D10_SVT_INT}, {"b0", D3D10_SVT_BOOL}, + {"i1", D3D10_SVT_UINT}, {"f_a", D3D10_SVT_FLOAT, TRUE}, {"i_a", D3D10_SVT_INT, TRUE}, {"b_a", D3D10_SVT_BOOL, TRUE}, @@ -5178,7 +5168,7 @@ static void test_effect_scalar_variable(void) effect_desc.ConstantBuffers); ok(effect_desc.SharedConstantBuffers == 0, "Unexpected shared constant buffers count %u.\n", effect_desc.SharedConstantBuffers); - ok(effect_desc.GlobalVariables == 6, "Unexpected global variables count %u.\n", + ok(effect_desc.GlobalVariables == 8, "Unexpected global variables count %u.\n", effect_desc.GlobalVariables); ok(effect_desc.SharedGlobalVariables == 0, "Unexpected shared global variables count %u.\n", effect_desc.SharedGlobalVariables); @@ -7638,6 +7628,154 @@ static void test_effect_raw_value(void) ok(!refcount, "Device has %u references left.\n", refcount); }
+#if 0 +uint i1; +uint i1_a[2]; +float4 fv1 = {0.5f, 0.6f, 0.7f, 0.8f}; +float4 fv1_a[2] = { { 1.0f, 1.1f, 1.2f, 1.3f }, {0.1f, 0.2f, 0.3f, 0.4f} }; +int i2 = 0x123; +int i2_a[2] = { 0x1, 0x2 }; +float f1 = 0.3f; + +technique10 tech +{ + pass P0 + { + SetBlendState(NULL, fv1, i2); + SetDepthStencilState(NULL, i1); + } + pass P1 + { + SetBlendState(NULL, fv1_a[1], i2_a[1]); + SetDepthStencilState(NULL, i1_a[1]); + } +} +#endif +static DWORD fx_test_effect_dynamic_numeric_field[] = +{ + 0x43425844, 0xc53c7634, 0x9d90c190, 0x5a0b43ea, 0x77aab553, 0x00000001, 0x000003af, 0x00000001, + 0x00000024, 0x30315846, 0x00000383, 0xfeff1001, 0x00000001, 0x00000007, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000197, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f6c4724, + 0x736c6162, 0x6e697500, 0x000d0074, 0x00010000, 0x00000000, 0x00040000, 0x00100000, 0x00040000, + 0x09190000, 0x31690000, 0x00000d00, 0x00000100, 0x00000200, 0x00001400, 0x00001000, 0x00000800, + 0x00091900, 0x5f316900, 0x6c660061, 0x3474616f, 0x00005200, 0x00000100, 0x00000000, 0x00001000, + 0x00001000, 0x00001000, 0x00210a00, 0x31766600, 0x00000000, 0x19999a3f, 0x3333333f, 0x4ccccd3f, + 0x0000523f, 0x00000100, 0x00000200, 0x00002000, 0x00001000, 0x00002000, 0x00210a00, 0x31766600, + 0x0000615f, 0xcd3f8000, 0x9a3f8ccc, 0x663f9999, 0xcd3fa666, 0xcd3dcccc, 0x9a3e4ccc, 0xcd3e9999, + 0x693ecccc, 0xcb00746e, 0x01000000, 0x00000000, 0x04000000, 0x10000000, 0x04000000, 0x11000000, + 0x69000009, 0x01230032, 0x00cb0000, 0x00010000, 0x00020000, 0x00140000, 0x00100000, 0x00080000, + 0x09110000, 0x32690000, 0x0100615f, 0x02000000, 0x66000000, 0x74616f6c, 0x00011b00, 0x00000100, + 0x00000000, 0x00000400, 0x00001000, 0x00000400, 0x00090900, 0x00316600, 0x3e99999a, 0x68636574, + 0x00305000, 0x00000001, 0x00000002, 0x00000000, 0x00000001, 0x00000002, 0x00000000, 0xa5003150, + 0x04000000, 0x0e000000, 0x04000001, 0x01000000, 0x02000000, 0x00000000, 0x4d000000, 0x04000000, + 0x01000000, 0x02000000, 0x00000000, 0x04000000, 0x90000000, 0x00000000, 0x07000000, 0xff000000, + 0x00ffffff, 0x2e000000, 0x12000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4d000000, 0x31000000, 0x00000000, 0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x75000000, + 0x59000000, 0x00000000, 0x30000000, 0x79000000, 0x00000000, 0x00000000, 0xa5000000, 0x89000000, + 0x00000000, 0x40000000, 0xab000000, 0x00000000, 0x00000000, 0xeb000000, 0xcf000000, 0x00000000, + 0x60000000, 0xee000000, 0x00000000, 0x00000000, 0x0e000000, 0xf2000001, 0x00000000, 0x70000000, + 0x13000000, 0x00000001, 0x00000000, 0x3d000000, 0x21000001, 0x00000001, 0x84000000, 0x40000000, + 0x00000001, 0x00000000, 0x44000000, 0x02000001, 0x00000000, 0x49000000, 0x05000001, 0x00000000, + 0x0a000000, 0x00000000, 0x02000000, 0x75000000, 0x0b000000, 0x00000000, 0x02000000, 0xeb000000, + 0x02000000, 0x00000000, 0x01000000, 0x4c000000, 0x09000001, 0x00000000, 0x02000000, 0x2e000000, + 0x01000000, 0x00000000, 0x01000000, 0x58000000, 0x64000001, 0x05000001, 0x00000000, 0x0a000000, + 0x00000000, 0x03000000, 0x67000000, 0x0b000001, 0x00000000, 0x03000000, 0x6f000000, 0x02000001, + 0x00000000, 0x01000000, 0x77000000, 0x09000001, 0x00000000, 0x03000000, 0x83000000, 0x01000001, + 0x00000000, 0x01000000, 0x8b000000, 0x00000001, +}; + +static void test_effect_dynamic_numeric_field(void) +{ + ID3D10EffectScalarVariable *scalar; + ID3D10DepthStencilState *ds_state; + ID3D10BlendState *blend_state; + UINT stencil_ref, sample_mask; + ID3D10EffectTechnique *tech; + D3D10_PASS_DESC pass_desc; + ID3D10EffectVariable *v; + ID3D10EffectPass *pass; + float blend_factor[4]; + ID3D10Effect *effect; + ID3D10Device *device; + ULONG refcount; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + hr = create_effect(fx_test_effect_dynamic_numeric_field, 0, device, NULL, &effect); + ok(SUCCEEDED(hr), "Failed to create an effect, hr %#x.\n", hr); + + tech = effect->lpVtbl->GetTechniqueByIndex(effect, 0); + ok(tech->lpVtbl->IsValid(tech), "Expected valid technique.\n"); + + /* Pass fields */ + pass = tech->lpVtbl->GetPassByName(tech, "P0"); + + ID3D10Device_OMSetDepthStencilState(device, NULL, 0x1); + memset(blend_factor, 0, sizeof(blend_factor)); + ID3D10Device_OMSetBlendState(device, NULL, blend_factor, 0); + hr = pass->lpVtbl->Apply(pass, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ID3D10Device_OMGetDepthStencilState(device, &ds_state, &stencil_ref); + ok(!stencil_ref, "Unexpected stencil ref value %#x.\n", stencil_ref); + ID3D10Device_OMGetBlendState(device, &blend_state, blend_factor, &sample_mask); + ok(blend_factor[0] == 0.5f, "Got unexpected blend_factor[0] %.8e.\n", blend_factor[0]); + ok(blend_factor[1] == 0.6f, "Got unexpected blend_factor[1] %.8e.\n", blend_factor[1]); + ok(blend_factor[2] == 0.7f, "Got unexpected blend_factor[2] %.8e.\n", blend_factor[2]); + ok(blend_factor[3] == 0.8f, "Got unexpected blend_factor[3] %.8e.\n", blend_factor[3]); + ok(sample_mask == 0x123, "Unexpected sample mask %#x.\n", sample_mask); + + v = effect->lpVtbl->GetVariableByName(effect, "i1"); + scalar = v->lpVtbl->AsScalar(v); + hr = scalar->lpVtbl->SetInt(scalar, 2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = pass->lpVtbl->Apply(pass, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ID3D10Device_OMGetDepthStencilState(device, &ds_state, &stencil_ref); + ok(stencil_ref == 0x2, "Unexpected stencil ref value %#x.\n", stencil_ref); + + hr = scalar->lpVtbl->SetInt(scalar, 3); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = pass->lpVtbl->GetDesc(pass, &pass_desc); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(pass_desc.StencilRef == 0x3, "Unexpected stencil ref value %#x.\n", stencil_ref); + ID3D10Device_OMGetDepthStencilState(device, &ds_state, &stencil_ref); + ok(stencil_ref == 0x2, "Unexpected stencil ref value %#x.\n", stencil_ref); + + pass = tech->lpVtbl->GetPassByName(tech, "P1"); + + v = effect->lpVtbl->GetVariableByName(effect, "i1_a"); + v = v->lpVtbl->GetElement(v, 1); + scalar = v->lpVtbl->AsScalar(v); + hr = scalar->lpVtbl->SetInt(scalar, 4); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + ID3D10Device_OMSetDepthStencilState(device, NULL, 0x1); + memset(blend_factor, 0, sizeof(blend_factor)); + ID3D10Device_OMSetBlendState(device, NULL, blend_factor, 0); + hr = pass->lpVtbl->Apply(pass, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ID3D10Device_OMGetDepthStencilState(device, &ds_state, &stencil_ref); + ok(stencil_ref == 0x4, "Unexpected stencil ref value %#x.\n", stencil_ref); + ID3D10Device_OMGetBlendState(device, &blend_state, blend_factor, &sample_mask); + ok(blend_factor[0] == 0.1f, "Got unexpected blend_factor[0] %.8e.\n", blend_factor[0]); + ok(blend_factor[1] == 0.2f, "Got unexpected blend_factor[1] %.8e.\n", blend_factor[1]); + ok(blend_factor[2] == 0.3f, "Got unexpected blend_factor[2] %.8e.\n", blend_factor[2]); + ok(blend_factor[3] == 0.4f, "Got unexpected blend_factor[3] %.8e.\n", blend_factor[3]); + ok(sample_mask == 0x2, "Unexpected sample mask %#x.\n", sample_mask); + + 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(); @@ -7661,4 +7799,5 @@ START_TEST(effect) test_effect_pool(); test_effect_default_variable_value(); test_effect_raw_value(); + test_effect_dynamic_numeric_field(); }
On Thu, Oct 28, 2021 at 9:46 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/d3d10_private.h | 9 + dlls/d3d10/effect.c | 341 ++++++++++++++++++++++++++----------- dlls/d3d10/tests/effect.c | 207 ++++++++++++++++++---- 3 files changed, 420 insertions(+), 137 deletions(-)
diff --git a/dlls/d3d10/d3d10_private.h b/dlls/d3d10/d3d10_private.h index 11b3b4e9482..f8e415f860b 100644 --- a/dlls/d3d10/d3d10_private.h +++ b/dlls/d3d10/d3d10_private.h @@ -95,6 +95,13 @@ struct d3d10_effect_shader_variable unsigned int isinline : 1; };
+struct d3d10_effect_prop_dependencies +{
- struct d3d10_effect_prop_dependency *entries;
- SIZE_T count;
- SIZE_T capacity;
+};
struct d3d10_effect_sampler_desc { D3D10_SAMPLER_DESC desc; @@ -118,6 +125,7 @@ struct d3d10_effect_state_object_variable ID3D10SamplerState *sampler; IUnknown *object; } object;
- struct d3d10_effect_prop_dependencies dependencies;
};
struct d3d10_effect_resource_variable @@ -217,6 +225,7 @@ struct d3d10_effect_pass char *name; struct d3d10_effect_annotations annotations;
- struct d3d10_effect_prop_dependencies dependencies; struct d3d10_effect_pass_shader_desc vs; struct d3d10_effect_pass_shader_desc ps; struct d3d10_effect_pass_shader_desc gs;
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 23374fdb48f..34a5eb1b701 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -168,6 +168,27 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+struct d3d10_effect_prop_dependency +{
- unsigned int id;
- unsigned int idx;
- unsigned int operation;
- union
- {
struct
{
struct d3d10_effect_variable *v;
unsigned int offset;
} var;
- } u;
+};
It should be possible to use anonymous unions now in d3d10, right? Not that you necessarily have to do that here, depending on what's going to happen to this struct in the following patches.
@@ -386,6 +407,148 @@ static const char *debug_d3d10_shader_variable_type(D3D10_SHADER_VARIABLE_TYPE t
#undef WINE_D3D10_TO_STR
+static HRESULT d3d10_effect_variable_get_raw_value(struct d3d10_effect_variable *v,
void *data, unsigned int offset, unsigned int count)
+{
- BOOL is_buffer;
- is_buffer = v->type->basetype == D3D10_SVT_CBUFFER || v->type->basetype == D3D10_SVT_TBUFFER;
- if (v->type->type_class == D3D10_SVC_OBJECT && !is_buffer)
- {
WARN("Not supported on object variables of type %s.\n",
debug_d3d10_shader_variable_type(v->type->basetype));
return D3DERR_INVALIDCALL;
- }
- if (!is_buffer)
- {
offset += v->buffer_offset;
v = v->buffer;
- }
- memcpy(data, v->u.buffer.local_buffer + offset, count);
- return S_OK;
+}
+static BOOL read_float_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, float *out_data, UINT idx)
I think you forgot to update these helpers after you introduced d3d10_effect_read_numeric_value(), specifically WRT replacing DWORD with uint32_t for value and UINT with unsigned int for idx.
Actually, it's probably nicer if you split the introduction of that helper to a separate patch. You could also change the argument types of read_value_list() in the same patch.
+static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_dependencies *deps,
void *container)
+{
- const struct d3d10_effect_state_property_info *property_info;
- struct d3d10_effect_prop_dependency *d;
- struct d3d10_effect_variable *v;
- unsigned int i, j, count;
- uint32_t value;
- void *dst;
- for (i = 0; i < deps->count; ++i)
- {
d = &deps->entries[i];
property_info = &property_infos[d->id];
dst = (char *)container + property_info->offset;
switch (d->operation)
{
case D3D10_EOO_VAR:
case D3D10_EOO_CONST_INDEX:
v = d->u.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_read_numeric_value(value, v->type->basetype, property_info->type, dst, j);
}
break;
default:
FIXME("Unsupported property update for %u.\n", d->operation);
}
- }
+}
It would be nice to have dirty flags to avoid unnecessary recomputation. For example, something like the "changed" flag we have for buffers but referring to variables and their values. Problem is, there are a few quirks (e.g. SetRawValue(), those wild out-of-bounds accesses) that make this quite problematic. So I can be convinced to let it go :)
It would be something for a separate patch anyway.
@@ -1695,6 +1793,14 @@ static BOOL read_value_list(const char *data, size_t data_size, DWORD offset, *(void **)out_data = &null_shader_resource_variable; break;
case D3D10_SVT_DEPTHSTENCIL:
*(void **)out_data = &null_depth_stencil_variable;
break;
case D3D10_SVT_BLEND:
*(void **)out_data = &null_blend_variable;
break;
default: FIXME("Unhandled out_type %#x.\n", out_type); return FALSE;
Would this also make sense as a separate patch?
@@ -1745,21 +1851,31 @@ static BOOL is_object_property_type_matching(const struct d3d10_effect_state_pro } }
+static HRESULT d3d10_effect_add_prop_dependency(struct d3d10_effect_prop_dependencies *d,
const struct d3d10_effect_prop_dependency *dep)
+{
- if (!d3d_array_reserve((void **)&d->entries, &d->capacity, d->count + 1, sizeof(*d->entries)))
return E_OUTOFMEMORY;
- d->entries[d->count++] = *dep;
- return S_OK;
+}
We probably want to go for the usual exponential growth pattern here. This separate helper is nice in that it can hide that kind of details away.
@@ -4873,6 +5004,7 @@ static BOOL get_value_as_bool(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_typ { case D3D10_SVT_FLOAT: case D3D10_SVT_INT:
case D3D10_SVT_UINT: case D3D10_SVT_BOOL: if (*(DWORD *)src_data) return -1;
@@ -4893,6 +5025,7 @@ static int get_value_as_int(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_type) return (int)(*(float *)src_data);
case D3D10_SVT_INT:
case D3D10_SVT_UINT: return *(int *)src_data; case D3D10_SVT_BOOL:
@@ -4911,6 +5044,7 @@ static float get_value_as_float(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_t return *(float *)src_data;
case D3D10_SVT_INT:
case D3D10_SVT_UINT: return (float)(*(int *)src_data); case D3D10_SVT_BOOL:
@@ -4941,6 +5075,7 @@ static void get_vector_as_type(BYTE *dst_data, D3D_SHADER_VARIABLE_TYPE dst_type break;
case D3D10_SVT_INT:
case D3D10_SVT_UINT: *(int *)dst_data_dword = get_value_as_int(src_data_dword, src_type); break;
These hunks should probably be split to a separate patch...
diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index a8a64a6ed0d..b379fc7bddc 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -4843,43 +4843,32 @@ cbuffer cb float f0, f_a[2]; int i0, i_a[2]; bool b0, b_a[2];
- uint i1, i1_a[2];
}; #endif static DWORD fx_test_scalar_variable[] = {
- 0x43425844, 0xe4da4aa6, 0x1380ddc5, 0x445edad5,
- 0x08581666, 0x00000001, 0x0000020b, 0x00000001,
- 0x00000024, 0x30315846, 0x000001df, 0xfeff1001,
- 0x00000001, 0x00000006, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x000000d3,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x66006263,
- 0x74616f6c, 0x00000700, 0x00000100, 0x00000000,
- 0x00000400, 0x00001000, 0x00000400, 0x00090900,
- 0x00306600, 0x00000007, 0x00000001, 0x00000002,
- 0x00000014, 0x00000010, 0x00000008, 0x00000909,
- 0x00615f66, 0x00746e69, 0x0000004c, 0x00000001,
- 0x00000000, 0x00000004, 0x00000010, 0x00000004,
- 0x00000911, 0x4c003069, 0x01000000, 0x02000000,
- 0x14000000, 0x10000000, 0x08000000, 0x11000000,
- 0x69000009, 0x6200615f, 0x006c6f6f, 0x0000008f,
- 0x00000001, 0x00000000, 0x00000004, 0x00000010,
- 0x00000004, 0x00000921, 0x8f003062, 0x01000000,
- 0x02000000, 0x14000000, 0x10000000, 0x08000000,
- 0x21000000, 0x62000009, 0x0400615f, 0x70000000,
- 0x00000000, 0x06000000, 0xff000000, 0x00ffffff,
- 0x29000000, 0x0d000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x48000000,
- 0x2c000000, 0x00000000, 0x10000000, 0x00000000,
- 0x00000000, 0x00000000, 0x6c000000, 0x50000000,
- 0x00000000, 0x24000000, 0x00000000, 0x00000000,
- 0x00000000, 0x8b000000, 0x6f000000, 0x00000000,
- 0x30000000, 0x00000000, 0x00000000, 0x00000000,
- 0xb0000000, 0x94000000, 0x00000000, 0x44000000,
- 0x00000000, 0x00000000, 0x00000000, 0xcf000000,
- 0xb3000000, 0x00000000, 0x50000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000,
- 0x43425844, 0x7d97f44c, 0x1da4b110, 0xb710407e, 0x26750c1c, 0x00000001, 0x00000288, 0x00000001,
- 0x00000024, 0x30315846, 0x0000025c, 0xfeff1001, 0x00000001, 0x00000008, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000118, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66006263,
- 0x74616f6c, 0x00000700, 0x00000100, 0x00000000, 0x00000400, 0x00001000, 0x00000400, 0x00090900,
- 0x00306600, 0x00000007, 0x00000001, 0x00000002, 0x00000014, 0x00000010, 0x00000008, 0x00000909,
- 0x00615f66, 0x00746e69, 0x0000004c, 0x00000001, 0x00000000, 0x00000004, 0x00000010, 0x00000004,
- 0x00000911, 0x4c003069, 0x01000000, 0x02000000, 0x14000000, 0x10000000, 0x08000000, 0x11000000,
- 0x69000009, 0x6200615f, 0x006c6f6f, 0x0000008f, 0x00000001, 0x00000000, 0x00000004, 0x00000010,
- 0x00000004, 0x00000921, 0x8f003062, 0x01000000, 0x02000000, 0x14000000, 0x10000000, 0x08000000,
- 0x21000000, 0x62000009, 0x7500615f, 0x00746e69, 0x000000d3, 0x00000001, 0x00000000, 0x00000004,
- 0x00000010, 0x00000004, 0x00000919, 0xd3003169, 0x01000000, 0x02000000, 0x14000000, 0x10000000,
- 0x08000000, 0x19000000, 0x69000009, 0x00615f31, 0x00000004, 0x00000090, 0x00000000, 0x00000008,
- 0xffffffff, 0x00000000, 0x00000029, 0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000048, 0x0000002c, 0x00000000, 0x00000010, 0x00000000, 0x00000000, 0x00000000,
- 0x0000006c, 0x00000050, 0x00000000, 0x00000024, 0x00000000, 0x00000000, 0x00000000, 0x0000008b,
- 0x0000006f, 0x00000000, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x000000b0, 0x00000094,
- 0x00000000, 0x00000044, 0x00000000, 0x00000000, 0x00000000, 0x000000cf, 0x000000b3, 0x00000000,
- 0x00000050, 0x00000000, 0x00000000, 0x00000000, 0x000000f4, 0x000000d8, 0x00000000, 0x00000064,
- 0x00000000, 0x00000000, 0x00000000, 0x00000113, 0x000000f7, 0x00000000, 0x00000070, 0x00000000,
- 0x00000000, 0x00000000,
};
static void test_scalar_methods(ID3D10EffectScalarVariable *var, D3D10_SHADER_VARIABLE_TYPE type, @@ -5146,6 +5135,7 @@ static void test_effect_scalar_variable(void) {"f0", D3D10_SVT_FLOAT}, {"i0", D3D10_SVT_INT}, {"b0", D3D10_SVT_BOOL},
{"i1", D3D10_SVT_UINT}, {"f_a", D3D10_SVT_FLOAT, TRUE}, {"i_a", D3D10_SVT_INT, TRUE}, {"b_a", D3D10_SVT_BOOL, TRUE},
@@ -5178,7 +5168,7 @@ static void test_effect_scalar_variable(void) effect_desc.ConstantBuffers); ok(effect_desc.SharedConstantBuffers == 0, "Unexpected shared constant buffers count %u.\n", effect_desc.SharedConstantBuffers);
- ok(effect_desc.GlobalVariables == 6, "Unexpected global variables count %u.\n",
- ok(effect_desc.GlobalVariables == 8, "Unexpected global variables count %u.\n", effect_desc.GlobalVariables); ok(effect_desc.SharedGlobalVariables == 0, "Unexpected shared global variables count %u.\n", effect_desc.SharedGlobalVariables);
... together with this test change.
On 10/29/21 9:35 PM, Matteo Bruni wrote:
On Thu, Oct 28, 2021 at 9:46 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/d3d10_private.h | 9 + dlls/d3d10/effect.c | 341 ++++++++++++++++++++++++++----------- dlls/d3d10/tests/effect.c | 207 ++++++++++++++++++---- 3 files changed, 420 insertions(+), 137 deletions(-)
diff --git a/dlls/d3d10/d3d10_private.h b/dlls/d3d10/d3d10_private.h index 11b3b4e9482..f8e415f860b 100644 --- a/dlls/d3d10/d3d10_private.h +++ b/dlls/d3d10/d3d10_private.h @@ -95,6 +95,13 @@ struct d3d10_effect_shader_variable unsigned int isinline : 1; };
+struct d3d10_effect_prop_dependencies +{
- struct d3d10_effect_prop_dependency *entries;
- SIZE_T count;
- SIZE_T capacity;
+};
struct d3d10_effect_sampler_desc { D3D10_SAMPLER_DESC desc; @@ -118,6 +125,7 @@ struct d3d10_effect_state_object_variable ID3D10SamplerState *sampler; IUnknown *object; } object;
- struct d3d10_effect_prop_dependencies dependencies;
};
struct d3d10_effect_resource_variable @@ -217,6 +225,7 @@ struct d3d10_effect_pass char *name; struct d3d10_effect_annotations annotations;
- struct d3d10_effect_prop_dependencies dependencies; struct d3d10_effect_pass_shader_desc vs; struct d3d10_effect_pass_shader_desc ps; struct d3d10_effect_pass_shader_desc gs;
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 23374fdb48f..34a5eb1b701 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -168,6 +168,27 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+struct d3d10_effect_prop_dependency +{
- unsigned int id;
- unsigned int idx;
- unsigned int operation;
- union
- {
struct
{
struct d3d10_effect_variable *v;
unsigned int offset;
} var;
- } u;
+};
It should be possible to use anonymous unions now in d3d10, right? Not that you necessarily have to do that here, depending on what's going to happen to this struct in the following patches.
It's extended in 5/5. We don't currently use anonymous unions there, so I'm simply following existing pattern.
@@ -386,6 +407,148 @@ static const char *debug_d3d10_shader_variable_type(D3D10_SHADER_VARIABLE_TYPE t
#undef WINE_D3D10_TO_STR
+static HRESULT d3d10_effect_variable_get_raw_value(struct d3d10_effect_variable *v,
void *data, unsigned int offset, unsigned int count)
+{
- BOOL is_buffer;
- is_buffer = v->type->basetype == D3D10_SVT_CBUFFER || v->type->basetype == D3D10_SVT_TBUFFER;
- if (v->type->type_class == D3D10_SVC_OBJECT && !is_buffer)
- {
WARN("Not supported on object variables of type %s.\n",
debug_d3d10_shader_variable_type(v->type->basetype));
return D3DERR_INVALIDCALL;
- }
- if (!is_buffer)
- {
offset += v->buffer_offset;
v = v->buffer;
- }
- memcpy(data, v->u.buffer.local_buffer + offset, count);
- return S_OK;
+}
+static BOOL read_float_value(DWORD value, D3D_SHADER_VARIABLE_TYPE in_type, float *out_data, UINT idx)
I think you forgot to update these helpers after you introduced d3d10_effect_read_numeric_value(), specifically WRT replacing DWORD with uint32_t for value and UINT with unsigned int for idx.
Actually, it's probably nicer if you split the introduction of that helper to a separate patch. You could also change the argument types of read_value_list() in the same patch.
Yes, will do.
+static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_dependencies *deps,
void *container)
+{
- const struct d3d10_effect_state_property_info *property_info;
- struct d3d10_effect_prop_dependency *d;
- struct d3d10_effect_variable *v;
- unsigned int i, j, count;
- uint32_t value;
- void *dst;
- for (i = 0; i < deps->count; ++i)
- {
d = &deps->entries[i];
property_info = &property_infos[d->id];
dst = (char *)container + property_info->offset;
switch (d->operation)
{
case D3D10_EOO_VAR:
case D3D10_EOO_CONST_INDEX:
v = d->u.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_read_numeric_value(value, v->type->basetype, property_info->type, dst, j);
}
break;
default:
FIXME("Unsupported property update for %u.\n", d->operation);
}
- }
+}
It would be nice to have dirty flags to avoid unnecessary recomputation. For example, something like the "changed" flag we have for buffers but referring to variables and their values. Problem is, there are a few quirks (e.g. SetRawValue(), those wild out-of-bounds accesses) that make this quite problematic. So I can be convinced to let it go :)
It would be useful for expressions I imagine, but even for expression it might be hard to quantify if all an expression does is a single ftou(), which is apparently common.
For value and index updates, I haven't measured obviously, because I didn't implement it.
The whole picture is:
--- foreach() { Â Â get_value(); Â Â put_value(); } use updated fields ---
which with change tracking will extend to
--- foreach() { Â Â if (changed) Â Â { Â Â Â Â Â Â get_value(); Â Â Â Â Â Â put_value(); Â Â Â Â Â Â replace_change_marker(); Â Â } } use updated fields ---
So when nothing changes it will still need to compare for each entry, and get/put is reduced to 4 byte read/write most of the time I think, if not always. Because e.g. setting things like arrays like blend factor produces complex expression, even if you set one element.
Regarding SetRawValue(), yes, the way it works is unfortunate, basically you'll have to track variables in constant buffer objects, so when SetRawValue is called on a buffer you mark them all as changed. But then when you do a larger than necessary raw value write on a variable, you potentially change adjacent variables too. Easy way is to mark all as changed when writing to buffers, and this and following (by offset) when writing to variables.
So that's additional overhead necessary to make property updates respect changed/dirty states.
It would be something for a separate patch anyway.
@@ -1695,6 +1793,14 @@ static BOOL read_value_list(const char *data, size_t data_size, DWORD offset, *(void **)out_data = &null_shader_resource_variable; break;
case D3D10_SVT_DEPTHSTENCIL:
*(void **)out_data = &null_depth_stencil_variable;
break;
case D3D10_SVT_BLEND:
*(void **)out_data = &null_blend_variable;
break;
default: FIXME("Unhandled out_type %#x.\n", out_type); return FALSE;
Would this also make sense as a separate patch?
It depends on how you look at it, e.g. setting stencil ref int with NULL object produces records like this, so it's sort of related. By I can split a much as necessary of course.
@@ -1745,21 +1851,31 @@ static BOOL is_object_property_type_matching(const struct d3d10_effect_state_pro } }
+static HRESULT d3d10_effect_add_prop_dependency(struct d3d10_effect_prop_dependencies *d,
const struct d3d10_effect_prop_dependency *dep)
+{
- if (!d3d_array_reserve((void **)&d->entries, &d->capacity, d->count + 1, sizeof(*d->entries)))
return E_OUTOFMEMORY;
- d->entries[d->count++] = *dep;
- return S_OK;
+}
We probably want to go for the usual exponential growth pattern here. This separate helper is nice in that it can hide that kind of details away.
d3d_array_reserve() already does something like that, conditionally doubling sizes. You mean it's not enough?
@@ -4873,6 +5004,7 @@ static BOOL get_value_as_bool(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_typ { case D3D10_SVT_FLOAT: case D3D10_SVT_INT:
case D3D10_SVT_UINT: case D3D10_SVT_BOOL: if (*(DWORD *)src_data) return -1;
@@ -4893,6 +5025,7 @@ static int get_value_as_int(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_type) return (int)(*(float *)src_data);
case D3D10_SVT_INT:
case D3D10_SVT_UINT: return *(int *)src_data; case D3D10_SVT_BOOL:
@@ -4911,6 +5044,7 @@ static float get_value_as_float(void *src_data, D3D10_SHADER_VARIABLE_TYPE src_t return *(float *)src_data;
case D3D10_SVT_INT:
case D3D10_SVT_UINT: return (float)(*(int *)src_data); case D3D10_SVT_BOOL:
@@ -4941,6 +5075,7 @@ static void get_vector_as_type(BYTE *dst_data, D3D_SHADER_VARIABLE_TYPE dst_type break;
case D3D10_SVT_INT:
case D3D10_SVT_UINT: *(int *)dst_data_dword = get_value_as_int(src_data_dword, src_type); break;
These hunks should probably be split to a separate patch...
That's true, will do.
diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index a8a64a6ed0d..b379fc7bddc 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -4843,43 +4843,32 @@ cbuffer cb float f0, f_a[2]; int i0, i_a[2]; bool b0, b_a[2];
- uint i1, i1_a[2];
}; #endif static DWORD fx_test_scalar_variable[] = {
- 0x43425844, 0xe4da4aa6, 0x1380ddc5, 0x445edad5,
- 0x08581666, 0x00000001, 0x0000020b, 0x00000001,
- 0x00000024, 0x30315846, 0x000001df, 0xfeff1001,
- 0x00000001, 0x00000006, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x000000d3,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x66006263,
- 0x74616f6c, 0x00000700, 0x00000100, 0x00000000,
- 0x00000400, 0x00001000, 0x00000400, 0x00090900,
- 0x00306600, 0x00000007, 0x00000001, 0x00000002,
- 0x00000014, 0x00000010, 0x00000008, 0x00000909,
- 0x00615f66, 0x00746e69, 0x0000004c, 0x00000001,
- 0x00000000, 0x00000004, 0x00000010, 0x00000004,
- 0x00000911, 0x4c003069, 0x01000000, 0x02000000,
- 0x14000000, 0x10000000, 0x08000000, 0x11000000,
- 0x69000009, 0x6200615f, 0x006c6f6f, 0x0000008f,
- 0x00000001, 0x00000000, 0x00000004, 0x00000010,
- 0x00000004, 0x00000921, 0x8f003062, 0x01000000,
- 0x02000000, 0x14000000, 0x10000000, 0x08000000,
- 0x21000000, 0x62000009, 0x0400615f, 0x70000000,
- 0x00000000, 0x06000000, 0xff000000, 0x00ffffff,
- 0x29000000, 0x0d000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x48000000,
- 0x2c000000, 0x00000000, 0x10000000, 0x00000000,
- 0x00000000, 0x00000000, 0x6c000000, 0x50000000,
- 0x00000000, 0x24000000, 0x00000000, 0x00000000,
- 0x00000000, 0x8b000000, 0x6f000000, 0x00000000,
- 0x30000000, 0x00000000, 0x00000000, 0x00000000,
- 0xb0000000, 0x94000000, 0x00000000, 0x44000000,
- 0x00000000, 0x00000000, 0x00000000, 0xcf000000,
- 0xb3000000, 0x00000000, 0x50000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000,
- 0x43425844, 0x7d97f44c, 0x1da4b110, 0xb710407e, 0x26750c1c, 0x00000001, 0x00000288, 0x00000001,
- 0x00000024, 0x30315846, 0x0000025c, 0xfeff1001, 0x00000001, 0x00000008, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000118, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66006263,
- 0x74616f6c, 0x00000700, 0x00000100, 0x00000000, 0x00000400, 0x00001000, 0x00000400, 0x00090900,
- 0x00306600, 0x00000007, 0x00000001, 0x00000002, 0x00000014, 0x00000010, 0x00000008, 0x00000909,
- 0x00615f66, 0x00746e69, 0x0000004c, 0x00000001, 0x00000000, 0x00000004, 0x00000010, 0x00000004,
- 0x00000911, 0x4c003069, 0x01000000, 0x02000000, 0x14000000, 0x10000000, 0x08000000, 0x11000000,
- 0x69000009, 0x6200615f, 0x006c6f6f, 0x0000008f, 0x00000001, 0x00000000, 0x00000004, 0x00000010,
- 0x00000004, 0x00000921, 0x8f003062, 0x01000000, 0x02000000, 0x14000000, 0x10000000, 0x08000000,
- 0x21000000, 0x62000009, 0x7500615f, 0x00746e69, 0x000000d3, 0x00000001, 0x00000000, 0x00000004,
- 0x00000010, 0x00000004, 0x00000919, 0xd3003169, 0x01000000, 0x02000000, 0x14000000, 0x10000000,
- 0x08000000, 0x19000000, 0x69000009, 0x00615f31, 0x00000004, 0x00000090, 0x00000000, 0x00000008,
- 0xffffffff, 0x00000000, 0x00000029, 0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000048, 0x0000002c, 0x00000000, 0x00000010, 0x00000000, 0x00000000, 0x00000000,
- 0x0000006c, 0x00000050, 0x00000000, 0x00000024, 0x00000000, 0x00000000, 0x00000000, 0x0000008b,
- 0x0000006f, 0x00000000, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x000000b0, 0x00000094,
- 0x00000000, 0x00000044, 0x00000000, 0x00000000, 0x00000000, 0x000000cf, 0x000000b3, 0x00000000,
- 0x00000050, 0x00000000, 0x00000000, 0x00000000, 0x000000f4, 0x000000d8, 0x00000000, 0x00000064,
- 0x00000000, 0x00000000, 0x00000000, 0x00000113, 0x000000f7, 0x00000000, 0x00000070, 0x00000000,
- 0x00000000, 0x00000000,
};
static void test_scalar_methods(ID3D10EffectScalarVariable *var, D3D10_SHADER_VARIABLE_TYPE type, @@ -5146,6 +5135,7 @@ static void test_effect_scalar_variable(void) {"f0", D3D10_SVT_FLOAT}, {"i0", D3D10_SVT_INT}, {"b0", D3D10_SVT_BOOL},
{"i1", D3D10_SVT_UINT}, {"f_a", D3D10_SVT_FLOAT, TRUE}, {"i_a", D3D10_SVT_INT, TRUE}, {"b_a", D3D10_SVT_BOOL, TRUE},
@@ -5178,7 +5168,7 @@ static void test_effect_scalar_variable(void) effect_desc.ConstantBuffers); ok(effect_desc.SharedConstantBuffers == 0, "Unexpected shared constant buffers count %u.\n", effect_desc.SharedConstantBuffers);
- ok(effect_desc.GlobalVariables == 6, "Unexpected global variables count %u.\n",
- ok(effect_desc.GlobalVariables == 8, "Unexpected global variables count %u.\n", effect_desc.GlobalVariables); ok(effect_desc.SharedGlobalVariables == 0, "Unexpected shared global variables count %u.\n", effect_desc.SharedGlobalVariables);
... together with this test change.
On Fri, Oct 29, 2021 at 9:01 PM Nikolay Sivov nsivov@codeweavers.com wrote:
On 10/29/21 9:35 PM, Matteo Bruni wrote:
On Thu, Oct 28, 2021 at 9:46 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/d3d10_private.h | 9 + dlls/d3d10/effect.c | 341 ++++++++++++++++++++++++++----------- dlls/d3d10/tests/effect.c | 207 ++++++++++++++++++---- 3 files changed, 420 insertions(+), 137 deletions(-)
diff --git a/dlls/d3d10/d3d10_private.h b/dlls/d3d10/d3d10_private.h index 11b3b4e9482..f8e415f860b 100644 --- a/dlls/d3d10/d3d10_private.h +++ b/dlls/d3d10/d3d10_private.h @@ -95,6 +95,13 @@ struct d3d10_effect_shader_variable unsigned int isinline : 1; };
+struct d3d10_effect_prop_dependencies +{
- struct d3d10_effect_prop_dependency *entries;
- SIZE_T count;
- SIZE_T capacity;
+};
struct d3d10_effect_sampler_desc { D3D10_SAMPLER_DESC desc; @@ -118,6 +125,7 @@ struct d3d10_effect_state_object_variable ID3D10SamplerState *sampler; IUnknown *object; } object;
- struct d3d10_effect_prop_dependencies dependencies;
};
struct d3d10_effect_resource_variable @@ -217,6 +225,7 @@ struct d3d10_effect_pass char *name; struct d3d10_effect_annotations annotations;
- struct d3d10_effect_prop_dependencies dependencies; struct d3d10_effect_pass_shader_desc vs; struct d3d10_effect_pass_shader_desc ps; struct d3d10_effect_pass_shader_desc gs;
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 23374fdb48f..34a5eb1b701 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -168,6 +168,27 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+struct d3d10_effect_prop_dependency +{
- unsigned int id;
- unsigned int idx;
- unsigned int operation;
- union
- {
struct
{
struct d3d10_effect_variable *v;
unsigned int offset;
} var;
- } u;
+};
It should be possible to use anonymous unions now in d3d10, right? Not that you necessarily have to do that here, depending on what's going to happen to this struct in the following patches.
It's extended in 5/5. We don't currently use anonymous unions there, so I'm simply following existing pattern.
Right, I guess this seemed as good a time as any to start using them. Either way it's fine to me.
+static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_dependencies *deps,
void *container)
+{
- const struct d3d10_effect_state_property_info *property_info;
- struct d3d10_effect_prop_dependency *d;
- struct d3d10_effect_variable *v;
- unsigned int i, j, count;
- uint32_t value;
- void *dst;
- for (i = 0; i < deps->count; ++i)
- {
d = &deps->entries[i];
property_info = &property_infos[d->id];
dst = (char *)container + property_info->offset;
switch (d->operation)
{
case D3D10_EOO_VAR:
case D3D10_EOO_CONST_INDEX:
v = d->u.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_read_numeric_value(value, v->type->basetype, property_info->type, dst, j);
}
break;
default:
FIXME("Unsupported property update for %u.\n", d->operation);
}
- }
+}
It would be nice to have dirty flags to avoid unnecessary recomputation. For example, something like the "changed" flag we have for buffers but referring to variables and their values. Problem is, there are a few quirks (e.g. SetRawValue(), those wild out-of-bounds accesses) that make this quite problematic. So I can be convinced to let it go :)
It would be useful for expressions I imagine, but even for expression it might be hard to quantify if all an expression does is a single ftou(), which is apparently common.
For value and index updates, I haven't measured obviously, because I didn't implement it.
The whole picture is:
foreach() { get_value(); put_value(); } use updated fields
which with change tracking will extend to
foreach() { if (changed) { get_value(); put_value(); replace_change_marker(); } } use updated fields
So when nothing changes it will still need to compare for each entry, and get/put is reduced to 4 byte read/write most of the time I think, if not always. Because e.g. setting things like arrays like blend factor produces complex expression, even if you set one element.
Regarding SetRawValue(), yes, the way it works is unfortunate, basically you'll have to track variables in constant buffer objects, so when SetRawValue is called on a buffer you mark them all as changed. But then when you do a larger than necessary raw value write on a variable, you potentially change adjacent variables too. Easy way is to mark all as changed when writing to buffers, and this and following (by offset) when writing to variables.
So that's additional overhead necessary to make property updates respect changed/dirty states.
Yeah, sounds like a lot of work for some pretty dubious benefit.
It would be something for a separate patch anyway.
@@ -1695,6 +1793,14 @@ static BOOL read_value_list(const char *data, size_t data_size, DWORD offset, *(void **)out_data = &null_shader_resource_variable; break;
case D3D10_SVT_DEPTHSTENCIL:
*(void **)out_data = &null_depth_stencil_variable;
break;
case D3D10_SVT_BLEND:
*(void **)out_data = &null_blend_variable;
break;
default: FIXME("Unhandled out_type %#x.\n", out_type); return FALSE;
Would this also make sense as a separate patch?
It depends on how you look at it, e.g. setting stencil ref int with NULL object produces records like this, so it's sort of related. By I can split a much as necessary of course.
Yeah, I think it can stand on its own but it's not too ugly to have it in here.
@@ -1745,21 +1851,31 @@ static BOOL is_object_property_type_matching(const struct d3d10_effect_state_pro } }
+static HRESULT d3d10_effect_add_prop_dependency(struct d3d10_effect_prop_dependencies *d,
const struct d3d10_effect_prop_dependency *dep)
+{
- if (!d3d_array_reserve((void **)&d->entries, &d->capacity, d->count + 1, sizeof(*d->entries)))
return E_OUTOFMEMORY;
- d->entries[d->count++] = *dep;
- return S_OK;
+}
We probably want to go for the usual exponential growth pattern here. This separate helper is nice in that it can hide that kind of details away.
d3d_array_reserve() already does something like that, conditionally doubling sizes. You mean it's not enough?
No you're right, somehow I misread that.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/effect.c | 96 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 19 deletions(-)
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 34a5eb1b701..788b48e45ae 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -5200,9 +5200,11 @@ static inline struct d3d10_effect_variable *impl_from_ID3D10EffectScalarVariable
static BOOL STDMETHODCALLTYPE d3d10_effect_scalar_variable_IsValid(ID3D10EffectScalarVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectScalarVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_scalar_variable; + return v != &null_scalar_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_scalar_variable_GetType( @@ -5536,9 +5538,11 @@ static inline struct d3d10_effect_variable *impl_from_ID3D10EffectVectorVariable
static BOOL STDMETHODCALLTYPE d3d10_effect_vector_variable_IsValid(ID3D10EffectVectorVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectVectorVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_vector_variable; + return v != &null_vector_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_vector_variable_GetType( @@ -6023,9 +6027,11 @@ static inline struct d3d10_effect_variable *impl_from_ID3D10EffectMatrixVariable
static BOOL STDMETHODCALLTYPE d3d10_effect_matrix_variable_IsValid(ID3D10EffectMatrixVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectMatrixVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_matrix_variable; + return v != &null_matrix_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_matrix_variable_GetType( @@ -6311,9 +6317,11 @@ static inline struct d3d10_effect_variable *impl_from_ID3D10EffectStringVariable
static BOOL STDMETHODCALLTYPE d3d10_effect_string_variable_IsValid(ID3D10EffectStringVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectStringVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_string_variable; + return v != &null_string_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_string_variable_GetType( @@ -6800,12 +6808,20 @@ static const struct ID3D10EffectShaderResourceVariableVtbl d3d10_effect_shader_r
/* ID3D10EffectVariable methods */
+static inline struct d3d10_effect_variable *impl_from_ID3D10EffectRenderTargetViewVariable( + ID3D10EffectRenderTargetViewVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d10_effect_variable, ID3D10EffectVariable_iface); +} + static BOOL STDMETHODCALLTYPE d3d10_effect_render_target_view_variable_IsValid( ID3D10EffectRenderTargetViewVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectRenderTargetViewVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_render_target_view_variable; + return v != &null_render_target_view_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_render_target_view_variable_GetType( @@ -7024,12 +7040,20 @@ static const struct ID3D10EffectRenderTargetViewVariableVtbl d3d10_effect_render
/* ID3D10EffectVariable methods */
+static inline struct d3d10_effect_variable *impl_from_ID3D10EffectDepthStencilViewVariable( + ID3D10EffectDepthStencilViewVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d10_effect_variable, ID3D10EffectVariable_iface); +} + static BOOL STDMETHODCALLTYPE d3d10_effect_depth_stencil_view_variable_IsValid( ID3D10EffectDepthStencilViewVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectDepthStencilViewVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_depth_stencil_view_variable; + return v != &null_depth_stencil_view_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_depth_stencil_view_variable_GetType( @@ -7250,9 +7274,11 @@ static const struct ID3D10EffectDepthStencilViewVariableVtbl d3d10_effect_depth_
static BOOL STDMETHODCALLTYPE d3d10_effect_shader_variable_IsValid(ID3D10EffectShaderVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectShaderVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_shader_variable; + return v != &null_shader_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_shader_variable_GetType( @@ -7644,11 +7670,19 @@ static const struct ID3D10EffectShaderVariableVtbl d3d10_effect_shader_variable_
/* ID3D10EffectVariable methods */
+static inline struct d3d10_effect_variable *impl_from_ID3D10EffectBlendVariable( + ID3D10EffectBlendVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d10_effect_variable, ID3D10EffectVariable_iface); +} + static BOOL STDMETHODCALLTYPE d3d10_effect_blend_variable_IsValid(ID3D10EffectBlendVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectBlendVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_blend_variable; + return v != &null_blend_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_blend_variable_GetType( @@ -7800,7 +7834,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_blend_variable_GetRawValue(ID3D10E static HRESULT STDMETHODCALLTYPE d3d10_effect_blend_variable_GetBlendState(ID3D10EffectBlendVariable *iface, UINT index, ID3D10BlendState **blend_state) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectBlendVariable(iface);
TRACE("iface %p, index %u, blend_state %p.\n", iface, index, blend_state);
@@ -7824,7 +7858,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_blend_variable_GetBlendState(ID3D1 static HRESULT STDMETHODCALLTYPE d3d10_effect_blend_variable_GetBackingStore(ID3D10EffectBlendVariable *iface, UINT index, D3D10_BLEND_DESC *desc) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectBlendVariable(iface);
TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
@@ -7878,11 +7912,19 @@ static const struct ID3D10EffectBlendVariableVtbl d3d10_effect_blend_variable_vt
/* ID3D10EffectVariable methods */
+static inline struct d3d10_effect_variable *impl_from_ID3D10EffectDepthStencilVariable( + ID3D10EffectDepthStencilVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d10_effect_variable, ID3D10EffectVariable_iface); +} + static BOOL STDMETHODCALLTYPE d3d10_effect_depth_stencil_variable_IsValid(ID3D10EffectDepthStencilVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectDepthStencilVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_depth_stencil_variable; + return v != &null_depth_stencil_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_depth_stencil_variable_GetType( @@ -8034,7 +8076,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_depth_stencil_variable_GetRawValue static HRESULT STDMETHODCALLTYPE d3d10_effect_depth_stencil_variable_GetDepthStencilState(ID3D10EffectDepthStencilVariable *iface, UINT index, ID3D10DepthStencilState **depth_stencil_state) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectDepthStencilVariable(iface);
TRACE("iface %p, index %u, depth_stencil_state %p.\n", iface, index, depth_stencil_state);
@@ -8058,7 +8100,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_depth_stencil_variable_GetDepthSte static HRESULT STDMETHODCALLTYPE d3d10_effect_depth_stencil_variable_GetBackingStore(ID3D10EffectDepthStencilVariable *iface, UINT index, D3D10_DEPTH_STENCIL_DESC *desc) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectDepthStencilVariable(iface);
TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
@@ -8112,11 +8154,19 @@ static const struct ID3D10EffectDepthStencilVariableVtbl d3d10_effect_depth_sten
/* ID3D10EffectVariable methods */
+static inline struct d3d10_effect_variable *impl_from_ID3D10EffectRasterizerVariable( + ID3D10EffectRasterizerVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d10_effect_variable, ID3D10EffectVariable_iface); +} + static BOOL STDMETHODCALLTYPE d3d10_effect_rasterizer_variable_IsValid(ID3D10EffectRasterizerVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectRasterizerVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_rasterizer_variable; + return v != &null_rasterizer_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_rasterizer_variable_GetType( @@ -8268,7 +8318,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_rasterizer_variable_GetRawValue(ID static HRESULT STDMETHODCALLTYPE d3d10_effect_rasterizer_variable_GetRasterizerState(ID3D10EffectRasterizerVariable *iface, UINT index, ID3D10RasterizerState **rasterizer_state) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectRasterizerVariable(iface);
TRACE("iface %p, index %u, rasterizer_state %p.\n", iface, index, rasterizer_state);
@@ -8292,7 +8342,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_rasterizer_variable_GetRasterizerS static HRESULT STDMETHODCALLTYPE d3d10_effect_rasterizer_variable_GetBackingStore(ID3D10EffectRasterizerVariable *iface, UINT index, D3D10_RASTERIZER_DESC *desc) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectRasterizerVariable(iface);
TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
@@ -8346,11 +8396,19 @@ static const struct ID3D10EffectRasterizerVariableVtbl d3d10_effect_rasterizer_v
/* ID3D10EffectVariable methods */
+static inline struct d3d10_effect_variable *impl_from_ID3D10EffectSamplerVariable( + ID3D10EffectSamplerVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d10_effect_variable, ID3D10EffectVariable_iface); +} + static BOOL STDMETHODCALLTYPE d3d10_effect_sampler_variable_IsValid(ID3D10EffectSamplerVariable *iface) { + struct d3d10_effect_variable *v = impl_from_ID3D10EffectSamplerVariable(iface); + TRACE("iface %p\n", iface);
- return (struct d3d10_effect_variable *)iface != &null_sampler_variable; + return v != &null_sampler_variable; }
static struct ID3D10EffectType * STDMETHODCALLTYPE d3d10_effect_sampler_variable_GetType( @@ -8502,7 +8560,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_sampler_variable_GetRawValue(ID3D1 static HRESULT STDMETHODCALLTYPE d3d10_effect_sampler_variable_GetSampler(ID3D10EffectSamplerVariable *iface, UINT index, ID3D10SamplerState **sampler) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectSamplerVariable(iface);
TRACE("iface %p, index %u, sampler %p.\n", iface, index, sampler);
@@ -8526,7 +8584,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_sampler_variable_GetSampler(ID3D10 static HRESULT STDMETHODCALLTYPE d3d10_effect_sampler_variable_GetBackingStore(ID3D10EffectSamplerVariable *iface, UINT index, D3D10_SAMPLER_DESC *desc) { - struct d3d10_effect_variable *v = impl_from_ID3D10EffectVariable((ID3D10EffectVariable *)iface); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectSamplerVariable(iface);
TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- This patch could have been split too but I guess I don't care enough in this particular case.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/d3d10_private.h | 1 + dlls/d3d10/effect.c | 12 ++---------- 2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/dlls/d3d10/d3d10_private.h b/dlls/d3d10/d3d10_private.h index f8e415f860b..7f83fb1182a 100644 --- a/dlls/d3d10/d3d10_private.h +++ b/dlls/d3d10/d3d10_private.h @@ -87,6 +87,7 @@ struct d3d10_effect_shader_variable ID3D10VertexShader *vs; ID3D10PixelShader *ps; ID3D10GeometryShader *gs; + IUnknown *object; } shader;
unsigned int resource_count; diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 788b48e45ae..003060598a3 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -3126,18 +3126,10 @@ static void d3d10_effect_shader_variable_destroy(struct d3d10_effect_shader_vari switch (type) { case D3D10_SVT_VERTEXSHADER: - if (s->shader.vs) - ID3D10VertexShader_Release(s->shader.vs); - break; - case D3D10_SVT_PIXELSHADER: - if (s->shader.ps) - ID3D10PixelShader_Release(s->shader.ps); - break; - case D3D10_SVT_GEOMETRYSHADER: - if (s->shader.gs) - ID3D10GeometryShader_Release(s->shader.gs); + if (s->shader.object) + IUnknown_Release(s->shader.object); break;
default:
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/effect.c | 560 +++++++++++++++++++++++++++++++++++++- dlls/d3d10/tests/effect.c | 114 ++++++++ 2 files changed, 672 insertions(+), 2 deletions(-)
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 003060598a3..5e93fdddde3 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) @@ -168,6 +171,92 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+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); + +struct preshader_op_info +{ + unsigned short idx; + unsigned short opcode; + char name[16]; + pres_op_func func; +}; + +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]; +} + +enum preshader_op +{ + D3D10_PRESHADER_OP_FTOU = 0, + D3D10_PRESHADER_OP_ADD, + D3D10_PRESHADER_OP_MAX, +}; + +static const struct preshader_op_info preshader_ops[] = +{ + { D3D10_PRESHADER_OP_FTOU, 0x133, "ftou", pres_ftou }, + { D3D10_PRESHADER_OP_ADD, 0x204, "add", pres_add }, +}; + +struct d3d10_ctab_var +{ + struct d3d10_effect_variable *v; + unsigned int offset; + unsigned int length; +}; + +struct d3d10_reg_table +{ + union + { + float *f; + DWORD *dword; + char *byte; + } u; + 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, +}; + +struct d3d10_effect_preshader +{ + struct d3d10_reg_table constants; + struct d3d10_reg_table cb; + struct d3d10_reg_table result; + struct d3d10_reg_table temp; + struct d3d10_reg_table code; + + struct d3d10_ctab_var *vars; + unsigned int vars_count; +}; + +struct d3d10_preshader_parse_context +{ + struct d3d10_effect_preshader *preshader; + struct d3d10_effect *effect; +}; + struct d3d10_effect_prop_dependency { unsigned int id; @@ -180,11 +269,125 @@ struct d3d10_effect_prop_dependency struct d3d10_effect_variable *v; unsigned int offset; } var; + struct + { + struct d3d10_effect_variable *v; + struct d3d10_effect_preshader index; + } index_expr; } u; };
+static HRESULT d3d10_reg_table_allocate(struct d3d10_reg_table *table, unsigned int count) +{ + if (!(table->u.f = heap_calloc(count, sizeof(*table->u.f)))) + return E_OUTOFMEMORY; + table->count = count; + return S_OK; +} + +static void d3d10_reg_table_clear(struct d3d10_reg_table *table) +{ + heap_free(table->u.f); + memset(table, 0, sizeof(*table)); +} + +static void d3d10_effect_preshader_clear(struct d3d10_effect_preshader *p) +{ + d3d10_reg_table_clear(&p->constants); + d3d10_reg_table_clear(&p->cb); + d3d10_reg_table_clear(&p->result); + d3d10_reg_table_clear(&p->temp); + d3d10_reg_table_clear(&p->code); + heap_free(p->vars); + p->vars = NULL; + p->vars_count = 0; +} + +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: + return p->constants.u.f + offset; + case D3D10_REG_TABLE_CB: + return p->cb.u.f + offset; + case D3D10_REG_TABLE_RESULT: + return p->result.u.f + offset; + case D3D10_REG_TABLE_TEMP: + return p->temp.u.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 = p->code.u.dword; + float *dst, *args[4], *retval; + struct preshader_instr ins; + + memset(p->result.u.f, 0, sizeof(*p->result.u.f) * p->result.count); + + /* Update constant buffer */ + dst = p->cb.u.f; + 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: currently ignored field */ + regt = *ip++; + offset = *ip++; + + args[j] = d3d10_effect_preshader_get_reg_ptr(p, regt, offset); + } + + ip++; /* TODO: currently ignored field */ + regt = *ip++; + offset = *ip++; + retval = d3d10_effect_preshader_get_reg_ptr(p, regt, offset); + + *retval = preshader_ops[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->u.index_expr.index); + break; + default: + ; + } + } heap_free(d->entries); memset(d, 0, sizeof(*d)); } @@ -512,10 +715,11 @@ static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_depende void *container) { const struct d3d10_effect_state_property_info *property_info; + unsigned int i, j, count, variable_idx, *dst_index; struct d3d10_effect_prop_dependency *d; struct d3d10_effect_variable *v; - unsigned int i, j, count; uint32_t value; + HRESULT hr; void *dst;
for (i = 0; i < deps->count; ++i) @@ -525,6 +729,7 @@ 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) { @@ -543,6 +748,39 @@ static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_depende
break;
+ case D3D10_EOO_INDEX_EXPRESSION: + + v = d->u.index_expr.v; + + /* Evaluate index. */ + if (FAILED(hr = d3d10_effect_preshader_eval(&d->u.index_expr.index))) + { + WARN("Failed to evaluate index expression, hr %#x.\n", hr); + return; + } + + variable_idx = *d->u.index_expr.index.result.u.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; + } + + switch (property_info->type) + { + case D3D10_SVT_VERTEXSHADER: + case D3D10_SVT_PIXELSHADER: + case D3D10_SVT_GEOMETRYSHADER: + ((void **)dst)[d->idx] = v; + *dst_index = variable_idx; + break; + default: + ((void **)dst)[d->idx] = &v->elements[variable_idx]; + } + break; + default: FIXME("Unsupported property update for %u.\n", d->operation); } @@ -1851,6 +2089,263 @@ static BOOL is_object_property_type_matching(const struct d3d10_effect_state_pro } }
+static HRESULT parse_fx10_preshader_instr(struct d3d10_effect_preshader *p, const char **ptr) +{ + unsigned int data_size = p->code.count * sizeof(DWORD); + unsigned int i, input_count, skip, opcode; + struct preshader_instr *ins; + + if (data_size < 2 * sizeof(DWORD)) + { + WARN("Byte code buffer ends unexpectedly.\n"); + return E_FAIL; + } + + ins = (struct preshader_instr *)*ptr; + read_dword(ptr, &skip); + read_dword(ptr, &input_count); + + opcode = ins->opcode; + ins->opcode = D3D10_PRESHADER_OP_MAX; + + TRACE("Opcode %#x, input count %u.\n", opcode, input_count); + + /* Patch original opcode with sequential index. */ + + /* TODO: use better search */ + for (i = 0; i < ARRAY_SIZE(preshader_ops); ++i) + { + if (opcode == preshader_ops[i].opcode) + { + ins->opcode = preshader_ops[i].idx; + break; + } + } + + if (ins->opcode == D3D10_PRESHADER_OP_MAX) + { + FIXME("Unrecognized opcode %#x.\n", opcode); + return E_FAIL; + } + + /* Inputs + 1 output */ + for (i = 0; i < input_count + 1; ++i) + { + unsigned int unknown, regt, offset; + + read_dword(ptr, &unknown); + if (unknown) + { + FIXME("Unexpected argument field %#x.\n", unknown); + return E_UNEXPECTED; + } + + read_dword(ptr, ®t); + read_dword(ptr, &offset); + + switch (regt) + { + case D3D10_REG_TABLE_RESULT: + p->result.count = max(p->result.count, offset + 1); + break; + case D3D10_REG_TABLE_TEMP: + p->temp.count = max(p->temp.count, 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, ins_count; + const char *ptr; + HRESULT hr; + + if (data_size % sizeof(DWORD)) + { + WARN("FXLC size misaligned %u.\n", data_size); + return E_FAIL; + } + + /* Parse through bytecode copy, so we can patch opcodes. */ + if (FAILED(hr = d3d10_reg_table_allocate(&p->code, data_size / sizeof(DWORD)))) return hr; + memcpy(p->code.u.dword, data, data_size); + + ptr = p->code.u.byte; + 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(p, &ptr))) + { + WARN("Failed to parse instruction %u.\n", i); + return hr; + } + } + + /* Allocate temporary registers and result */ + if (FAILED(hr = d3d10_reg_table_allocate(&p->result, p->result.count))) return hr; + if (FAILED(hr = d3d10_reg_table_allocate(&p->temp, p->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; + const char *ptr = data; + + if (data_size < sizeof(DWORD)) + { + WARN("Invalid CLI4 chunk size %u.\n", data_size); + return E_FAIL; + } + + read_dword(&ptr, &p->constants.count); + + TRACE("%u literal constants.\n", p->constants.count); + + if (!require_space(4, p->constants.count, sizeof(DWORD), data_size)) + { + WARN("Invalid constant table size %u.\n", data_size); + return E_FAIL; + } + + if (!(p->constants.u.f = heap_calloc(p->constants.count, sizeof(*p->constants.u.f)))) + return E_OUTOFMEMORY; + + memcpy(p->constants.u.f, ptr, p->constants.count * sizeof(*p->constants.u.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, info_offset, unused, 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, &unused); + read_dword(&ptr, &unused); + read_dword(&ptr, &unused); + read_dword(&ptr, &p->vars_count); + read_dword(&ptr, &info_offset); + read_dword(&ptr, &unused); + read_dword(&ptr, &unused); + + if (!require_space(info_offset, p->vars_count, sizeof(*info) / sizeof(DWORD), + data_size)) + { + WARN("Invalid constant info section offset %#x.\n", info_offset); + return E_FAIL; + } + + 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 + info_offset); + 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->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) { @@ -1866,9 +2361,9 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size const char **ptr, enum d3d10_effect_container_type container_type, struct d3d10_effect *effect, void *container, struct d3d10_effect_prop_dependencies *d) { + uint32_t value_offset, code_offset, sodecl_offset, blob_size, operation; const struct d3d10_effect_state_property_info *property_info; unsigned int variable_idx, *dst_index, offset, idx, id; - UINT value_offset, sodecl_offset, operation; struct d3d10_effect_prop_dependency dep; struct d3d10_effect_variable *variable; const char *data_ptr; @@ -2055,6 +2550,61 @@ static HRESULT parse_fx10_property_assignment(const char *data, size_t data_size
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 (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.u.index_expr.v = variable; + if (FAILED(hr = parse_fx10_preshader(data_ptr, blob_size, effect, &dep.u.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 */ @@ -4000,6 +4550,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;
@@ -4025,6 +4577,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;
@@ -4050,6 +4604,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 b379fc7bddc..fb00871139e 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -7776,6 +7776,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) +{ + ID3D10EffectTechnique *tech; + ID3D10EffectPass *pass; + ID3D10Effect *effect; + ID3D10Device *device; + ULONG refcount; + HRESULT hr; + D3D10_PASS_SHADER_DESC shader_desc; + ID3D10EffectVectorVariable *vector; + ID3D10EffectVariable *v; + float val[4]; + + 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(); @@ -7800,4 +7913,5 @@ START_TEST(effect) test_effect_default_variable_value(); test_effect_raw_value(); test_effect_dynamic_numeric_field(); + test_effect_index_expression(); }
On Thu, Oct 28, 2021 at 9:46 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/effect.c | 560 +++++++++++++++++++++++++++++++++++++- dlls/d3d10/tests/effect.c | 114 ++++++++ 2 files changed, 672 insertions(+), 2 deletions(-)
My general question / concern on this patch is whether there is room for code sharing of some kind with d3dx9. Aside from the practical issue that there is no proper place to put the shared code at the moment (there is still hope I'll send patches for that eventually), my feeling is that we could reuse some helpers at least, with some moderate work.
I'm okay with duplicating stuff like this for the time being, as long as we keep the door open to merging code back afterwards.
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 003060598a3..5e93fdddde3 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) @@ -168,6 +171,92 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+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);
+struct preshader_op_info +{
- unsigned short idx;
- unsigned short opcode;
- char name[16];
- pres_op_func func;
+};
+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];
+}
+enum preshader_op +{
- D3D10_PRESHADER_OP_FTOU = 0,
- D3D10_PRESHADER_OP_ADD,
- D3D10_PRESHADER_OP_MAX,
+};
It looks like you meant to use D3D10_PRESHADER_OP_MAX purely as a sentinel but that's confusing at best (in fact there is a MAX op in d3dx9 at least).
I also have a nitpick: moving the definition of preshader_op_info right here, just above the definition of preshader_ops[], seems nicer.
+static const struct preshader_op_info preshader_ops[] = +{
- { D3D10_PRESHADER_OP_FTOU, 0x133, "ftou", pres_ftou },
- { D3D10_PRESHADER_OP_ADD, 0x204, "add", pres_add },
+};
+struct d3d10_ctab_var +{
- struct d3d10_effect_variable *v;
- unsigned int offset;
- unsigned int length;
+};
+struct d3d10_reg_table +{
- union
- {
float *f;
DWORD *dword;
char *byte;
- } u;
- 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,
+};
+struct d3d10_effect_preshader +{
- struct d3d10_reg_table constants;
- struct d3d10_reg_table cb;
- struct d3d10_reg_table result;
- struct d3d10_reg_table temp;
- struct d3d10_reg_table code;
- struct d3d10_ctab_var *vars;
- unsigned int vars_count;
+};
It might make sense to organize the various struct d3d10_reg_table entries into a single array indexed by an enum d3d10_reg_table_type value. It should allow some simplification down the line, like for example...
+static void d3d10_effect_preshader_clear(struct d3d10_effect_preshader *p) +{
- d3d10_reg_table_clear(&p->constants);
- d3d10_reg_table_clear(&p->cb);
- d3d10_reg_table_clear(&p->result);
- d3d10_reg_table_clear(&p->temp);
- d3d10_reg_table_clear(&p->code);
- heap_free(p->vars);
- p->vars = NULL;
- p->vars_count = 0;
+}
... here, or...
+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:
return p->constants.u.f + offset;
case D3D10_REG_TABLE_CB:
return p->cb.u.f + offset;
case D3D10_REG_TABLE_RESULT:
return p->result.u.f + offset;
case D3D10_REG_TABLE_TEMP:
return p->temp.u.f + offset;
default:
return NULL;
- }
+}
... here, this one should become trivial. You want to NULL-check the table before accessing it, either explicitly or with an assert.
@@ -543,6 +748,39 @@ static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_depende
break;
case D3D10_EOO_INDEX_EXPRESSION:
v = d->u.index_expr.v;
/* Evaluate index. */
if (FAILED(hr = d3d10_effect_preshader_eval(&d->u.index_expr.index)))
{
WARN("Failed to evaluate index expression, hr %#x.\n", hr);
return;
}
That kind of comment doesn't seem very helpful.
variable_idx = *d->u.index_expr.index.result.u.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;
}
switch (property_info->type)
{
case D3D10_SVT_VERTEXSHADER:
case D3D10_SVT_PIXELSHADER:
case D3D10_SVT_GEOMETRYSHADER:
((void **)dst)[d->idx] = v;
*dst_index = variable_idx;
break;
default:
((void **)dst)[d->idx] = &v->elements[variable_idx];
}
break;
default: FIXME("Unsupported property update for %u.\n", d->operation); }
+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, info_offset, unused, 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, &unused);
- read_dword(&ptr, &unused);
- read_dword(&ptr, &unused);
- read_dword(&ptr, &p->vars_count);
- read_dword(&ptr, &info_offset);
- read_dword(&ptr, &unused);
- read_dword(&ptr, &unused);
Any clue about all those unused DWORDs?
- if (!require_space(info_offset, p->vars_count, sizeof(*info) / sizeof(DWORD),
data_size))
- {
WARN("Invalid constant info section offset %#x.\n", info_offset);
return E_FAIL;
- }
- 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 + info_offset);
- 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->cb, cb_reg_count * 4)))
- {
WARN("Failed to allocate variables buffer.\n");
return hr;
- }
- return S_OK;
+}
On 10/29/21 10:29 PM, Matteo Bruni wrote:
On Thu, Oct 28, 2021 at 9:46 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/effect.c | 560 +++++++++++++++++++++++++++++++++++++- dlls/d3d10/tests/effect.c | 114 ++++++++ 2 files changed, 672 insertions(+), 2 deletions(-)
My general question / concern on this patch is whether there is room for code sharing of some kind with d3dx9. Aside from the practical issue that there is no proper place to put the shared code at the moment (there is still hope I'll send patches for that eventually), my feeling is that we could reuse some helpers at least, with some moderate work.
I'm okay with duplicating stuff like this for the time being, as long as we keep the door open to merging code back afterwards.
It would certainly be nice if it matched d3dx9 variant. I think only FXLC data format matches so far, not sure if fully or not, regarding variable addressing. Literal constants from CLI4 are different (hence name change), CTAB has same format, but data is packed - you address individual components, not registers. Then there is D3DXGetShaderConstantTable() integration in d3dx9, which we can't use easily, unless you share more, after some reshuffling. Register tables are numbered differently too, and addressing is different. From what I've tried it's using {table_idx,idx} to address components. Next thing is that immediate results are doubles in d3dx9, and I don't see this in d3d10.
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 003060598a3..5e93fdddde3 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) @@ -168,6 +171,92 @@ enum d3d10_effect_container_type D3D10_C_SAMPLER, };
+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);
+struct preshader_op_info +{
- unsigned short idx;
- unsigned short opcode;
- char name[16];
- pres_op_func func;
+};
+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];
+}
+enum preshader_op +{
- D3D10_PRESHADER_OP_FTOU = 0,
- D3D10_PRESHADER_OP_ADD,
- D3D10_PRESHADER_OP_MAX,
+};
It looks like you meant to use D3D10_PRESHADER_OP_MAX purely as a sentinel but that's confusing at best (in fact there is a MAX op in d3dx9 at least).
I can see now how this is confusing, didn't think of max(), because I didn't have to deal with it.
I also have a nitpick: moving the definition of preshader_op_info right here, just above the definition of preshader_ops[], seems nicer.
+static const struct preshader_op_info preshader_ops[] = +{
- { D3D10_PRESHADER_OP_FTOU, 0x133, "ftou", pres_ftou },
- { D3D10_PRESHADER_OP_ADD, 0x204, "add", pres_add },
+};
+struct d3d10_ctab_var +{
- struct d3d10_effect_variable *v;
- unsigned int offset;
- unsigned int length;
+};
+struct d3d10_reg_table +{
- union
- {
float *f;
DWORD *dword;
char *byte;
- } u;
- 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,
+};
+struct d3d10_effect_preshader +{
- struct d3d10_reg_table constants;
- struct d3d10_reg_table cb;
- struct d3d10_reg_table result;
- struct d3d10_reg_table temp;
- struct d3d10_reg_table code;
- struct d3d10_ctab_var *vars;
- unsigned int vars_count;
+};
It might make sense to organize the various struct d3d10_reg_table entries into a single array indexed by an enum d3d10_reg_table_type value. It should allow some simplification down the line, like for example...
Yes, I wanted to do it like that, or maybe even started in earlier versions. Natural way to refer to them would be with d3d10_reg_table_type, which is rather sparse. Maybe they do have tables 3, 5, and 6, but I haven't found them yet. And "code" one is obviously different.
+static void d3d10_effect_preshader_clear(struct d3d10_effect_preshader *p) +{
- d3d10_reg_table_clear(&p->constants);
- d3d10_reg_table_clear(&p->cb);
- d3d10_reg_table_clear(&p->result);
- d3d10_reg_table_clear(&p->temp);
- d3d10_reg_table_clear(&p->code);
- heap_free(p->vars);
- p->vars = NULL;
- p->vars_count = 0;
+}
... here, or...
+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:
return p->constants.u.f + offset;
case D3D10_REG_TABLE_CB:
return p->cb.u.f + offset;
case D3D10_REG_TABLE_RESULT:
return p->result.u.f + offset;
case D3D10_REG_TABLE_TEMP:
return p->temp.u.f + offset;
default:
return NULL;
- }
+}
... here, this one should become trivial. You want to NULL-check the table before accessing it, either explicitly or with an assert.
@@ -543,6 +748,39 @@ static void d3d10_effect_update_dependent_props(struct d3d10_effect_prop_depende
break;
case D3D10_EOO_INDEX_EXPRESSION:
v = d->u.index_expr.v;
/* Evaluate index. */
if (FAILED(hr = d3d10_effect_preshader_eval(&d->u.index_expr.index)))
{
WARN("Failed to evaluate index expression, hr %#x.\n", hr);
return;
}
That kind of comment doesn't seem very helpful.
variable_idx = *d->u.index_expr.index.result.u.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;
}
switch (property_info->type)
{
case D3D10_SVT_VERTEXSHADER:
case D3D10_SVT_PIXELSHADER:
case D3D10_SVT_GEOMETRYSHADER:
((void **)dst)[d->idx] = v;
*dst_index = variable_idx;
break;
default:
((void **)dst)[d->idx] = &v->elements[variable_idx];
}
break;
default: FIXME("Unsupported property update for %u.\n", d->operation); }
+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, info_offset, unused, 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, &unused);
- read_dword(&ptr, &unused);
- read_dword(&ptr, &unused);
- read_dword(&ptr, &p->vars_count);
- read_dword(&ptr, &info_offset);
- read_dword(&ptr, &unused);
- read_dword(&ptr, &unused);
Any clue about all those unused DWORDs?
It's ctab_header.
- if (!require_space(info_offset, p->vars_count, sizeof(*info) / sizeof(DWORD),
data_size))
- {
WARN("Invalid constant info section offset %#x.\n", info_offset);
return E_FAIL;
- }
- 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 + info_offset);
- 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->cb, cb_reg_count * 4)))
- {
WARN("Failed to allocate variables buffer.\n");
return hr;
- }
- return S_OK;
+}