[PATCH 4/5] d3dx9/tests: Add ID3DXConstantTable struct test.

Matteo Bruni matteo.mystral at gmail.com
Fri Aug 2 07:23:23 CDT 2013


2013/8/1 Matteo Bruni <matteo.mystral at gmail.com>:
> Instead of generating an entry for the struct with the correct
> members, the compiler generates TWO entries for sbnf, one with all its
> fields in D3DXRS_FLOAT4 and the other with D3DXRS_BOOL. Which, if I'm
> reading this correctly, makes 0 sense.
> Calling GetConstantByName() on the various fields then happen to
> return the first instance of the struct. It's the same with native
> d3dx9, FWIW.
>

I take this partially back, actually it might make sense after all.
Calling GetConstantDesc in general returns an array of
D3DXCONSTANT_DESC, not necessarily just one. I always wondered why but
I failed to make the connection to this case, until now.

Long wall of text follows, sorry. Case in point:

>> // Registers:
>> //
>> //   Name         Reg   Size
>> //   ------------ ----- ----
>> //   sb           b0       3
>> //   snb          b3       3
>> //   sbn          b6       2
>> //   sbnf         b8       1
>> //   sn           c0       3
>> //   sbn          c3       3
>> //   sbnf         c6       3
>> //   sbnf2        c9       3
>> //   sbnf3        c12      3
>> //   snb          c15      2
>>

Notice how there is an overallocation of the constants: for sbnf there
are 3 float AND one bool registers allocated. Now, checking again
+d3dx output but tracing some more stuff:

trace:d3dx:parse_ctab_constant_type name sbnf, elements 1, defaultvalue 0x18e1d0
trace:d3dx:parse_ctab_constant_type regset D3DXRS_FLOAT4, regidx 6, regcount 3
trace:d3dx:parse_ctab_constant_type class D3DXPC_STRUCT, type
D3DXPT_VOID, rows 1, columns 3, elements 1, struct_members 3
trace:d3dx:parse_ctab_constant_type name b4, elements 1, defaultvalue 0x18e1d0
trace:d3dx:parse_ctab_constant_type regset D3DXRS_FLOAT4, regidx 6, regcount 0
trace:d3dx:parse_ctab_constant_type class D3DXPC_SCALAR, type
D3DXPT_BOOL, rows 1, columns 1, elements 1, struct_members 0
trace:d3dx:parse_ctab_constant_type name n4, elements 1, defaultvalue 0x18e1e0
trace:d3dx:parse_ctab_constant_type regset D3DXRS_FLOAT4, regidx 7, regcount 0
trace:d3dx:parse_ctab_constant_type class D3DXPC_SCALAR, type
D3DXPT_INT, rows 1, columns 1, elements 1, struct_members 0
trace:d3dx:parse_ctab_constant_type name f4, elements 1, defaultvalue 0x18e1f0
trace:d3dx:parse_ctab_constant_type regset D3DXRS_FLOAT4, regidx 8, regcount 0
trace:d3dx:parse_ctab_constant_type class D3DXPC_SCALAR, type
D3DXPT_FLOAT, rows 1, columns 1, elements 1, struct_members 0
trace:d3dx:parse_ctab_constant_type name sbnf, elements 1, defaultvalue 0x18e124
trace:d3dx:parse_ctab_constant_type regset D3DXRS_BOOL, regidx 8, regcount 1
trace:d3dx:parse_ctab_constant_type class D3DXPC_STRUCT, type
D3DXPT_VOID, rows 1, columns 3, elements 1, struct_members 3
trace:d3dx:parse_ctab_constant_type name b4, elements 1, defaultvalue 0x18e124
trace:d3dx:parse_ctab_constant_type regset D3DXRS_BOOL, regidx 8, regcount 0
trace:d3dx:parse_ctab_constant_type class D3DXPC_SCALAR, type
D3DXPT_BOOL, rows 1, columns 1, elements 1, struct_members 0
trace:d3dx:parse_ctab_constant_type name n4, elements 1, defaultvalue 0x18e128
trace:d3dx:parse_ctab_constant_type regset D3DXRS_BOOL, regidx 9, regcount 0
trace:d3dx:parse_ctab_constant_type class D3DXPC_SCALAR, type
D3DXPT_INT, rows 1, columns 1, elements 1, struct_members 0
trace:d3dx:parse_ctab_constant_type name f4, elements 1, defaultvalue 0x18e12c
trace:d3dx:parse_ctab_constant_type regset D3DXRS_BOOL, regidx 9, regcount 0
trace:d3dx:parse_ctab_constant_type class D3DXPC_SCALAR, type
D3DXPT_FLOAT, rows 1, columns 1, elements 1, struct_members 0

