Commit 32f4be1d by Nicolas Capens Committed by Nicolas Capens

Optimize copying image data for presentation

A highly generic Blitter::blitToBuffer() method was used for copying pixels without requiring any format conversion or scaling. This change removes Blitter::blitToBuffer() and the unused blitFromBuffer() methods and implements a copyTo() method which does straightforward memcpy() of the data. Also consistently add 'To' and 'From' to the Image class's copy, blit, and resolve methods to avoid any confusion about which direction the transfer happens. Benchmark results: Run on (48 X 2594 MHz CPU s) CPU Caches: L1 Data 32 KiB (x24) L1 Instruction 32 KiB (x24) L2 Unified 256 KiB (x24) L3 Unified 30720 KiB (x2) --------------------------------------------------------- Benchmark Time CPU Iterations --------------------------------------------------------- (LLVM, before) Triangle/Hello 8.69 ms 7.39 ms 112 (LLVM, after) Triangle/Hello 0.878 ms 0.454 ms 2133 (Subzero, before) Triangle/Hello 26.2 ms 24.8 ms 41 (Subzero, after) Triangle/Hello 1.11 ms 0.432 ms 1339 Bug: b/147967959 Change-Id: I76a103bbb6e582f987ef1c3cc39d17779ae4ac99 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/45650 Presubmit-Ready: Nicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Tested-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent af1f2159
...@@ -1724,128 +1724,22 @@ Blitter::CornerUpdateRoutineType Blitter::getCornerUpdateRoutine(const State &st ...@@ -1724,128 +1724,22 @@ Blitter::CornerUpdateRoutineType Blitter::getCornerUpdateRoutine(const State &st
return cornerUpdateRoutine; return cornerUpdateRoutine;
} }
void Blitter::blitToBuffer(const vk::Image *src, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch) void Blitter::copy(const vk::Image *src, uint8_t *dst, unsigned int dstPitch)
{ {
auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask); VkExtent3D extent = src->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
auto format = src->getFormat(aspect); size_t rowBytes = src->getFormat(VK_IMAGE_ASPECT_COLOR_BIT).bytes() * extent.width;
State state(format, format, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT, Options{ false, false }); unsigned int srcPitch = src->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
ASSERT(dstPitch >= rowBytes && srcPitch >= rowBytes && src->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0).height >= extent.height);
auto blitRoutine = getBlitRoutine(state); const uint8_t *s = (uint8_t *)src->getTexelPointer({ 0, 0, 0 }, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 });
if(!blitRoutine) uint8_t *d = dst;
{
return;
}
BlitData data = {
nullptr, // source
dst, // dest
src->rowPitchBytes(aspect, subresource.mipLevel), // sPitchB
bufferRowPitch, // dPitchB
src->slicePitchBytes(aspect, subresource.mipLevel), // sSliceB
bufferSlicePitch, // dSliceB
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0, // x0d
static_cast<int>(extent.width), // x1d
0, // y0d
static_cast<int>(extent.height), // y1d
0, // z0d
static_cast<int>(extent.depth), // z1d
static_cast<int>(extent.width), // sWidth
static_cast<int>(extent.height), // sHeight
static_cast<int>(extent.depth), // sDepth
false, // filter3D
};
VkImageSubresource srcSubres = {
subresource.aspectMask,
subresource.mipLevel,
subresource.baseArrayLayer
};
VkImageSubresourceRange srcSubresRange = {
subresource.aspectMask,
subresource.mipLevel,
1,
subresource.baseArrayLayer,
subresource.layerCount
};
uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
for(; srcSubres.arrayLayer <= lastLayer; srcSubres.arrayLayer++)
{
data.source = src->getTexelPointer({ 0, 0, 0 }, srcSubres);
ASSERT(data.source < src->end());
blitRoutine(&data);
}
}
void Blitter::blitFromBuffer(const vk::Image *dst, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *src, int bufferRowPitch, int bufferSlicePitch)
{
auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
auto format = dst->getFormat(aspect);
State state(format, format, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT, Options{ false, false });
auto blitRoutine = getBlitRoutine(state); for(uint32_t y = 0; y < extent.height; y++)
if(!blitRoutine)
{ {
return; memcpy(d, s, rowBytes);
}
BlitData data = {
src, // source
nullptr, // dest
bufferRowPitch, // sPitchB
dst->rowPitchBytes(aspect, subresource.mipLevel), // dPitchB
bufferSlicePitch, // sSliceB
dst->slicePitchBytes(aspect, subresource.mipLevel), // dSliceB
static_cast<float>(-offset.x), // x0
static_cast<float>(-offset.y), // y0
static_cast<float>(-offset.z), // z0
1.0f, // w
1.0f, // h
1.0f, // d
offset.x, // x0d
static_cast<int>(offset.x + extent.width), // x1d
offset.y, // y0d
static_cast<int>(offset.y + extent.height), // y1d
offset.z, // z0d
static_cast<int>(offset.z + extent.depth), // z1d
static_cast<int>(extent.width), // sWidth
static_cast<int>(extent.height), // sHeight;
static_cast<int>(extent.depth), // sDepth;
false, // filter3D
};
VkImageSubresource dstSubres = {
subresource.aspectMask,
subresource.mipLevel,
subresource.baseArrayLayer
};
VkImageSubresourceRange dstSubresRange = { s += srcPitch;
subresource.aspectMask, d += dstPitch;
subresource.mipLevel,
1,
subresource.baseArrayLayer,
subresource.layerCount
};
uint32_t lastLayer = dst->getLastLayerIndex(dstSubresRange);
for(; dstSubres.arrayLayer <= lastLayer; dstSubres.arrayLayer++)
{
data.dest = dst->getTexelPointer({ 0, 0, 0 }, dstSubres);
ASSERT(data.dest < dst->end());
blitRoutine(&data);
} }
} }
......
...@@ -144,8 +144,7 @@ public: ...@@ -144,8 +144,7 @@ public:
void clear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea = nullptr); void clear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea = nullptr);
void blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter); void blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter);
void blitToBuffer(const vk::Image *src, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch); void copy(const vk::Image *src, uint8_t *dst, unsigned int dstPitch);
void blitFromBuffer(const vk::Image *dst, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *src, int bufferRowPitch, int bufferSlicePitch);
void updateBorders(vk::Image *image, const VkImageSubresource &subresource); void updateBorders(vk::Image *image, const VkImageSubresource &subresource);
......
...@@ -970,7 +970,7 @@ public: ...@@ -970,7 +970,7 @@ public:
void play(vk::CommandBuffer::ExecutionState &executionState) override void play(vk::CommandBuffer::ExecutionState &executionState) override
{ {
srcImage->blit(dstImage, region, filter); srcImage->blitTo(dstImage, region, filter);
} }
std::string description() override { return "vkCmdBlitImage()"; } std::string description() override { return "vkCmdBlitImage()"; }
...@@ -994,7 +994,7 @@ public: ...@@ -994,7 +994,7 @@ public:
void play(vk::CommandBuffer::ExecutionState &executionState) override void play(vk::CommandBuffer::ExecutionState &executionState) override
{ {
srcImage->resolve(dstImage, region); srcImage->resolveTo(dstImage, region);
} }
std::string description() override { return "vkCmdBlitImage()"; } std::string description() override { return "vkCmdBlitImage()"; }
......
...@@ -886,9 +886,10 @@ const Image *Image::getSampledImage(const vk::Format &imageViewFormat) const ...@@ -886,9 +886,10 @@ const Image *Image::getSampledImage(const vk::Format &imageViewFormat) const
return (decompressedImage && isImageViewCompressed) ? decompressedImage : this; return (decompressedImage && isImageViewCompressed) ? decompressedImage : this;
} }
void Image::blit(Image *dstImage, const VkImageBlit &region, VkFilter filter) const void Image::blitTo(Image *dstImage, const VkImageBlit &region, VkFilter filter) const
{ {
device->getBlitter()->blit(this, dstImage, region, filter); device->getBlitter()->blit(this, dstImage, region, filter);
VkImageSubresourceRange subresourceRange = { VkImageSubresourceRange subresourceRange = {
region.dstSubresource.aspectMask, region.dstSubresource.aspectMask,
region.dstSubresource.mipLevel, region.dstSubresource.mipLevel,
...@@ -899,12 +900,12 @@ void Image::blit(Image *dstImage, const VkImageBlit &region, VkFilter filter) co ...@@ -899,12 +900,12 @@ void Image::blit(Image *dstImage, const VkImageBlit &region, VkFilter filter) co
dstImage->prepareForSampling(subresourceRange); dstImage->prepareForSampling(subresourceRange);
} }
void Image::blitToBuffer(VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch) const void Image::copyTo(uint8_t *dst, unsigned int dstPitch) const
{ {
device->getBlitter()->blitToBuffer(this, subresource, offset, extent, dst, bufferRowPitch, bufferSlicePitch); device->getBlitter()->copy(this, dst, dstPitch);
} }
void Image::resolve(Image *dstImage, const VkImageResolve &region) const void Image::resolveTo(Image *dstImage, const VkImageResolve &region) const
{ {
VkImageBlit blitRegion; VkImageBlit blitRegion;
......
...@@ -58,9 +58,9 @@ public: ...@@ -58,9 +58,9 @@ public:
void copyTo(Buffer *dstBuffer, const VkBufferImageCopy &region); void copyTo(Buffer *dstBuffer, const VkBufferImageCopy &region);
void copyFrom(Buffer *srcBuffer, const VkBufferImageCopy &region); void copyFrom(Buffer *srcBuffer, const VkBufferImageCopy &region);
void blit(Image *dstImage, const VkImageBlit &region, VkFilter filter) const; void blitTo(Image *dstImage, const VkImageBlit &region, VkFilter filter) const;
void blitToBuffer(VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch) const; void copyTo(uint8_t *dst, unsigned int dstPitch) const;
void resolve(Image *dstImage, const VkImageResolve &region) const; void resolveTo(Image *dstImage, const VkImageResolve &region) const;
void clear(const VkClearValue &clearValue, const vk::Format &viewFormat, const VkRect2D &renderArea, const VkImageSubresourceRange &subresourceRange); void clear(const VkClearValue &clearValue, const vk::Format &viewFormat, const VkRect2D &renderArea, const VkImageSubresourceRange &subresourceRange);
void clear(const VkClearColorValue &color, const VkImageSubresourceRange &subresourceRange); void clear(const VkClearColorValue &color, const VkImageSubresourceRange &subresourceRange);
void clear(const VkClearDepthStencilValue &color, const VkImageSubresourceRange &subresourceRange); void clear(const VkClearDepthStencilValue &color, const VkImageSubresourceRange &subresourceRange);
......
...@@ -40,16 +40,16 @@ std::vector<uint32_t> preprocessSpirv( ...@@ -40,16 +40,16 @@ std::vector<uint32_t> preprocessSpirv(
{ {
spvtools::Optimizer opt{ SPV_ENV_VULKAN_1_1 }; spvtools::Optimizer opt{ SPV_ENV_VULKAN_1_1 };
opt.SetMessageConsumer([](spv_message_level_t level, const char *, const spv_position_t &p, const char *m) { opt.SetMessageConsumer([](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
switch(level) switch(level)
{ {
case SPV_MSG_FATAL: sw::warn("SPIR-V FATAL: %d:%d %s\n", int(p.line), int(p.column), m); case SPV_MSG_FATAL: sw::warn("SPIR-V FATAL: %d:%d %s\n", int(position.line), int(position.column), message);
case SPV_MSG_INTERNAL_ERROR: sw::warn("SPIR-V INTERNAL_ERROR: %d:%d %s\n", int(p.line), int(p.column), m); case SPV_MSG_INTERNAL_ERROR: sw::warn("SPIR-V INTERNAL_ERROR: %d:%d %s\n", int(position.line), int(position.column), message);
case SPV_MSG_ERROR: sw::warn("SPIR-V ERROR: %d:%d %s\n", int(p.line), int(p.column), m); case SPV_MSG_ERROR: sw::warn("SPIR-V ERROR: %d:%d %s\n", int(position.line), int(position.column), message);
case SPV_MSG_WARNING: sw::warn("SPIR-V WARNING: %d:%d %s\n", int(p.line), int(p.column), m); case SPV_MSG_WARNING: sw::warn("SPIR-V WARNING: %d:%d %s\n", int(position.line), int(position.column), message);
case SPV_MSG_INFO: sw::trace("SPIR-V INFO: %d:%d %s\n", int(p.line), int(p.column), m); case SPV_MSG_INFO: sw::trace("SPIR-V INFO: %d:%d %s\n", int(position.line), int(position.column), message);
case SPV_MSG_DEBUG: sw::trace("SPIR-V DEBUG: %d:%d %s\n", int(p.line), int(p.column), m); case SPV_MSG_DEBUG: sw::trace("SPIR-V DEBUG: %d:%d %s\n", int(position.line), int(position.column), message);
default: sw::trace("SPIR-V MESSAGE: %d:%d %s\n", int(p.line), int(p.column), m); default: sw::trace("SPIR-V MESSAGE: %d:%d %s\n", int(position.line), int(position.column), message);
} }
}); });
......
...@@ -95,11 +95,7 @@ VkResult Win32SurfaceKHR::present(PresentImage *image) ...@@ -95,11 +95,7 @@ VkResult Win32SurfaceKHR::present(PresentImage *image)
return VK_ERROR_OUT_OF_DATE_KHR; return VK_ERROR_OUT_OF_DATE_KHR;
} }
VkImageSubresourceLayers subresourceLayers{}; image->getImage()->copyTo(reinterpret_cast<uint8_t *>(framebuffer), bitmapRowPitch);
subresourceLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceLayers.layerCount = 1;
image->getImage()->blitToBuffer(subresourceLayers, VkOffset3D{}, extent, reinterpret_cast<uint8_t *>(framebuffer), bitmapRowPitch, 0);
StretchBlt(windowContext, 0, 0, extent.width, extent.height, bitmapContext, 0, 0, extent.width, extent.height, SRCCOPY); StretchBlt(windowContext, 0, 0, extent.width, extent.height, bitmapContext, 0, 0, extent.width, extent.height, SRCCOPY);
......
...@@ -55,7 +55,7 @@ private: ...@@ -55,7 +55,7 @@ private:
VkExtent2D windowExtent = {}; VkExtent2D windowExtent = {};
HBITMAP bitmap = {}; HBITMAP bitmap = {};
int bitmapRowPitch = 0; unsigned int bitmapRowPitch = 0;
void *framebuffer = nullptr; void *framebuffer = nullptr;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment