[PATCH 1/2] d3dx9_36: Added support for structs and arrays to ID3DXConstantTable (Try 2)

Travis Athougies iammisc at gmail.com
Wed Jul 13 17:50:01 CDT 2011


Needed for Assassin's Creed Brotherhood and Dead Space 2.

Changes from last patch:
    - New way of distinguishing handles from strings
    - Support for parent constants in ID3DXConstantTable::GetConstantByName and ID3DXConstantTable::GetConstant
    - Implemented ID3DXContantTable::GetConstantElement

---
 dlls/d3dx9_36/shader.c |  338 ++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 284 insertions(+), 54 deletions(-)

diff --git a/dlls/d3dx9_36/shader.c b/dlls/d3dx9_36/shader.c
index bddef33..52475b6 100644
--- a/dlls/d3dx9_36/shader.c
+++ b/dlls/d3dx9_36/shader.c
@@ -612,6 +612,8 @@ HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module,
 
 typedef struct ctab_constant {
     D3DXCONSTANT_DESC desc;
+
+    DWORD member_count;
     struct ctab_constant *members;
 } ctab_constant;
 
@@ -636,6 +638,133 @@ static inline int is_vertex_shader(DWORD version)
     return (version & 0xFFFF0000) == 0xFFFE0000;
 }
 
+static DWORD calc_bytes(D3DXCONSTANT_DESC *desc)
+{
+    if (desc->RegisterSet != D3DXRS_FLOAT4 && desc->RegisterSet != D3DXRS_SAMPLER)
+        FIXME("Don't know how to calculate Bytes for constants of type %d\n",
+                desc->RegisterSet);
+
+    return 4 * desc->Elements * desc->Rows * desc->Columns;
+}
+
+static ctab_constant *is_valid_sub_constant(ctab_constant *base, D3DXHANDLE parameter)
+{
+    UINT i;
+    ctab_constant *c;
+
+    if (base->member_count == 0)
+        return NULL;
+
+    for (i = 0; i < base->member_count; i++)
+    {
+        if (((ctab_constant *)parameter) == &base->members[i])
+            return (ctab_constant *)parameter;
+
+        c = is_valid_sub_constant(&base->members[i], parameter);
+        if (c) return c;
+    }
+
+    return NULL;
+}
+
+static ctab_constant *is_valid_constant(ID3DXConstantTableImpl *This, D3DXHANDLE parameter)
+{
+    UINT i;
+    ctab_constant *c;
+
+    for (i = 0; i < This->desc.Constants; i++)
+    {
+        if ((ctab_constant *)parameter == &This->constants[i])
+            return (ctab_constant *)parameter;
+
+        c = is_valid_sub_constant(&This->constants[i], parameter);
+        if (c) return c;
+    }
+
+    return NULL;
+}
+
+static ctab_constant *lookup_element(ID3DXConstantTableImpl *This, ctab_constant *c, UINT index)
+{
+    if (index >= c->desc.Elements || index >= c->member_count || !c->members)
+        return NULL;
+
+    return &c->members[index];
+}
+
+static ctab_constant *lookup_constant_by_name(ID3DXConstantTableImpl *This, ctab_constant *c, LPCSTR name)
+{
+    ctab_constant *members;
+    char *end_name, *begin_index, *end_index;
+    UINT name_length, member_count, i;
+    INT index;
+
+    TRACE("(%p, %p, %s)\n", This, c, name);
+
+    end_name = strchr(name, '.');
+    if (end_name)
+        name_length = end_name - name;
+    else
+        name_length = strlen(name);
+
+    begin_index = strchr(name, '[');
+    if (begin_index && (begin_index - name) < name_length)
+    {
+        index = strtol(begin_index + 1, &end_index, 10);
+        if (*end_index != ']')
+        {
+            TRACE("Invalid index in name: %s\n", name);
+            return NULL;
+        }
+        name_length = begin_index - name;
+    } else
+        index = -1;
+
+    if (c)
+    {
+        if (c->desc.StructMembers == 0)
+        {
+            TRACE("Can't get %s from under %s: %s is not a structure\n", name, c->desc.Name, c->desc.Name);
+            return NULL;
+        }
+
+        member_count = c->desc.StructMembers;
+        members = c->members;
+    }
+    else if (!c)
+    {
+        member_count = This->desc.Constants;
+        members = This->constants;
+    }
+
+    for (i = 0; i < member_count; i++)
+    {
+        if (strlen(members[i].desc.Name) == name_length && memcmp(members[i].desc.Name, name, name_length) == 0)
+        {
+            if (index == -1)
+            {
+                if (end_name)
+                    return lookup_constant_by_name(This, &members[i], end_name + 1);
+                else
+                    return &members[i];
+            }
+            else
+            {
+                ctab_constant *elem = lookup_element(This, &members[i], index);
+                if (!elem)
+                    return NULL;
+
+                if (end_name)
+                    return lookup_constant_by_name(This, elem, end_name + 1);
+                else
+                    return elem;
+            }
+        }
+    }
+
+    return NULL;
+}
+
 /*** IUnknown methods ***/
 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable* iface, REFIID riid, void** ppvObject)
 {
@@ -666,6 +795,17 @@ static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable* iface)
     return InterlockedIncrement(&This->ref);
 }
 
