+}
+
+static void *vc4_get_yuv_vs(struct pipe_context *pctx)
+{
+ struct vc4_context *vc4 = vc4_context(pctx);
+ struct pipe_screen *pscreen = pctx->screen;
+
+ if (vc4->yuv_linear_blit_vs)
+ return vc4->yuv_linear_blit_vs;
+
+ const struct nir_shader_compiler_options *options =
+ pscreen->get_compiler_options(pscreen,
+ PIPE_SHADER_IR_NIR,
+ PIPE_SHADER_VERTEX);
+
+ nir_builder b;
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, options);
+ b.shader->info.name = ralloc_strdup(b.shader, "linear_blit_vs");
+
+ const struct glsl_type *vec4 = glsl_vec4_type();
+ nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
+ vec4, "pos");
+
+ nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,
+ vec4, "gl_Position");
+ pos_out->data.location = VARYING_SLOT_POS;
+
+ nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf);
+
+ struct pipe_shader_state shader_tmpl = {
+ .type = PIPE_SHADER_IR_NIR,
+ .ir.nir = b.shader,
+ };
+
+ vc4->yuv_linear_blit_vs = pctx->create_vs_state(pctx, &shader_tmpl);
+
+ return vc4->yuv_linear_blit_vs;
+}
+
+static void *vc4_get_yuv_fs(struct pipe_context *pctx, int cpp)
+{
+ struct vc4_context *vc4 = vc4_context(pctx);
+ struct pipe_screen *pscreen = pctx->screen;
+ struct pipe_shader_state **cached_shader;
+ const char *name;
+
+ if (cpp == 1) {
+ cached_shader = &vc4->yuv_linear_blit_fs_8bit;
+ name = "linear_blit_8bit_fs";
+ } else {
+ cached_shader = &vc4->yuv_linear_blit_fs_16bit;
+ name = "linear_blit_16bit_fs";
+ }
+
+ if (*cached_shader)
+ return *cached_shader;
+
+ const struct nir_shader_compiler_options *options =
+ pscreen->get_compiler_options(pscreen,
+ PIPE_SHADER_IR_NIR,
+ PIPE_SHADER_FRAGMENT);
+
+ nir_builder b;
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, options);
+ b.shader->info.name = ralloc_strdup(b.shader, name);
+
+ const struct glsl_type *vec4 = glsl_vec4_type();
+ const struct glsl_type *glsl_int = glsl_int_type();
+
+ nir_variable *color_out = nir_variable_create(b.shader, nir_var_shader_out,
+ vec4, "f_color");
+ color_out->data.location = FRAG_RESULT_COLOR;
+
+ nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
+ vec4, "pos");
+ pos_in->data.location = VARYING_SLOT_POS;
+ nir_ssa_def *pos = nir_load_var(&b, pos_in);
+
+ nir_ssa_def *one = nir_imm_int(&b, 1);
+ nir_ssa_def *two = nir_imm_int(&b, 2);
+
+ nir_ssa_def *x = nir_f2i32(&b, nir_channel(&b, pos, 0));
+ nir_ssa_def *y = nir_f2i32(&b, nir_channel(&b, pos, 1));
+
+ nir_variable *stride_in = nir_variable_create(b.shader, nir_var_uniform,
+ glsl_int, "stride");
+ nir_ssa_def *stride = nir_load_var(&b, stride_in);
+
+ nir_ssa_def *x_offset;
+ nir_ssa_def *y_offset;
+ if (cpp == 1) {
+ nir_ssa_def *intra_utile_x_offset =
+ nir_ishl(&b, nir_iand(&b, x, one), two);
+ nir_ssa_def *inter_utile_x_offset =
+ nir_ishl(&b, nir_iand(&b, x, nir_imm_int(&b, ~3)), one);
+
+ x_offset = nir_iadd(&b,
+ intra_utile_x_offset,
+ inter_utile_x_offset);
+ y_offset = nir_imul(&b,
+ nir_iadd(&b,
+ nir_ishl(&b, y, one),
+ nir_ushr(&b, nir_iand(&b, x, two), one)),
+ stride);
+ } else {
+ x_offset = nir_ishl(&b, x, two);
+ y_offset = nir_imul(&b, y, stride);
+ }
+
+ nir_intrinsic_instr *load =
+ nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_ubo);
+ load->num_components = 1;
+ nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, 32, NULL);
+ load->src[0] = nir_src_for_ssa(one);
+ load->src[1] = nir_src_for_ssa(nir_iadd(&b, x_offset, y_offset));
+ nir_builder_instr_insert(&b, &load->instr);
+
+ nir_store_var(&b, color_out,
+ nir_unpack_unorm_4x8(&b, &load->dest.ssa),
+ 0xf);
+
+ struct pipe_shader_state shader_tmpl = {
+ .type = PIPE_SHADER_IR_NIR,
+ .ir.nir = b.shader,
+ };