v3dv: add a blit fallback path for vkCmdResolveImage

This fallback is required when we have to do partial resolves. It
works the same way as other blit fallbacks for copy operations: it
will bind the source image as a source texture and blit the selected
region to the destination image.

The difference in this case is that the source image is multisampled
and the blit shader needs to fetch and average individual samples for
each texel.

This gets us to pass all the remaining test cases in
dEQP-VK.api.copy_and_blit.core.resolve_image.*

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
Iago Toral Quiroga 2020-07-29 09:49:47 +02:00 committed by Marge Bot
parent 6c27dbdbc9
commit f219795a26
2 changed files with 156 additions and 21 deletions

View File

@ -2846,6 +2846,7 @@ static void
get_blit_pipeline_cache_key(VkFormat dst_format,
VkFormat src_format,
VkColorComponentFlags cmask,
VkSampleCountFlagBits src_samples,
uint8_t *key)
{
memset(key, 0, V3DV_META_BLIT_CACHE_KEY_SIZE);
@ -2871,6 +2872,9 @@ get_blit_pipeline_cache_key(VkFormat dst_format,
*p = cmask;
p++;
*p = src_samples;
p++;
assert(((uint8_t*)p - key) == V3DV_META_BLIT_CACHE_KEY_SIZE);
}
@ -3067,12 +3071,14 @@ gen_tex_coords(nir_builder *b)
}
static nir_ssa_def *
build_nir_tex_op(struct nir_builder *b,
struct v3dv_device *device,
nir_ssa_def *tex_pos,
enum glsl_base_type tex_type,
enum glsl_sampler_dim dim)
build_nir_tex_op_default(struct nir_builder *b,
struct v3dv_device *device,
nir_ssa_def *tex_pos,
enum glsl_base_type tex_type,
enum glsl_sampler_dim dim)
{
assert(dim != GLSL_SAMPLER_DIM_MS);
const struct glsl_type *sampler_type =
glsl_sampler_type(dim, false, false, tex_type);
nir_variable *sampler =
@ -3100,6 +3106,79 @@ build_nir_tex_op(struct nir_builder *b,
return &tex->dest.ssa;
}
/* Fetches all samples at the given position and averages them */
static nir_ssa_def *
build_nir_tex_op_ms(struct nir_builder *b,
struct v3dv_device *device,
nir_ssa_def *tex_pos,
enum glsl_base_type tex_type,
VkSampleCountFlagBits src_samples)
{
assert(src_samples > VK_SAMPLE_COUNT_1_BIT);
const enum glsl_sampler_dim dim = GLSL_SAMPLER_DIM_MS;
const struct glsl_type *sampler_type =
glsl_sampler_type(dim, false, false, tex_type);
nir_variable *sampler =
nir_variable_create(b->shader, nir_var_uniform, sampler_type, "s_tex");
sampler->data.descriptor_set = 0;
sampler->data.binding = 0;
/* For multisampled texture sources we need to use fetching instead of
* normalized texture coordinates. We already configured our blit coordinates
* to be in texel units, but here we still need to convert them from
* floating point to integer.
*/
nir_ssa_def *itex_pos = nir_f2i32(b, tex_pos);
nir_ssa_def *tmp;
nir_ssa_def *tex_deref = &nir_build_deref_var(b, sampler)->dest.ssa;
for (uint32_t i = 0; i < src_samples; i++) {
nir_tex_instr *tex = nir_tex_instr_create(b->shader, 4);
tex->sampler_dim = dim;
tex->op = nir_texop_txf_ms;
tex->src[0].src_type = nir_tex_src_coord;
tex->src[0].src = nir_src_for_ssa(itex_pos);
tex->src[1].src_type = nir_tex_src_texture_deref;
tex->src[1].src = nir_src_for_ssa(tex_deref);
tex->src[2].src_type = nir_tex_src_sampler_deref;
tex->src[2].src = nir_src_for_ssa(tex_deref);
tex->src[3].src_type = nir_tex_src_ms_index;
tex->src[3].src = nir_src_for_ssa(nir_imm_int(b, i));
tex->dest_type =
nir_alu_type_get_base_type(nir_get_nir_type_for_glsl_base_type(tex_type));
tex->is_array = false;
tex->coord_components = tex_pos->num_components;
nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
nir_builder_instr_insert(b, &tex->instr);
if (i == 0)
tmp = &tex->dest.ssa;
else
tmp = nir_fadd(b, tmp, &tex->dest.ssa);
}
return nir_fmul(b, tmp, nir_imm_float(b, 1.0f / src_samples));
}
static nir_ssa_def *
build_nir_tex_op(struct nir_builder *b,
struct v3dv_device *device,
nir_ssa_def *tex_pos,
enum glsl_base_type tex_type,
VkSampleCountFlagBits src_samples,
enum glsl_sampler_dim dim)
{
switch (dim) {
case GLSL_SAMPLER_DIM_MS:
assert(src_samples == VK_SAMPLE_COUNT_4_BIT);
return build_nir_tex_op_ms(b, device, tex_pos, tex_type, src_samples);
default:
assert(src_samples == VK_SAMPLE_COUNT_1_BIT);
return build_nir_tex_op_default(b, device, tex_pos, tex_type, dim);
}
}
static nir_shader *
get_blit_vs()
{
@ -3134,6 +3213,7 @@ get_channel_mask_for_sampler_dim(enum glsl_sampler_dim sampler_dim)
switch (sampler_dim) {
case GLSL_SAMPLER_DIM_1D: return 0x1;
case GLSL_SAMPLER_DIM_2D: return 0x3;
case GLSL_SAMPLER_DIM_MS: return 0x3;
case GLSL_SAMPLER_DIM_3D: return 0x7;
default:
unreachable("invalid sampler dim");
@ -3144,6 +3224,7 @@ static nir_shader *
get_color_blit_fs(struct v3dv_device *device,
VkFormat dst_format,
VkFormat src_format,
VkSampleCountFlagBits src_samples,
enum glsl_sampler_dim sampler_dim)
{
nir_builder b;
@ -3171,7 +3252,7 @@ get_color_blit_fs(struct v3dv_device *device,
nir_ssa_def *color = build_nir_tex_op(&b, device, tex_coord,
glsl_get_base_type(fs_out_type),
sampler_dim);
src_samples, sampler_dim);
/* For integer textures, if the bit-size of the destination is too small to
* hold source value, Vulkan (CTS) expects the implementation to clamp to the
@ -3333,11 +3414,20 @@ create_pipeline(struct v3dv_device *device,
}
static enum glsl_sampler_dim
get_sampler_dim_for_image_type(VkImageType type)
get_sampler_dim(VkImageType type, VkSampleCountFlagBits src_samples)
{
/* From the Vulkan 1.0 spec, VkImageCreateInfo Validu Usage:
*
* "If samples is not VK_SAMPLE_COUNT_1_BIT, then imageType must be
* VK_IMAGE_TYPE_2D, ..."
*/
assert(src_samples == VK_SAMPLE_COUNT_1_BIT || type == VK_IMAGE_TYPE_2D);
switch (type) {
case VK_IMAGE_TYPE_1D: return GLSL_SAMPLER_DIM_1D;
case VK_IMAGE_TYPE_2D: return GLSL_SAMPLER_DIM_2D;
case VK_IMAGE_TYPE_2D:
return src_samples == VK_SAMPLE_COUNT_1_BIT ? GLSL_SAMPLER_DIM_2D :
GLSL_SAMPLER_DIM_MS;
case VK_IMAGE_TYPE_3D: return GLSL_SAMPLER_DIM_3D;
default:
unreachable("Invalid image type");
@ -3350,6 +3440,7 @@ create_blit_pipeline(struct v3dv_device *device,
VkFormat src_format,
VkColorComponentFlags cmask,
VkImageType src_type,
VkSampleCountFlagBits src_samples,
VkRenderPass _pass,
VkPipelineLayout pipeline_layout,
VkPipeline *pipeline)
@ -3361,11 +3452,11 @@ create_blit_pipeline(struct v3dv_device *device,
assert(vk_format_is_color(src_format));
const enum glsl_sampler_dim sampler_dim =
get_sampler_dim_for_image_type(src_type);
get_sampler_dim(src_type, src_samples);
nir_shader *vs_nir = get_blit_vs();
nir_shader *fs_nir =
get_color_blit_fs(device, dst_format, src_format, sampler_dim);
get_color_blit_fs(device, dst_format, src_format, src_samples, sampler_dim);
const VkPipelineVertexInputStateCreateInfo vi_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
@ -3410,6 +3501,7 @@ get_blit_pipeline(struct v3dv_device *device,
VkFormat src_format,
VkColorComponentFlags cmask,
VkImageType src_type,
VkSampleCountFlagBits src_samples,
struct v3dv_meta_blit_pipeline **pipeline)
{
bool ok = true;
@ -3425,7 +3517,7 @@ get_blit_pipeline(struct v3dv_device *device,
return false;
uint8_t key[V3DV_META_BLIT_CACHE_KEY_SIZE];
get_blit_pipeline_cache_key(dst_format, src_format, cmask, key);
get_blit_pipeline_cache_key(dst_format, src_format, cmask, src_samples, key);
mtx_lock(&device->meta.mtx);
struct hash_entry *entry =
_mesa_hash_table_search(device->meta.blit.cache[src_type], &key);
@ -3451,6 +3543,7 @@ get_blit_pipeline(struct v3dv_device *device,
src_format,
cmask,
src_type,
src_samples,
(*pipeline)->pass,
device->meta.blit.playout,
&(*pipeline)->pipeline);
@ -3675,16 +3768,25 @@ blit_shader(struct v3dv_cmd_buffer *cmd_buffer,
uint32_t layer_count = max_dst_layer - min_dst_layer;
/* Translate source blit coordinates to normalized texture coordinates
* and handle mirroring.
/* Translate source blit coordinates to normalized texture coordinates for
* single sampled textures. For multisampled textures we require
* unnormalized coordinates, since we can only do texelFetch on them.
*/
const float coords[4] = {
(float)src_x / (float)src_level_w,
(float)src_y / (float)src_level_h,
(float)(src_x + src_w) / (float)src_level_w,
(float)(src_y + src_h) / (float)src_level_h,
float coords[4] = {
(float)src_x,
(float)src_y,
(float)(src_x + src_w),
(float)(src_y + src_h),
};
if (src->samples == VK_SAMPLE_COUNT_1_BIT) {
coords[0] /= (float)src_level_w;
coords[1] /= (float)src_level_h;
coords[2] /= (float)src_level_w;
coords[3] /= (float)src_level_h;
}
/* Handle mirroring */
const bool mirror_x = dst_mirror_x != src_mirror_x;
const bool mirror_y = dst_mirror_y != src_mirror_y;
float tex_coords[5] = {
@ -3712,8 +3814,8 @@ blit_shader(struct v3dv_cmd_buffer *cmd_buffer,
/* Get the blit pipeline */
struct v3dv_meta_blit_pipeline *pipeline = NULL;
bool ok = get_blit_pipeline(cmd_buffer->device,
dst_format, src_format,
cmask, src->type, &pipeline);
dst_format, src_format, cmask,
src->type, src->samples, &pipeline);
if (!ok)
return handled;
assert(pipeline && pipeline->pipeline && pipeline->pass);
@ -4074,6 +4176,37 @@ resolve_image_tlb(struct v3dv_cmd_buffer *cmd_buffer,
return true;
}
static bool
resolve_image_blit(struct v3dv_cmd_buffer *cmd_buffer,
struct v3dv_image *dst,
struct v3dv_image *src,
const VkImageResolve *region)
{
const VkImageBlit blit_region = {
.srcSubresource = region->srcSubresource,
.srcOffsets = {
region->srcOffset,
{
region->srcOffset.x + region->extent.width,
region->srcOffset.y + region->extent.height,
}
},
.dstSubresource = region->dstSubresource,
.dstOffsets = {
region->dstOffset,
{
region->dstOffset.x + region->extent.width,
region->dstOffset.y + region->extent.height,
}
},
};
return blit_shader(cmd_buffer,
dst, dst->vk_format,
src, src->vk_format,
0, NULL,
&blit_region, VK_FILTER_NEAREST);
}
void
v3dv_CmdResolveImage(VkCommandBuffer commandBuffer,
VkImage srcImage,
@ -4097,6 +4230,8 @@ v3dv_CmdResolveImage(VkCommandBuffer commandBuffer,
for (uint32_t i = 0; i < regionCount; i++) {
if (resolve_image_tlb(cmd_buffer, dst, src, &pRegions[i]))
continue;
if (resolve_image_blit(cmd_buffer, dst, src, &pRegions[i]))
continue;
unreachable("Unsupported multismaple resolve operation");
}
}

View File

@ -262,7 +262,7 @@ struct v3dv_meta_blit_pipeline {
VkRenderPass pass;
};
#define V3DV_META_BLIT_CACHE_KEY_SIZE (3 * sizeof(uint32_t))
#define V3DV_META_BLIT_CACHE_KEY_SIZE (4 * sizeof(uint32_t))
struct v3dv_pipeline_cache_stats {
uint32_t miss;