//=============================================================================== // Copyright (c) 2007-2016 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_ATC.cpp // Description: implementation of the CCodec_ATC class // ////////////////////////////////////////////////////////////////////////////// #include "common.h" #include "codec_atc.h" #include "compressonator_tc.h" #include "compressonatorxcodec.h" using namespace CMP; ////////////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////////////// CCodec_ATC::CCodec_ATC(CodecType codecType) : CCodec_Block_4x4(codecType) { } CCodec_ATC::~CCodec_ATC() { } CodecError CCodec_ATC::CompressRGBBlock(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2]) { Color888_t srcRGB[4][4]; unsigned int colorLow565or1555, colorHigh565; for(int y = 0; y < 4; y++) { for(DWORD x = 0; x < 4; x++) { srcRGB[x][y].red = rgbBlock[(x*16) + (y*4) + ATC_RGBA8888_CHANNEL_R]; srcRGB[x][y].green = rgbBlock[(x*16) + (y*4) + ATC_RGBA8888_CHANNEL_G]; srcRGB[x][y].blue = rgbBlock[(x*16) + (y*4) + ATC_RGBA8888_CHANNEL_B]; } } compressedBlock[1] = atiEncodeRGBBlockATITC(&srcRGB, &colorLow565or1555, &colorHigh565); compressedBlock[0] = (colorHigh565 << 16) | colorLow565or1555; return CE_OK; } void CCodec_ATC::DecompressRGBBlock(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2]) { Color888_t destRGB[4][4]; unsigned int colorLow565or1555 = compressedBlock[0] & 0xffff; unsigned int colorHigh565 = (compressedBlock[0] >> 16) & 0xffff; atiDecodeRGBBlockATITC(&destRGB, compressedBlock[1], colorLow565or1555, colorHigh565); for(DWORD y = 0; y < 4; y++) { for(DWORD x = 0; x < 4; x++) { rgbBlock[(x*16) + (y*4) + ATC_RGBA8888_CHANNEL_R] = destRGB[x][y].red; rgbBlock[(x*16) + (y*4) + ATC_RGBA8888_CHANNEL_G] = destRGB[x][y].green; rgbBlock[(x*16) + (y*4) + ATC_RGBA8888_CHANNEL_B] = destRGB[x][y].blue; } } } CodecError CCodec_ATC::CompressRGBABlock_ExplicitAlpha(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) { CMP_BYTE alphaBlock[BLOCK_SIZE_4X4]; for(CMP_DWORD i = 0; i < 16; i++) alphaBlock[i] = static_cast(((DWORD*)rgbaBlock)[i] >> ATC_RGBA8888_OFFSET_A); CodecError err = CompressExplicitAlphaBlock(alphaBlock, &compressedBlock[ATC_OFFSET_ALPHA]); if(err != CE_OK) return err; return CompressRGBBlock(rgbaBlock, &compressedBlock[ATC_OFFSET_RGB]); } void CCodec_ATC::DecompressRGBABlock_ExplicitAlpha(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) { CMP_BYTE alphaBlock[BLOCK_SIZE_4X4]; DecompressExplicitAlphaBlock(alphaBlock, &compressedBlock[ATC_OFFSET_ALPHA]); DecompressRGBBlock(rgbaBlock, &compressedBlock[ATC_OFFSET_RGB]); for(CMP_DWORD i = 0; i < 16; i++) ((DWORD*)rgbaBlock)[i] = (alphaBlock[i] << ATC_RGBA8888_OFFSET_A) | (((DWORD*)rgbaBlock)[i] & ~(BYTE_MASK << ATC_RGBA8888_OFFSET_A)); } CodecError CCodec_ATC::CompressRGBABlock_InterpolatedAlpha(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) { CMP_BYTE alphaBlock[BLOCK_SIZE_4X4]; for(CMP_DWORD i = 0; i < 16; i++) alphaBlock[i] = static_cast(((DWORD*)rgbaBlock)[i] >> ATC_RGBA8888_OFFSET_A); CodecError err = CompressInterpolatedAlphaBlock(alphaBlock, &compressedBlock[ATC_OFFSET_ALPHA]); if(err != CE_OK) return err; return CompressRGBBlock(rgbaBlock, &compressedBlock[ATC_OFFSET_RGB]); } void CCodec_ATC::DecompressRGBABlock_InterpolatedAlpha(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) { CMP_BYTE alphaBlock[BLOCK_SIZE_4X4]; DecompressInterpolatedAlphaBlock(alphaBlock, &compressedBlock[ATC_OFFSET_ALPHA]); DecompressRGBBlock(rgbaBlock, &compressedBlock[ATC_OFFSET_RGB]); for(CMP_DWORD i = 0; i < 16; i++) ((DWORD*)rgbaBlock)[i] = (alphaBlock[i] << ATC_RGBA8888_OFFSET_A) | (((DWORD*)rgbaBlock)[i] & ~(BYTE_MASK << ATC_RGBA8888_OFFSET_A)); } #define EXPLICIT_ALPHA_PIXEL_MASK 0xf #define EXPLICIT_ALPHA_PIXEL_BPP 4 CodecError CCodec_ATC::CompressExplicitAlphaBlock(CMP_BYTE alphaBlock[BLOCK_SIZE_4X4], CMP_DWORD compressedBlock[2]) { compressedBlock[0] = compressedBlock[1] = 0; for(int i=0; i<16; i++) { int nBlock = i < 8 ? 0 : 1; CMP_BYTE cAlpha = (CMP_BYTE) ((alphaBlock[i] + ((alphaBlock[i] >> EXPLICIT_ALPHA_PIXEL_BPP) < 0x8 ? 7 : 8) - (alphaBlock[i] >> EXPLICIT_ALPHA_PIXEL_BPP)) >> EXPLICIT_ALPHA_PIXEL_BPP); if(cAlpha > EXPLICIT_ALPHA_PIXEL_MASK) cAlpha = EXPLICIT_ALPHA_PIXEL_MASK; compressedBlock[nBlock] |= (cAlpha << ((i % 8) * EXPLICIT_ALPHA_PIXEL_BPP)); } return CE_OK; } void CCodec_ATC::DecompressExplicitAlphaBlock(CMP_BYTE alphaBlock[BLOCK_SIZE_4X4], CMP_DWORD compressedBlock[2]) { for(int i=0; i<16; i++) { int nBlock = i < 8 ? 0 : 1; CMP_BYTE cAlpha = (CMP_BYTE) ((compressedBlock[nBlock] >> ((i % 8) * EXPLICIT_ALPHA_PIXEL_BPP)) & EXPLICIT_ALPHA_PIXEL_MASK); alphaBlock[i] = (CMP_BYTE) ((cAlpha << EXPLICIT_ALPHA_PIXEL_BPP) | cAlpha); } } CodecError CCodec_ATC::CompressInterpolatedAlphaBlock(CMP_BYTE alphaBlock[BLOCK_SIZE_4X4], CMP_DWORD compressedBlock[2]) { BYTE nEndpoints[2][2]; BYTE nIndices[2][BLOCK_SIZE_4X4]; float fError8 = CompBlock1X(alphaBlock, BLOCK_SIZE_4X4, nEndpoints[0], nIndices[0], 8, false, m_bUseSSE2, 8, 0, true); float fError6 = (fError8 == 0.f) ? FLT_MAX : CompBlock1X(alphaBlock, BLOCK_SIZE_4X4, nEndpoints[1], nIndices[1], 6, true, m_bUseSSE2, 8, 0, true); if(fError8 <= fError6) EncodeAlphaBlock(compressedBlock, nEndpoints[0], nIndices[0]); else EncodeAlphaBlock(compressedBlock, nEndpoints[1], nIndices[1]); return CE_OK; } void CCodec_ATC::EncodeAlphaBlock(CMP_DWORD compressedBlock[2], BYTE nEndpoints[2], BYTE nIndices[BLOCK_SIZE_4X4]) { compressedBlock[0] = ((int)nEndpoints[0]) | (((int)nEndpoints[1])<<8); compressedBlock[1] = 0; for(int i = 0; i < BLOCK_SIZE_4X4; i++) { if(i < 5) compressedBlock[0] |= (nIndices[i] & 0x7) << (16 + (i * 3)); else if(i > 5) compressedBlock[1] |= (nIndices[i] & 0x7) << (2 + (i-6) * 3); else { compressedBlock[0] |= (nIndices[i] & 0x1) << 31; compressedBlock[1] |= (nIndices[i] & 0x6) >> 1; } } } void CCodec_ATC::DecompressInterpolatedAlphaBlock(CMP_BYTE alphaBlock[BLOCK_SIZE_4X4], CMP_DWORD compressedBlock[2]) { CMP_BYTE alpha[8]; GetCompressedAlphaRamp(alpha, compressedBlock); for(int i = 0; i < BLOCK_SIZE_4X4; i++) { CMP_DWORD index; if(i < 5) index = (compressedBlock[0] & (0x7 << (16 + (i * 3)))) >> (16 + (i * 3)); else if(i > 5) index = (compressedBlock[1] & (0x7 << (2 + (i-6)*3))) >> (2 + (i-6)*3); else { index = (compressedBlock[0] & 0x80000000) >> 31; index |= (compressedBlock[1] & 0x3) << 1; } alphaBlock[i] = alpha[index]; } } void CCodec_ATC::GetCompressedAlphaRamp(CMP_BYTE alpha[8], CMP_DWORD compressedBlock[2]) { alpha[0] = (CMP_BYTE)(compressedBlock[0] & 0xff); alpha[1] = (CMP_BYTE)((compressedBlock[0]>>8) & 0xff); if (alpha[0] > alpha[1]) { // 8-alpha block: derive the other six alphas. // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. alpha[2] = static_cast((6 * alpha[0] + 1 * alpha[1] + 3) / 7); // bit code 010 alpha[3] = static_cast((5 * alpha[0] + 2 * alpha[1] + 3) / 7); // bit code 011 alpha[4] = static_cast((4 * alpha[0] + 3 * alpha[1] + 3) / 7); // bit code 100 alpha[5] = static_cast((3 * alpha[0] + 4 * alpha[1] + 3) / 7); // bit code 101 alpha[6] = static_cast((2 * alpha[0] + 5 * alpha[1] + 3) / 7); // bit code 110 alpha[7] = static_cast((1 * alpha[0] + 6 * alpha[1] + 3) / 7); // bit code 111 } else { // 6-alpha block. // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. alpha[2] = static_cast((4 * alpha[0] + 1 * alpha[1] + 2) / 5); // Bit code 010 alpha[3] = static_cast((3 * alpha[0] + 2 * alpha[1] + 2) / 5); // Bit code 011 alpha[4] = static_cast((2 * alpha[0] + 3 * alpha[1] + 2) / 5); // Bit code 100 alpha[5] = static_cast((1 * alpha[0] + 4 * alpha[1] + 2) / 5); // Bit code 101 alpha[6] = 0; // Bit code 110 alpha[7] = 255; // Bit code 111 } }