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);
*p = cmask;
p++;
+ *p = src_samples;
+ p++;
+
assert(((uint8_t*)p - key) == V3DV_META_BLIT_CACHE_KEY_SIZE);
}
}
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 =
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()
{
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");
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;
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
}
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");
VkFormat src_format,
VkColorComponentFlags cmask,
VkImageType src_type,
+ VkSampleCountFlagBits src_samples,
VkRenderPass _pass,
VkPipelineLayout pipeline_layout,
VkPipeline *pipeline)
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,
VkFormat src_format,
VkColorComponentFlags cmask,
VkImageType src_type,
+ VkSampleCountFlagBits src_samples,
struct v3dv_meta_blit_pipeline **pipeline)
{
bool ok = true;
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);
src_format,
cmask,
src_type,
+ src_samples,
(*pipeline)->pass,
device->meta.blit.playout,
&(*pipeline)->pipeline);
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] = {
/* 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);
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,
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");
}
}