+static void release_constants(ctab_constant *constants, UINT count)
+{
+    UINT i;
+
+    for (i = 0; i < count; i++)
+        if (constants[i].member_count > 0)
+            release_constants(constants[i].members, constants[i].member_count);
+
+    HeapFree(GetProcessHeap(), 0, constants);
+}
+
 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable* iface)
 {
     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
@@ -675,7 +815,8 @@ static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable* iface)
 
     if (!ref)
     {
-        HeapFree(GetProcessHeap(), 0, This->constants);
+        release_constants(This->constants, This->desc.Constants);
+
         HeapFree(GetProcessHeap(), 0, This->ctab);
         HeapFree(GetProcessHeap(), 0, This);
     }
@@ -729,16 +870,13 @@ static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable*
         return D3DERR_INVALIDCALL;
 
     /* Applications can pass the name of the constant in place of the handle */
-    if (!((UINT_PTR)constant >> 16))
-        constant_info = &This->constants[(UINT_PTR)constant - 1];
+    if (is_valid_constant(This, constant))
+        constant_info = (ctab_constant *)constant;
     else
-    {
-        D3DXHANDLE c = ID3DXConstantTable_GetConstantByName(iface, NULL, constant);
-        if (!c)
-            return D3DERR_INVALIDCALL;
+        constant_info = lookup_constant_by_name(This, NULL, (LPCSTR)constant);
 
-        constant_info = &This->constants[(UINT_PTR)c - 1];
-    }
+    if (!constant_info)
+      return D3DERR_INVALIDCALL;
 
     if (desc)
         *desc = constant_info->desc;
@@ -773,22 +911,29 @@ static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable*
 
     TRACE("(%p)->(%p, %d)\n", This, constant, index);
 
-    if (constant)
+    if (is_valid_constant(This, constant))
     {
-        FIXME("Only top level constants supported\n");
-        return NULL;
+        ctab_constant *c = (ctab_constant *)constant;
+
+        if (index >= c->member_count)
+            return NULL;
+
+        return (D3DXHANDLE)(DWORD_PTR)&c->members[index];
     }
+    else if (!constant)
+    {
+        if (index >= This->desc.Constants)
+            return NULL;
 
-    if (index >= This->desc.Constants)
+        return (D3DXHANDLE)(DWORD_PTR)&This->constants[index];
+    }
+    else
         return NULL;
-
-    return (D3DXHANDLE)(DWORD_PTR)(index + 1);
 }
 
 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable* iface, D3DXHANDLE constant, LPCSTR name)
 {
     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
-    UINT i;
 
     TRACE("(%p)->(%p, %s)\n", This, constant, name);
 
@@ -801,20 +946,26 @@ static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantT
         return NULL;
     }
 
