anv/blit2d: Add support for RGB destinations
authorJason Ekstrand <jason.ekstrand@intel.com>
Tue, 2 Aug 2016 15:47:51 +0000 (08:47 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 23 Aug 2016 18:45:24 +0000 (11:45 -0700)
This fixes 104 of the new image_clearing and copy_and_blit Vulkan CTS
tests.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
src/intel/vulkan/anv_meta_blit2d.c

index 27ddb8add99a2795521227de37396648a1d22be9..7085f2da8b1e40f668fd95a115782b37f67f7c96 100644 (file)
@@ -92,6 +92,21 @@ vk_format_for_size(int bs)
    }
 }
 
+/* This function returns the format corresponding to a single component of the
+ * RGB format for the given size returned by vk_format_for_size().
+ */
+static VkFormat
+vk_single_component_format_for_rgb_size(int bs)
+{
+   switch (bs) {
+   case 3: return VK_FORMAT_R8_UNORM;
+   case 6: return VK_FORMAT_R16_UNORM;
+   case 12: return VK_FORMAT_R32_UINT;
+   default:
+      unreachable("Invalid format block size");
+   }
+}
+
 static void
 create_iview(struct anv_cmd_buffer *cmd_buffer,
              struct anv_meta_blit2d_surf *surf,
@@ -663,6 +678,141 @@ anv_meta_blit2d_w_tiled_dst(struct anv_cmd_buffer *cmd_buffer,
    }
 }
 
