+ color = nir_vec(b, chans, 4);
+ } else {
+ /* This path only supports UINT formats */
+ assert(src_fmtl->channels.r.type == ISL_UINT);
+ assert(dst_fmtl->channels.r.type == ISL_UINT);
+
+ const unsigned src_bpc = src_fmtl->channels.r.bits;
+ const unsigned dst_bpc = dst_fmtl->channels.r.bits;
+
+ assert(src_fmtl->channels.g.bits == 0 ||
+ src_fmtl->channels.g.bits == src_fmtl->channels.r.bits);
+ assert(src_fmtl->channels.b.bits == 0 ||
+ src_fmtl->channels.b.bits == src_fmtl->channels.r.bits);
+ assert(src_fmtl->channels.a.bits == 0 ||
+ src_fmtl->channels.a.bits == src_fmtl->channels.r.bits);
+ assert(dst_fmtl->channels.g.bits == 0 ||
+ dst_fmtl->channels.g.bits == dst_fmtl->channels.r.bits);
+ assert(dst_fmtl->channels.b.bits == 0 ||
+ dst_fmtl->channels.b.bits == dst_fmtl->channels.r.bits);
+ assert(dst_fmtl->channels.a.bits == 0 ||
+ dst_fmtl->channels.a.bits == dst_fmtl->channels.r.bits);
+
+ /* Restrict to only the channels we actually have */
+ const unsigned src_channels =
+ isl_format_get_num_channels(key->src_format);
+ color = nir_channels(b, color, (1 << src_channels) - 1);
+
+ color = nir_format_bitcast_uvec_unmasked(b, color, src_bpc, dst_bpc);
+ }
+
+ /* Blorp likes to assume that colors are vec4s */
+ nir_ssa_def *u = nir_ssa_undef(b, 1, 32);
+ nir_ssa_def *chans[4] = { u, u, u, u };
+ for (unsigned i = 0; i < color->num_components; i++)
+ chans[i] = nir_channel(b, color, i);
+ return nir_vec4(b, chans[0], chans[1], chans[2], chans[3]);
+}
+
+static nir_ssa_def *
+select_color_channel(struct nir_builder *b, nir_ssa_def *color,
+ nir_alu_type data_type,
+ enum isl_channel_select chan)
+{
+ if (chan == ISL_CHANNEL_SELECT_ZERO) {
+ return nir_imm_int(b, 0);
+ } else if (chan == ISL_CHANNEL_SELECT_ONE) {
+ switch (data_type) {
+ case nir_type_int:
+ case nir_type_uint:
+ return nir_imm_int(b, 1);
+ case nir_type_float:
+ return nir_imm_float(b, 1);
+ default:
+ unreachable("Invalid data type");
+ }
+ } else {
+ assert((unsigned)(chan - ISL_CHANNEL_SELECT_RED) < 4);
+ return nir_channel(b, color, chan - ISL_CHANNEL_SELECT_RED);
+ }
+}
+
+static nir_ssa_def *
+swizzle_color(struct nir_builder *b, nir_ssa_def *color,
+ struct isl_swizzle swizzle, nir_alu_type data_type)
+{
+ return nir_vec4(b,
+ select_color_channel(b, color, data_type, swizzle.r),
+ select_color_channel(b, color, data_type, swizzle.g),
+ select_color_channel(b, color, data_type, swizzle.b),
+ select_color_channel(b, color, data_type, swizzle.a));
+}
+
+static nir_ssa_def *
+convert_color(struct nir_builder *b, nir_ssa_def *color,
+ const struct brw_blorp_blit_prog_key *key)
+{
+ /* All of our color conversions end up generating a single-channel color
+ * value that we need to write out.
+ */
+ nir_ssa_def *value;
+
+ if (key->dst_format == ISL_FORMAT_R24_UNORM_X8_TYPELESS) {
+ /* The destination image is bound as R32_UINT but the data needs to be
+ * in R24_UNORM_X8_TYPELESS. The bottom 24 are the actual data and the
+ * top 8 need to be zero. We can accomplish this by simply multiplying
+ * by a factor to scale things down.
+ */
+ unsigned factor = (1 << 24) - 1;
+ value = nir_fsat(b, nir_channel(b, color, 0));
+ value = nir_f2i32(b, nir_fmul(b, value, nir_imm_float(b, factor)));
+ } else if (key->dst_format == ISL_FORMAT_L8_UNORM_SRGB) {
+ value = nir_format_linear_to_srgb(b, nir_channel(b, color, 0));
+ } else if (key->dst_format == ISL_FORMAT_R8G8B8_UNORM_SRGB) {
+ value = nir_format_linear_to_srgb(b, color);
+ } else if (key->dst_format == ISL_FORMAT_R9G9B9E5_SHAREDEXP) {
+ value = nir_format_pack_r9g9b9e5(b, color);
+ } else {
+ unreachable("Unsupported format conversion");
+ }