2020-07-31 11:31:32 +08:00

371 lines
11 KiB
C++

//===============================================================================
// Copyright (c) 2007-2018 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2004-2006 ATI Technologies Inc.
//===============================================================================
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
// File Name: Codec_ETC2.cpp
// Description: implementation of the CCodec_ETC2 class
//
#include "Codec_ETC2.h"
#pragma warning( push )
#pragma warning(disable:4244)
using namespace CMP;
bool g_alphaTableInitialized = false;
//////////////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////////////
void CCodec_ETC2::setupAlphaTable()
{
if (!g_alphaTableInitialized)
{
#ifdef USE_ETCPACK
setupAlphaTableAndValtab();
#else
cmp_setupAlphaTable();
#endif
g_alphaTableInitialized = true;
}
}
CCodec_ETC2::CCodec_ETC2(CodecType codecType) :
CCodec_Block_4x4(codecType)
{
#ifdef USE_ETCPACK
readCompressParams();
switch (codecType)
{
case CT_ETC2_RGB:
case CT_ETC2_SRGB:
format = ETC2PACKAGE_RGB_NO_MIPMAPS;
break;
case CT_ETC2_RGBA1:
case CT_ETC2_SRGBA1:
setupAlphaTable();
format = ETC2PACKAGE_RGBA1_NO_MIPMAPS;
break;
case CT_ETC2_RGBA:
case CT_ETC2_SRGBA:
setupAlphaTable();
format = ETC2PACKAGE_RGBA_NO_MIPMAPS;
break;
default:
format = ETC2PACKAGE_RGB_NO_MIPMAPS;
break;
}
#else
switch (codecType)
{
case CT_ETC2_RGBA1:
case CT_ETC2_SRGBA1:
case CT_ETC2_RGBA:
case CT_ETC2_SRGBA:
setupAlphaTable();
break;
}
#endif
}
CCodec_ETC2::~CCodec_ETC2()
{
}
//=============
// ETC2 RGB
//=============
CodecError CCodec_ETC2::CompressRGBBlock(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2])
{
Color888_t srcRGB[4][4];
for(int y = 0; y < 4; y++)
{
for(DWORD x = 0; x < 4; x++)
{
srcRGB[x][y].red = rgbBlock[(x*16) + (y*4) + RGBA8888_CHANNEL_R];
srcRGB[x][y].green = rgbBlock[(x*16) + (y*4) + RGBA8888_CHANNEL_G];
srcRGB[x][y].blue = rgbBlock[(x*16) + (y*4) + RGBA8888_CHANNEL_B];
}
}
unsigned int uiCompressedBlockHi, uiCompressedBlockLo;
unsigned char tmp[4 * 4 * 3]; // Decompressed image
#ifdef USE_ETCPACK
if (m_fast)
{
compressBlockETC2FastPerceptual((uint8 *)&srcRGB, (uint8 *)tmp, 4, 4, 0, 0, uiCompressedBlockHi, uiCompressedBlockLo);
}
else
compressBlockETC2ExhaustivePerceptual((uint8 *)&srcRGB, (uint8 *)tmp, 4, 4, 0, 0, uiCompressedBlockHi, uiCompressedBlockLo);
#else
cmp_compressBlockETC2FastPerceptual((uint8 *)&srcRGB, (uint8 *)tmp, uiCompressedBlockHi, uiCompressedBlockLo);
#endif
compressedBlock[0] = SWIZZLE_DWORD(uiCompressedBlockHi); // Required format for GPU
compressedBlock[1] = SWIZZLE_DWORD(uiCompressedBlockLo); // Required format for GPU
return CE_OK;
}
void CCodec_ETC2::DecompressRGBBlock(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2])
{
unsigned int uiCompressedBlockHi = SWIZZLE_DWORD(compressedBlock[0]);
unsigned int uiCompressedBlockLo = SWIZZLE_DWORD(compressedBlock[1]);
#ifdef USE_ETCPACK
Color888_t destRGB[4][4];
decompressBlockETC2(uiCompressedBlockHi, uiCompressedBlockLo, (uint8*)destRGB, 4, 4, 0, 0);
for(DWORD y = 0; y < 4; y++)
{
for(DWORD x = 0; x < 4; x++)
{
rgbBlock[(x*16) + (y*4) + RGBA8888_CHANNEL_R] = destRGB[x][y].red;
rgbBlock[(x*16) + (y*4) + RGBA8888_CHANNEL_G] = destRGB[x][y].green;
rgbBlock[(x*16) + (y*4) + RGBA8888_CHANNEL_B] = destRGB[x][y].blue;
}
}
#else
union
{
CMP_DWORD cmp[2];
uint64 block;
}data;
union
{
Color888_t rgb;
uint32 blockRGBA;
} pixels;
data.cmp[0] = uiCompressedBlockLo;
data.cmp[1] = uiCompressedBlockHi;
CMP_BYTE pixelpos;
for (uint32 y = 0; y < 4; y++)
for (uint32 x = 0; x < 4; x++)
{
cmp_decompressETC2Pixel(data.block,(uint32 &)pixels.rgb, x, y);
pixelpos = (y * 16) + (x * 4);
rgbBlock[pixelpos + RGBA8888_CHANNEL_R] = pixels.rgb.red;
rgbBlock[pixelpos + RGBA8888_CHANNEL_G] = pixels.rgb.green;
rgbBlock[pixelpos + RGBA8888_CHANNEL_B] = pixels.rgb.blue;
}
#endif
}
//=============
// ETC2 RGBA
//=============
CodecError CCodec_ETC2::CompressRGBABlock(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4])
{
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
CMP_BYTE ii = 0;
for (DWORD y = 0; y < 4; y++)
{
for (DWORD x = 0; x < 4; x++)
{
alphaBlock[ii++] = rgbaBlock[(x * 4) + (y * 16) + RGBA8888_CHANNEL_A];
}
}
union
{
uint8 alphadata[8];
CMP_DWORD CompressedAlphaBlock[2];
} data;
#ifdef USE_ETCPACK
if (m_fast)
compressBlockAlphaFast(alphaBlock, 0, 0, 4, 4, data.alphadata);
else
compressBlockAlphaSlow(alphaBlock, 0, 0, 4, 4, data.alphadata);
#else
cmp_compressBlockAlphaFast(alphaBlock, data.alphadata);
#endif
compressedBlock[0] = data.CompressedAlphaBlock[0];
compressedBlock[1] = data.CompressedAlphaBlock[1];
return CompressRGBBlock(rgbaBlock, &compressedBlock[ATC_OFFSET_RGB]);
}
void CCodec_ETC2::DecompressRGBABlock(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4])
{
union
{
uint8 alphadata[8];
CMP_DWORD CompressedAlphaBlock[2];
} data;
uint8_t alphaimg[BLOCK_SIZE_4X4];
data.CompressedAlphaBlock[0] = compressedBlock[0];
data.CompressedAlphaBlock[1] = compressedBlock[1];
#ifdef USE_ETCPACK
Color888_t destRGB[4][4];
decompressBlockAlpha(data.alphadata, alphaimg, 4, 4, 0, 0);
unsigned int uiCompressedBlockHi = SWIZZLE_DWORD(compressedBlock[2]);
unsigned int uiCompressedBlockLo = SWIZZLE_DWORD(compressedBlock[3]);
decompressBlockETC2(uiCompressedBlockHi, uiCompressedBlockLo, (uint8*)destRGB, 4, 4, 0, 0);
CMP_BYTE ii = 0;
for (CMP_BYTE y = 0; y < 4; y++)
{
for (CMP_BYTE x = 0; x < 4; x++)
{
rgbaBlock[(x * 16) + (y * 4) + RGBA8888_CHANNEL_R] = destRGB[x][y].red;
rgbaBlock[(x * 16) + (y * 4) + RGBA8888_CHANNEL_G] = destRGB[x][y].green;
rgbaBlock[(x * 16) + (y * 4) + RGBA8888_CHANNEL_B] = destRGB[x][y].blue;
rgbaBlock[(x * 4) + (y * 16) + RGBA8888_CHANNEL_A] = alphaimg[ii];
ii++;
}
}
#else
cmp_decompressRGBABlockAlpha(data.alphadata, alphaimg);
//cmp_decompressBlockETC2c(uiCompressedBlockHi, uiCompressedBlockLo, (uint8*)destRGB);
DecompressRGBBlock(rgbaBlock, &compressedBlock[2]);
CMP_BYTE ii = 0;
for (CMP_BYTE y = 0; y < 4; y++)
{
for (CMP_BYTE x = 0; x < 4; x++)
{
rgbaBlock[(x * 4) + (y * 16) + RGBA8888_CHANNEL_A] = alphaimg[ii];
ii++;
}
}
#endif
}
//=============
// ETC2 RGBA1
//=============
CodecError CCodec_ETC2::CompressRGBA1Block(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2])
{
Color888_t srcRGB[4][4];
unsigned int uiCompressedBlockHi, uiCompressedBlockLo;
unsigned char tmp[4 * 4 * 3]; // Decompressed image
// Swizzle RGBA input to match required BGRA input
int pixelPos;
unsigned char srcAlpha[16];
int ii=0;
for (int y = 0; y < 4; y++)
{
for (DWORD x = 0; x < 4; x++)
{
pixelPos = (x * 16) + (y * 4);
srcRGB[x][y].red = rgbaBlock[pixelPos + RGBA8888_CHANNEL_R];
srcRGB[x][y].green = rgbaBlock[pixelPos + RGBA8888_CHANNEL_G];
srcRGB[x][y].blue = rgbaBlock[pixelPos + RGBA8888_CHANNEL_B];
srcAlpha[ii++] = rgbaBlock[(x*4) + (y*16) + RGBA8888_CHANNEL_A] > 128?255:0;
}
}
#ifdef USE_ETCPACK
compressBlockETC2Fast((uint8 *)&srcRGB, (uint8 *)srcAlpha, (uint8 *)tmp, 4, 4, 0, 0, uiCompressedBlockHi, uiCompressedBlockLo);
#else
cmp_compressBlockETC2Fast((uint8 *)&srcRGB, (uint8 *)srcAlpha, (uint8 *)tmp, uiCompressedBlockHi, uiCompressedBlockLo);
#endif
compressedBlock[0] = SWIZZLE_DWORD(uiCompressedBlockHi);
compressedBlock[1] = SWIZZLE_DWORD(uiCompressedBlockLo);
return CE_OK;
}
void CCodec_ETC2::DecompressRGBA1Block(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2])
{
Color888_t destRGB[4][4] = {0};
unsigned int uiCompressedBlockHi = SWIZZLE_DWORD(compressedBlock[0]);
unsigned int uiCompressedBlockLo = SWIZZLE_DWORD(compressedBlock[1]);
#ifdef USE_ETCPACK
uint8 dstAlpha[BLOCK_SIZE_4X4];
decompressBlockETC21BitAlpha(uiCompressedBlockHi, uiCompressedBlockLo, (uint8*)destRGB, dstAlpha, 4, 4, 0, 0);
int ii = 0;
int pixelPos;
for (DWORD y = 0; y < 4; y++)
{
for (DWORD x = 0; x < 4; x++)
{
pixelPos = (x * 4) + (y * 16);
rgbaBlock[pixelPos + RGBA8888_CHANNEL_R] = destRGB[y][x].red;
rgbaBlock[pixelPos + RGBA8888_CHANNEL_G] = destRGB[y][x].green;
rgbaBlock[pixelPos + RGBA8888_CHANNEL_B] = destRGB[y][x].blue;
rgbaBlock[pixelPos + RGBA8888_CHANNEL_A] = dstAlpha[ii++];
}
}
#else
// cmp_decompressBlockETC21BitAlphaC(uiCompressedBlockHi, uiCompressedBlockLo, (uint8*)destRGB, dstAlpha);
union
{
CMP_DWORD cmp[2];
uint64 block;
}data;
union
{
uint8 rgba[4];
uint32 blockRGBA;
} pixel;
data.cmp[0] = uiCompressedBlockLo;
data.cmp[1] = uiCompressedBlockHi;
CMP_BYTE pixelpos;
for (uint32 y = 0; y < 4; y++)
for (uint32 x = 0; x < 4; x++)
{
cmp_decompressETC21BitAlpha(data.block, (uint32 &)pixel.blockRGBA, x, y);
pixelpos = (y * 16) + (x * 4);
rgbaBlock[pixelpos + RGBA8888_CHANNEL_R] = pixel.rgba[0];
rgbaBlock[pixelpos + RGBA8888_CHANNEL_G] = pixel.rgba[1];
rgbaBlock[pixelpos + RGBA8888_CHANNEL_B] = pixel.rgba[2];
rgbaBlock[pixelpos + RGBA8888_CHANNEL_A] = pixel.rgba[3];
}
#endif
#pragma warning( pop )
}