ir_function_signature *map_builtin(ir_function_signature *sig);
- bool progress;
-
/* Set of rvalues that can be lowered. This will be filled in by
* find_lowerable_rvalues_visitor. Only the root node of a lowerable section
* will be added to this set.
find_lowerable_rvalues_visitor(struct set *result,
const struct gl_shader_compiler_options *options);
- bool can_lower_type(const glsl_type *type) const;
static void stack_enter(class ir_instruction *ir, void *data);
static void stack_leave(class ir_instruction *ir, void *data);
virtual ir_visitor_status visit_leave(ir_expression *);
};
-bool
-find_lowerable_rvalues_visitor::can_lower_type(const glsl_type *type) const
+static bool
+can_lower_type(const struct gl_shader_compiler_options *options,
+ const glsl_type *type)
{
/* Don’t lower any expressions involving non-float types except bool and
* texture samplers. This will rule out operations that change the type such
find_lowerable_rvalues_visitor::handle_precision(const glsl_type *type,
int precision) const
{
- if (!can_lower_type(type))
+ if (!can_lower_type(options, type))
return CANT_LOWER;
switch (precision) {
{
stack_enter(ir, this);
- if (!can_lower_type(ir->type))
+ if (!can_lower_type(options, ir->type))
stack.back().state = CANT_LOWER;
stack_leave(ir, this);
{
ir_hierarchical_visitor::visit_enter(ir);
- if (stack.back().state == UNKNOWN) {
- /* The precision of the sample value depends on the precision of the
- * sampler.
- */
- stack.back().state = handle_precision(ir->type,
- ir->sampler->precision());
- }
-
+ /* The precision of the sample value depends on the precision of the
+ * sampler.
+ */
+ stack.back().state = handle_precision(ir->type,
+ ir->sampler->precision());
return visit_continue;
}
{
ir_hierarchical_visitor::visit_enter(ir);
- if (!can_lower_type(ir->type))
+ if (!can_lower_type(options, ir->type))
stack.back().state = CANT_LOWER;
/* Don't lower precision for derivative calculations */
return visit_continue;
}
+static bool
+function_always_returns_mediump_or_lowp(const char *name)
+{
+ return !strcmp(name, "bitCount") ||
+ !strcmp(name, "findLSB") ||
+ !strcmp(name, "findMSB") ||
+ !strcmp(name, "unpackHalf2x16") ||
+ !strcmp(name, "unpackUnorm4x8") ||
+ !strcmp(name, "unpackSnorm4x8");
+}
+
static bool
is_lowerable_builtin(ir_call *ir,
const struct set *lowerable_rvalues)
* uses lower precision. The function parameters don't matter.
*/
if (var && var->type->without_array()->is_sampler()) {
+ /* textureSize always returns highp. */
+ if (!strcmp(ir->callee_name(), "textureSize"))
+ return false;
+
return var->data.precision == GLSL_PRECISION_MEDIUM ||
var->data.precision == GLSL_PRECISION_LOW;
}
}
- if (!ir->callee->is_builtin())
+ if (!ir->callee->is_builtin() ||
+ /* Parameters are always highp: */
+ !strcmp(ir->callee_name(), "floatBitsToInt") ||
+ !strcmp(ir->callee_name(), "floatBitsToUint") ||
+ !strcmp(ir->callee_name(), "intBitsToFloat") ||
+ !strcmp(ir->callee_name(), "uintBitsToFloat") ||
+ !strcmp(ir->callee_name(), "bitfieldReverse") ||
+ !strcmp(ir->callee_name(), "frexp") ||
+ !strcmp(ir->callee_name(), "ldexp") ||
+ /* Parameters and outputs are always highp: */
+ /* TODO: The operations are highp, but carry and borrow outputs are lowp. */
+ !strcmp(ir->callee_name(), "uaddCarry") ||
+ !strcmp(ir->callee_name(), "usubBorrow") ||
+ !strcmp(ir->callee_name(), "imulExtended") ||
+ !strcmp(ir->callee_name(), "umulExtended") ||
+ !strcmp(ir->callee_name(), "unpackUnorm2x16") ||
+ !strcmp(ir->callee_name(), "unpackSnorm2x16") ||
+ /* Outputs are highp: */
+ !strcmp(ir->callee_name(), "packUnorm2x16") ||
+ !strcmp(ir->callee_name(), "packSnorm2x16") ||
+ /* Parameters are mediump and outputs are highp. The parameters should
+ * be optimized in NIR, not here, e.g:
+ * - packHalf2x16 can just be a bitcast from f16vec2 to uint32
+ * - Other opcodes don't have to convert parameters to highp if the hw
+ * has f16 versions. Optimize in NIR accordingly.
+ */
+ !strcmp(ir->callee_name(), "packHalf2x16") ||
+ !strcmp(ir->callee_name(), "packUnorm4x8") ||
+ !strcmp(ir->callee_name(), "packSnorm4x8"))
return false;
assert(ir->callee->return_precision == GLSL_PRECISION_NONE);
+ /* Number of parameters to check if they are lowerable. */
+ unsigned check_parameters = ir->actual_parameters.length();
+
+ /* Interpolation functions only consider the precision of the interpolant. */
+ /* Bitfield functions ignore the precision of "offset" and "bits". */
+ if (!strcmp(ir->callee_name(), "interpolateAtOffset") ||
+ !strcmp(ir->callee_name(), "interpolateAtSample") ||
+ !strcmp(ir->callee_name(), "bitfieldExtract")) {
+ check_parameters = 1;
+ } else if (!strcmp(ir->callee_name(), "bitfieldInsert")) {
+ check_parameters = 2;
+ } if (function_always_returns_mediump_or_lowp(ir->callee_name())) {
+ /* These only lower the return value. Parameters keep their precision,
+ * which is preserved in map_builtin.
+ */
+ check_parameters = 0;
+ }
+
foreach_in_list(ir_rvalue, param, &ir->actual_parameters) {
+ if (!check_parameters)
+ break;
+
if (!param->as_constant() &&
_mesa_set_search(lowerable_rvalues, param) == NULL)
return false;
+
+ --check_parameters;
}
return true;
assert(v.stack.empty());
}
+static const glsl_type *
+lower_glsl_type(const glsl_type *type)
+{
+ glsl_base_type new_base_type;
+
+ switch (type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ new_base_type = GLSL_TYPE_FLOAT16;
+ break;
+ case GLSL_TYPE_INT:
+ new_base_type = GLSL_TYPE_INT16;
+ break;
+ case GLSL_TYPE_UINT:
+ new_base_type = GLSL_TYPE_UINT16;
+ break;
+ default:
+ unreachable("invalid type");
+ return NULL;
+ }
+
+ return glsl_type::get_instance(new_base_type,
+ type->vector_elements,
+ type->matrix_columns,
+ type->explicit_stride,
+ type->interface_row_major);
+}
+
static ir_rvalue *
-convert_precision(glsl_base_type type, bool up, ir_rvalue *ir)
+convert_precision(bool up, ir_rvalue *ir)
{
unsigned new_type, op;
if (up) {
- switch (type) {
+ switch (ir->type->base_type) {
case GLSL_TYPE_FLOAT16:
new_type = GLSL_TYPE_FLOAT;
op = ir_unop_f162f;
return NULL;
}
} else {
- switch (type) {
+ switch (ir->type->base_type) {
case GLSL_TYPE_FLOAT:
new_type = GLSL_TYPE_FLOAT16;
op = ir_unop_f2fmp;
return new(mem_ctx) ir_expression(op, desired_type, ir, NULL);
}
-static glsl_base_type
-lower_type(glsl_base_type type)
-{
- switch (type) {
- case GLSL_TYPE_FLOAT:
- return GLSL_TYPE_FLOAT16;
- case GLSL_TYPE_INT:
- return GLSL_TYPE_INT16;
- case GLSL_TYPE_UINT:
- return GLSL_TYPE_UINT16;
- default:
- unreachable("invalid type");
- return GLSL_TYPE_ERROR;;
- }
-}
-
void
lower_precision_visitor::handle_rvalue(ir_rvalue **rvalue)
{
if (ir->as_dereference()) {
if (!ir->type->is_boolean())
- *rvalue = convert_precision(ir->type->base_type, false, ir);
- } else if (ir->type->base_type == GLSL_TYPE_FLOAT ||
- ir->type->base_type == GLSL_TYPE_INT ||
- ir->type->base_type == GLSL_TYPE_UINT) {
- ir->type = glsl_type::get_instance(lower_type(ir->type->base_type),
- ir->type->vector_elements,
- ir->type->matrix_columns,
- ir->type->explicit_stride,
- ir->type->interface_row_major);
+ *rvalue = convert_precision(false, ir);
+ } else if (ir->type->is_32bit()) {
+ ir->type = lower_glsl_type(ir->type);
ir_constant *const_ir = ir->as_constant();
/* We don’t need to add the final conversion if the final type has been
* converted to bool
*/
- if ((*rvalue)->type->base_type != GLSL_TYPE_BOOL)
- *rvalue = convert_precision((*rvalue)->type->base_type, true, *rvalue);
-
- progress = true;
+ if ((*rvalue)->type->base_type != GLSL_TYPE_BOOL) {
+ *rvalue = convert_precision(true, *rvalue);
+ }
}
ir_visitor_status
ir_function_signature *lowered_sig =
sig->clone(lowered_builtin_mem_ctx, clone_ht);
- foreach_in_list(ir_variable, param, &lowered_sig->parameters) {
- param->data.precision = GLSL_PRECISION_MEDIUM;
+ /* Functions that always return mediump or lowp should keep their
+ * parameters intact, because they can be highp. NIR can lower
+ * the up-conversion for parameters if needed.
+ */
+ if (!function_always_returns_mediump_or_lowp(sig->function_name())) {
+ foreach_in_list(ir_variable, param, &lowered_sig->parameters) {
+ param->data.precision = GLSL_PRECISION_MEDIUM;
+ }
}
lower_precision(options, &lowered_sig->body);
}
find_precision_visitor::find_precision_visitor(const struct gl_shader_compiler_options *options)
- : progress(false),
- lowerable_rvalues(_mesa_pointer_set_create(NULL)),
+ : lowerable_rvalues(_mesa_pointer_set_create(NULL)),
lowered_builtins(NULL),
clone_ht(NULL),
lowered_builtin_mem_ctx(NULL),
}
-bool
+void
lower_precision(const struct gl_shader_compiler_options *options,
exec_list *instructions)
{
find_lowerable_rvalues(options, instructions, v.lowerable_rvalues);
visit_list_elements(&v, instructions);
-
- return v.progress;
}