+static unsigned
+pan_format_from_nir_base(nir_alu_type base)
+{
+ switch (base) {
+ case nir_type_int:
+ return MALI_FORMAT_SINT;
+ case nir_type_uint:
+ case nir_type_bool:
+ return MALI_FORMAT_UINT;
+ case nir_type_float:
+ return MALI_CHANNEL_FLOAT;
+ default:
+ unreachable("Invalid base");
+ }
+}
+
+static unsigned
+pan_format_from_nir_size(nir_alu_type base, unsigned size)
+{
+ if (base == nir_type_float) {
+ switch (size) {
+ case 16: return MALI_FORMAT_SINT;
+ case 32: return MALI_FORMAT_UNORM;
+ default:
+ unreachable("Invalid float size for format");
+ }
+ } else {
+ switch (size) {
+ case 1:
+ case 8: return MALI_CHANNEL_8;
+ case 16: return MALI_CHANNEL_16;
+ case 32: return MALI_CHANNEL_32;
+ default:
+ unreachable("Invalid int size for format");
+ }
+ }
+}
+
+static enum mali_format
+pan_format_from_glsl(const struct glsl_type *type, unsigned precision, unsigned frac)
+{
+ const struct glsl_type *column = glsl_without_array_or_matrix(type);
+ enum glsl_base_type glsl_base = glsl_get_base_type(column);
+ nir_alu_type t = nir_get_nir_type_for_glsl_base_type(glsl_base);
+ unsigned chan = glsl_get_components(column);
+
+ /* If we have a fractional location added, we need to increase the size
+ * so it will fit, i.e. a vec3 in YZW requires us to allocate a vec4.
+ * We could do better but this is an edge case as it is, normally
+ * packed varyings will be aligned. */
+ chan += frac;
+
+ assert(chan >= 1 && chan <= 4);
+
+ unsigned base = nir_alu_type_get_base_type(t);
+ unsigned size = nir_alu_type_get_type_size(t);
+
+ /* Demote to fp16 where possible. int16 varyings are TODO as the hw
+ * will saturate instead of wrap which is not conformant, so we need to
+ * insert i2i16/u2u16 instructions before the st_vary_32i/32u to get
+ * the intended behaviour */
+
+ bool is_16 = (precision == GLSL_PRECISION_MEDIUM)
+ || (precision == GLSL_PRECISION_LOW);
+
+ if (is_16 && base == nir_type_float)
+ size = 16;
+ else
+ size = 32;
+
+ return pan_format_from_nir_base(base) |
+ pan_format_from_nir_size(base, size) |
+ MALI_NR_CHANNELS(chan);
+}
+
+static enum bifrost_shader_type
+bifrost_blend_type_from_nir(nir_alu_type nir_type)
+{
+ switch(nir_type) {
+ case 0: /* Render target not in use */
+ return 0;
+ case nir_type_float16:
+ return BIFROST_BLEND_F16;
+ case nir_type_float32:
+ return BIFROST_BLEND_F32;
+ case nir_type_int32:
+ return BIFROST_BLEND_I32;
+ case nir_type_uint32:
+ return BIFROST_BLEND_U32;
+ case nir_type_int16:
+ return BIFROST_BLEND_I16;
+ case nir_type_uint16:
+ return BIFROST_BLEND_U16;
+ default:
+ unreachable("Unsupported blend shader type for NIR alu type");
+ return 0;
+ }
+}
+