[PATCH 2/3] d3dx9: Support relative addressing in preshader.

Paul Gofman gofmanp at gmail.com
Thu Mar 23 18:39:01 CDT 2017


On 03/24/2017 01:57 AM, Matteo Bruni wrote:
> 2017-03-23 16:06 GMT+01:00 Paul Gofman <gofmanp at gmail.com>:
>> Signed-off-by: Paul Gofman <gofmanp at gmail.com>
>> ---
>>   dlls/d3dx9_36/preshader.c    | 103 ++++++++++++++++++++++++++++++++++++-------
>>   dlls/d3dx9_36/tests/effect.c |  38 ++++++++--------
>>   2 files changed, 106 insertions(+), 35 deletions(-)
>>
>> diff --git a/dlls/d3dx9_36/preshader.c b/dlls/d3dx9_36/preshader.c
>> index 9aedc99..2974ffd 100644
>> --- a/dlls/d3dx9_36/preshader.c
>> +++ b/dlls/d3dx9_36/preshader.c
>> @@ -191,6 +191,8 @@ struct d3dx_pres_operand
>>       /* offset is component index, not register index, e. g.
>>          offset for component c3.y is 13 (3 * 4 + 1) */
>>       unsigned int offset;
>> +    enum pres_reg_tables base_reg_table;
>> +    unsigned int base_reg_offset;
>>   };
> It would be nicer to create a struct for storing together table and
> offset and to pass it around to the various functions taking both
> arguments, like parse_pres_reg().
> It should probably be a separate patch before this one.
Actually I can't guess the case when base_reg_table would be not a 
floating constant preshader input. Maybe I just remove this variable and 
check with FIXME during parsing?
>
>> +    size = rs->table_sizes[table] * table_info[table].reg_component_count;
>> +    if (offset >= size)
>> +    {
>> +        if ((offset & 255) < size)
>> +            offset &= 255;
>> +        else
>> +            offset = offset % size;
>> +    }
> Is this just to try and avoid the modulo operation in some cases or is
> there a deeper reason?
> If the former, you could extend that to all the power-of-two sizes by
> first checking if that's the case (!(size & size - 1)) and, if so,
> and-ing offset with the mask (size - 1). That's assuming the compiler
> doesn't do the same optimization already.
>
> Let me know if there is some other reason instead.
Just doing (offset % size) will lead to different results and will break 
the tests. The logic in this out of range index checking is a bit mind 
breaking.
>
>>   static double exec_get_arg(struct d3dx_regstore *rs, const struct d3dx_pres_operand *opr, unsigned int comp)
>>   {
>> -    if (!regstore_is_val_set_reg(rs, opr->table, (opr->offset + comp) / table_info[opr->table].reg_component_count))
>> -        WARN("Using uninitialized input, table %u, offset %u.\n", opr->table, opr->offset + comp);
>> +    unsigned int base_offset, index;
>> +
>> +    if (opr->base_reg_table == PRES_REGTAB_COUNT)
>> +        index = 0;
>> +    else
>> +        index = (int)exec_get_reg_value(rs, opr->base_reg_table, opr->base_reg_offset);
> I think it's better with lrint() in place of the cast.
I just want to note that whenever the input is from floating values FX 
compiler generates preshader instructions which do the rounding, and 
skips that if the base register comes from integers. Do you think we 
need to do extra rounding in this case?
>
>> +    if (index >= rs->table_sizes[opr->table] && opr->table == PRES_REGTAB_CONST)
>> +    {
>> +        unsigned int size_pow2;
>> +
>> +        for (size_pow2 = 1; size_pow2 < rs->table_sizes[opr->table]; size_pow2 <<= 1)
>> +            ;
>> +        index &= (size_pow2 - 1);
>> +        if (index >= rs->table_sizes[opr->table])
>> +            return 0.0;
>> +    }
> I don't think we necessarily have to follow native's madness on buffer
> overflows to the letter. Since you did, that's certainly fine though.
>
     I think I finally guessed the principle how native d3dx clamps 
indexes, at least finally I got stable match for the tests involving any 
index numbers. I thought it could make some sense as we sometimes see 
apps depending on out of bounds access behaviour, especially if native 
implementation can return zeroes (either stable or by chance like here).

     As I can guess the logic behind it, it has some allocation size on 
the floating constant table which is the power of 2, and it first 
ultimately puts the index to this allocation range with modulo 
operation. Then, if the index is bigger than the actual number of 
constants, it returns zero. This logic is a bit different for indexing 
immediate constants though (which is used when indirect addressing 
selects something from vector or matrix), which never returns ultimate 
zeroes, probably because the memory allocation for immediate constants 
is always exact and is not done in chunks. I have no clear idea though 
why (offset & 255) < size is a special case, can only guess than maybe 
it is related somehow to casting offset to byte at some point.




More information about the wine-devel mailing list