From: Jason Ekstrand Date: Tue, 2 Aug 2016 15:47:51 +0000 (-0700) Subject: anv/blit2d: Add support for RGB destinations X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cf3cf2ecfc019051f9ffb72dcbe1baeeb5a7a34a;p=mesa.git anv/blit2d: Add support for RGB destinations This fixes 104 of the new image_clearing and copy_and_blit Vulkan CTS tests. Signed-off-by: Jason Ekstrand Cc: "12.0" --- diff --git a/src/intel/vulkan/anv_meta_blit2d.c b/src/intel/vulkan/anv_meta_blit2d.c index 27ddb8add99..7085f2da8b1 100644 --- a/src/intel/vulkan/anv_meta_blit2d.c +++ b/src/intel/vulkan/anv_meta_blit2d.c @@ -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; }