Sure enough, if you call GetConstantDesc() for sbnf, passing an array
of two D3DXCONSTANT_DESC and setting the count to 2, you get both
filled. Same with its struct members.
Here's what I get from a quickly hacked test with native d3dx9:

shader.c:6243: sbnf (0) registerset is 2.
shader.c:6244: sbnf (0) registerindex is 6.
shader.c:6245: sbnf (0) registercount is 3.
shader.c:6243: sbnf (1) registerset is 0.
shader.c:6244: sbnf (1) registerindex is 8.
shader.c:6245: sbnf (1) registercount is 1.

shader.c:6243: sbnf.b4 (0) registerset is 2.
shader.c:6244: sbnf.b4 (0) registerindex is 6.
shader.c:6245: sbnf.b4 (0) registercount is 1.
shader.c:6243: sbnf.b4 (1) registerset is 0.
shader.c:6244: sbnf.b4 (1) registerindex is 8.
shader.c:6245: sbnf.b4 (1) registercount is 1.

shader.c:6243: sbnf.n4 (0) registerset is 2.
shader.c:6244: sbnf.n4 (0) registerindex is 7.
shader.c:6245: sbnf.n4 (0) registercount is 1.
shader.c:6243: sbnf.n4 (1) registerset is 0.
shader.c:6244: sbnf.n4 (1) registerindex is 9.
shader.c:6245: sbnf.n4 (1) registercount is 0.

shader.c:6243: sbnf.f4 (0) registerset is 2.
shader.c:6244: sbnf.f4 (0) registerindex is 8.
shader.c:6245: sbnf.f4 (0) registercount is 1.
shader.c:6243: sbnf.f4 (1) registerset is 0.
shader.c:6244: sbnf.f4 (1) registerindex is 9.
shader.c:6245: sbnf.f4 (1) registercount is 0.

The 0 or 1 in parentheses indicate that the line refers to the first
or the second D3DXCONSTANT_DESC respectively. Apparently the registers
assigned to a struct are allocated to its members in order, until they
run out. This also matches with the output from fxc, if you look at
the generated code in particular.
On MSDN, in the page for GetConstantDesc, it mentions something about
RegisterCount being 0 in some cases (then failing to say anything
meaningful on the when and the why). I guess this is pretty much it.

I haven't tested it, but I also expect that setting the value of one
of those struct members via the constant table (e.g. SetFloat(device,
"sbnf.f4", f)) updates all the "instances" of the constant.

As for the why it is done like this, I guess that's because the
compiler might potentially need to have the same constant in multiple
registersets (because of the lack of orthogonality between the D3D
opcodes and the data types). But it's just a guess.

It looks like quite a number of changes to our ID3DXConstantTable are
necessary for this. As far as I can see, the current code for
computing the register count for struct members is okay already.
What's missing is the ability to store and return multiple
D3DXCONSTANT_DESC for each constant and to update all the locations on
calls to the various Set* functions as well (assuming that's what
actually happens). There might be more but I can't think of anything
else right now. Probably it's best to start with fixing / adding
tests...

Cheers,
Matteo.



More information about the wine-devel mailing list