panvk: implement VK_EXT_host_image_copy for tiled images

Since we don't have a CPU implementation of AFBC compression, host copy
is only implemented for u-interleaved tiling.

Signed-off-by: Olivia Lee <olivia.lee@collabora.com>
Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35910>
This commit is contained in:
Olivia Lee 2025-06-28 18:55:34 -07:00 committed by Marge Bot
parent 0f6a06bbba
commit 476fb5c5cf
3 changed files with 122 additions and 48 deletions

View file

@ -6,6 +6,7 @@
#include "panvk_device.h"
#include "panvk_device_memory.h"
#include "panvk_entrypoints.h"
#include "pan_tiling.h"
#include "panvk_image.h"
#include "vk_object.h"
@ -31,8 +32,10 @@ panvk_copy_image_to_from_memory(struct image_params img,
VkExtent3D extent, VkHostImageCopyFlags flags,
bool memory_to_img)
{
/* We don't support copying tiled images yet */
assert(img.img->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR);
/* AFBC should be disabled on images used for host image copy */
assert(img.img->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR ||
img.img->vk.drm_format_mod == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
bool linear = img.img->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR;
/* We don't have to care about the multisample layout for image/memory
* copies. From the Vulkan 1.4.317 spec:
@ -61,7 +64,8 @@ panvk_copy_image_to_from_memory(struct image_params img,
VkFormat vkfmt =
vk_format_get_aspect_format(img.img->vk.format, img.subres.aspectMask);
const struct util_format_description *fmt = vk_format_description(vkfmt);
enum pipe_format pfmt = vk_format_to_pipe_format(vkfmt);
const struct util_format_description *fmt = util_format_description(pfmt);
unsigned block_width_px = fmt->block.width;
unsigned block_height_px = fmt->block.height;
@ -98,20 +102,37 @@ panvk_copy_image_to_from_memory(struct image_params img,
* layout, image_stride_B applies to both */
void *mem_depth_ptr = mem_layer_ptr + z * mem.layout.image_stride_B;
for (unsigned y = 0; y < extent.height; y += block_height_px) {
unsigned img_y_bl = (y + img.offset.y) / block_height_px;
unsigned mem_y_bl = y / block_height_px;
unsigned img_x_bl = img.offset.x / block_width_px;
void *img_row_ptr = img_depth_ptr +
img_y_bl * slice_layout->tiled_or_linear.row_stride_B +
img_x_bl * block_size_B;
void *mem_row_ptr = mem_depth_ptr +
mem_y_bl * mem.layout.row_stride_B;
if (linear) {
for (unsigned y = 0; y < extent.height; y += block_height_px) {
unsigned img_y_bl = (y + img.offset.y) / block_height_px;
unsigned mem_y_bl = y / block_height_px;
unsigned img_x_bl = img.offset.x / block_width_px;
void *img_row_ptr = img_depth_ptr +
img_y_bl * slice_layout->tiled_or_linear.row_stride_B +
img_x_bl * block_size_B;
void *mem_row_ptr = mem_depth_ptr +
mem_y_bl * mem.layout.row_stride_B;
if (memory_to_img)
memcpy(img_row_ptr, mem_row_ptr, row_size_B);
else
memcpy(mem_row_ptr, img_row_ptr, row_size_B);
}
} else {
if (memory_to_img)
memcpy(img_row_ptr, mem_row_ptr, row_size_B);
pan_store_tiled_image(
img_depth_ptr, mem_depth_ptr,
img.offset.x, img.offset.y, extent.width, extent.height,
slice_layout->tiled_or_linear.row_stride_B,
mem.layout.row_stride_B,
pfmt);
else
memcpy(mem_row_ptr, img_row_ptr, row_size_B);
pan_load_tiled_image(
mem_depth_ptr, img_depth_ptr,
img.offset.x, img.offset.y, extent.width, extent.height,
mem.layout.row_stride_B,
slice_layout->tiled_or_linear.row_stride_B,
pfmt);
}
}
}
@ -212,9 +233,13 @@ panvk_copy_image_to_image(struct panvk_image *dst, void *dst_cpu,
const VkImageCopy2 *region,
VkHostImageCopyFlags flags)
{
/* We don't support copying tiled images yet */
assert(src->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR);
assert(dst->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR);
/* AFBC should be disabled on images used for host image copy */
assert(src->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR ||
src->vk.drm_format_mod == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
assert(dst->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR ||
dst->vk.drm_format_mod == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
bool src_linear = src->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR;
bool dst_linear = dst->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR;
VkImageSubresourceLayers src_subres = region->srcSubresource;
VkImageSubresourceLayers dst_subres = region->dstSubresource;
@ -241,10 +266,12 @@ panvk_copy_image_to_image(struct panvk_image *dst, void *dst_cpu,
vk_format_get_aspect_format(src->vk.format, src_subres.aspectMask);
VkFormat dst_vkfmt =
vk_format_get_aspect_format(dst->vk.format, dst_subres.aspectMask);
enum pipe_format src_pfmt = vk_format_to_pipe_format(src_vkfmt);
enum pipe_format dst_pfmt = vk_format_to_pipe_format(dst_vkfmt);
const struct util_format_description *src_fmt =
vk_format_description(src_vkfmt);
util_format_description(src_pfmt);
const struct util_format_description *dst_fmt =
vk_format_description(dst_vkfmt);
util_format_description(dst_pfmt);
unsigned block_width_px = src_fmt->block.width;
unsigned block_height_px = src_fmt->block.height;
@ -300,19 +327,55 @@ panvk_copy_image_to_image(struct panvk_image *dst, void *dst_cpu,
void *dst_depth_ptr = dst_layer_ptr +
dst_z * dst_slice_layout->tiled_or_linear.surface_stride_B;
for (unsigned y = 0; y < region->extent.height; y += block_height_px) {
unsigned src_y_bl = (y + region->srcOffset.y) / block_height_px;
unsigned dst_y_bl = (y + region->dstOffset.y) / block_height_px;
if (src_linear && dst_linear) {
for (unsigned y = 0; y < region->extent.height;
y += block_height_px) {
unsigned src_y_bl = (y + region->srcOffset.y) / block_height_px;
unsigned dst_y_bl = (y + region->dstOffset.y) / block_height_px;
unsigned src_x_bl = region->srcOffset.x / block_width_px;
unsigned dst_x_bl = region->dstOffset.x / block_width_px;
void *src_row_ptr = src_depth_ptr +
src_y_bl * src_slice_layout->tiled_or_linear.row_stride_B +
src_x_bl * block_size_B;
void *dst_row_ptr = dst_depth_ptr +
dst_y_bl * dst_slice_layout->tiled_or_linear.row_stride_B +
dst_x_bl * block_size_B;
memcpy(dst_row_ptr, src_row_ptr, row_size_B);
}
} else if (src_linear && !dst_linear) {
unsigned src_y_bl = region->srcOffset.y / block_height_px;
unsigned src_x_bl = region->srcOffset.x / block_width_px;
unsigned dst_x_bl = region->dstOffset.x / block_width_px;
void *src_row_ptr = src_depth_ptr +
src_y_bl * src_slice_layout->tiled_or_linear.row_stride_B +
src_x_bl * block_size_B;
pan_store_tiled_image(
dst_depth_ptr, src_row_ptr,
region->dstOffset.x, region->dstOffset.y,
region->extent.width, region->extent.height,
dst_slice_layout->tiled_or_linear.row_stride_B,
src_slice_layout->tiled_or_linear.row_stride_B,
src_pfmt);
} else if (!src_linear && dst_linear) {
unsigned dst_y_bl = region->dstOffset.y / block_height_px;
unsigned dst_x_bl = region->dstOffset.x / block_width_px;
void *dst_row_ptr = dst_depth_ptr +
dst_y_bl * dst_slice_layout->tiled_or_linear.row_stride_B +
dst_x_bl * block_size_B;
memcpy(dst_row_ptr, src_row_ptr, row_size_B);
pan_load_tiled_image(
dst_row_ptr, src_depth_ptr,
region->srcOffset.x, region->srcOffset.y,
region->extent.width, region->extent.height,
dst_slice_layout->tiled_or_linear.row_stride_B,
src_slice_layout->tiled_or_linear.row_stride_B,
dst_pfmt);
} else {
pan_copy_tiled_image(
dst_depth_ptr, src_depth_ptr, region->dstOffset.x,
region->dstOffset.y, region->srcOffset.x, region->srcOffset.y,
region->extent.width, region->extent.height,
dst_slice_layout->tiled_or_linear.row_stride_B,
src_slice_layout->tiled_or_linear.row_stride_B, src_pfmt);
}
}
}

View file

@ -59,6 +59,7 @@ panvk_image_can_use_afbc(
/* Disallow AFBC if either of these is true
* - PANVK_DEBUG does not have the 'afbc' flag set
* - storage image views are requested
* - host image copies are requested
* - the GPU doesn't support AFBC
* - the format is not AFBC-able
* - tiling is set to linear
@ -68,7 +69,8 @@ panvk_image_can_use_afbc(
*/
return
(instance->debug_flags & PANVK_DEBUG_AFBC) &&
!(usage & (VK_IMAGE_USAGE_STORAGE_BIT)) &&
!(usage & (VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_HOST_TRANSFER_BIT)) &&
pan_query_afbc(&phys_dev->kmod.props) &&
pan_afbc_supports_format(arch, pfmt) &&
tiling == VK_IMAGE_TILING_OPTIMAL &&

View file

@ -27,6 +27,7 @@
#include "panvk_physical_device.h"
#include "panvk_wsi.h"
#include "pan_afbc.h"
#include "pan_props.h"
#include "genxml/gen_macros.h"
@ -530,7 +531,7 @@ format_is_supported(struct panvk_physical_device *physical_device,
static VkFormatFeatureFlags2
get_image_plane_format_features(struct panvk_physical_device *physical_device,
VkFormat format, VkImageTiling tiling)
VkFormat format)
{
VkFormatFeatureFlags2 features = 0;
enum pipe_format pfmt = vk_format_to_pipe_format(format);
@ -583,8 +584,7 @@ get_image_plane_format_features(struct panvk_physical_device *physical_device,
if (fmt.bind & PAN_BIND_DEPTH_STENCIL)
features |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
if (features != 0 && vk_format_is_color(format) &&
tiling == VK_IMAGE_TILING_LINEAR)
if (features != 0 && vk_format_is_color(format))
features |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT;
return features;
@ -592,7 +592,7 @@ get_image_plane_format_features(struct panvk_physical_device *physical_device,
static VkFormatFeatureFlags2
get_image_format_features(struct panvk_physical_device *physical_device,
VkFormat format, VkImageTiling tiling)
VkFormat format)
{
const struct vk_format_ycbcr_info *ycbcr_info =
vk_format_get_ycbcr_info(format);
@ -603,7 +603,7 @@ get_image_format_features(struct panvk_physical_device *physical_device,
return 0;
if (ycbcr_info == NULL)
return get_image_plane_format_features(physical_device, format, tiling);
return get_image_plane_format_features(physical_device, format);
if (unsupported_yuv_format(vk_format_to_pipe_format(format)))
return 0;
@ -617,8 +617,7 @@ get_image_format_features(struct panvk_physical_device *physical_device,
const struct vk_format_ycbcr_plane *plane_info =
&ycbcr_info->planes[plane];
features &=
get_image_plane_format_features(physical_device, plane_info->format,
tiling);
get_image_plane_format_features(physical_device, plane_info->format);
if (plane_info->denominator_scales[0] > 1 ||
plane_info->denominator_scales[1] > 1)
cosited_chroma = true;
@ -739,26 +738,22 @@ panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
{
VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
VkFormatFeatureFlags2 tex_linear =
get_image_format_features(physical_device, format,
VK_IMAGE_TILING_LINEAR);
VkFormatFeatureFlags2 tex_optimal =
get_image_format_features(physical_device, format,
VK_IMAGE_TILING_OPTIMAL);
VkFormatFeatureFlags2 tex =
get_image_format_features(physical_device, format);
VkFormatFeatureFlags2 buffer =
get_buffer_format_features(physical_device, format);
pFormatProperties->formatProperties = (VkFormatProperties){
.linearTilingFeatures = tex_linear,
.optimalTilingFeatures = tex_optimal,
.linearTilingFeatures = tex,
.optimalTilingFeatures = tex,
.bufferFeatures = buffer,
};
VkFormatProperties3 *formatProperties3 =
vk_find_struct(pFormatProperties->pNext, FORMAT_PROPERTIES_3);
if (formatProperties3) {
formatProperties3->linearTilingFeatures = tex_linear;
formatProperties3->optimalTilingFeatures = tex_optimal;
formatProperties3->linearTilingFeatures = tex;
formatProperties3->optimalTilingFeatures = tex;
formatProperties3->bufferFeatures = buffer;
}
@ -886,15 +881,14 @@ get_image_format_properties(struct panvk_physical_device *physical_device,
*/
if (ycbcr_info == NULL) {
format_feature_flags =
get_image_format_features(physical_device, info->format, info->tiling);
get_image_format_features(physical_device, info->format);
} else {
format_feature_flags = ~0u;
assert(ycbcr_info->n_planes > 0);
for (uint8_t plane = 0; plane < ycbcr_info->n_planes; plane++) {
const VkFormat plane_format = ycbcr_info->planes[plane].format;
format_feature_flags &=
get_image_format_features(physical_device, plane_format,
info->tiling);
get_image_format_features(physical_device, plane_format);
}
}
@ -1080,6 +1074,7 @@ panvk_GetPhysicalDeviceImageFormatProperties2(
VkImageFormatProperties2 *base_props)
{
VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
const VkImageStencilUsageCreateInfo *stencil_usage_info = NULL;
const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL;
VkExternalImageFormatProperties *external_props = NULL;
@ -1098,6 +1093,9 @@ panvk_GetPhysicalDeviceImageFormatProperties2(
/* Extract input structs */
vk_foreach_struct_const(s, base_info->pNext) {
switch (s->sType) {
case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO:
stencil_usage_info = (const void*)s;
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO:
external_info = (const void *)s;
break;
@ -1172,8 +1170,19 @@ panvk_GetPhysicalDeviceImageFormatProperties2(
}
if (hic_props) {
hic_props->optimalDeviceAccess = true;
hic_props->identicalMemoryLayout = true;
VkImageUsageFlags stencil_usage = stencil_usage_info ?
stencil_usage_info->stencilUsage : base_info->usage;
/* We don't support AFBC for images used for host transfer. So, if an
* image could have been tiled as AFBC if it weren't for host transfer,
* report suboptimal access. */
VkImageUsageFlags usage = base_info->usage | stencil_usage;
usage &= ~VK_IMAGE_USAGE_HOST_TRANSFER_BIT;
bool can_use_afbc = panvk_image_can_use_afbc(
physical_device, base_info->format, usage, base_info->type,
base_info->tiling, base_info->flags);
hic_props->optimalDeviceAccess = !can_use_afbc;
hic_props->identicalMemoryLayout = !can_use_afbc;
}
const struct vk_format_ycbcr_info *ycbcr_info =