From 1cd61ee94875efbf546455212e67ccc6bac111c6 Mon Sep 17 00:00:00 2001 From: Olivia Lee Date: Fri, 27 Jun 2025 23:24:04 -0700 Subject: [PATCH] panvk: implement VK_EXT_host_image_copy for linear color images Depth/stencil and tiled images require some additional complexity, so will be implemented in later commits. Signed-off-by: Olivia Lee Reviewed-by: Erik Faye-Lund Part-of: --- docs/features.txt | 2 +- docs/relnotes/new_features.txt | 1 + src/panfrost/vulkan/meson.build | 1 + src/panfrost/vulkan/panvk_host_copy.c | 366 ++++++++++++++++++ src/panfrost/vulkan/panvk_image.c | 5 + src/panfrost/vulkan/panvk_physical_device.c | 43 +- .../vulkan/panvk_vX_physical_device.c | 47 +++ 7 files changed, 452 insertions(+), 13 deletions(-) create mode 100644 src/panfrost/vulkan/panvk_host_copy.c diff --git a/docs/features.txt b/docs/features.txt index 85ab589dff1..364f017429b 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -525,7 +525,7 @@ Vulkan 1.4 -- all DONE: anv, hk, lvp, nvk, radv/gfx8+, tu/a7xx+, vn VK_KHR_shader_float_controls2 DONE (anv, lvp, nvk, panvk/v10+, radv, tu, vn) VK_KHR_shader_subgroup_rotate DONE (anv, lvp, nvk, panvk, radv, tu, vn) VK_KHR_vertex_attribute_divisor DONE (anv, lvp, nvk, panvk, radv, tu, v3dv, vn) - VK_EXT_host_image_copy DONE (anv, lvp, nvk/Turing+, radv/gfx10+, tu, vn) + VK_EXT_host_image_copy DONE (anv, lvp, nvk/Turing+, panvk, radv/gfx10+, tu, vn) VK_EXT_pipeline_protected_access DONE (anv/gfx12+, vn) VK_EXT_pipeline_robustness DONE (anv, lvp, nvk, panvk, radv, v3dv, tu, vn) diff --git a/docs/relnotes/new_features.txt b/docs/relnotes/new_features.txt index da87b10bcdf..574bcd8bb16 100644 --- a/docs/relnotes/new_features.txt +++ b/docs/relnotes/new_features.txt @@ -72,3 +72,4 @@ deprecated EGL_WL_bind_wayland_display VK_KHR_shader_atomic_int64 on panvk/v10+ VK_EXT_host_image_copy on RADV (RDNA1+) VK_KHR_cooperative_matrix on nvk/turing+ +VK_KHR_host_image_copy on panvk diff --git a/src/panfrost/vulkan/meson.build b/src/panfrost/vulkan/meson.build index 97ea65fdcf4..c25fd45bdcc 100644 --- a/src/panfrost/vulkan/meson.build +++ b/src/panfrost/vulkan/meson.build @@ -39,6 +39,7 @@ libpanvk_files = files( 'panvk_buffer.c', 'panvk_cmd_pool.c', 'panvk_device_memory.c', + 'panvk_host_copy.c', 'panvk_image.c', 'panvk_instance.c', 'panvk_mempool.c', diff --git a/src/panfrost/vulkan/panvk_host_copy.c b/src/panfrost/vulkan/panvk_host_copy.c new file mode 100644 index 00000000000..5df6d068b64 --- /dev/null +++ b/src/panfrost/vulkan/panvk_host_copy.c @@ -0,0 +1,366 @@ +/* + * Copyright © 2025 Collabora Ltd. + * SPDX-License-Identifier: MIT + */ + +#include "panvk_device.h" +#include "panvk_device_memory.h" +#include "panvk_entrypoints.h" +#include "panvk_image.h" + +#include "vk_object.h" +#include "vk_util.h" + +struct image_params { + struct panvk_image *img; + void *ptr; + VkOffset3D offset; + VkImageSubresourceLayers subres; +}; + +struct memory_params { + void *ptr; + struct vk_image_buffer_layout layout; +}; + +/* Copy either memory->image or image->memory. The direction is controlled by + * the memory_to_img argument. */ +static void +panvk_copy_image_to_from_memory(struct image_params img, + struct memory_params mem, + 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); + + /* We don't have to care about the multisample layout for image/memory + * copies. From the Vulkan 1.4.317 spec: + * + * VUID-VkCopyImageToMemoryInfo-srcImage-07973 srcImage must have a sample + * count equal to VK_SAMPLE_COUNT_1_BIT + * + * VUID-VkCopyMemoryToImageInfo-dstImage-07973 dstImage must have a sample + * count equal to VK_SAMPLE_COUNT_1_BIT + */ + assert(img.img->vk.samples == VK_SAMPLE_COUNT_1_BIT); + + /* From the Vulkan 1.4.317 spec: + * + * VUID-VkImageToMemoryCopy-aspectMask-09103 The aspectMask member of + * imageSubresource must only have a single bit set + */ + assert(util_bitcount(img.subres.aspectMask) == 1); + unsigned plane_idx = + panvk_plane_index(img.img->vk.format, img.subres.aspectMask); + assert(plane_idx < PANVK_MAX_PLANES); + struct panvk_image_plane *plane = &img.img->planes[plane_idx]; + const struct pan_image_layout *plane_layout = &plane->plane.layout; + const struct pan_image_slice_layout *slice_layout = + &plane_layout->slices[img.subres.mipLevel]; + + VkFormat vkfmt = + vk_format_get_aspect_format(img.img->vk.format, img.subres.aspectMask); + const struct util_format_description *fmt = vk_format_description(vkfmt); + + unsigned block_width_px = fmt->block.width; + unsigned block_height_px = fmt->block.height; + assert(fmt->block.bits % 8 == 0); + unsigned block_size_B = fmt->block.bits / 8; + assert(mem.layout.element_size_B == block_size_B); + + unsigned row_size_bl = DIV_ROUND_UP(extent.width, block_width_px); + unsigned row_size_B = row_size_bl * block_size_B; + + unsigned layer_count = + vk_image_subresource_layer_count(&img.img->vk, &img.subres); + + void *img_base_ptr = img.ptr + plane->offset + slice_layout->offset_B; + for (unsigned layer = 0; layer < layer_count; layer++) { + unsigned img_layer = layer + img.subres.baseArrayLayer; + void *img_layer_ptr = img_base_ptr + + img_layer * plane_layout->array_stride_B; + void *mem_layer_ptr = mem.ptr + layer * mem.layout.image_stride_B; + + if (flags & VK_HOST_IMAGE_COPY_MEMCPY_BIT) { + if (memory_to_img) + memcpy(img_layer_ptr, mem_layer_ptr, slice_layout->size_B); + else + memcpy(mem_layer_ptr, img_layer_ptr, slice_layout->size_B); + continue; + } + + for (unsigned z = 0; z < extent.depth; z++) { + unsigned img_z = z + img.offset.z; + void *img_depth_ptr = img_layer_ptr + + img_z * slice_layout->tiled_or_linear.surface_stride_B; + /* There is no distinction between array and 3D images in the memory + * 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 (memory_to_img) + memcpy(img_row_ptr, mem_row_ptr, row_size_B); + else + memcpy(mem_row_ptr, img_row_ptr, row_size_B); + } + } + } +} + +static void +panvk_copy_memory_to_image(struct panvk_image *dst, void *dst_cpu, + const VkMemoryToImageCopy *region, + VkHostImageCopyFlags flags) +{ + struct memory_params src_params = { + /* Casting away const, but we don't write to it so it's fine */ + .ptr = (void *) region->pHostPointer, + .layout = vk_memory_to_image_copy_layout(&dst->vk, region), + }; + struct image_params dst_params = { + .img = dst, + .ptr = dst_cpu, + .offset = region->imageOffset, + .subres = region->imageSubresource, + }; + + panvk_copy_image_to_from_memory( + dst_params, src_params, region->imageExtent, flags, true); +} + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_CopyMemoryToImage(VkDevice device, const VkCopyMemoryToImageInfo *info) +{ + VK_FROM_HANDLE(panvk_device, dev, device); + VK_FROM_HANDLE(panvk_image, dst, info->dstImage); + + void *dst_cpu = pan_kmod_bo_mmap( + dst->mem->bo, 0, pan_kmod_bo_size(dst->mem->bo), PROT_WRITE, MAP_SHARED, + NULL); + if (dst_cpu == MAP_FAILED) + return panvk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED, + "Failed to CPU map image"); + + for (unsigned i = 0; i < info->regionCount; i++) { + panvk_copy_memory_to_image(dst, dst_cpu, &info->pRegions[i], + info->flags); + } + + ASSERTED int ret = os_munmap(dst_cpu, pan_kmod_bo_size(dst->mem->bo)); + assert(!ret); + + return VK_SUCCESS; +} + +static void +panvk_copy_image_to_memory(struct panvk_image *src, void *src_cpu, + const VkImageToMemoryCopy *region, + VkHostImageCopyFlags flags) +{ + struct memory_params dst_params = { + .ptr = region->pHostPointer, + .layout = vk_image_to_memory_copy_layout(&src->vk, region), + }; + struct image_params src_params = { + .img = src, + .ptr = src_cpu, + .offset = region->imageOffset, + .subres = region->imageSubresource, + }; + + panvk_copy_image_to_from_memory( + src_params, dst_params, region->imageExtent, flags, false); +} + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_CopyImageToMemory(VkDevice device, const VkCopyImageToMemoryInfo *info) +{ + VK_FROM_HANDLE(panvk_device, dev, device); + VK_FROM_HANDLE(panvk_image, src, info->srcImage); + + void *src_cpu = pan_kmod_bo_mmap( + src->mem->bo, 0, pan_kmod_bo_size(src->mem->bo), PROT_READ, MAP_SHARED, + NULL); + if (src_cpu == MAP_FAILED) + return panvk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED, + "Failed to CPU map image"); + + for (unsigned i = 0; i < info->regionCount; i++) { + panvk_copy_image_to_memory(src, src_cpu, &info->pRegions[i], + info->flags); + } + + ASSERTED int ret = os_munmap(src_cpu, pan_kmod_bo_size(src->mem->bo)); + assert(!ret); + + return VK_SUCCESS; +} + +static void +panvk_copy_image_to_image(struct panvk_image *dst, void *dst_cpu, + struct panvk_image *src, void *src_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); + + VkImageSubresourceLayers src_subres = region->srcSubresource; + VkImageSubresourceLayers dst_subres = region->dstSubresource; + + /* Multiple aspect bits are only allowed with ZS, which we don't support */ + assert(util_bitcount(src_subres.aspectMask == 1)); + assert(util_bitcount(dst_subres.aspectMask == 1)); + unsigned src_plane_idx = + panvk_plane_index(src->vk.format, src_subres.aspectMask); + unsigned dst_plane_idx = + panvk_plane_index(dst->vk.format, dst_subres.aspectMask); + assert(src_plane_idx < PANVK_MAX_PLANES); + assert(dst_plane_idx < PANVK_MAX_PLANES); + struct panvk_image_plane *src_plane = &src->planes[src_plane_idx]; + struct panvk_image_plane *dst_plane = &dst->planes[dst_plane_idx]; + const struct pan_image_layout *src_plane_layout = &dst_plane->plane.layout; + const struct pan_image_layout *dst_plane_layout = &src_plane->plane.layout; + const struct pan_image_slice_layout *src_slice_layout = + &src_plane_layout->slices[src_subres.mipLevel]; + const struct pan_image_slice_layout *dst_slice_layout = + &dst_plane_layout->slices[dst_subres.mipLevel]; + + VkFormat src_vkfmt = + 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); + const struct util_format_description *src_fmt = + vk_format_description(src_vkfmt); + const struct util_format_description *dst_fmt = + vk_format_description(dst_vkfmt); + + unsigned block_width_px = src_fmt->block.width; + unsigned block_height_px = src_fmt->block.height; + assert(src_fmt->block.bits % 8 == 0); + unsigned block_size_B = src_fmt->block.bits / 8; + + /* This doesn't actually seem to be a requirement in the spec, but that's + * probably unintentional */ + assert(dst_fmt->block.width == block_width_px); + assert(dst_fmt->block.height == block_height_px); + assert(dst_fmt->block.bits == src_fmt->block.bits); + + unsigned row_size_bl = DIV_ROUND_UP(region->extent.width, block_width_px); + unsigned row_size_B = row_size_bl * block_size_B; + + unsigned src_layer_count = + vk_image_subresource_layer_count(&src->vk, &src_subres); + unsigned dst_layer_count = + vk_image_subresource_layer_count(&dst->vk, &dst_subres); + /* This also is not explicitly required in the spec */ + assert(src_layer_count == dst_layer_count); + unsigned layer_count = src_layer_count; + + unsigned sample_count = src->vk.samples; + /* This also is not explicitly required in the spec */ + assert(dst->vk.samples == sample_count); + /* Multisampled images are implemented as 3D */ + unsigned depth = sample_count > 1 ? sample_count : region->extent.depth; + + void *src_base_ptr = + src_cpu + src_plane->offset + src_slice_layout->offset_B; + void *dst_base_ptr = + dst_cpu + dst_plane->offset + dst_slice_layout->offset_B; + for (unsigned layer = 0; layer < layer_count; layer++) { + unsigned src_layer = layer + src_subres.baseArrayLayer; + unsigned dst_layer = layer + dst_subres.baseArrayLayer; + void *src_layer_ptr = src_base_ptr + + src_layer * src_slice_layout->tiled_or_linear.surface_stride_B; + void *dst_layer_ptr = dst_base_ptr + + dst_layer * dst_slice_layout->tiled_or_linear.surface_stride_B; + + if (flags & VK_HOST_IMAGE_COPY_MEMCPY_BIT) { + assert(src_slice_layout->size_B == dst_slice_layout->size_B); + memcpy(dst_layer_ptr, src_layer_ptr, src_slice_layout->size_B); + continue; + } + + for (unsigned z = 0; z < depth; z++) { + unsigned src_z = z + region->srcOffset.z; + unsigned dst_z = z + region->dstOffset.z; + void *src_depth_ptr = src_layer_ptr + + src_z * src_slice_layout->tiled_or_linear.surface_stride_B; + 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; + 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); + } + } + } +} + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_CopyImageToImage(VkDevice device, const VkCopyImageToImageInfo *info) +{ + VkResult result = VK_SUCCESS; + + VK_FROM_HANDLE(panvk_device, dev, device); + VK_FROM_HANDLE(panvk_image, dst, info->dstImage); + VK_FROM_HANDLE(panvk_image, src, info->srcImage); + + void *dst_cpu = pan_kmod_bo_mmap( + dst->mem->bo, 0, pan_kmod_bo_size(dst->mem->bo), PROT_WRITE, MAP_SHARED, + NULL); + if (dst_cpu == MAP_FAILED) + return panvk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED, + "Failed to CPU map image"); + + void *src_cpu = pan_kmod_bo_mmap( + src->mem->bo, 0, pan_kmod_bo_size(src->mem->bo), PROT_READ, MAP_SHARED, + NULL); + if (src_cpu == MAP_FAILED) { + result = panvk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED, + "Failed to CPU map image"); + goto unmap_dst; + } + + for (unsigned i = 0; i < info->regionCount; i++) { + panvk_copy_image_to_image(dst, dst_cpu, src, src_cpu, &info->pRegions[i], + info->flags); + } + + ASSERTED int ret = os_munmap(src_cpu, pan_kmod_bo_size(src->mem->bo)); + assert(!ret); +unmap_dst: + ret = os_munmap(dst_cpu, pan_kmod_bo_size(dst->mem->bo)); + assert(!ret); + + return result; +} + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_TransitionImageLayout(VkDevice device, uint32_t transitionCount, + const VkHostImageLayoutTransitionInfo *transitions) +{ + /* We don't use image layouts, this is a no-op */ + return VK_SUCCESS; +} diff --git a/src/panfrost/vulkan/panvk_image.c b/src/panfrost/vulkan/panvk_image.c index 777b6519135..90036fad459 100644 --- a/src/panfrost/vulkan/panvk_image.c +++ b/src/panfrost/vulkan/panvk_image.c @@ -530,6 +530,11 @@ get_image_subresource_layout(const struct panvk_image *image, layout->rowPitch = slice_layout->tiled_or_linear.row_stride_B; layout->depthPitch = slice_layout->tiled_or_linear.surface_stride_B; } + + VkSubresourceHostMemcpySize *memcpy_size = + vk_find_struct(layout2->pNext, SUBRESOURCE_HOST_MEMCPY_SIZE); + if (memcpy_size) + memcpy_size->size = slice_layout->size_B; } VKAPI_ATTR void VKAPI_CALL diff --git a/src/panfrost/vulkan/panvk_physical_device.c b/src/panfrost/vulkan/panvk_physical_device.c index b7e02c5e071..aa1f571d186 100644 --- a/src/panfrost/vulkan/panvk_physical_device.c +++ b/src/panfrost/vulkan/panvk_physical_device.c @@ -530,7 +530,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) + VkFormat format, VkImageTiling tiling) { VkFormatFeatureFlags2 features = 0; enum pipe_format pfmt = vk_format_to_pipe_format(format); @@ -583,12 +583,16 @@ 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) + features |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT; + return features; } static VkFormatFeatureFlags2 get_image_format_features(struct panvk_physical_device *physical_device, - VkFormat format) + VkFormat format, VkImageTiling tiling) { const struct vk_format_ycbcr_info *ycbcr_info = vk_format_get_ycbcr_info(format); @@ -599,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); + return get_image_plane_format_features(physical_device, format, tiling); if (unsupported_yuv_format(vk_format_to_pipe_format(format))) return 0; @@ -613,7 +617,8 @@ 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); + get_image_plane_format_features(physical_device, plane_info->format, + tiling); if (plane_info->denominator_scales[0] > 1 || plane_info->denominator_scales[1] > 1) cosited_chroma = true; @@ -734,22 +739,26 @@ panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, { VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); - VkFormatFeatureFlags2 tex = - get_image_format_features(physical_device, format); + 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 buffer = get_buffer_format_features(physical_device, format); pFormatProperties->formatProperties = (VkFormatProperties){ - .linearTilingFeatures = tex, - .optimalTilingFeatures = tex, + .linearTilingFeatures = tex_linear, + .optimalTilingFeatures = tex_optimal, .bufferFeatures = buffer, }; VkFormatProperties3 *formatProperties3 = vk_find_struct(pFormatProperties->pNext, FORMAT_PROPERTIES_3); if (formatProperties3) { - formatProperties3->linearTilingFeatures = tex; - formatProperties3->optimalTilingFeatures = tex; + formatProperties3->linearTilingFeatures = tex_linear; + formatProperties3->optimalTilingFeatures = tex_optimal; formatProperties3->bufferFeatures = buffer; } @@ -877,14 +886,15 @@ 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); + get_image_format_features(physical_device, info->format, info->tiling); } 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); + get_image_format_features(physical_device, plane_format, + info->tiling); } } @@ -1075,6 +1085,7 @@ panvk_GetPhysicalDeviceImageFormatProperties2( VkExternalImageFormatProperties *external_props = NULL; VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL; VkFormatFeatureFlags2 format_feature_flags; + VkHostImageCopyDevicePerformanceQuery *hic_props = NULL; VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL; VkResult result; @@ -1107,6 +1118,9 @@ panvk_GetPhysicalDeviceImageFormatProperties2( case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: cubic_props = (void *)s; break; + case VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY: + hic_props = (void *)s; + break; case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: ycbcr_props = (void *)s; break; @@ -1157,6 +1171,11 @@ panvk_GetPhysicalDeviceImageFormatProperties2( } } + if (hic_props) { + hic_props->optimalDeviceAccess = true; + hic_props->identicalMemoryLayout = true; + } + const struct vk_format_ycbcr_info *ycbcr_info = vk_format_get_ycbcr_info(base_info->format); const unsigned plane_count = diff --git a/src/panfrost/vulkan/panvk_vX_physical_device.c b/src/panfrost/vulkan/panvk_vX_physical_device.c index 93635403bb0..533184f69a7 100644 --- a/src/panfrost/vulkan/panvk_vX_physical_device.c +++ b/src/panfrost/vulkan/panvk_vX_physical_device.c @@ -138,6 +138,7 @@ panvk_per_arch(get_physical_device_extensions)( .EXT_global_priority_query = true, .EXT_graphics_pipeline_library = true, .EXT_hdr_metadata = true, + .EXT_host_image_copy = true, .EXT_host_query_reset = true, .EXT_image_2d_view_of_3d = true, /* EXT_image_drm_format_modifier depends on KHR_sampler_ycbcr_conversion */ @@ -377,6 +378,9 @@ panvk_per_arch(get_physical_device_features)( /* VK_KHR_global_priority */ .globalPriorityQuery = true, + /* VK_EXT_host_image_copy */ + .hostImageCopy = true, + /* VK_KHR_index_type_uint8 */ .indexTypeUint8 = true, @@ -943,6 +947,9 @@ panvk_per_arch(get_physical_device_properties)( .pixelRate = device->model->rates.pixel, .texelRate = device->model->rates.texel, .fmaRate = device->model->rates.fma, + + /* VK_EXT_host_image_copy */ + .identicalMemoryTypeRequirements = true, }; snprintf(properties->deviceName, sizeof(properties->deviceName), "%s", @@ -986,4 +993,44 @@ panvk_per_arch(get_physical_device_properties)( memcpy(properties->shaderModuleIdentifierAlgorithmUUID, vk_shaderModuleIdentifierAlgorithmUUID, sizeof(properties->shaderModuleIdentifierAlgorithmUUID)); + + /* VK_EXT_host_image_copy */ + /* We don't use image layouts, advertise all of them */ + static VkImageLayout supported_host_copy_layouts[] = { + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_PREINITIALIZED, + + /* Only if vk1.1+ is supported */ +#if PAN_ARCH >= 10 + /* Vulkan 1.1 */ + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, + + /* Vulkan 1.2 */ + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + + /* Vulkan 1.3 */ + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + + /* Vulkan 1.4 */ + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ, +#endif + }; + properties->pCopySrcLayouts = supported_host_copy_layouts; + properties->copySrcLayoutCount = ARRAY_SIZE(supported_host_copy_layouts); + properties->pCopyDstLayouts = supported_host_copy_layouts; + properties->copyDstLayoutCount = ARRAY_SIZE(supported_host_copy_layouts); + /* All HW has the same tiling layout, key off build hash only */ + STATIC_ASSERT(sizeof(instance->driver_build_sha) >= VK_UUID_SIZE); + memcpy(properties->optimalTilingLayoutUUID, instance->driver_build_sha, + VK_UUID_SIZE); }