[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