[Mesa-dev] [PATCH 07/17] glsl/ir: Add builtin constant function support for doubles

Ilia Mirkin imirkin at alum.mit.edu
Thu Feb 5 18:08:13 PST 2015


On Thu, Feb 5, 2015 at 1:57 PM, Matt Turner <mattst88 at gmail.com> wrote:
> On Thu, Feb 5, 2015 at 3:05 AM, Topi Pohjolainen
> <topi.pohjolainen at intel.com> wrote:
>> From: Dave Airlie <airlied at gmail.com>
>>
>> (was: add double support)
>
> I was going to suggest removing this from the commit subjects, but
> just so you don't miss this one, remove it too. :)

Yeah, these are all gone.

>
>>
>> Signed-off-by: Dave Airlie <airlied at redhat.com>
>> ---
>>  src/glsl/ir_constant_expression.cpp | 234 +++++++++++++++++++++++++++++++-----
>>  1 file changed, 202 insertions(+), 32 deletions(-)
>>
>> diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp
>> index 1e8b3a3..4387a51 100644
>> --- a/src/glsl/ir_constant_expression.cpp
>> +++ b/src/glsl/ir_constant_expression.cpp
>> @@ -60,7 +60,7 @@ static double copysign(double x, double y)
>>  #endif
>>
>>  static float
>> -dot(ir_constant *op0, ir_constant *op1)
>> +dot_f(ir_constant *op0, ir_constant *op1)
>>  {
>>     assert(op0->type->is_float() && op1->type->is_float());
>>
>> @@ -71,6 +71,18 @@ dot(ir_constant *op0, ir_constant *op1)
>>     return result;
>>  }
>>
>> +static double
>> +dot_d(ir_constant *op0, ir_constant *op1)
>> +{
>> +   assert(op0->type->is_double() && op1->type->is_double());
>> +
>> +   double result = 0;
>> +   for (unsigned c = 0; c < op0->type->components(); c++)
>> +      result += op0->value.d[c] * op1->value.d[c];
>> +
>> +   return result;
>> +}
>> +
>>  /* This method is the only one supported by gcc.  Unions in particular
>>   * are iffy, and read-through-converted-pointer is killed by strict
>>   * aliasing.  OTOH, the compiler sees through the memcpy, so the
>> @@ -667,32 +679,75 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
>>             data.b[0] = true;
>>        }
>>        break;
>> -
>> -   case ir_unop_trunc:
>> +   case ir_unop_d2f:
>> +      assert(op[0]->type->base_type == GLSL_TYPE_DOUBLE);
>> +      for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> +        data.f[c] = op[0]->value.d[c];
>> +      }
>> +      break;
>> +   case ir_unop_f2d:
>>        assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
>>        for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> -        data.f[c] = truncf(op[0]->value.f[c]);
>> +        data.d[c] = op[0]->value.f[c];
>> +      }
>> +      break;
>> +   case ir_unop_d2i:
>> +      assert(op[0]->type->base_type == GLSL_TYPE_DOUBLE);
>> +      for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> +        data.i[c] = op[0]->value.d[c];
>> +      }
>> +      break;
>> +   case ir_unop_i2d:
>> +      assert(op[0]->type->base_type == GLSL_TYPE_INT);
>> +      for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> +        data.d[c] = op[0]->value.i[c];
>> +      }
>> +      break;
>> +   case ir_unop_d2u:
>> +      assert(op[0]->type->base_type == GLSL_TYPE_DOUBLE);
>> +      for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> +        data.u[c] = op[0]->value.d[c];
>> +      }
>> +      break;
>> +   case ir_unop_u2d:
>
> Missing b2d/d2b.

They don't exist...

>
>> +      assert(op[0]->type->base_type == GLSL_TYPE_UINT);
>> +      for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> +        data.d[c] = op[0]->value.u[c];
>> +      }
>> +      break;
>> +   case ir_unop_trunc:
>> +      for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> +         if (op[0]->type->base_type == GLSL_TYPE_DOUBLE)
>> +            data.d[c] = trunc(op[0]->value.d[c]);
>> +         else
>> +            data.f[c] = truncf(op[0]->value.f[c]);
>>        }
>>        break;
>>
>>     case ir_unop_round_even:
>> -      assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
>>        for (unsigned c = 0; c < op[0]->type->components(); c++) {
>> -        data.f[c] = _mesa_round_to_even(op[0]->value.f[c]);
>> +         if (op[0]->type->base_type == GLSL_TYPE_DOUBLE)
>> +            data.d[c] = _mesa_round_to_even(op[0]->value.d[c]);
>
> _mesa_round_to_even takes a float. This can't work.
>
> And, looking at the implementation and the comment above it... can't
> we do better and actually implement a real round-to-even function?

_mesa_round_to_even returns an int, so it can't work for floats
either. I don't think fixing this needs to be part of the series...
it'll just fail horribly for too-big things.

>
>> +         else
>> +            data.f[c] = _mesa_round_to_even(op[0]->value.f[c]);
>>        }
>>        break;
>>
>> @@ -1474,6 +1600,17 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
>>           data.f[c] = CLAMP(op[0]->value.f[c], 0.0f, 1.0f);
>>        }
>>        break;
>> +   case ir_unop_pack_double_2x32: {
>> +      uint64_t temp;
>> +      temp = (uint64_t)op[0]->value.u[0] | ((uint64_t)op[0]->value.u[1] << 32);
>> +      data.d[0] = *(double *)&temp;
>
> I'm not sure if this is safe for big endian. Would a memcpy be endian
> safe (and also avoid breaking strict aliasing rules)?

>From https://www.opengl.org/sdk/docs/man/html/packDouble2x32.xhtml :

"""
The first vector component (v[0]) specifies the 32 least significant
bits of the result; the second component (v[1]) specifies the 32 most
significant bits.
"""

This stuff gives me a headache. Does it mean that we need to byteswap
the resulting temp on BE machines? Either way, I'm pretty sure that a
plain memcpy wouldn't help here.

>
>> +
>> +      break;
>> +   }
>> +   case ir_unop_unpack_double_2x32:
>> +      data.u[0] = *(uint32_t *)&op[0]->value.d[0];
>> +      data.u[1] = *((uint32_t *)&op[0]->value.d[0] + 1);
>
> Same comment about memcpy.

Same comment about headache ;) Happy to just stick a XXX in there and
move on. Thoughts?

>
>> +      break;
>>
>>     case ir_triop_bitfield_extract: {
>>        int offset = op[1]->value.i[0];


More information about the mesa-dev mailing list