ETC2 Image decompression and sampling
The ETC2 decoder already existed in SwiftShader, so this cl hooks it
up in vk::Image. In order to be transparent to the user, any time a
compressed image is created, another image is simultaneously created,
which will eventually contain the decompressed image.
Bug b/119620767
Tests: dEQP-VK.pipeline.sampler.view_type.2d.format.etc2_r8g8b8a1_unorm_block.*
Tests: dEQP-VK.pipeline.sampler.view_type.2d.format.etc2_r8g8b8a8_unorm_block.*
Tests: dEQP-VK.pipeline.sampler.view_type.2d.format.eac_r11g11_unorm_block.*
Change-Id: I8bfdccccd9cad30e5b707ba82aac2b581ec2a90e
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29428
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index 25c1a9a..e0566a1 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -341,24 +341,24 @@
VkOffset3D offset = {-1, -1, 0};
// TODO(b/129523279): Implement as 6 consecutive layers instead of separate pointers.
- mipmap.buffer[face] = imageView->getOffsetPointer(offset, aspect, level, face);
+ mipmap.buffer[face] = imageView->getOffsetPointer(offset, aspect, level, face, ImageView::SAMPLING);
}
}
else
{
VkOffset3D offset = {0, 0, 0};
- mipmap.buffer[0] = imageView->getOffsetPointer(offset, aspect, level, 0);
+ mipmap.buffer[0] = imageView->getOffsetPointer(offset, aspect, level, 0, ImageView::SAMPLING);
}
VkExtent3D extent = imageView->getMipLevelExtent(level);
- Format format = imageView->getFormat();
+ Format format = imageView->getFormat(ImageView::SAMPLING);
int layers = imageView->getSubresourceRange().layerCount;
// TODO(b/129523279): Untangle depth vs layers throughout the sampler
int width = extent.width;
int height = extent.height;
int depth = layers > 1 ? layers : extent.depth;
- int pitchP = imageView->rowPitchBytes(aspect, level) / format.bytes();
- int sliceP = (layers > 1 ? imageView->layerPitchBytes(aspect) : imageView->slicePitchBytes(aspect, level)) / format.bytes();
+ int pitchP = imageView->rowPitchBytes(aspect, level, ImageView::SAMPLING) / format.bytes();
+ int sliceP = (layers > 1 ? imageView->layerPitchBytes(aspect, ImageView::SAMPLING) : imageView->slicePitchBytes(aspect, level, ImageView::SAMPLING)) / format.bytes();
if(mipmapLevel == 0)
{
diff --git a/src/Vulkan/VkFormat.cpp b/src/Vulkan/VkFormat.cpp
index 8e40265..d1debf4 100644
--- a/src/Vulkan/VkFormat.cpp
+++ b/src/Vulkan/VkFormat.cpp
@@ -136,6 +136,9 @@
case VK_FORMAT_R8G8B8A8_SRGB:
case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
+ case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
return true;
default:
return false;
@@ -350,6 +353,35 @@
}
}
+VkFormat Format::getDecompressedFormat() const
+{
+ // Note: our ETC2 decoder decompresses the 64 bit RGB compressed texel data to B8G8R8
+ switch(format)
+ {
+ case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+ return VK_FORMAT_B8G8R8_UNORM;
+ case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+ return VK_FORMAT_B8G8R8_SRGB;
+ case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+ return VK_FORMAT_B8G8R8A8_UNORM;
+ case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+ return VK_FORMAT_B8G8R8A8_SRGB;
+ case VK_FORMAT_EAC_R11_UNORM_BLOCK:
+ return VK_FORMAT_R16_UNORM;
+ case VK_FORMAT_EAC_R11_SNORM_BLOCK:
+ return VK_FORMAT_R16_SNORM;
+ case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
+ return VK_FORMAT_R16G16_UNORM;
+ case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
+ return VK_FORMAT_R16G16_SNORM;
+ default:
+ UNIMPLEMENTED("format: %d", int(format));
+ return VK_FORMAT_UNDEFINED;
+ }
+}
+
VkFormat Format::compatibleFormat() const
{
// According to the Vulkan 1.1 Spec, 37.1.6. Format Compatibility Classes:
@@ -901,6 +933,8 @@
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ case VK_FORMAT_EAC_R11_UNORM_BLOCK:
+ case VK_FORMAT_EAC_R11_SNORM_BLOCK:
return 1;
case VK_FORMAT_R4G4_UNORM_PACK8:
case VK_FORMAT_R8G8_UNORM:
@@ -923,6 +957,8 @@
case VK_FORMAT_R64G64_UINT:
case VK_FORMAT_R64G64_SINT:
case VK_FORMAT_R64G64_SFLOAT:
+ case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
+ case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
return 2;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
case VK_FORMAT_B5G6R5_UNORM_PACK16:
@@ -956,6 +992,8 @@
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+ case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
return 3;
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
@@ -1008,6 +1046,10 @@
case VK_FORMAT_R64G64B64A64_UINT:
case VK_FORMAT_R64G64B64A64_SINT:
case VK_FORMAT_R64G64B64A64_SFLOAT:
+ 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:
return 4;
default:
UNIMPLEMENTED("Format: %d", int(format));
@@ -1092,6 +1134,11 @@
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+ case VK_FORMAT_EAC_R11_UNORM_BLOCK:
+ case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
return true;
case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_SSCALED:
@@ -1116,6 +1163,11 @@
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R64G64B64A64_SINT:
case VK_FORMAT_R64G64B64A64_SFLOAT:
+ case VK_FORMAT_EAC_R11_SNORM_BLOCK:
+ case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
return false;
case VK_FORMAT_R8_SNORM:
case VK_FORMAT_R8_USCALED:
@@ -1685,14 +1737,20 @@
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R8_UNORM:
- case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_UINT:
@@ -1722,9 +1780,12 @@
switch(format)
{
case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R8_SNORM:
case VK_FORMAT_R8G8_SNORM:
@@ -1742,7 +1803,10 @@
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
- case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R32_SINT:
case VK_FORMAT_R32_UINT:
@@ -1796,9 +1860,12 @@
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
@@ -1809,7 +1876,10 @@
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
return false;
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_UINT:
@@ -1846,10 +1916,16 @@
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R8G8B8A8_UINT:
case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_UINT:
@@ -1909,14 +1985,20 @@
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R8_UNORM:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_UINT:
@@ -1949,6 +2031,8 @@
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R8_SINT:
case VK_FORMAT_R8_UINT:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_UINT:
case VK_FORMAT_R16_SFLOAT:
@@ -1962,6 +2046,7 @@
case VK_FORMAT_R8G8_UINT:
case VK_FORMAT_R16G16_SINT:
case VK_FORMAT_R16G16_UINT:
+ case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16_UNORM:
case VK_FORMAT_R16G16_SFLOAT:
case VK_FORMAT_R32G32_SINT:
@@ -1971,12 +2056,15 @@
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ case VK_FORMAT_B8G8R8_UNORM:
+ case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R8G8B8A8_UINT:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16G16B16A16_SINT:
case VK_FORMAT_R16G16B16A16_UINT:
diff --git a/src/Vulkan/VkFormat.h b/src/Vulkan/VkFormat.h
index 24a3724..26b19e4 100644
--- a/src/Vulkan/VkFormat.h
+++ b/src/Vulkan/VkFormat.h
@@ -47,6 +47,7 @@
bool isCompatible(const Format& other) const;
bool isCompressed() const;
+ VkFormat getDecompressedFormat() const;
int blockWidth() const;
int blockHeight() const;
int bytesPerBlock() const;
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index a2784e6..166050c 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -17,6 +17,7 @@
#include "VkDevice.hpp"
#include "VkImage.hpp"
#include "Device/Blitter.hpp"
+#include "Device/ETC_Decoder.hpp"
#include <cstring>
namespace
@@ -36,6 +37,33 @@
if (!aspects) aspects |= VK_IMAGE_ASPECT_COLOR_BIT;
return aspects;
}
+
+ ETC_Decoder::InputType GetInputType(const vk::Format& format)
+ {
+ switch(format)
+ {
+ case VK_FORMAT_EAC_R11_UNORM_BLOCK:
+ return ETC_Decoder::ETC_R_UNSIGNED;
+ case VK_FORMAT_EAC_R11_SNORM_BLOCK:
+ return ETC_Decoder::ETC_R_SIGNED;
+ case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
+ return ETC_Decoder::ETC_RG_UNSIGNED;
+ case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
+ return ETC_Decoder::ETC_RG_SIGNED;
+ case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+ return ETC_Decoder::ETC_RGB;
+ case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+ return ETC_Decoder::ETC_RGB_PUNCHTHROUGH_ALPHA;
+ case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+ case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+ return ETC_Decoder::ETC_RGBA;
+ default:
+ UNIMPLEMENTED("format: %d", int(format));
+ return ETC_Decoder::ETC_RGBA;
+ }
+ }
}
namespace vk
@@ -53,15 +81,26 @@
tiling(pCreateInfo->pCreateInfo->tiling),
usage(pCreateInfo->pCreateInfo->usage)
{
+ if(format.isCompressed())
+ {
+ VkImageCreateInfo imageCreateInfo = *(pCreateInfo->pCreateInfo);
+ imageCreateInfo.format = format.getDecompressedFormat();
+ Image::CreateInfo createInfo = { &imageCreateInfo, pCreateInfo->device };
+ decompressedImage = new (mem) Image(&createInfo, nullptr);
+ }
}
void Image::destroy(const VkAllocationCallbacks* pAllocator)
{
+ if(decompressedImage)
+ {
+ vk::deallocate(decompressedImage, pAllocator);
+ }
}
size_t Image::ComputeRequiredAllocationSize(const Image::CreateInfo* pCreateInfo)
{
- return 0;
+ return Format(pCreateInfo->pCreateInfo->format).isCompressed() ? sizeof(Image) : 0;
}
const VkMemoryRequirements Image::getMemoryRequirements() const
@@ -69,7 +108,8 @@
VkMemoryRequirements memoryRequirements;
memoryRequirements.alignment = vk::REQUIRED_MEMORY_ALIGNMENT;
memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT;
- memoryRequirements.size = getStorageSize(GetAspects(format));
+ memoryRequirements.size = getStorageSize(GetAspects(format)) +
+ (decompressedImage ? decompressedImage->getStorageSize(GetAspects(decompressedImage->format)) : 0);
return memoryRequirements;
}
@@ -77,6 +117,11 @@
{
deviceMemory = Cast(pDeviceMemory);
memoryOffset = pMemoryOffset;
+ if(decompressedImage)
+ {
+ decompressedImage->deviceMemory = deviceMemory;
+ decompressedImage->memoryOffset = memoryOffset + getStorageSize(GetAspects(format));
+ }
}
void Image::getSubresourceLayout(const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) const
@@ -345,6 +390,12 @@
srcMemory += srcLayerSize;
dstMemory += dstLayerSize;
}
+
+ if(bufferIsSource && decompressedImage)
+ {
+ prepareForSampling({ region.imageSubresource.aspectMask, region.imageSubresource.mipLevel, 1,
+ region.imageSubresource.baseArrayLayer, region.imageSubresource.layerCount });
+ }
}
void Image::copyTo(VkBuffer dstBuffer, const VkBufferImageCopy& region)
@@ -631,6 +682,7 @@
{
if (aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT))
{
+ ASSERT(!format.isCompressed());
return arrayLayers * (getLayerSize(VK_IMAGE_ASPECT_DEPTH_BIT) + getLayerSize(VK_IMAGE_ASPECT_STENCIL_BIT));
}
return arrayLayers * getLayerSize(static_cast<VkImageAspectFlagBits>(aspectMask));
@@ -758,4 +810,53 @@
}
}
+void Image::prepareForSampling(const VkImageSubresourceRange& subresourceRange) const
+{
+ switch(format)
+ {
+ 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_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:
+ decodeETC2(subresourceRange);
+ break;
+ default:
+ break;
+ }
+}
+
+void Image::decodeETC2(const VkImageSubresourceRange& subresourceRange) const
+{
+ ASSERT(decompressedImage);
+
+ ETC_Decoder::InputType inputType = GetInputType(format);
+
+ uint32_t lastLayer = getLastLayerIndex(subresourceRange);
+ uint32_t lastMipLevel = getLastMipLevel(subresourceRange);
+
+ VkImageSubresourceLayers subresourceLayers = { subresourceRange.aspectMask, subresourceRange.baseMipLevel, subresourceRange.baseArrayLayer, 1 };
+ for(; subresourceLayers.baseArrayLayer <= lastLayer; subresourceLayers.baseArrayLayer++)
+ {
+ for(; subresourceLayers.mipLevel <= lastMipLevel; subresourceLayers.mipLevel++)
+ {
+ uint8_t* source = static_cast<uint8_t*>(getTexelPointer({ 0, 0, 0 }, subresourceLayers));
+ uint8_t* dest = static_cast<uint8_t*>(decompressedImage->getTexelPointer({ 0, 0, 0 }, subresourceLayers));
+
+ VkExtent3D mipLevelExtent = getMipLevelExtent(subresourceLayers.mipLevel);
+
+ int bytes = decompressedImage->format.bytes();
+ int pitchB = decompressedImage->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresourceLayers.mipLevel);
+
+ ETC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height,
+ mipLevelExtent.width, mipLevelExtent.height, pitchB, bytes, inputType);
+ }
+ }
+}
+
} // namespace vk
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index eff44b0..2090832 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -70,6 +70,9 @@
uint8_t* end() const;
VkDeviceSize getLayerSize(VkImageAspectFlagBits aspect) const;
+ void prepareForSampling(const VkImageSubresourceRange& subresourceRange) const;
+ const Image* getSampledImage() const { return decompressedImage ? decompressedImage : this; }
+
static Format GetFormat(const vk::Format& format, VkImageAspectFlagBits aspect);
private:
@@ -89,6 +92,7 @@
VkFormat getClearFormat() const;
void clear(void* pixelData, VkFormat pixelFormat, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D& renderArea);
int borderSize(VkImageAspectFlagBits aspect) const;
+ void decodeETC2(const VkImageSubresourceRange& subresourceRange) const;
const Device *const device = nullptr;
DeviceMemory* deviceMemory = nullptr;
@@ -102,6 +106,7 @@
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
VkImageUsageFlags usage = (VkImageUsageFlags)0;
+ Image* decompressedImage = nullptr;
};
static inline Image* Cast(VkImage object)
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index 23f79c8..9abefd6 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -171,7 +171,46 @@
image->copyTo(*(resolveAttachment->image), region);
}
-void *ImageView::getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const
+const Image* ImageView::getImage(Usage usage) const
+{
+ switch(usage)
+ {
+ case RAW:
+ return image;
+ case SAMPLING:
+ return image->getSampledImage();
+ default:
+ UNIMPLEMENTED("usage %d", int(usage));
+ return nullptr;
+ }
+}
+
+Format ImageView::getFormat(Usage usage) const
+{
+ return ((usage == RAW) || (getImage(usage) == image)) ? format : getImage(usage)->getFormat();
+}
+
+int ImageView::rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage) const
+{
+ return getImage(usage)->rowPitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel);
+}
+
+int ImageView::slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage) const
+{
+ return getImage(usage)->slicePitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel);
+}
+
+int ImageView::layerPitchBytes(VkImageAspectFlagBits aspect, Usage usage) const
+{
+ return static_cast<int>(getImage(usage)->getLayerSize(aspect));
+}
+
+VkExtent3D ImageView::getMipLevelExtent(uint32_t mipLevel) const
+{
+ return image->getMipLevelExtent(subresourceRange.baseMipLevel + mipLevel);
+}
+
+void *ImageView::getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer, Usage usage) const
{
ASSERT(mipLevel < subresourceRange.levelCount);
@@ -182,7 +221,7 @@
subresourceRange.baseArrayLayer + layer,
subresourceRange.layerCount
};
- return image->getTexelPointer(offset, imageSubresourceLayers);
+ return getImage(usage)->getTexelPointer(offset, imageSubresourceLayers);
}
}
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp
index fad7bfb..27d909c 100644
--- a/src/Vulkan/VkImageView.hpp
+++ b/src/Vulkan/VkImageView.hpp
@@ -28,6 +28,11 @@
class ImageView : public Object<ImageView, VkImageView>
{
public:
+ // Image usage:
+ // RAW: Use the base image as is
+ // SAMPLING: Image used for texture sampling
+ enum Usage { RAW, SAMPLING };
+
ImageView(const VkImageViewCreateInfo* pCreateInfo, void* mem);
~ImageView() = delete;
void destroy(const VkAllocationCallbacks* pAllocator);
@@ -39,17 +44,19 @@
void resolve(ImageView* resolveAttachment);
VkImageViewType getType() const { return viewType; }
- Format getFormat() const { return format; }
+ Format getFormat(Usage usage = RAW) const;
int getSampleCount() const { return image->getSampleCountFlagBits(); }
- int rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const { return image->rowPitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel); }
- int slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const { return image->slicePitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel); }
- int layerPitchBytes(VkImageAspectFlagBits aspect) const { return static_cast<int>(image->getLayerSize(aspect)); }
- VkExtent3D getMipLevelExtent(uint32_t mipLevel) const { return image->getMipLevelExtent(subresourceRange.baseMipLevel + mipLevel); }
+ int rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage = RAW) const;
+ int slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage = RAW) const;
+ int layerPitchBytes(VkImageAspectFlagBits aspect, Usage usage = RAW) const;
+ VkExtent3D getMipLevelExtent(uint32_t mipLevel) const;
- void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const;
+ void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer, Usage usage = RAW) const;
bool hasDepthAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; }
bool hasStencilAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; }
+ void prepareForSampling() const { image->prepareForSampling(subresourceRange); }
+
const VkComponentMapping &getComponentMapping() const { return components; }
const VkImageSubresourceRange &getSubresourceRange() const { return subresourceRange; }
size_t getImageSizeInBytes() const { return image->getMemoryRequirements().size; }
@@ -59,6 +66,7 @@
static std::atomic<uint32_t> nextID;
bool imageTypesMatch(VkImageType imageType) const;
+ const Image* getImage(Usage usage) const;
Image *const image = nullptr;
const VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;