mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-23 08:38:08 +02:00
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>
214 lines
7.4 KiB
C
214 lines
7.4 KiB
C
/*
|
|
* 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;
|
|
}
|