add compressed format for metal (#19762)

This commit is contained in:
coulsonwang 2019-06-03 18:34:28 +08:00 committed by minggo
parent 10b2799051
commit 89ba801628
5 changed files with 112 additions and 67 deletions

View File

@ -1634,7 +1634,7 @@ bool Image::initWithETCData(const unsigned char * data, ssize_t dataLen)
if (Configuration::getInstance()->supportsETC())
{
//old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy.
#ifdef GL_ETC1_RGB8_OES
#if defined(GL_ETC1_RGB8_OES) || defined(CC_USE_METAL)
_pixelFormat = backend::PixelFormat::ETC;
_dataLen = dataLen - ETC_PKM_HEADER_SIZE;
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));

View File

@ -61,70 +61,55 @@ namespace {
typedef Texture2D::PixelFormatInfoMap::value_type PixelFormatInfoMapValue;
static const PixelFormatInfoMapValue TexturePixelFormatInfoTablesValue[] =
{
PixelFormatInfoMapValue(backend::PixelFormat::BGRA8888, Texture2D::PixelFormatInfo(GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE, 32, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGBA8888, Texture2D::PixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 32, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGBA4444, Texture2D::PixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGB5A1, Texture2D::PixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGB565, Texture2D::PixelFormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::RGB888, Texture2D::PixelFormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 24, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::A8, Texture2D::PixelFormatInfo(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 8, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::I8, Texture2D::PixelFormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 8, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::AI88, Texture2D::PixelFormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16, false, true)),
#ifndef CC_USE_METAL
//OpenGL only
#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC2, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC2A, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, true)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC4, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC4A, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, true)),
#endif
#else
//Metal && iOS
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC2, Texture2D::PixelFormatInfo(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC2A, Texture2D::PixelFormatInfo(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, true)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC4, Texture2D::PixelFormatInfo(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC4A, Texture2D::PixelFormatInfo(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, true)),
#endif
PixelFormatInfoMapValue(backend::PixelFormat::BGRA8888, Texture2D::PixelFormatInfo(32, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGBA8888, Texture2D::PixelFormatInfo(32, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGBA4444, Texture2D::PixelFormatInfo(16, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGB5A1, Texture2D::PixelFormatInfo(16, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::RGB565, Texture2D::PixelFormatInfo(16, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::RGB888, Texture2D::PixelFormatInfo(24, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::A8, Texture2D::PixelFormatInfo(8, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::I8, Texture2D::PixelFormatInfo(8, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::AI88, Texture2D::PixelFormatInfo(16, false, true)),
#if defined( GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC2, Texture2D::PixelFormatInfo(2, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC2A, Texture2D::PixelFormatInfo(2, true, true)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC4, Texture2D::PixelFormatInfo(4, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::PVRTC4A, Texture2D::PixelFormatInfo(4, true, true)),
#endif
#ifdef GL_ETC1_RGB8_OES
PixelFormatInfoMapValue(backend::PixelFormat::ETC, Texture2D::PixelFormatInfo(GL_ETC1_RGB8_OES, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
#if defined(GL_ETC1_RGB8_OES) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
PixelFormatInfoMapValue(backend::PixelFormat::ETC, Texture2D::PixelFormatInfo(4, true, false)),
#endif
#ifdef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
PixelFormatInfoMapValue(backend::PixelFormat::S3TC_DXT1, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
#if defined(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
PixelFormatInfoMapValue(backend::PixelFormat::S3TC_DXT1, Texture2D::PixelFormatInfo(4, true, false)),
#endif
#ifdef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
PixelFormatInfoMapValue(backend::PixelFormat::S3TC_DXT3, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
#if defined(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
PixelFormatInfoMapValue(backend::PixelFormat::S3TC_DXT3, Texture2D::PixelFormatInfo(8, true, false)),
#endif
#ifdef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
PixelFormatInfoMapValue(backend::PixelFormat::S3TC_DXT5, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
#if defined(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
PixelFormatInfoMapValue(backend::PixelFormat::S3TC_DXT5, Texture2D::PixelFormatInfo(8, true, false)),
#endif
#ifdef GL_ATC_RGB_AMD
PixelFormatInfoMapValue(backend::PixelFormat::ATC_RGB, Texture2D::PixelFormatInfo(GL_ATC_RGB_AMD,
0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::ATC_RGB, Texture2D::PixelFormatInfo(4, true, false)),
#endif
#ifdef GL_ATC_RGBA_EXPLICIT_ALPHA_AMD
PixelFormatInfoMapValue(backend::PixelFormat::ATC_EXPLICIT_ALPHA, Texture2D::PixelFormatInfo(GL_ATC_RGBA_EXPLICIT_ALPHA_AMD,
0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::ATC_EXPLICIT_ALPHA, Texture2D::PixelFormatInfo(8, true, false)),
#endif
#ifdef GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD
PixelFormatInfoMapValue(backend::PixelFormat::ATC_INTERPOLATED_ALPHA, Texture2D::PixelFormatInfo(GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD,
0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
PixelFormatInfoMapValue(backend::PixelFormat::ATC_INTERPOLATED_ALPHA, Texture2D::PixelFormatInfo(8, true, false)),
#endif
//metal formats
#ifdef CC_USE_METAL
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
PixelFormatInfoMapValue(backend::PixelFormat::MTL_ABGR4, Texture2D::PixelFormatInfo(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 16, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::MTL_B5G6R5, Texture2D::PixelFormatInfo(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 16, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::MTL_BGR5A1, Texture2D::PixelFormatInfo(0xFFFFFFFF,0xFFFFFFFF, 0xFFFFFFFF, 16, false, true)),
#endif
PixelFormatInfoMapValue(backend::PixelFormat::MTL_ABGR4, Texture2D::PixelFormatInfo(16, false, true)),
PixelFormatInfoMapValue(backend::PixelFormat::MTL_B5G6R5, Texture2D::PixelFormatInfo(16, false, false)),
PixelFormatInfoMapValue(backend::PixelFormat::MTL_BGR5A1, Texture2D::PixelFormatInfo(16, false, true)),
#endif
};
}

View File

@ -74,18 +74,12 @@ class CC_DLL Texture2D : public Ref
public:
struct PixelFormatInfo {
PixelFormatInfo(GLenum anInternalFormat, GLenum aFormat, GLenum aType, int aBpp, bool aCompressed, bool anAlpha)
: internalFormat(anInternalFormat)
, format(aFormat)
, type(aType)
, bpp(aBpp)
PixelFormatInfo(int aBpp, bool aCompressed, bool anAlpha)
: bpp(aBpp)
, compressed(aCompressed)
, alpha(anAlpha)
{}
GLenum internalFormat;
GLenum format;
GLenum type;
int bpp;
bool compressed;
bool alpha;

View File

@ -105,17 +105,77 @@ namespace
}
}
bool isCompressedFormat(PixelFormat textureFormat)
uint32_t getBytesPerRowETC(MTLPixelFormat pixleFormat, uint32_t width)
{
uint32_t bytesPerRow = 0;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
uint32_t bytesPerBlock = 0, blockWidth = 4;
switch (pixleFormat) {
case MTLPixelFormatETC2_RGB8:
case MTLPixelFormatETC2_RGB8A1:
case MTLPixelFormatEAC_R11Unorm:
bytesPerBlock = 8;
break;
case MTLPixelFormatEAC_RGBA8:
case MTLPixelFormatEAC_RG11Unorm:
bytesPerBlock = 16;
break;
default:
assert(false); //TODO coulsonwang
break;
}
auto blocksPerRow = (width + (blockWidth - 1)) / blockWidth;
bytesPerRow = blocksPerRow * bytesPerBlock;
#endif
return bytesPerRow;
}
uint32_t getBytesPerRowS3TC(MTLPixelFormat pixleFormat, uint32_t width)
{
uint32_t bytesPerRow = 0;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
uint32_t bytesPerBlock = 0, blockWidth = 4;
switch (pixleFormat) {
case MTLPixelFormatBC1_RGBA:
bytesPerBlock = 8;
break;
case MTLPixelFormatBC2_RGBA:
case MTLPixelFormatBC3_RGBA:
bytesPerBlock = 16;
break;
default:
break;
}
auto blocksPerRow = (width + (blockWidth - 1)) / blockWidth;
bytesPerRow = blocksPerRow * bytesPerBlock;
#endif
return bytesPerRow;
}
uint32_t getBytesPerRow(PixelFormat textureFormat, uint32_t width, uint32_t bitsPerElement)
{
MTLPixelFormat pixelFormat = Utils::toMTLPixelFormat(textureFormat);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
bool isCompressed = (pixelFormat >= MTLPixelFormatPVRTC_RGB_2BPP &&
pixelFormat <= MTLPixelFormatASTC_12x12_LDR);
#else
bool isCompressed = (pixelFormat >= MTLPixelFormatBC1_RGBA &&
pixelFormat <= MTLPixelFormatBC7_RGBAUnorm_sRGB);
#endif
return isCompressed;
uint32_t bytesPerRow = 0;
if(textureFormat >= PixelFormat::PVRTC2 &&
textureFormat <= PixelFormat::PVRTC4A)
{
bytesPerRow = 0;
}
else if (textureFormat == PixelFormat::ETC)
{
bytesPerRow = getBytesPerRowETC(pixelFormat, width);
}
else if(textureFormat >= PixelFormat::S3TC_DXT1 &&
textureFormat <= PixelFormat::S3TC_DXT5)
{
bytesPerRow = getBytesPerRowS3TC(pixelFormat, width);
}
else
{
bytesPerRow = width * bitsPerElement / 8;
}
return bytesPerRow;
}
}
@ -124,7 +184,6 @@ TextureMTL::TextureMTL(id<MTLDevice> mtlDevice, const TextureDescriptor& descrip
{
_mtlDevice = mtlDevice;
updateTextureDescriptor(descriptor);
_isCompressed = isCompressedFormat(descriptor.textureFormat);
}
TextureMTL::~TextureMTL()
@ -169,9 +228,7 @@ void TextureMTL::updateSubData(uint32_t xoffset, uint32_t yoffset, uint32_t widt
(uint32_t)(width * height),
_textureFormat, &convertedData);
//TODO coulsonwang, it seems that only PVRTC has such limitation.
//when pixel format is a compressed one, bytePerRow should be set to ZERO
int bytesPerRow = _isCompressed ? 0 : (width * _bitsPerElement / 8);
int bytesPerRow = getBytesPerRow(_textureFormat, width, _bitsPerElement);
[_mtlTexture replaceRegion:region
mipmapLevel:level

View File

@ -97,6 +97,15 @@ MTLPixelFormat Utils::toMTLPixelFormat(PixelFormat textureFormat)
return MTLPixelFormatPVRTC_RGBA_2BPP;
case PixelFormat::PVRTC2:
return MTLPixelFormatPVRTC_RGB_2BPP;
case TextureFormat::ETC1:
return MTLPixelFormatETC2_RGB8;
#else
case PixelFormat::S3TC_DXT1:
return MTLPixelFormatBC1_RGBA;
case PixelFormat::S3TC_DXT3:
return MTLPixelFormatBC2_RGBA;
case PixelFormat::S3TC_DXT5:
return MTLPixelFormatBC3_RGBA;
#endif
case PixelFormat::RGBA8888:
return MTLPixelFormatRGBA8Unorm;