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;