venus: implement host image copy commands
The img-2-img and layout transition are trivial passthrough. For img-2-mem and mem-2-img copies, host pointer has to be sized for proper protocol encoding and decoding, and we have to either query or calculate on our own based on VK_HOST_IMAGE_COPY_MEMCPY_EXT flag being used or not. Signed-off-by: Yiwei Zhang <zzyiwei@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33757>
This commit is contained in:
@@ -59,6 +59,7 @@ libvn_files = files(
|
||||
'vn_device.c',
|
||||
'vn_device_memory.c',
|
||||
'vn_feedback.c',
|
||||
'vn_host_copy.c',
|
||||
'vn_icd.c',
|
||||
'vn_image.c',
|
||||
'vn_instance.c',
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "vn_common.h"
|
||||
|
||||
#include "venus-protocol/vn_protocol_driver_host_copy.h"
|
||||
#include "vk_format.h"
|
||||
|
||||
#include "vn_device.h"
|
||||
|
||||
VkResult
|
||||
vn_TransitionImageLayout(VkDevice device,
|
||||
uint32_t transitionCount,
|
||||
const VkHostImageLayoutTransitionInfo *pTransitions)
|
||||
{
|
||||
struct vn_device *dev = vn_device_from_handle(device);
|
||||
|
||||
vn_async_vkTransitionImageLayout(dev->primary_ring, device,
|
||||
transitionCount, pTransitions);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
vn_CopyImageToImage(VkDevice device,
|
||||
const VkCopyImageToImageInfo *pCopyImageToImageInfo)
|
||||
{
|
||||
struct vn_device *dev = vn_device_from_handle(device);
|
||||
|
||||
vn_async_vkCopyImageToImage(dev->primary_ring, device,
|
||||
pCopyImageToImageInfo);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static size_t
|
||||
vn_get_memcpy_size(VkDevice dev_handle,
|
||||
VkImage img_handle,
|
||||
const VkImageSubresourceLayers *subres_layers)
|
||||
{
|
||||
VK_FROM_HANDLE(vk_image, img_vk, img_handle);
|
||||
|
||||
const uint32_t layer_count =
|
||||
vk_image_subresource_layer_count(img_vk, subres_layers);
|
||||
size_t total_size = 0;
|
||||
|
||||
for (uint32_t i = 0; i < layer_count; i++) {
|
||||
const VkImageSubresource2 subres = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2,
|
||||
.imageSubresource =
|
||||
(VkImageSubresource){
|
||||
.aspectMask = subres_layers->aspectMask,
|
||||
.mipLevel = subres_layers->mipLevel,
|
||||
.arrayLayer = subres_layers->baseArrayLayer + i,
|
||||
},
|
||||
};
|
||||
|
||||
VkSubresourceHostMemcpySize copy_size = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE,
|
||||
};
|
||||
VkSubresourceLayout2 layout = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2,
|
||||
.pNext = ©_size,
|
||||
};
|
||||
|
||||
vn_GetImageSubresourceLayout2(dev_handle, img_handle, &subres, &layout);
|
||||
|
||||
total_size += copy_size.size;
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
vn_get_copy_size(VkImage img_handle,
|
||||
const VkImageSubresourceLayers *subres_layers,
|
||||
uint32_t mem_row_length,
|
||||
uint32_t mem_img_height,
|
||||
VkExtent3D img_extent)
|
||||
{
|
||||
VK_FROM_HANDLE(vk_image, img_vk, img_handle);
|
||||
|
||||
VkFormat format = img_vk->format;
|
||||
|
||||
/* Per spec: Table 30. Depth/Stencil Aspect Copy Table */
|
||||
const bool copy_depth =
|
||||
subres_layers->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
const bool copy_stencil =
|
||||
subres_layers->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
if (copy_depth && !copy_stencil)
|
||||
format = vk_format_depth_only(format);
|
||||
else if (!copy_depth && copy_stencil)
|
||||
format = vk_format_stencil_only(format);
|
||||
|
||||
const uint32_t width = mem_row_length ?: img_extent.width;
|
||||
const uint32_t height = mem_img_height ?: img_extent.height;
|
||||
const uint32_t bw = vk_format_get_blockwidth(format);
|
||||
const uint32_t bh = vk_format_get_blockheight(format);
|
||||
const uint32_t bs = vk_format_get_blocksize(format);
|
||||
|
||||
/* Per spec: Copying Data Between Buffers and Images */
|
||||
const size_t row_extent = DIV_ROUND_UP(width, bw) * bs;
|
||||
const size_t slice_extent = DIV_ROUND_UP(height, bh) * row_extent;
|
||||
const size_t layer_extent = img_extent.depth * slice_extent;
|
||||
|
||||
const uint32_t layer_count =
|
||||
vk_image_subresource_layer_count(img_vk, subres_layers);
|
||||
|
||||
/* Venus must use the theoretically minimum size to avoid OOB access */
|
||||
const size_t last_layer_offset = (layer_count - 1) * layer_extent;
|
||||
const size_t last_slice_offset =
|
||||
(img_extent.depth - 1) * slice_extent + last_layer_offset;
|
||||
const size_t last_row_offset =
|
||||
(DIV_ROUND_UP(img_extent.height, bh) - 1) * row_extent +
|
||||
last_slice_offset;
|
||||
const size_t last_row_size = DIV_ROUND_UP(img_extent.width, bw) * bs;
|
||||
|
||||
return last_row_size + last_row_offset;
|
||||
}
|
||||
|
||||
VkResult
|
||||
vn_CopyImageToMemory(VkDevice device,
|
||||
const VkCopyImageToMemoryInfo *pCopyImageToMemoryInfo)
|
||||
{
|
||||
struct vn_device *dev = vn_device_from_handle(device);
|
||||
const VkCopyImageToMemoryInfo *info = pCopyImageToMemoryInfo;
|
||||
const VkImageToMemoryCopy *regions = info->pRegions;
|
||||
|
||||
for (uint32_t i = 0; i < info->regionCount; i++) {
|
||||
const size_t data_size =
|
||||
(info->flags & VK_HOST_IMAGE_COPY_MEMCPY)
|
||||
? vn_get_memcpy_size(device, info->srcImage,
|
||||
®ions[i].imageSubresource)
|
||||
: vn_get_copy_size(info->srcImage, ®ions[i].imageSubresource,
|
||||
regions[i].memoryRowLength,
|
||||
regions[i].memoryImageHeight,
|
||||
regions[i].imageExtent);
|
||||
|
||||
const VkCopyImageToMemoryInfoMESA local_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_MESA,
|
||||
.flags = info->flags,
|
||||
.srcImage = info->srcImage,
|
||||
.srcImageLayout = info->srcImageLayout,
|
||||
.memoryRowLength = regions[i].memoryRowLength,
|
||||
.memoryImageHeight = regions[i].memoryImageHeight,
|
||||
.imageSubresource = regions[i].imageSubresource,
|
||||
.imageOffset = regions[i].imageOffset,
|
||||
.imageExtent = regions[i].imageExtent,
|
||||
};
|
||||
|
||||
/* We do per region copy here for the optimal performance via renderer
|
||||
* side in-place host pointer encoding: the temp alloc and memcpy to
|
||||
* reply shmem are both skipped. The flatten overhead is trivial as
|
||||
* compared to the host copy perf win.
|
||||
*/
|
||||
VkResult ret = vn_call_vkCopyImageToMemoryMESA(
|
||||
dev->primary_ring, device, &local_info, data_size,
|
||||
regions[i].pHostPointer);
|
||||
if (ret != VK_SUCCESS)
|
||||
return vn_error(dev->instance, ret);
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
vn_CopyMemoryToImage(VkDevice device,
|
||||
const VkCopyMemoryToImageInfo *pCopyMemoryToImageInfo)
|
||||
{
|
||||
struct vn_device *dev = vn_device_from_handle(device);
|
||||
const VkCopyMemoryToImageInfo *info = pCopyMemoryToImageInfo;
|
||||
const VkMemoryToImageCopy *regions = info->pRegions;
|
||||
|
||||
STACK_ARRAY(VkMemoryToImageCopyMESA, local_regions, info->regionCount);
|
||||
|
||||
for (uint32_t i = 0; i < info->regionCount; i++) {
|
||||
const size_t data_size =
|
||||
(info->flags & VK_HOST_IMAGE_COPY_MEMCPY)
|
||||
? vn_get_memcpy_size(device, info->dstImage,
|
||||
®ions[i].imageSubresource)
|
||||
: vn_get_copy_size(info->dstImage, ®ions[i].imageSubresource,
|
||||
regions[i].memoryRowLength,
|
||||
regions[i].memoryImageHeight,
|
||||
regions[i].imageExtent);
|
||||
|
||||
local_regions[i] = (VkMemoryToImageCopyMESA){
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_MESA,
|
||||
.dataSize = data_size,
|
||||
.pData = regions[i].pHostPointer,
|
||||
.memoryRowLength = regions[i].memoryRowLength,
|
||||
.memoryImageHeight = regions[i].memoryImageHeight,
|
||||
.imageSubresource = regions[i].imageSubresource,
|
||||
.imageOffset = regions[i].imageOffset,
|
||||
.imageExtent = regions[i].imageExtent,
|
||||
};
|
||||
}
|
||||
|
||||
const VkCopyMemoryToImageInfoMESA local_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_MESA,
|
||||
.flags = info->flags,
|
||||
.dstImage = info->dstImage,
|
||||
.dstImageLayout = info->dstImageLayout,
|
||||
.regionCount = info->regionCount,
|
||||
.pRegions = local_regions,
|
||||
};
|
||||
|
||||
vn_async_vkCopyMemoryToImageMESA(dev->primary_ring, device, &local_info);
|
||||
|
||||
STACK_ARRAY_FINISH(local_regions);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user