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 <jason@jlekstrand.net>
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
This commit is contained in:
Jason Ekstrand 2016-08-02 08:47:51 -07:00
parent 16ddda8452
commit cf3cf2ecfc

View 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;
}