Commit ac873347 by Alexis Hetu Committed by Alexis Hétu

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: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com>
parent bb12b0e4
......@@ -1547,7 +1547,7 @@ namespace sw
return blitRoutine;
}
void Blitter::blit(vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter)
void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter)
{
if(dst->getFormat() == VK_FORMAT_UNDEFINED)
{
......
......@@ -106,7 +106,7 @@ namespace sw
void clear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea = nullptr);
void blit(vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter);
void blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter);
private:
bool fastClear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea);
......
......@@ -26,11 +26,11 @@ namespace
return (value < -128) ? -128 : ((value > 127) ? 127 : value);
}
inline int clampEAC(int value, bool isSigned)
inline short clampEAC(short value, bool isSigned)
{
int min = isSigned ? -1023 : 0;
int max = isSigned ? 1023 : 2047;
return (value < min) ? min : ((value > max) ? max : value);
short min = isSigned ? -1023 : 0;
short max = isSigned ? 1023 : 2047;
return (value < min) ? min : ((value > max) ? max : value) << 5;
}
struct bgra8
......@@ -95,7 +95,7 @@ namespace
{
for(int j = 0; j < 4 && (y + j) < h; j++)
{
int* sDst = reinterpret_cast<int*>(dest);
short* sDst = reinterpret_cast<short*>(dest);
for(int i = 0; i < 4 && (x + i) < w; i++)
{
for(int c = nbChannels - 1; c >= 0; c--)
......
......@@ -55,7 +55,7 @@ SpirvShader::ImageSampler *SpirvShader::getImageSampler(uint32_t inst, const vk:
Sampler samplerState = {};
samplerState.textureType = convertTextureType(imageView->getType());
samplerState.textureFormat = imageView->getFormat();
samplerState.textureFormat = imageView->getFormat(vk::ImageView::SAMPLING);
samplerState.textureFilter = convertFilterMode(sampler);
samplerState.border = sampler->borderColor;
......
......@@ -341,24 +341,24 @@ void DescriptorSetLayout::WriteDescriptorSet(DescriptorSet *dstSet, VkDescriptor
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)
{
......
......@@ -136,6 +136,9 @@ bool Format::isSRGBformat() const
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 @@ bool Format::isCompressed() const
}
}
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 @@ int Format::componentCount() const
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 @@ int Format::componentCount() const
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 @@ int Format::componentCount() const
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 @@ int Format::componentCount() const
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 @@ bool Format::isUnsignedComponent(int component) const
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 @@ bool Format::isUnsignedComponent(int component) const
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 @@ bool Format::has16bitTextureFormat() const
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 @@ bool Format::has8bitTextureComponents() const
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 @@ bool Format::has8bitTextureComponents() const
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 @@ bool Format::has16bitTextureComponents() const
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 @@ bool Format::has16bitTextureComponents() const
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 @@ bool Format::has32bitIntegerTextureComponents() const
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 @@ bool Format::hasYuvFormat() const
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 @@ bool Format::isRGBComponent(int component) const
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 @@ bool Format::isRGBComponent(int component) const
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 @@ bool Format::isRGBComponent(int component) const
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:
......
......@@ -47,6 +47,7 @@ public:
bool isCompatible(const Format& other) const;
bool isCompressed() const;
VkFormat getDecompressedFormat() const;
int blockWidth() const;
int blockHeight() const;
int bytesPerBlock() const;
......
......@@ -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 @@ namespace
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 @@ Image::Image(const Image::CreateInfo* pCreateInfo, void* mem) :
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 @@ const VkMemoryRequirements Image::getMemoryRequirements() const
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 @@ void Image::bind(VkDeviceMemory pDeviceMemory, VkDeviceSize pMemoryOffset)
{
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 @@ void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSou
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 @@ VkDeviceSize Image::getStorageSize(VkImageAspectFlags aspectMask) const
{
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::clear(const VkClearValue& clearValue, const vk::Format& viewFormat,
}
}
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
......@@ -70,6 +70,9 @@ public:
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 @@ private:
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 @@ private:
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)
......
......@@ -171,7 +171,46 @@ void ImageView::resolve(ImageView* resolveAttachment)
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 @@ void *ImageView::getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBit
subresourceRange.baseArrayLayer + layer,
subresourceRange.layerCount
};
return image->getTexelPointer(offset, imageSubresourceLayers);
return getImage(usage)->getTexelPointer(offset, imageSubresourceLayers);
}
}
......@@ -28,6 +28,11 @@ namespace vk
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 @@ public:
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 @@ private:
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;
......
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