+
+ nir_ssa_def *pos_int = nir_f2i(&b, nir_load_var(&b, tex_pos_in));
+ unsigned swiz[4] = { 0, 1 };
+ nir_ssa_def *tex_pos = nir_swizzle(&b, pos_int, swiz, 2, false);
+ nir_ssa_def *tex_pitch = nir_channel(&b, pos_int, 2);
+
+ nir_ssa_def *color = txf_func(&b, device, tex_pos, tex_pitch);
+ nir_store_var(&b, color_out, color, 0xf);
+
+ return b.shader;
+}
+
+static const VkPipelineVertexInputStateCreateInfo w_tiled_vi_create_info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = 2,
+ .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
+ {
+ .binding = 0,
+ .stride = 0,
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ },
+ {
+ .binding = 1,
+ .stride = 2 * sizeof(float),
+ .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
+ },
+ },
+ .vertexAttributeDescriptionCount = 4,
+ .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
+ {
+ /* VUE Header */
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_UINT,
+ .offset = 0
+ },
+ {
+ /* Position */
+ .location = 1,
+ .binding = 1,
+ .format = VK_FORMAT_R32G32_SFLOAT,
+ .offset = 0
+ },
+ {
+ /* Texture Offset */
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32_UINT,
+ .offset = 16
+ },
+ {
+ /* Destination bounds */
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_UINT,
+ .offset = 28
+ },
+ },
+};
+
+static nir_shader *
+build_nir_w_tiled_fragment_shader(struct anv_device *device,
+ texel_fetch_build_func txf_func)
+{
+ const struct glsl_type *vec4 = glsl_vec4_type();
+ const struct glsl_type *ivec3 = glsl_vector_type(GLSL_TYPE_INT, 3);
+ const struct glsl_type *uvec4 = glsl_vector_type(GLSL_TYPE_UINT, 4);
+ nir_builder b;
+
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
+ b.shader->info.name = ralloc_strdup(b.shader, "meta_blit2d_fs");
+
+ /* We need gl_FragCoord so we know our Y-tiled position */
+ nir_variable *frag_coord_in = nir_variable_create(b.shader,
+ nir_var_shader_in,
+ vec4, "gl_FragCoord");
+ frag_coord_in->data.location = VARYING_SLOT_POS;
+ frag_coord_in->data.origin_upper_left = true;
+
+ /* In location 0 we have an ivec3 that has the offset from dest to
+ * source in the first two components and the stride in the third.
+ */
+ nir_variable *tex_off_in = nir_variable_create(b.shader, nir_var_shader_in,
+ ivec3, "v_tex_off");
+ tex_off_in->data.location = VARYING_SLOT_VAR0;
+ tex_off_in->data.interpolation = INTERP_QUALIFIER_FLAT;
+
+ /* In location 1 we have a uvec4 that gives us the bounds of the
+ * destination. We need to discard if we get outside this boundary.
+ */
+ nir_variable *bounds_in = nir_variable_create(b.shader, nir_var_shader_in,
+ uvec4, "v_bounds");
+ bounds_in->data.location = VARYING_SLOT_VAR1;
+ bounds_in->data.interpolation = INTERP_QUALIFIER_FLAT;
+
+ nir_variable *color_out = nir_variable_create(b.shader, nir_var_shader_out,
+ vec4, "f_color");
+ color_out->data.location = FRAG_RESULT_DATA0;
+
+ nir_ssa_def *frag_coord_int = nir_f2i(&b, nir_load_var(&b, frag_coord_in));
+ nir_ssa_def *x_Y = nir_channel(&b, frag_coord_int, 0);
+ nir_ssa_def *y_Y = nir_channel(&b, frag_coord_int, 1);
+
+ /* Compute the W-tiled position from the Y-tiled position */
+ nir_ssa_def *x_W = nir_iand(&b, x_Y, nir_imm_int(&b, 0xffffff80));
+ x_W = nir_ushr(&b, x_W, nir_imm_int(&b, 1));
+ x_W = nir_copy_bits(&b, x_W, 0, x_Y, 0, 1);
+ x_W = nir_copy_bits(&b, x_W, 1, x_Y, 2, 1);
+ x_W = nir_copy_bits(&b, x_W, 2, y_Y, 0, 1);
+ x_W = nir_copy_bits(&b, x_W, 3, x_Y, 4, 3);
+
+ nir_ssa_def *y_W = nir_iand(&b, y_Y, nir_imm_int(&b, 0xffffffe0));
+ y_W = nir_ishl(&b, y_W, nir_imm_int(&b, 1));
+ y_W = nir_copy_bits(&b, y_W, 0, x_Y, 1, 1);
+ y_W = nir_copy_bits(&b, y_W, 1, x_Y, 3, 1);
+ y_W = nir_copy_bits(&b, y_W, 2, y_Y, 1, 4);
+
+ /* Figure out if we are out-of-bounds and discard */
+ nir_ssa_def *bounds = nir_load_var(&b, bounds_in);
+ nir_ssa_def *oob =
+ nir_ior(&b, nir_ult(&b, x_W, nir_channel(&b, bounds, 0)),
+ nir_ior(&b, nir_ult(&b, y_W, nir_channel(&b, bounds, 1)),
+ nir_ior(&b, nir_uge(&b, x_W, nir_channel(&b, bounds, 2)),
+ nir_uge(&b, y_W, nir_channel(&b, bounds, 3)))));
+
+ nir_intrinsic_instr *discard =
+ nir_intrinsic_instr_create(b.shader, nir_intrinsic_discard_if);
+ discard->src[0] = nir_src_for_ssa(oob);
+ nir_builder_instr_insert(&b, &discard->instr);
+
+ nir_ssa_def *tex_off = nir_channels(&b, nir_load_var(&b, tex_off_in), 0x3);
+ nir_ssa_def *tex_pos = nir_iadd(&b, nir_vec2(&b, x_W, y_W), tex_off);
+ nir_ssa_def *tex_pitch = nir_channel(&b, nir_load_var(&b, tex_off_in), 2);
+
+ nir_ssa_def *color = txf_func(&b, device, tex_pos, tex_pitch);
+ nir_store_var(&b, color_out, color, 0xf);