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()) if (Configuration::getInstance()->supportsETC())
{ {
//old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy. //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; _pixelFormat = backend::PixelFormat::ETC;
_dataLen = dataLen - ETC_PKM_HEADER_SIZE; _dataLen = dataLen - ETC_PKM_HEADER_SIZE;
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char))); _data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));

View File

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

View File

@ -74,18 +74,12 @@ class CC_DLL Texture2D : public Ref
public: public:
struct PixelFormatInfo { struct PixelFormatInfo {
PixelFormatInfo(GLenum anInternalFormat, GLenum aFormat, GLenum aType, int aBpp, bool aCompressed, bool anAlpha) PixelFormatInfo(int aBpp, bool aCompressed, bool anAlpha)
: internalFormat(anInternalFormat) : bpp(aBpp)
, format(aFormat)
, type(aType)
, bpp(aBpp)
, compressed(aCompressed) , compressed(aCompressed)
, alpha(anAlpha) , alpha(anAlpha)
{} {}
GLenum internalFormat;
GLenum format;
GLenum type;
int bpp; int bpp;
bool compressed; bool compressed;
bool alpha; 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); MTLPixelFormat pixelFormat = Utils::toMTLPixelFormat(textureFormat);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) uint32_t bytesPerRow = 0;
bool isCompressed = (pixelFormat >= MTLPixelFormatPVRTC_RGB_2BPP &&
pixelFormat <= MTLPixelFormatASTC_12x12_LDR); if(textureFormat >= PixelFormat::PVRTC2 &&
#else textureFormat <= PixelFormat::PVRTC4A)
bool isCompressed = (pixelFormat >= MTLPixelFormatBC1_RGBA && {
pixelFormat <= MTLPixelFormatBC7_RGBAUnorm_sRGB); bytesPerRow = 0;
#endif }
return isCompressed; 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; _mtlDevice = mtlDevice;
updateTextureDescriptor(descriptor); updateTextureDescriptor(descriptor);
_isCompressed = isCompressedFormat(descriptor.textureFormat);
} }
TextureMTL::~TextureMTL() TextureMTL::~TextureMTL()
@ -169,9 +228,7 @@ void TextureMTL::updateSubData(uint32_t xoffset, uint32_t yoffset, uint32_t widt
(uint32_t)(width * height), (uint32_t)(width * height),
_textureFormat, &convertedData); _textureFormat, &convertedData);
//TODO coulsonwang, it seems that only PVRTC has such limitation. int bytesPerRow = getBytesPerRow(_textureFormat, width, _bitsPerElement);
//when pixel format is a compressed one, bytePerRow should be set to ZERO
int bytesPerRow = _isCompressed ? 0 : (width * _bitsPerElement / 8);
[_mtlTexture replaceRegion:region [_mtlTexture replaceRegion:region
mipmapLevel:level mipmapLevel:level

View File

@ -97,6 +97,15 @@ MTLPixelFormat Utils::toMTLPixelFormat(PixelFormat textureFormat)
return MTLPixelFormatPVRTC_RGBA_2BPP; return MTLPixelFormatPVRTC_RGBA_2BPP;
case PixelFormat::PVRTC2: case PixelFormat::PVRTC2:
return MTLPixelFormatPVRTC_RGB_2BPP; 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 #endif
case PixelFormat::RGBA8888: case PixelFormat::RGBA8888:
return MTLPixelFormatRGBA8Unorm; return MTLPixelFormatRGBA8Unorm;