Commit 979f940a by Alexis Hetu Committed by Alexis Hétu

Add support for compressed image copy

Copying compressed images is just a matter of taking block size into account and using a block as a single unit of measure, instead of using a texel. Bug b/119620767 Tests: dEQP-VK.api.copy_and_blit.core.image_to_image.all_formats.color.* Change-Id: Ie77defc197ac7abb09a8555b384093fd50be681b Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28048Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Presubmit-Ready: Alexis Hétu <sugoi@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 94f195b1
...@@ -318,6 +318,273 @@ bool Format::isFloatFormat() const ...@@ -318,6 +318,273 @@ bool Format::isFloatFormat() const
return false; return false;
} }
bool Format::isCompressed() const
{
switch(format)
{
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
return true;
default:
return false;
}
}
int Format::blockWidth() const
{
switch(format)
{
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
return 4;
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
return 5;
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
return 6;
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
return 8;
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
return 10;
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
return 12;
default:
return 1;
}
}
int Format::blockHeight() const
{
switch(format)
{
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
return 4;
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
return 5;
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
return 6;
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
return 8;
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
return 10;
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
return 12;
default:
return 1;
}
}
int Format::bytesPerBlock() const
{
switch(format)
{
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
return 8;
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
return 16;
default:
return bytes();
}
}
int Format::componentCount() const int Format::componentCount() const
{ {
switch(format) switch(format)
......
...@@ -45,6 +45,11 @@ public: ...@@ -45,6 +45,11 @@ public:
bool isSRGBwritable() const; bool isSRGBwritable() const;
bool isFloatFormat() const; bool isFloatFormat() const;
bool isCompressed() const;
int blockWidth() const;
int blockHeight() const;
int bytesPerBlock() const;
int componentCount() const; int componentCount() const;
bool isUnsignedComponent(int component) const; bool isUnsignedComponent(int component) const;
......
...@@ -141,8 +141,10 @@ void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion) ...@@ -141,8 +141,10 @@ void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion)
VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(pRegion.srcSubresource.aspectMask); VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(pRegion.srcSubresource.aspectMask);
VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(pRegion.dstSubresource.aspectMask); VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(pRegion.dstSubresource.aspectMask);
int srcBytesPerTexel = bytesPerTexel(srcAspect); Format srcFormat = getFormat(srcAspect);
ASSERT(srcBytesPerTexel == dst->bytesPerTexel(dstAspect)); Format dstFormat = dst->getFormat(dstAspect);
int srcBytesPerBlock = srcFormat.bytesPerBlock();
ASSERT(srcBytesPerBlock == dstFormat.bytesPerBlock());
const uint8_t* srcMem = static_cast<const uint8_t*>(getTexelPointer(pRegion.srcOffset, pRegion.srcSubresource)); const uint8_t* srcMem = static_cast<const uint8_t*>(getTexelPointer(pRegion.srcOffset, pRegion.srcSubresource));
uint8_t* dstMem = static_cast<uint8_t*>(dst->getTexelPointer(pRegion.dstOffset, pRegion.dstSubresource)); uint8_t* dstMem = static_cast<uint8_t*>(dst->getTexelPointer(pRegion.dstOffset, pRegion.dstSubresource));
...@@ -154,49 +156,58 @@ void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion) ...@@ -154,49 +156,58 @@ void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion)
VkExtent3D srcExtent = getMipLevelExtent(pRegion.srcSubresource.mipLevel); VkExtent3D srcExtent = getMipLevelExtent(pRegion.srcSubresource.mipLevel);
VkExtent3D dstExtent = dst->getMipLevelExtent(pRegion.dstSubresource.mipLevel); VkExtent3D dstExtent = dst->getMipLevelExtent(pRegion.dstSubresource.mipLevel);
VkExtent3D copyExtent = imageExtentInBlocks(pRegion.extent, srcAspect);
bool isSinglePlane = (pRegion.extent.depth == 1); bool isSinglePlane = (copyExtent.depth == 1);
bool isSingleLine = (pRegion.extent.height == 1) && isSinglePlane; bool isSingleLine = (copyExtent.height == 1) && isSinglePlane;
// In order to copy multiple lines using a single memcpy call, we // In order to copy multiple lines using a single memcpy call, we
// have to make sure that we need to copy the entire line and that // have to make sure that we need to copy the entire line and that
// both source and destination lines have the same length in bytes // both source and destination lines have the same length in bytes
bool isEntireLine = (pRegion.extent.width == srcExtent.width) && bool isEntireLine = (pRegion.extent.width == srcExtent.width) &&
(pRegion.extent.width == dstExtent.width) && (pRegion.extent.width == dstExtent.width) &&
(srcRowPitchBytes == dstRowPitchBytes); // For non compressed formats, blockWidth is 1. For compressed
// formats, rowPitchBytes returns the number of bytes for a row of
// blocks, so we have to divide by the block height, which means:
// srcRowPitchBytes / srcBlockWidth == dstRowPitchBytes / dstBlockWidth
// And, to avoid potential non exact integer division, for example if a
// block has 16 bytes and represents 5 lines, we change the equation to:
// srcRowPitchBytes * dstBlockWidth == dstRowPitchBytes * srcBlockWidth
((srcRowPitchBytes * dstFormat.blockWidth()) ==
(dstRowPitchBytes * srcFormat.blockWidth()));
// In order to copy multiple planes using a single memcpy call, we // In order to copy multiple planes using a single memcpy call, we
// have to make sure that we need to copy the entire plane and that // have to make sure that we need to copy the entire plane and that
// both source and destination planes have the same length in bytes // both source and destination planes have the same length in bytes
bool isEntirePlane = isEntireLine && bool isEntirePlane = isEntireLine &&
(pRegion.extent.height == srcExtent.height) && (copyExtent.height == srcExtent.height) &&
(pRegion.extent.height == dstExtent.height) && (copyExtent.height == dstExtent.height) &&
(srcSlicePitchBytes == dstSlicePitchBytes); (srcSlicePitchBytes == dstSlicePitchBytes);
if(isSingleLine) // Copy one line if(isSingleLine) // Copy one line
{ {
size_t copySize = pRegion.extent.width * srcBytesPerTexel; size_t copySize = copyExtent.width * srcBytesPerBlock;
ASSERT((srcMem + copySize) < end()); ASSERT((srcMem + copySize) < end());
ASSERT((dstMem + copySize) < dst->end()); ASSERT((dstMem + copySize) < dst->end());
memcpy(dstMem, srcMem, copySize); memcpy(dstMem, srcMem, copySize);
} }
else if(isEntireLine && isSinglePlane) // Copy one plane else if(isEntireLine && isSinglePlane) // Copy one plane
{ {
size_t copySize = pRegion.extent.height * srcRowPitchBytes; size_t copySize = copyExtent.height * srcRowPitchBytes;
ASSERT((srcMem + copySize) < end()); ASSERT((srcMem + copySize) < end());
ASSERT((dstMem + copySize) < dst->end()); ASSERT((dstMem + copySize) < dst->end());
memcpy(dstMem, srcMem, copySize); memcpy(dstMem, srcMem, copySize);
} }
else if(isEntirePlane) // Copy multiple planes else if(isEntirePlane) // Copy multiple planes
{ {
size_t copySize = pRegion.extent.depth * srcSlicePitchBytes; size_t copySize = copyExtent.depth * srcSlicePitchBytes;
ASSERT((srcMem + copySize) < end()); ASSERT((srcMem + copySize) < end());
ASSERT((dstMem + copySize) < dst->end()); ASSERT((dstMem + copySize) < dst->end());
memcpy(dstMem, srcMem, copySize); memcpy(dstMem, srcMem, copySize);
} }
else if(isEntireLine) // Copy plane by plane else if(isEntireLine) // Copy plane by plane
{ {
size_t copySize = pRegion.extent.height * srcRowPitchBytes; size_t copySize = copyExtent.height * srcRowPitchBytes;
for(uint32_t z = 0; z < pRegion.extent.depth; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes) for(uint32_t z = 0; z < copyExtent.depth; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes)
{ {
ASSERT((srcMem + copySize) < end()); ASSERT((srcMem + copySize) < end());
ASSERT((dstMem + copySize) < dst->end()); ASSERT((dstMem + copySize) < dst->end());
...@@ -205,11 +216,11 @@ void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion) ...@@ -205,11 +216,11 @@ void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion)
} }
else // Copy line by line else // Copy line by line
{ {
size_t copySize = pRegion.extent.width * srcBytesPerTexel; size_t copySize = copyExtent.width * srcBytesPerBlock;
for(uint32_t z = 0; z < pRegion.extent.depth; z++) for(uint32_t z = 0; z < copyExtent.depth; z++)
{ {
for(uint32_t y = 0; y < pRegion.extent.height; y++, dstMem += dstRowPitchBytes, srcMem += srcRowPitchBytes) for(uint32_t y = 0; y < copyExtent.height; y++, dstMem += dstRowPitchBytes, srcMem += srcRowPitchBytes)
{ {
ASSERT((srcMem + copySize) < end()); ASSERT((srcMem + copySize) < end());
ASSERT((dstMem + copySize) < dst->end()); ASSERT((dstMem + copySize) < dst->end());
...@@ -230,26 +241,26 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou ...@@ -230,26 +241,26 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou
VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask); VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask);
Format copyFormat = getFormat(aspect);
VkExtent3D mipLevelExtent = getMipLevelExtent(region.imageSubresource.mipLevel); VkExtent3D mipLevelExtent = getMipLevelExtent(region.imageSubresource.mipLevel);
int imageBytesPerTexel = bytesPerTexel(aspect); VkExtent3D imageExtent = imageExtentInBlocks(region.imageExtent, aspect);
VkExtent2D bufferExtent = bufferExtentInBlocks({ imageExtent.width, imageExtent.height }, region);
int imageBytesPerBlock = copyFormat.bytesPerBlock();
int imageRowPitchBytes = rowPitchBytes(aspect, region.imageSubresource.mipLevel); int imageRowPitchBytes = rowPitchBytes(aspect, region.imageSubresource.mipLevel);
int imageSlicePitchBytes = slicePitchBytes(aspect, region.imageSubresource.mipLevel); int imageSlicePitchBytes = slicePitchBytes(aspect, region.imageSubresource.mipLevel);
int bufferRowPitchBytes = ((region.bufferRowLength == 0) ? region.imageExtent.width : region.bufferRowLength) * int bufferRowPitchBytes = bufferExtent.width * imageBytesPerBlock;
imageBytesPerTexel; int bufferSlicePitchBytes = bufferExtent.height * bufferRowPitchBytes;
int bufferSlicePitchBytes = (((region.bufferImageHeight == 0) || (region.bufferRowLength == 0))) ?
region.imageExtent.height * bufferRowPitchBytes :
(region.bufferImageHeight * region.bufferRowLength) * imageBytesPerTexel;
int srcSlicePitchBytes = bufferIsSource ? bufferSlicePitchBytes : imageSlicePitchBytes; int srcSlicePitchBytes = bufferIsSource ? bufferSlicePitchBytes : imageSlicePitchBytes;
int dstSlicePitchBytes = bufferIsSource ? imageSlicePitchBytes : bufferSlicePitchBytes; int dstSlicePitchBytes = bufferIsSource ? imageSlicePitchBytes : bufferSlicePitchBytes;
int srcRowPitchBytes = bufferIsSource ? bufferRowPitchBytes : imageRowPitchBytes; int srcRowPitchBytes = bufferIsSource ? bufferRowPitchBytes : imageRowPitchBytes;
int dstRowPitchBytes = bufferIsSource ? imageRowPitchBytes : bufferRowPitchBytes; int dstRowPitchBytes = bufferIsSource ? imageRowPitchBytes : bufferRowPitchBytes;
bool isSinglePlane = (region.imageExtent.depth == 1); bool isSinglePlane = (imageExtent.depth == 1);
bool isSingleLine = (region.imageExtent.height == 1) && isSinglePlane; bool isSingleLine = (imageExtent.height == 1) && isSinglePlane;
bool isEntireLine = (region.imageExtent.width == mipLevelExtent.width) && bool isEntireLine = (imageExtent.width == mipLevelExtent.width) &&
(imageRowPitchBytes == bufferRowPitchBytes); (imageRowPitchBytes == bufferRowPitchBytes);
bool isEntirePlane = isEntireLine && (region.imageExtent.height == mipLevelExtent.height) && bool isEntirePlane = isEntireLine && (imageExtent.height == mipLevelExtent.height) &&
(imageSlicePitchBytes == bufferSlicePitchBytes); (imageSlicePitchBytes == bufferSlicePitchBytes);
Buffer* buffer = Cast(buf); Buffer* buffer = Cast(buf);
...@@ -262,28 +273,28 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou ...@@ -262,28 +273,28 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou
VkDeviceSize bufferLayerSize = 0; VkDeviceSize bufferLayerSize = 0;
if(isSingleLine) if(isSingleLine)
{ {
copySize = region.imageExtent.width * imageBytesPerTexel; copySize = imageExtent.width * imageBytesPerBlock;
bufferLayerSize = copySize; bufferLayerSize = copySize;
} }
else if(isEntireLine && isSinglePlane) else if(isEntireLine && isSinglePlane)
{ {
copySize = region.imageExtent.height * imageRowPitchBytes; copySize = imageExtent.height * imageRowPitchBytes;
bufferLayerSize = copySize; bufferLayerSize = copySize;
} }
else if(isEntirePlane) else if(isEntirePlane)
{ {
copySize = region.imageExtent.depth * imageSlicePitchBytes; // Copy multiple planes copySize = imageExtent.depth * imageSlicePitchBytes; // Copy multiple planes
bufferLayerSize = copySize; bufferLayerSize = copySize;
} }
else if(isEntireLine) // Copy plane by plane else if(isEntireLine) // Copy plane by plane
{ {
copySize = region.imageExtent.height * imageRowPitchBytes; copySize = imageExtent.height * imageRowPitchBytes;
bufferLayerSize = copySize * region.imageExtent.depth; bufferLayerSize = copySize * imageExtent.depth;
} }
else // Copy line by line else // Copy line by line
{ {
copySize = region.imageExtent.width * imageBytesPerTexel; copySize = imageExtent.width * imageBytesPerBlock;
bufferLayerSize = copySize * region.imageExtent.depth * region.imageExtent.height; bufferLayerSize = copySize * imageExtent.depth * imageExtent.height;
} }
VkDeviceSize imageLayerSize = getLayerSize(aspect); VkDeviceSize imageLayerSize = getLayerSize(aspect);
...@@ -302,7 +313,7 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou ...@@ -302,7 +313,7 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou
{ {
uint8_t* srcPlaneMemory = srcMemory; uint8_t* srcPlaneMemory = srcMemory;
uint8_t* dstPlaneMemory = dstMemory; uint8_t* dstPlaneMemory = dstMemory;
for(uint32_t z = 0; z < region.imageExtent.depth; z++) for(uint32_t z = 0; z < imageExtent.depth; z++)
{ {
ASSERT(((bufferIsSource ? dstPlaneMemory : srcPlaneMemory) + copySize) < end()); ASSERT(((bufferIsSource ? dstPlaneMemory : srcPlaneMemory) + copySize) < end());
ASSERT(((bufferIsSource ? srcPlaneMemory : dstPlaneMemory) + copySize) < buffer->end()); ASSERT(((bufferIsSource ? srcPlaneMemory : dstPlaneMemory) + copySize) < buffer->end());
...@@ -315,11 +326,11 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou ...@@ -315,11 +326,11 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou
{ {
uint8_t* srcLayerMemory = srcMemory; uint8_t* srcLayerMemory = srcMemory;
uint8_t* dstLayerMemory = dstMemory; uint8_t* dstLayerMemory = dstMemory;
for(uint32_t z = 0; z < region.imageExtent.depth; z++) for(uint32_t z = 0; z < imageExtent.depth; z++)
{ {
uint8_t* srcPlaneMemory = srcLayerMemory; uint8_t* srcPlaneMemory = srcLayerMemory;
uint8_t* dstPlaneMemory = dstLayerMemory; uint8_t* dstPlaneMemory = dstLayerMemory;
for(uint32_t y = 0; y < region.imageExtent.height; y++) for(uint32_t y = 0; y < imageExtent.height; y++)
{ {
ASSERT(((bufferIsSource ? dstPlaneMemory : srcPlaneMemory) + copySize) < end()); ASSERT(((bufferIsSource ? dstPlaneMemory : srcPlaneMemory) + copySize) < end());
ASSERT(((bufferIsSource ? srcPlaneMemory : dstPlaneMemory) + copySize) < buffer->end()); ASSERT(((bufferIsSource ? srcPlaneMemory : dstPlaneMemory) + copySize) < buffer->end());
...@@ -354,12 +365,79 @@ void* Image::getTexelPointer(const VkOffset3D& offset, const VkImageSubresourceL ...@@ -354,12 +365,79 @@ void* Image::getTexelPointer(const VkOffset3D& offset, const VkImageSubresourceL
getMemoryOffset(aspect, subresource.mipLevel, subresource.baseArrayLayer)); getMemoryOffset(aspect, subresource.mipLevel, subresource.baseArrayLayer));
} }
VkExtent3D Image::imageExtentInBlocks(const VkExtent3D& extent, VkImageAspectFlagBits aspect) const
{
VkExtent3D adjustedExtent = extent;
Format usedFormat = getFormat(aspect);
if(usedFormat.isCompressed())
{
// When using a compressed format, we use the block as the base unit, instead of the texel
int blockWidth = usedFormat.blockWidth();
int blockHeight = usedFormat.blockHeight();
ASSERT(((extent.width % blockWidth) == 0) && ((extent.height % blockHeight) == 0)); // We can't offset within a block
adjustedExtent.width /= blockWidth;
adjustedExtent.height /= blockHeight;
}
return adjustedExtent;
}
VkOffset3D Image::imageOffsetInBlocks(const VkOffset3D& offset, VkImageAspectFlagBits aspect) const
{
VkOffset3D adjustedOffset = offset;
Format usedFormat = getFormat(aspect);
if(usedFormat.isCompressed())
{
// When using a compressed format, we use the block as the base unit, instead of the texel
int blockWidth = usedFormat.blockWidth();
int blockHeight = usedFormat.blockHeight();
ASSERT(((offset.x % blockWidth) == 0) && ((offset.y % blockHeight) == 0)); // We can't offset within a block
adjustedOffset.x /= blockWidth;
adjustedOffset.y /= blockHeight;
}
return adjustedOffset;
}
VkExtent2D Image::bufferExtentInBlocks(const VkExtent2D& extent, const VkBufferImageCopy& region) const
{
VkExtent2D adjustedExtent = extent;
VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask);
Format usedFormat = getFormat(aspect);
if(region.bufferRowLength != 0)
{
adjustedExtent.width = region.bufferRowLength;
if(usedFormat.isCompressed())
{
int blockWidth = usedFormat.blockWidth();
ASSERT((adjustedExtent.width % blockWidth) == 0);
adjustedExtent.width /= blockWidth;
}
}
if(region.bufferImageHeight != 0)
{
adjustedExtent.height = region.bufferImageHeight;
if(usedFormat.isCompressed())
{
int blockHeight = usedFormat.blockHeight();
ASSERT((adjustedExtent.height % blockHeight) == 0);
adjustedExtent.height /= blockHeight;
}
}
return adjustedExtent;
}
VkDeviceSize Image::texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const VkDeviceSize Image::texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const
{ {
VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask); VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
return offset.z * slicePitchBytes(aspect, subresource.mipLevel) + VkOffset3D adjustedOffset = imageOffsetInBlocks(offset, aspect);
(offset.y + (isCube() ? 1 : 0)) * rowPitchBytes(aspect, subresource.mipLevel) + return adjustedOffset.z * slicePitchBytes(aspect, subresource.mipLevel) +
(offset.x + (isCube() ? 1 : 0)) * bytesPerTexel(aspect); (adjustedOffset.y + (isCube() ? 1 : 0)) * rowPitchBytes(aspect, subresource.mipLevel) +
(adjustedOffset.x + (isCube() ? 1 : 0)) * getFormat(aspect).bytesPerBlock();
} }
VkExtent3D Image::getMipLevelExtent(uint32_t mipLevel) const VkExtent3D Image::getMipLevelExtent(uint32_t mipLevel) const
......
...@@ -76,6 +76,9 @@ private: ...@@ -76,6 +76,9 @@ private:
VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const; VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const;
VkDeviceSize texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const; VkDeviceSize texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const;
VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect) const; VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect) const;
VkExtent3D imageExtentInBlocks(const VkExtent3D& extent, VkImageAspectFlagBits aspect) const;
VkOffset3D imageOffsetInBlocks(const VkOffset3D& offset, VkImageAspectFlagBits aspect) const;
VkExtent2D bufferExtentInBlocks(const VkExtent2D& extent, const VkBufferImageCopy& region) const;
int bytesPerTexel(VkImageAspectFlagBits flags) const; int bytesPerTexel(VkImageAspectFlagBits flags) const;
VkFormat getClearFormat() const; VkFormat getClearFormat() const;
void clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, const VkRect2D& renderArea); void clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, const VkRect2D& renderArea);
......
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