Implement image blitting
First simple implementation of image blitting.
Note that layers are not yet taken into account.
Passes almost all tests in (There are only 2 failures,
which both have an off by 1 error on a single pixel):
dEQP-VK.api.copy_and_blit.core.blit_image.simple_tests.*
Bug b/118619338 b/119620767
Change-Id: I1e0ac88089d6159924569099ea6345804a219d2c
Reviewed-on: https://swiftshader-review.googlesource.com/c/23268
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 7525749..86e2436 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -220,6 +220,25 @@
const VkBufferImageCopy region;
};
+struct BlitImage : public CommandBuffer::Command
+{
+ BlitImage(VkImage srcImage, VkImage dstImage, const VkImageBlit& region, VkFilter filter) :
+ srcImage(srcImage), dstImage(dstImage), region(region), filter(filter)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState)
+ {
+ Cast(srcImage)->blit(dstImage, region, filter);
+ }
+
+private:
+ VkImage srcImage;
+ VkImage dstImage;
+ const VkImageBlit& region;
+ VkFilter filter;
+};
+
struct PipelineBarrier : public CommandBuffer::Command
{
PipelineBarrier()
@@ -530,7 +549,16 @@
void CommandBuffer::blitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout,
uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter)
{
- UNIMPLEMENTED();
+ ASSERT(state == RECORDING);
+ ASSERT(srcImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
+ srcImageLayout == VK_IMAGE_LAYOUT_GENERAL);
+ ASSERT(dstImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
+ dstImageLayout == VK_IMAGE_LAYOUT_GENERAL);
+
+ for(uint32_t i = 0; i < regionCount; i++)
+ {
+ commands->push_back(std::make_unique<BlitImage>(srcImage, dstImage, pRegions[i], filter));
+ }
}
void CommandBuffer::copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout,
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 16e3fd9..0310615 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -368,6 +368,54 @@
return arrayLayers * extent.depth * slicePitchB;
}
+sw::Surface* Image::asSurface(const VkImageAspectFlags& flags) const
+{
+ return sw::Surface::create(extent.width, extent.height, extent.depth, getFormat(flags),
+ deviceMemory->getOffsetPointer(memoryOffset),
+ rowPitchBytes(flags), slicePitchBytes(flags));
+}
+
+void Image::blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter)
+{
+ VkImageAspectFlags srcFlags = region.srcSubresource.aspectMask;
+ VkImageAspectFlags dstFlags = region.dstSubresource.aspectMask;
+ if((region.srcSubresource.baseArrayLayer != 0) ||
+ (region.dstSubresource.baseArrayLayer != 0) ||
+ (region.srcSubresource.layerCount != 1) ||
+ (region.dstSubresource.layerCount != 1) ||
+ (region.srcSubresource.mipLevel != 0) ||
+ (region.dstSubresource.mipLevel != 0) ||
+ (srcFlags != dstFlags))
+ {
+ UNIMPLEMENTED();
+ }
+
+ int32_t numSlices = (region.srcOffsets[1].z - region.srcOffsets[0].z);
+ ASSERT(numSlices == (region.dstOffsets[1].z - region.dstOffsets[0].z));
+
+ sw::Surface* srcSurface = asSurface(srcFlags);
+ sw::Surface* dstSurface = Cast(dstImage)->asSurface(dstFlags);
+
+ sw::SliceRectF sRect(static_cast<float>(region.srcOffsets[0].x), static_cast<float>(region.srcOffsets[0].y),
+ static_cast<float>(region.srcOffsets[1].x), static_cast<float>(region.srcOffsets[1].y),
+ region.srcOffsets[0].z);
+
+ sw::SliceRect dRect(region.dstOffsets[0].x, region.dstOffsets[0].y,
+ region.dstOffsets[1].x, region.dstOffsets[1].y, region.dstOffsets[0].z);
+
+ sw::Blitter blitter;
+ for(int i = 0; i < numSlices; i++)
+ {
+ blitter.blit(srcSurface, sRect, dstSurface, dRect,
+ {filter != VK_FILTER_NEAREST, srcFlags == VK_IMAGE_ASPECT_STENCIL_BIT, false});
+ sRect.slice++;
+ dRect.slice++;
+ }
+
+ delete srcSurface;
+ delete dstSurface;
+}
+
void Image::clear(const VkClearValue& clearValue, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange)
{
if(!((subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
@@ -398,9 +446,7 @@
renderArea.offset.y + renderArea.extent.height);
const sw::SliceRect dRect(rect);
- sw::Surface* surface = sw::Surface::create(extent.width, extent.height, extent.depth,
- getFormat(subresourceRange.aspectMask), deviceMemory->getOffsetPointer(memoryOffset),
- rowPitchBytes(subresourceRange.aspectMask), slicePitchBytes(subresourceRange.aspectMask));
+ sw::Surface* surface = asSurface(subresourceRange.aspectMask);
sw::Blitter blitter;
blitter.clear((void*)clearValue.color.float32, clearFormat, surface, dRect, 0xF);
delete surface;
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 006b3c6..cfcd379 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -42,6 +42,7 @@
void copyTo(VkBuffer dstBuffer, const VkBufferImageCopy& region);
void copyFrom(VkBuffer srcBuffer, const VkBufferImageCopy& region);
+ void blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter);
void clear(const VkClearValue& clearValue, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange);
VkImageType getImageType() const { return imageType; }
@@ -58,6 +59,7 @@
int bytesPerTexel(const VkImageAspectFlags& flags) const;
VkFormat getFormat(const VkImageAspectFlags& flags) const;
int getBorder() const;
+ sw::Surface* asSurface(const VkImageAspectFlags& flags) const;
DeviceMemory* deviceMemory = nullptr;
VkDeviceSize memoryOffset = 0;