+static void
+anv_meta_blit2d_rgb_dst(struct anv_cmd_buffer *cmd_buffer,
+                        struct anv_meta_blit2d_surf *src,
+                        enum blit2d_src_type src_type,
+                        struct anv_meta_blit2d_surf *dst,
+                        unsigned num_rects,
+                        struct anv_meta_blit2d_rect *rects)
+{
+   struct anv_device *device = cmd_buffer->device;
+
+   for (unsigned r = 0; r < num_rects; ++r) {
+      struct blit2d_src_temps src_temps;
+      blit2d_bind_src(cmd_buffer, src, src_type, &rects[r], &src_temps);
+
+      assert(dst->bs % 3 == 0);
+      assert(dst->tiling == ISL_TILING_LINEAR);
+
+      uint32_t offset;
+      isl_tiling_get_intratile_offset_el(&cmd_buffer->device->isl_dev,
+                                         dst->tiling, 1, dst->pitch,
+                                         rects[r].dst_x, rects[r].dst_y,
+                                         &offset,
+                                         &rects[r].dst_x, &rects[r].dst_y);
+
+      /* A red surface three times as wide as the actual RGB destination */
+      struct anv_meta_blit2d_surf dst_R = {
+         .bo = dst->bo,
+         .tiling = dst->tiling,
+         .base_offset = dst->base_offset,
+         .bs = dst->bs / 3,
+         .pitch = dst->pitch,
+      };
+
+      struct blit2d_dst_temps dst_temps;
+      blit2d_bind_dst(cmd_buffer, &dst_R, offset,
+                      (rects[r].dst_x + rects[r].width) * 3,
+                      rects[r].dst_y + rects[r].height,
+                      vk_single_component_format_for_rgb_size(dst->bs),
+                      &dst_temps);
+
+      struct blit_vb_data {
+         float pos[2];
+         float tex_coord[3];
+      } *vb_data;
+
+      unsigned vb_size = sizeof(struct anv_vue_header) + 3 * sizeof(*vb_data);
+
+      struct anv_state vb_state =
+         anv_cmd_buffer_alloc_dynamic_state(cmd_buffer, vb_size, 16);
+      memset(vb_state.map, 0, sizeof(struct anv_vue_header));
+      vb_data = vb_state.map + sizeof(struct anv_vue_header);
+
+      vb_data[0] = (struct blit_vb_data) {
+         .pos = {
+            (rects[r].dst_x + rects[r].width) * 3,
+            rects[r].dst_y + rects[r].height,
+         },
+         .tex_coord = {
+            rects[r].src_x + rects[r].width,
+            rects[r].src_y + rects[r].height,
+            src->pitch,
+         },
+      };
+
+      vb_data[1] = (struct blit_vb_data) {
+         .pos = {
+            rects[r].dst_x * 3,
+            rects[r].dst_y + rects[r].height,
+         },
+         .tex_coord = {
+            rects[r].src_x,
+            rects[r].src_y + rects[r].height,
+            src->pitch,
+         },
+      };
+
+      vb_data[2] = (struct blit_vb_data) {
+         .pos = {
+            rects[r].dst_x * 3,
+            rects[r].dst_y,
+         },
+         .tex_coord = {
+            rects[r].src_x,
+            rects[r].src_y,
+            src->pitch,
+         },
+      };
+
+      if (!device->info.has_llc)
+         anv_state_clflush(vb_state);
+
+      struct anv_buffer vertex_buffer = {
+         .device = device,
+         .size = vb_size,
+         .bo = &device->dynamic_state_block_pool.bo,
+         .offset = vb_state.offset,
+      };
+
+      anv_CmdBindVertexBuffers(anv_cmd_buffer_to_handle(cmd_buffer), 0, 2,
+         (VkBuffer[]) {
+            anv_buffer_to_handle(&vertex_buffer),
+            anv_buffer_to_handle(&vertex_buffer)
+         },
+         (VkDeviceSize[]) {
+            0,
+            sizeof(struct anv_vue_header),
+         });
+
+      ANV_CALL(CmdBeginRenderPass)(anv_cmd_buffer_to_handle(cmd_buffer),
+         &(VkRenderPassBeginInfo) {
+            .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+            .renderPass = device->meta_state.blit2d.render_pass,
+            .framebuffer = dst_temps.fb,
+            .renderArea = {
+               .offset = { rects[r].dst_x, rects[r].dst_y, },
+               .extent = { rects[r].width, rects[r].height },
+            },
+            .clearValueCount = 0,
+            .pClearValues = NULL,
+         }, VK_SUBPASS_CONTENTS_INLINE);
+
+      bind_pipeline(cmd_buffer, src_type, BLIT2D_DST_TYPE_RGB);
+
+      ANV_CALL(CmdDraw)(anv_cmd_buffer_to_handle(cmd_buffer), 3, 1, 0, 0);
+
+      ANV_CALL(CmdEndRenderPass)(anv_cmd_buffer_to_handle(cmd_buffer));
+
+      /* At the point where we emit the draw call, all data from the
+       * descriptor sets, etc. has been used.  We are free to delete it.
+       */
+      blit2d_unbind_src(cmd_buffer, src_type, &src_temps);
+      blit2d_unbind_dst(cmd_buffer, &dst_temps);
+   }
+}
+
 void
 anv_meta_blit2d(struct anv_cmd_buffer *cmd_buffer,
                 struct anv_meta_blit2d_surf *src,
@@ -682,7 +832,8 @@ anv_meta_blit2d(struct anv_cmd_buffer *cmd_buffer,
                                   num_rects, rects);
       return;
    } else if (dst->bs % 3 == 0) {
-      anv_finishme("Blitting to RGB destinations not yet supported");
+      anv_meta_blit2d_rgb_dst(cmd_buffer, src, src_type, dst,
+                              num_rects, rects);
       return;
    } else {
       assert(util_is_power_of_two(dst->bs));
@@ -908,6 +1059,61 @@ build_nir_copy_fragment_shader(struct anv_device *device,
    return b.shader;
 }
 
+/* RGB copies have the same interface as normal copies */
+#define rgb_vi_create_info normal_vi_create_info
+
+static nir_shader *
+build_nir_rgb_fragment_shader(struct anv_device *device,
+                              texel_fetch_build_func txf_func)
+{
+   const struct glsl_type *vec4 = glsl_vec4_type();
+   const struct glsl_type *vec3 = glsl_vector_type(GLSL_TYPE_FLOAT, 3);
+   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");
+
+   nir_variable *tex_pos_in = nir_variable_create(b.shader, nir_var_shader_in,
+                                                  vec3, "v_tex_pos");
+   tex_pos_in->data.location = VARYING_SLOT_VAR0;
+
+   nir_variable *color_out = nir_variable_create(b.shader, nir_var_shader_out,
+                                                 vec4, "f_color");
+   color_out->data.location = FRAG_RESULT_DATA0;
+
+   /* We need gl_FragCoord so we know our 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;
+
+   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);
+
+   /* We figure out which component we are by the x component of FragCoord */
+   nir_ssa_def *frag_coord_int = nir_f2i(&b, nir_load_var(&b, frag_coord_in));
+   nir_ssa_def *comp = nir_umod(&b, nir_channel(&b, frag_coord_int, 0),
+                                    nir_imm_int(&b, 3));
+
+   /* Select the given channel from the texelFetch result */
+   nir_ssa_def *color_channel =
+      nir_bcsel(&b, nir_ieq(&b, comp, nir_imm_int(&b, 0)),
+                    nir_channel(&b, color, 0),
+                    nir_bcsel(&b, nir_ieq(&b, comp, nir_imm_int(&b, 1)),
+                                  nir_channel(&b, color, 1),
+                                  nir_channel(&b, color, 2)));
+
+   nir_ssa_def *u = nir_ssa_undef(&b, 1, 32);
+   nir_store_var(&b, color_out, nir_vec4(&b, color_channel, u, u, u), 0x1);
+
+   return b.shader;
+}
+
 static const VkPipelineVertexInputStateCreateInfo w_tiled_vi_create_info = {
    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
    .vertexBindingDescriptionCount = 2,
@@ -1111,7 +1317,13 @@ blit2d_init_pipeline(struct anv_device *device,
       vi_create_info = &w_tiled_vi_create_info;
       break;
    case BLIT2D_DST_TYPE_RGB:
-      /* Not yet supported */
+      /* RGB destinations and W-detiling don't mix */
+      if (src_type != BLIT2D_SRC_TYPE_NORMAL)
+         return VK_SUCCESS;
+
+      fs.nir = build_nir_rgb_fragment_shader(device, src_func);
+      vi_create_info = &rgb_vi_create_info;
+      break;
    default:
       return VK_SUCCESS;
    }