pvr: Implement vkCmdBlitImage API.
Signed-off-by: Rajnesh Kanwal <rajnesh.kanwal@imgtec.com> Acked-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21550>
This commit is contained in:

committed by
Marge Bot

parent
4c31121329
commit
5827f0098c
@@ -46,12 +46,6 @@
|
||||
/* TODO: Investigate where this limit comes from. */
|
||||
#define PVR_MAX_TRANSFER_SIZE_IN_TEXELS 2048U
|
||||
|
||||
void pvr_CmdBlitImage2KHR(VkCommandBuffer commandBuffer,
|
||||
const VkBlitImageInfo2 *pBlitImageInfo)
|
||||
{
|
||||
assert(!"Unimplemented");
|
||||
}
|
||||
|
||||
void pvr_CmdCopyImageToBuffer2KHR(
|
||||
VkCommandBuffer commandBuffer,
|
||||
const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo)
|
||||
@@ -181,6 +175,196 @@ static void pvr_setup_transfer_surface(struct pvr_device *device,
|
||||
rect->extent.height = extent->height;
|
||||
}
|
||||
|
||||
void pvr_CmdBlitImage2KHR(VkCommandBuffer commandBuffer,
|
||||
const VkBlitImageInfo2KHR *pBlitImageInfo)
|
||||
{
|
||||
PVR_FROM_HANDLE(pvr_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
PVR_FROM_HANDLE(pvr_image, src, pBlitImageInfo->srcImage);
|
||||
PVR_FROM_HANDLE(pvr_image, dst, pBlitImageInfo->dstImage);
|
||||
struct pvr_device *device = cmd_buffer->device;
|
||||
enum pvr_filter filter = PVR_FILTER_DONTCARE;
|
||||
|
||||
PVR_CHECK_COMMAND_BUFFER_BUILDING_STATE(cmd_buffer);
|
||||
|
||||
if (pBlitImageInfo->filter == VK_FILTER_LINEAR)
|
||||
filter = PVR_FILTER_LINEAR;
|
||||
|
||||
for (uint32_t i = 0U; i < pBlitImageInfo->regionCount; i++) {
|
||||
const VkImageBlit2 *region = &pBlitImageInfo->pRegions[i];
|
||||
|
||||
assert(region->srcSubresource.layerCount ==
|
||||
region->dstSubresource.layerCount);
|
||||
const bool inverted_dst_z =
|
||||
(region->dstOffsets[1].z < region->dstOffsets[0].z);
|
||||
const bool inverted_src_z =
|
||||
(region->srcOffsets[1].z < region->srcOffsets[0].z);
|
||||
const uint32_t min_src_z = inverted_src_z ? region->srcOffsets[1].z
|
||||
: region->srcOffsets[0].z;
|
||||
const uint32_t max_src_z = inverted_src_z ? region->srcOffsets[0].z
|
||||
: region->srcOffsets[1].z;
|
||||
const uint32_t min_dst_z = inverted_dst_z ? region->dstOffsets[1].z
|
||||
: region->dstOffsets[0].z;
|
||||
const uint32_t max_dst_z = inverted_dst_z ? region->dstOffsets[0].z
|
||||
: region->dstOffsets[1].z;
|
||||
|
||||
const uint32_t src_width =
|
||||
region->srcOffsets[1].x - region->srcOffsets[0].x;
|
||||
const uint32_t src_height =
|
||||
region->srcOffsets[1].y - region->srcOffsets[0].y;
|
||||
const uint32_t dst_width =
|
||||
region->dstOffsets[1].x - region->dstOffsets[0].x;
|
||||
const uint32_t dst_height =
|
||||
region->dstOffsets[1].y - region->dstOffsets[0].y;
|
||||
|
||||
float initial_depth_offset;
|
||||
VkExtent3D src_extent;
|
||||
VkExtent3D dst_extent;
|
||||
float z_slice_stride;
|
||||
|
||||
/* If any of the extent regions is zero, then reject the blit and
|
||||
* continue.
|
||||
*/
|
||||
if (!src_width || !src_height || !dst_width || !dst_height ||
|
||||
!(max_dst_z - min_dst_z) || !(max_src_z - min_src_z)) {
|
||||
mesa_loge("BlitImage: Region %i has an area of zero", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
src_extent = (VkExtent3D){
|
||||
.width = src_width,
|
||||
.height = src_height,
|
||||
.depth = 0U,
|
||||
};
|
||||
|
||||
dst_extent = (VkExtent3D){
|
||||
.width = dst_width,
|
||||
.height = dst_height,
|
||||
.depth = 0U,
|
||||
};
|
||||
|
||||
/* The z_position of a transfer surface is intended to be in the range
|
||||
* of 0.0f <= z_position <= depth. It will be used as a texture coordinate
|
||||
* in the source surface for cases where linear filtering is enabled, so
|
||||
* the fractional part will need to represent the exact midpoint of a z
|
||||
* slice range in the source texture, as it maps to each destination
|
||||
* slice.
|
||||
*
|
||||
* For destination surfaces, the fractional part is discarded, so
|
||||
* we can safely pass the slice index.
|
||||
*/
|
||||
|
||||
/* Calculate the ratio of z slices in our source region to that of our
|
||||
* destination region, to get the number of z slices in our source region
|
||||
* to iterate over for each destination slice.
|
||||
*
|
||||
* If our destination region is inverted, we iterate backwards.
|
||||
*/
|
||||
z_slice_stride =
|
||||
(inverted_dst_z ? -1.0f : 1.0f) *
|
||||
((float)(max_src_z - min_src_z) / (float)(max_dst_z - min_dst_z));
|
||||
|
||||
/* Offset the initial depth offset by half of the z slice stride, into the
|
||||
* blit region's z range.
|
||||
*/
|
||||
initial_depth_offset =
|
||||
(inverted_dst_z ? max_src_z : min_src_z) + (0.5f * z_slice_stride);
|
||||
|
||||
for (uint32_t j = 0U; j < region->srcSubresource.layerCount; j++) {
|
||||
struct pvr_transfer_cmd_surface src_surface = { 0 };
|
||||
struct pvr_transfer_cmd_surface dst_surface = { 0 };
|
||||
VkRect2D src_rect;
|
||||
VkRect2D dst_rect;
|
||||
|
||||
/* Get the subresource info for the src and dst images, this is
|
||||
* required when incrementing the address of the depth slice used by
|
||||
* the transfer surface.
|
||||
*/
|
||||
VkSubresourceLayout src_info, dst_info;
|
||||
const VkImageSubresource src_sub_resource = {
|
||||
.aspectMask = region->srcSubresource.aspectMask,
|
||||
.mipLevel = region->srcSubresource.mipLevel,
|
||||
.arrayLayer = region->srcSubresource.baseArrayLayer + j,
|
||||
};
|
||||
const VkImageSubresource dst_sub_resource = {
|
||||
.aspectMask = region->dstSubresource.aspectMask,
|
||||
.mipLevel = region->dstSubresource.mipLevel,
|
||||
.arrayLayer = region->dstSubresource.baseArrayLayer + j,
|
||||
};
|
||||
|
||||
pvr_get_image_subresource_layout(src, &src_sub_resource, &src_info);
|
||||
pvr_get_image_subresource_layout(dst, &dst_sub_resource, &dst_info);
|
||||
|
||||
/* Setup the transfer surfaces once per image layer, which saves us
|
||||
* from repeating subresource queries by manually incrementing the
|
||||
* depth slices.
|
||||
*/
|
||||
pvr_setup_transfer_surface(device,
|
||||
&src_surface,
|
||||
&src_rect,
|
||||
src,
|
||||
region->srcSubresource.baseArrayLayer + j,
|
||||
region->srcSubresource.mipLevel,
|
||||
®ion->srcOffsets[0],
|
||||
&src_extent,
|
||||
initial_depth_offset,
|
||||
src->vk.format,
|
||||
region->srcSubresource.aspectMask);
|
||||
|
||||
pvr_setup_transfer_surface(device,
|
||||
&dst_surface,
|
||||
&dst_rect,
|
||||
dst,
|
||||
region->dstSubresource.baseArrayLayer + j,
|
||||
region->dstSubresource.mipLevel,
|
||||
®ion->dstOffsets[0],
|
||||
&dst_extent,
|
||||
min_dst_z,
|
||||
dst->vk.format,
|
||||
region->dstSubresource.aspectMask);
|
||||
|
||||
for (uint32_t dst_z = min_dst_z; dst_z < max_dst_z; dst_z++) {
|
||||
struct pvr_transfer_cmd *transfer_cmd;
|
||||
VkResult result;
|
||||
|
||||
/* TODO: See if we can allocate all the transfer cmds in one go. */
|
||||
transfer_cmd = pvr_transfer_cmd_alloc(cmd_buffer);
|
||||
if (!transfer_cmd)
|
||||
return;
|
||||
|
||||
transfer_cmd->mappings[0].src_rect = src_rect;
|
||||
transfer_cmd->mappings[0].dst_rect = dst_rect;
|
||||
transfer_cmd->mapping_count++;
|
||||
|
||||
transfer_cmd->src = src_surface;
|
||||
transfer_cmd->src_present = true;
|
||||
|
||||
transfer_cmd->dst = dst_surface;
|
||||
transfer_cmd->scissor = dst_rect;
|
||||
|
||||
transfer_cmd->filter = filter;
|
||||
|
||||
result = pvr_cmd_buffer_add_transfer_cmd(cmd_buffer, transfer_cmd);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_free(&cmd_buffer->vk.pool->alloc, transfer_cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_surface.mem_layout == PVR_MEMLAYOUT_3DTWIDDLED) {
|
||||
src_surface.z_position += z_slice_stride;
|
||||
} else {
|
||||
src_surface.dev_addr.addr +=
|
||||
src_info.depthPitch * ((uint32_t)z_slice_stride);
|
||||
}
|
||||
|
||||
if (dst_surface.mem_layout == PVR_MEMLAYOUT_3DTWIDDLED)
|
||||
dst_surface.z_position += 1.0f;
|
||||
else
|
||||
dst_surface.dev_addr.addr += dst_info.depthPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VkFormat pvr_get_copy_format(VkFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
|
Reference in New Issue
Block a user