-    for (i = 0; i < This->desc.Constants; i++)
-        if (!strcmp(This->constants[i].desc.Name, name))
-            return (D3DXHANDLE)(DWORD_PTR)(i + 1);
-
-    return NULL;
+    if (!constant || is_valid_constant(This, constant)) {
+        return (D3DXHANDLE)(DWORD_PTR)lookup_constant_by_name(This, (ctab_constant *)constant, name);
+    } else
+        return NULL;
 }
 
 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
 {
     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
+    ctab_constant *c;
 
-    FIXME("(%p)->(%p, %d): stub\n", This, constant, index);
+    if (is_valid_constant(This, constant))
+        c = (ctab_constant *)constant;
+    else
+        c = lookup_constant_by_name(This, NULL, constant);
 
-    return NULL;
+    if (!c)
+        return NULL;
+
+    return (D3DXHANDLE)(DWORD_PTR)lookup_element(This, c, index);
 }
 
 static HRESULT set_float_array(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, const void *data,
@@ -1119,13 +1270,17 @@ static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
 };
 
-static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant)
+static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant, char* ctab);
+
+static HRESULT parse_ctab_constant_element_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant, char *ctab)
 {
+    HRESULT hr;
+
     constant->desc.Class = type->Class;
     constant->desc.Type = type->Type;
     constant->desc.Rows = type->Rows;
     constant->desc.Columns = type->Columns;
-    constant->desc.Elements = type->Elements;
+    constant->desc.Elements = 1;
     constant->desc.StructMembers = type->StructMembers;
 
     TRACE("class = %d, type = %d, rows = %d, columns = %d, elements = %d, struct_members = %d\n",
@@ -1134,11 +1289,111 @@ static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_co
 
     if ((constant->desc.Class == D3DXPC_STRUCT) && constant->desc.StructMembers)
     {
-        FIXME("Struct not supported yet\n");
-        return E_NOTIMPL;
+        D3DXSHADER_STRUCTMEMBERINFO* members = (LPD3DXSHADER_STRUCTMEMBERINFO)(ctab + type->StructMemberInfo);
+        UINT i;
+        WORD reg = constant->desc.RegisterIndex;
+        DWORD default_value_offset = 0;
+
+        constant->member_count = constant->desc.StructMembers;
+        constant->members = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ctab_constant) * constant->member_count);
+
+        for (i = 0; i < constant->member_count; i++)
+        {
+            constant->members[i].desc.Name = ctab + members[i].Name;
+
+            constant->members[i].desc.RegisterSet = constant->desc.RegisterSet;
+            constant->members[i].desc.RegisterIndex = reg;
+            constant->members[i].desc.RegisterCount = 0;
+
+            constant->members[i].desc.DefaultValue = (LPVOID)((DWORD_PTR)constant->desc.DefaultValue + default_value_offset);
+
+            hr = parse_ctab_constant_type((LPD3DXSHADER_TYPEINFO)(ctab + members[i].TypeInfo), &constant->members[i], ctab);
+            if (hr != D3D_OK)
+                goto error;
+
+            TRACE("  name = %s (under %s), rs = %d, index = %d, count = %d\n", constant->members[i].desc.Name, constant->desc.Name,
+                    constant->members[i].desc.RegisterSet, constant->members[i].desc.RegisterIndex, constant->members[i].desc.RegisterCount);
+
+            reg += constant->members[i].desc.RegisterCount;
+            default_value_offset += constant->members[i].desc.Bytes;
+        }
+
+        if (constant->desc.RegisterCount == 0)
+            /* If RegisterCount wasn't calculated for us, we have to calculate it */
+            constant->desc.RegisterCount = reg - constant->desc.RegisterIndex;
+    } else {
+        constant->member_count = 0;
+        constant->members = NULL;
     }
 
