blob: 6b12317702c7370f202a2594633b3d6d448a9118 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "tests/common/vk_image_utils.h"
#include "tests/common/utils.h"
void
vk_cmd_image_layout_transition(VkCommandBuffer command_buffer,
VkImage image,
VkPipelineStageFlags src_stage,
VkImageLayout src_layout,
VkPipelineStageFlags dst_stage,
VkImageLayout dst_layout)
{
// TODO(digit): Complete this and put in test framework header.
VkAccessFlags src_access = (VkAccessFlags)0;
switch (src_stage)
{
case VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT:
break;
case VK_PIPELINE_STAGE_TRANSFER_BIT:
src_access = VK_ACCESS_TRANSFER_READ_BIT;
break;
case VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT:
src_access = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT:
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
break;
default:
ASSERT_MSG(false, "Unsupported source pipeline stage 0x%x\n", src_stage);
}
// TODO(digit): Complete this and put in test framework header.
VkAccessFlags dst_access = (VkAccessFlags)0;
switch (dst_stage)
{
case VK_PIPELINE_STAGE_TRANSFER_BIT:
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT:
dst_access = VK_ACCESS_SHADER_WRITE_BIT;
break;
case VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT:
break;
default:
ASSERT_MSG(false, "Unsupported destination pipeline stage 0x%x\n", src_stage);
}
const VkImageMemoryBarrier image_memory_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = NULL,
.srcAccessMask = src_access,
.dstAccessMask = dst_access,
.oldLayout = src_layout,
.newLayout = dst_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
vkCmdPipelineBarrier(command_buffer,
src_stage,
dst_stage,
0, // dependencyFlags
0, // memoryBarrierCount
NULL, // pMemoryBarriers
0, // bufferMemoryBarrierCount
NULL, // pBufferMemoryBarriers
1, // imageMemoryBarrierCount,
&image_memory_barrier);
}
bool
vk_image_copy_info_clip(vk_image_copy_info_t * info)
{
if (info->copy.src_x < 0)
{
info->copy.w += info->copy.src_x;
info->copy.dst_x -= info->copy.src_x;
info->copy.src_x = 0;
}
if (info->copy.src_y < 0)
{
info->copy.h += info->copy.src_y;
info->copy.dst_y -= info->copy.src_y;
info->copy.src_y = 0;
}
if (info->copy.dst_x < 0)
{
info->copy.w += info->copy.dst_x;
info->copy.src_x -= info->copy.dst_x;
info->copy.dst_x = 0;
}
if (info->copy.dst_y < 0)
{
info->copy.h += info->copy.dst_y;
info->copy.src_y -= info->copy.dst_y;
info->copy.dst_y = 0;
}
int32_t delta;
delta = info->copy.src_x + info->copy.w - (int32_t)info->src.width;
if (delta > 0)
{
info->copy.w -= delta;
}
delta = info->copy.src_y + info->copy.h - (int32_t)info->src.height;
if (delta > 0)
{
info->copy.h -= delta;
}
delta = info->copy.dst_x + info->copy.w - (int32_t)info->dst.width;
if (delta > 0)
{
info->copy.w -= delta;
}
delta = info->copy.dst_y + info->copy.h - (int32_t)info->dst.height;
if (delta > 0)
{
info->copy.h -= delta;
}
return (info->copy.w > 0 && info->copy.h > 0);
}
extern void
vk_cmd_copy_buffer_to_image(VkCommandBuffer command_buffer,
VkBuffer src_buffer,
uint32_t src_stride,
uint32_t src_bytes_per_pixel,
VkImage dst_image,
VkImageLayout dst_image_layout,
vk_image_copy_info_t info)
{
if (!vk_image_copy_info_clip(&info))
return;
const VkBufferImageCopy buffer_image_copy = {
.bufferOffset = (VkDeviceSize)(info.copy.src_y * src_stride +
info.copy.src_x * src_bytes_per_pixel),
.bufferRowLength = src_stride / src_bytes_per_pixel,
.bufferImageHeight = (uint32_t) info.copy.h,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = {
.x = info.copy.dst_x,
.y = info.copy.dst_y,
.z = 0,
},
.imageExtent = {
.width = (uint32_t) info.copy.w,
.height = (uint32_t) info.copy.h,
.depth = 1,
},
};
vkCmdCopyBufferToImage(command_buffer,
src_buffer,
dst_image,
dst_image_layout,
1,
&buffer_image_copy);
}
extern void
vk_cmd_copy_image_to_image(VkCommandBuffer command_buffer,
VkImage src_image,
VkImageLayout src_image_layout,
VkImage dst_image,
VkImageLayout dst_image_layout,
vk_image_copy_info_t info)
{
if (!vk_image_copy_info_clip(&info))
return;
const VkImageCopy image_copy = {
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.srcOffset = {
.x = info.copy.src_x,
.y = info.copy.src_y,
.z = 0,
},
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.dstOffset = {
.x = info.copy.dst_x,
.y = info.copy.dst_y,
.z = 0,
},
.extent = {
.width = (uint32_t) info.copy.w,
.height = (uint32_t) info.copy.h,
.depth = 1,
},
};
vkCmdCopyImage(command_buffer,
src_image,
src_image_layout,
dst_image,
dst_image_layout,
1,
&image_copy);
}
extern void
vk_cmd_copy_image_to_buffer(VkCommandBuffer command_buffer,
VkImage src_image,
VkImageLayout src_image_layout,
VkBuffer dst_buffer,
uint32_t dst_stride,
uint32_t dst_bytes_per_pixel,
vk_image_copy_info_t info)
{
if (!vk_image_copy_info_clip(&info))
return;
const VkBufferImageCopy buffer_image_copy = {
.bufferOffset = (VkDeviceSize)(info.copy.dst_y * dst_stride +
info.copy.dst_x * dst_bytes_per_pixel),
.bufferRowLength = dst_stride / dst_bytes_per_pixel,
.bufferImageHeight = (uint32_t) info.copy.h,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = {
.x = info.copy.src_x,
.y = info.copy.src_y,
.z = 0,
},
.imageExtent = {
.width = (uint32_t) info.copy.w,
.height = (uint32_t) info.copy.h,
.depth = 1,
},
};
vkCmdCopyImageToBuffer(command_buffer,
src_image,
src_image_layout,
dst_buffer,
1,
&buffer_image_copy);
}
extern void
vk_cmd_copy_buffer_to_buffer(VkCommandBuffer command_buffer,
VkBuffer src_buffer,
uint32_t src_stride,
VkBuffer dst_buffer,
uint32_t dst_stride,
uint32_t common_bytes_per_pixel,
vk_image_copy_info_t info)
{
if (!vk_image_copy_info_clip(&info))
return;
// Perform a single copy operation when possible.
if (src_stride == dst_stride && info.copy.w * common_bytes_per_pixel == src_stride)
{
vkCmdCopyBuffer(
command_buffer,
src_buffer,
dst_buffer,
1,
&(const VkBufferCopy){
.srcOffset = info.copy.src_x * common_bytes_per_pixel + info.copy.src_y * src_stride,
.dstOffset = info.copy.dst_x * common_bytes_per_pixel + info.copy.dst_y * dst_stride,
.size = src_stride * info.copy.h,
});
return;
}
// Otherwise, enqueue multiple commands, where each command tries to copy
// up to 16 scanlines.
#define MAX_SCANLINES 16u
VkBufferCopy copies[MAX_SCANLINES];
uint32_t count = 0;
for (int32_t y = 0; y < info.copy.h; y++)
{
copies[count] = (const VkBufferCopy){
.srcOffset = info.copy.src_x * common_bytes_per_pixel + (info.copy.src_y + y) * src_stride,
.dstOffset = info.copy.dst_x * common_bytes_per_pixel + (info.copy.dst_y + y) * dst_stride,
.size = common_bytes_per_pixel * info.copy.w,
};
count++;
if (count == MAX_SCANLINES || y + (int32_t)count == info.copy.h)
{
vkCmdCopyBuffer(command_buffer, src_buffer, dst_buffer, count, copies);
count = 0;
}
}
}