+    constant->desc.Bytes = calc_bytes(&constant->desc);
+
+    return D3D_OK;
+
+error:
+    if (constant->members)
+        release_constants(constant->members, constant->desc.StructMembers);
+
+    return hr;
+}
+
+static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant, char* ctab)
+{
+    HRESULT hr;
+    UINT i;
+
+    constant->desc.Class = type->Class;
+    constant->desc.Type = type->Type;
+    constant->desc.Rows = type->Rows;
+    constant->desc.Columns = type->Columns;
+    constant->desc.Elements = type->Elements;
+    constant->desc.StructMembers = type->StructMembers;
+
+    TRACE("class = %d, type = %d, rows = %d, columns = %d, elements = %d, struct_members = %d\n",
+          constant->desc.Class, constant->desc.Type, constant->desc.Elements,
+          constant->desc.Rows, constant->desc.Columns, constant->desc.StructMembers);
+
+    if (constant->desc.RegisterCount == 0)
+        /* If RegisterCount wasn't calculated for us, we have to calculate it */
+        constant->desc.RegisterCount = constant->desc.Elements * constant->desc.Rows;
+
+    constant->desc.Bytes = calc_bytes(&constant->desc);
+
+    if (constant->desc.Elements > 1)
+    {
+        DWORD bytes_per_element = constant->desc.Bytes / constant->desc.Elements;
+        DWORD registers_per_element = constant->desc.RegisterCount / constant->desc.Elements;
+
+        constant->member_count = constant->desc.Elements;
+        constant->members = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ctab_constant) * constant->member_count);
+
+        for (i = 0; i < constant->desc.Elements; i++)
+        {
+            constant->members[i].desc.Name = constant->desc.Name;
+            constant->members[i].desc.RegisterSet = constant->desc.RegisterSet;
+            constant->members[i].desc.RegisterIndex = constant->desc.RegisterIndex + registers_per_element * i;
+            constant->members[i].desc.RegisterCount = registers_per_element;
+            constant->members[i].desc.DefaultValue = (LPVOID)((DWORD_PTR)constant->desc.DefaultValue + bytes_per_element * i);
+
+            hr = parse_ctab_constant_element_type(type, &constant->members[i], ctab);
+            if (hr != D3D_OK)
+                goto error;
+
+            TRACE("  elem %d (under %s), rs = %d, index = %d, count = %d\n", i, constant->desc.Name, constant->desc.RegisterSet,
+                    constant->members[i].desc.RegisterIndex, constant->members[i].desc.RegisterCount);
+        }
+
+        return D3D_OK;
+    } else
+        return parse_ctab_constant_element_type(type, constant, ctab);
+
     return D3D_OK;
+
+error:
+    if (constant->members)
+        release_constants(constant->members, constant->desc.Elements);
+
+    return hr;
 }
 
 HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
@@ -1204,13 +1459,6 @@ HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
     if (ctab_header->Target)
         TRACE("Target = %s\n", object->ctab + ctab_header->Target);
 
-    if (object->desc.Constants > 65535)
-    {
-        FIXME("Too many constants (%u)\n", object->desc.Constants);
-        hr = E_NOTIMPL;
-        goto error;
-    }
-
     object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                   sizeof(*object->constants) * object->desc.Constants);
     if (!object->constants)
@@ -1231,25 +1479,9 @@ HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
         object->constants[i].desc.DefaultValue = object->ctab + constant_info[i].DefaultValue;
 
         hr = parse_ctab_constant_type((LPD3DXSHADER_TYPEINFO)(object->ctab + constant_info[i].TypeInfo),
-             &object->constants[i]);
+             &object->constants[i], object->ctab);
         if (hr != D3D_OK)
             goto error;
-
-        if (constant_info[i].RegisterSet != D3DXRS_FLOAT4 &&
-                constant_info[i].RegisterSet != D3DXRS_SAMPLER)
-            FIXME("Don't know how to calculate Bytes for constants of type %d\n",
-                    constant_info[i].RegisterSet);
-
-        /*
-         * D3DXRS_FLOAT4 and D3DXRS_SAMPLER have a base size of 4
-         * (not taking into account dimensions and element count)
-         */
-        object->constants[i].desc.Bytes = 4;
-
-        /* Take into account dimensions and elements */
-        object->constants[i].desc.Bytes *= object->constants[i].desc.Elements;
-        object->constants[i].desc.Bytes *= object->constants[i].desc.Rows *
-                object->constants[i].desc.Columns;
     }
 
     *constant_table = &object->ID3DXConstantTable_iface;
@@ -1258,9 +1490,7 @@ HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
 
 error:
 
-    HeapFree(GetProcessHeap(), 0, object->constants);
-    HeapFree(GetProcessHeap(), 0, object->ctab);
-    HeapFree(GetProcessHeap(), 0, object);
+    ID3DXConstantTableImpl_Release((ID3DXConstantTable *)object);
 
     return hr;
 }
-- 
1.6.4.4




More information about the wine-patches mailing list