/*
* Copyright © 2014 Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* 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, sub license, 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 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
* NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
* AND/OR ITS SUPPLIERS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*/
/**
***************************************************************************************************
* @file addrelemlib.cpp
* @brief Contains the class implementation for element/pixel related functions
***************************************************************************************************
*/
#include "addrelemlib.h"
#include "addrlib.h"
/**
***************************************************************************************************
* AddrElemLib::AddrElemLib
*
* @brief
* constructor
*
* @return
* N/A
***************************************************************************************************
*/
AddrElemLib::AddrElemLib(
AddrLib* const pAddrLib) : ///< [in] Parent addrlib instance pointer
AddrObject(pAddrLib->GetClient()),
m_pAddrLib(pAddrLib)
{
switch (m_pAddrLib->GetAddrChipFamily())
{
case ADDR_CHIP_FAMILY_R6XX:
m_depthPlanarType = ADDR_DEPTH_PLANAR_R600;
m_fp16ExportNorm = 0;
break;
case ADDR_CHIP_FAMILY_R7XX:
m_depthPlanarType = ADDR_DEPTH_PLANAR_R600;
m_fp16ExportNorm = 1;
break;
case ADDR_CHIP_FAMILY_R8XX:
case ADDR_CHIP_FAMILY_NI: // Same as 8xx
m_depthPlanarType = ADDR_DEPTH_PLANAR_R800;
m_fp16ExportNorm = 1;
break;
default:
m_fp16ExportNorm = 1;
m_depthPlanarType = ADDR_DEPTH_PLANAR_R800;
}
m_configFlags.value = 0;
}
/**
***************************************************************************************************
* AddrElemLib::~AddrElemLib
*
* @brief
* destructor
*
* @return
* N/A
***************************************************************************************************
*/
AddrElemLib::~AddrElemLib()
{
}
/**
***************************************************************************************************
* AddrElemLib::Create
*
* @brief
* Creates and initializes AddrLib object.
*
* @return
* Returns point to ADDR_CREATEINFO if successful.
***************************************************************************************************
*/
AddrElemLib* AddrElemLib::Create(
const AddrLib* const pAddrLib) ///< [in] Pointer of parent AddrLib instance
{
AddrElemLib* pElemLib = NULL;
if (pAddrLib)
{
pElemLib = new(pAddrLib->GetClient()) AddrElemLib(const_cast<AddrLib* const>(pAddrLib));
}
return pElemLib;
}
/**************************************************************************************************
* AddrElemLib::Flt32sToInt32s
*
* @brief
* Convert a ADDR_FLT_32 value to Int32 value
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::Flt32sToInt32s(
ADDR_FLT_32 value, ///< [in] ADDR_FLT_32 value
UINT_32 bits, ///< [in] nubmer of bits in value
AddrNumberType numberType, ///< [in] the type of number
UINT_32* pResult) ///< [out] Int32 value
{
UINT_8 round = 128; //ADDR_ROUND_BY_HALF
UINT_32 uscale;
UINT_32 sign;
//convert each component to an INT_32
switch ( numberType )
{
case ADDR_NO_NUMBER: //fall through
case ADDR_ZERO: //fall through
case ADDR_ONE: //fall through
case ADDR_EPSILON: //fall through
return; // these are zero-bit components, so don't set result
case ADDR_UINT_BITS: // unsigned integer bit field, clamped to range
uscale = (1<<bits) - 1;
if (bits == 32) // special case unsigned 32-bit int
{
*pResult = value.i;
}
else
{
if ((value.i < 0) || (value.u > uscale))
{
*pResult = uscale;
}
else
{
*pResult = value.i;
}
return;
}
// The algorithm used in the DB and TX differs at one value for 24-bit unorms
case ADDR_UNORM_R6XXDB: // unsigned repeating fraction
if ((bits==24) && (value.i == 0x33000000))
{
*pResult = 1;
return;
} // Else treat like ADDR_UNORM_R6XX
case ADDR_UNORM_R6XX: // unsigned repeating fraction
if (value.f <= 0)
{
*pResult = 0; // first clamp to [0..1]
}
else
{
if (value.f >= 1)
{
*pResult = (1<<bits) - 1;
}
else
{
if ((value.i | 0x87FFFFFF) == 0xFFFFFFFF)
{
*pResult = 0; // NaN, so force to 0
}
#if 0 // floating point version for documentation
else
{
FLOAT f = value.f * ((1<<bits) - 1);
*pResult = static_cast<INT_32>(f + (round/256.0f));
}
#endif
else
{
ADDR_FLT_32 scaled;
ADDR_FLT_32 shifted;
UINT_64 truncated, rounded;
UINT_32 altShift;
UINT_32 mask = (1 << bits) - 1;
UINT_32 half = 1 << (bits - 1);
UINT_32 mant24 = (value.i & 0x7FFFFF) + 0x800000;
UINT_64 temp = mant24 - (mant24>>bits) -
static_cast<INT_32>((mant24 & mask) > half);
UINT_32 exp8 = value.i >> 23;
UINT_32 shift = 126 - exp8 + 24 - bits;
UINT_64 final;
if (shift >= 32) // This is zero, even with maximum dither add
{
final = 0;
}
else
{
final = ((temp<<8) + (static_cast<UINT_64>(round)<<shift)) >> (shift+8);
}
//ADDR_EXIT( *pResult == final,
// ("Float %x converted to %d-bit Unorm %x != bitwise %x",
// value.u, bits, (UINT_32)*pResult, (UINT_32)final) );
if (final > mask)
{
final = mask;
}
scaled.f = value.f * ((1<<bits) - 1);
shifted.f = (scaled.f * 256);
truncated = ((shifted.i&0x7FFFFF) + (INT_64)0x800000) << 8;
altShift = 126 + 24 + 8 - ((shifted.i>>23)&0xFF);
truncated = (altShift > 60) ? 0 : truncated >> altShift;
rounded = static_cast<INT_32>((round + truncated) >> 8);
//if (rounded > ((1<<bits) - 1))
// rounded = ((1<<bits) - 1);
*pResult = static_cast<INT_32>(rounded); //(INT_32)final;
}
}
}
return;
case ADDR_S8FLOAT32: // 32-bit IEEE float, passes through NaN values
*pResult = value.i;
return;
// @@ FIX ROUNDING in this code, fix the denorm case
case ADDR_U4FLOATC: // Unsigned float, 4-bit exponent. bias 15, clamped [0..1]
sign = (value.i >> 31) & 1;
if ((value.i&0x7F800000) == 0x7F800000) // If NaN or INF:
{
if ((value.i&0x007FFFFF) != 0) // then if NaN
{
*pResult = 0; // return 0
}
else
{
*pResult = (sign)?0:0xF00000; // else +INF->+1, -INF->0
}
return;
}
if (value.f <= 0)
{
*pResult = 0;
}
else
{
if (value.f>=1)
{
*pResult = 0xF << (bits-4);
}
else
{
if ((value.i>>23) > 112 )
{
// 24-bit float: normalized
// value.i += 1 << (22-bits+4);
// round the IEEE mantissa to mantissa size
// @@ NOTE: add code to support rounding
value.u &= 0x7FFFFFF; // mask off high 4 exponent bits
*pResult = value.i >> (23-bits+4);// shift off unused mantissa bits
}
else
{
// 24-bit float: denormalized
value.f = value.f / (1<<28) / (1<<28);
value.f = value.f / (1<<28) / (1<<28); // convert to IEEE denorm
// value.i += 1 << (22-bits+4);
// round the IEEE mantissa to mantissa size
// @@ NOTE: add code to support rounding
*pResult = value.i >> (23-bits+4); // shift off unused mantissa bits
}
}
}
return;
default: // invalid number mode
//ADDR_EXIT(0, ("Invalid AddrNumber %d", numberType) );
break;
}
}
/**
***************************************************************************************************
* AddrElemLib::Int32sToPixel
*
* @brief
* Pack 32-bit integer values into an uncompressed pixel,
* in the proper order
*
* @return
* N/A
*
* @note
* This entry point packes four 32-bit integer values into
* an uncompressed pixel. The pixel values are specifies in
* standard order, e.g. depth/stencil. This routine asserts
* if called on compressed pixel.
***************************************************************************************************
*/
VOID AddrElemLib::Int32sToPixel(
UINT_32 numComps, ///< [in] number of components
UINT_32* pComps, ///< [in] compnents
UINT_32* pCompBits, ///< [in] total bits in each component
UINT_32* pCompStart, ///< [in] the first bit position of each component
ADDR_COMPONENT_FLAGS properties, ///< [in] properties about byteAligned, exportNorm
UINT_32 resultBits, ///< [in] result bits: total bpp after decompression
UINT_8* pPixel) ///< [out] a depth/stencil pixel value
{
UINT_32 i;
UINT_32 j;
UINT_32 start;
UINT_32 size;
UINT_32 byte;
UINT_32 value = 0;
UINT_32 compMask;
UINT_32 elemMask=0;
UINT_32 elementXor = 0; // address xor when reading bytes from elements
// @@ NOTE: assert if called on a compressed format!
if (properties.byteAligned) // Components are all byte-sized
{
for (i = 0; i < numComps; i++) // Then for each component
{
// Copy the bytes of the component into the element
start = pCompStart[i] / 8;
size = pCompBits[i] / 8;
for (j = 0; j < size; j++)
{
pPixel[(j+start)^elementXor] = static_cast<UINT_8>(pComps[i] >> (8*j));
}
}
}
else // Element is 32-bits or less, components are bit fields
{
// First, extract each component in turn and combine it into a 32-bit value
for (i = 0; i < numComps; i++)
{
compMask = (1 << pCompBits[i]) - 1;
elemMask |= compMask << pCompStart[i];
value |= (pComps[i] & compMask) << pCompStart[i];
}
// Mext, copy the masked value into the element
size = (resultBits + 7) / 8;
for (i = 0; i < size; i++)
{
byte = pPixel[i^elementXor] & ~(elemMask >> (8*i));
pPixel[i^elementXor] = static_cast<UINT_8>(byte | ((elemMask & value) >> (8*i)));
}
}
}
/**
***************************************************************************************************
* Flt32ToDepthPixel
*
* @brief
* Convert a FLT_32 value to a depth/stencil pixel value
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::Flt32ToDepthPixel(
AddrDepthFormat format, ///< [in] Depth format
const ADDR_FLT_32 comps[2], ///< [in] two components of depth
UINT_8* pPixel ///< [out] depth pixel value
) const
{
UINT_32 i;
UINT_32 values[2];
ADDR_COMPONENT_FLAGS properties; // byteAligned, exportNorm
UINT_32 resultBits = 0; // result bits: total bits per pixel after decompression
ADDR_PIXEL_FORMATINFO fmt;
// get type for each component
PixGetDepthCompInfo(format, &fmt);
//initialize properties
properties.byteAligned = TRUE;
properties.exportNorm = TRUE;
properties.floatComp = FALSE;
//set properties and result bits
for (i = 0; i < 2; i++)
{
if ((fmt.compBit[i] & 7) || (fmt.compStart[i] & 7))
{
properties.byteAligned = FALSE;
}
if (resultBits < fmt.compStart[i] + fmt.compBit[i])
{
resultBits = fmt.compStart[i] + fmt.compBit[i];
}
// Clear ADDR_EXPORT_NORM if can't be represented as 11-bit or smaller [-1..+1] format
if (fmt.compBit[i] > 11 || fmt.numType[i] >= ADDR_USCALED)
{
properties.exportNorm = FALSE;
}
// Mark if there are any floating point components
if ((fmt.numType[i] == ADDR_U4FLOATC) || (fmt.numType[i] >= ADDR_S8FLOAT) )
{
properties.floatComp = TRUE;
}
}
// Convert the two input floats to integer values
for (i = 0; i < 2; i++)
{
Flt32sToInt32s(comps[i], fmt.compBit[i], fmt.numType[i], &values[i]);
}
// Then pack the two integer components, in the proper order
Int32sToPixel(2, values, fmt.compBit, fmt.compStart, properties, resultBits, pPixel );
}
/**
***************************************************************************************************
* Flt32ToColorPixel
*
* @brief
* Convert a FLT_32 value to a red/green/blue/alpha pixel value
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::Flt32ToColorPixel(
AddrColorFormat format, ///< [in] Color format
AddrSurfaceNumber surfNum, ///< [in] Surface number
AddrSurfaceSwap surfSwap, ///< [in] Surface swap
const ADDR_FLT_32 comps[4], ///< [in] four components of color
UINT_8* pPixel ///< [out] a red/green/blue/alpha pixel value
) const
{
ADDR_PIXEL_FORMATINFO pixelInfo;
UINT_32 i;
UINT_32 values[4];
ADDR_COMPONENT_FLAGS properties; // byteAligned, exportNorm
UINT_32 resultBits = 0; // result bits: total bits per pixel after decompression
memset(&pixelInfo, 0, sizeof(ADDR_PIXEL_FORMATINFO));
PixGetColorCompInfo(format, surfNum, surfSwap, &pixelInfo);
//initialize properties
properties.byteAligned = TRUE;
properties.exportNorm = TRUE;
properties.floatComp = FALSE;
//set properties and result bits
for (i = 0; i < 4; i++)
{
if ( (pixelInfo.compBit[i] & 7) || (pixelInfo.compStart[i] & 7) )
{
properties.byteAligned = FALSE;
}
if (resultBits < pixelInfo.compStart[i] + pixelInfo.compBit[i])
{
resultBits = pixelInfo.compStart[i] + pixelInfo.compBit[i];
}
if (m_fp16ExportNorm)
{
// Clear ADDR_EXPORT_NORM if can't be represented as 11-bit or smaller [-1..+1] format
// or if it's not FP and <=16 bits
if (((pixelInfo.compBit[i] > 11) || (pixelInfo.numType[i] >= ADDR_USCALED))
&& (pixelInfo.numType[i] !=ADDR_U4FLOATC))
{
properties.exportNorm = FALSE;
}
}
else
{
// Clear ADDR_EXPORT_NORM if can't be represented as 11-bit or smaller [-1..+1] format
if (pixelInfo.compBit[i] > 11 || pixelInfo.numType[i] >= ADDR_USCALED)
{
properties.exportNorm = FALSE;
}
}
// Mark if there are any floating point components
if ( (pixelInfo.numType[i] == ADDR_U4FLOATC) ||
(pixelInfo.numType[i] >= ADDR_S8FLOAT) )
{
properties.floatComp = TRUE;
}
}
// Convert the four input floats to integer values
for (i = 0; i < 4; i++)
{
Flt32sToInt32s(comps[i], pixelInfo.compBit[i], pixelInfo.numType[i], &values[i]);
}
// Then pack the four integer components, in the proper order
Int32sToPixel(4, values, &pixelInfo.compBit[0], &pixelInfo.compStart[0],
properties, resultBits, pPixel);
}
/**
***************************************************************************************************
* AddrElemLib::GetCompType
*
* @brief
* Fill per component info
*
* @return
* N/A
*
***************************************************************************************************
*/
VOID AddrElemLib::GetCompType(
AddrColorFormat format, ///< [in] surface format
AddrSurfaceNumber numType, ///< [in] number type
ADDR_PIXEL_FORMATINFO* pInfo) ///< [in][out] per component info out
{
BOOL_32 handled = FALSE;
// Floating point formats override the number format
switch (format)
{
case ADDR_COLOR_16_FLOAT: // fall through for all pure floating point format
case ADDR_COLOR_16_16_FLOAT:
case ADDR_COLOR_16_16_16_16_FLOAT:
case ADDR_COLOR_32_FLOAT:
case ADDR_COLOR_32_32_FLOAT:
case ADDR_COLOR_32_32_32_32_FLOAT:
case ADDR_COLOR_10_11_11_FLOAT:
case ADDR_COLOR_11_11_10_FLOAT:
numType = ADDR_NUMBER_FLOAT;
break;
// Special handling for the depth formats
case ADDR_COLOR_8_24: // fall through for these 2 similar format
case ADDR_COLOR_24_8:
for (UINT_32 c = 0; c < 4; c++)
{
if (pInfo->compBit[c] == 8)
{
pInfo->numType[c] = ADDR_UINT_BITS;
}
else if (pInfo->compBit[c] == 24)
{
pInfo->numType[c] = ADDR_UNORM_R6XX;
}
else
{
pInfo->numType[c] = ADDR_NO_NUMBER;
}
}
handled = TRUE;
break;
case ADDR_COLOR_8_24_FLOAT: // fall through for these 3 similar format
case ADDR_COLOR_24_8_FLOAT:
case ADDR_COLOR_X24_8_32_FLOAT:
for (UINT_32 c = 0; c < 4; c++)
{
if (pInfo->compBit[c] == 8)
{
pInfo->numType[c] = ADDR_UINT_BITS;
}
else if (pInfo->compBit[c] == 24)
{
pInfo->numType[c] = ADDR_U4FLOATC;
}
else if (pInfo->compBit[c] == 32)
{
pInfo->numType[c] = ADDR_S8FLOAT32;
}
else
{
pInfo->numType[c] = ADDR_NO_NUMBER;
}
}
handled = TRUE;
break;
default:
break;
}
if (!handled)
{
for (UINT_32 c = 0; c < 4; c++)
{
// Assign a number type for each component
AddrSurfaceNumber cnum;
// First handle default component values
if (pInfo->compBit[c] == 0)
{
if (c < 3)
{
pInfo->numType[c] = ADDR_ZERO; // Default is zero for RGB
}
else if (numType == ADDR_NUMBER_UINT || numType == ADDR_NUMBER_SINT)
{
pInfo->numType[c] = ADDR_EPSILON; // Alpha INT_32 bits default is 0x01
}
else
{
pInfo->numType[c] = ADDR_ONE; // Alpha normal default is float 1.0
}
continue;
}
// Now handle small components
else if (pInfo->compBit[c] == 1)
{
if (numType == ADDR_NUMBER_UINT || numType == ADDR_NUMBER_SINT)
{
cnum = ADDR_NUMBER_UINT;
}
else
{
cnum = ADDR_NUMBER_UNORM;
}
}
else
{
cnum = numType;
}
// If no default, set the number type fom num, compbits, and architecture
switch (cnum)
{
case ADDR_NUMBER_SRGB:
pInfo->numType[c] = (c < 3) ? ADDR_GAMMA8_R6XX : ADDR_UNORM_R6XX;
break;
case ADDR_NUMBER_UNORM:
pInfo->numType[c] = ADDR_UNORM_R6XX;
break;
case ADDR_NUMBER_SNORM:
pInfo->numType[c] = ADDR_SNORM_R6XX;
break;
case ADDR_NUMBER_USCALED:
pInfo->numType[c] = ADDR_USCALED; // @@ Do we need separate Pele routine?
break;
case ADDR_NUMBER_SSCALED:
pInfo->numType[c] = ADDR_SSCALED; // @@ Do we need separate Pele routine?
break;
case ADDR_NUMBER_FLOAT:
if (pInfo->compBit[c] == 32)
{
pInfo->numType[c] = ADDR_S8FLOAT32;
}
else if (pInfo->compBit[c] == 16)
{
pInfo->numType[c] = ADDR_S5FLOAT;
}
else if (pInfo->compBit[c] >= 10)
{
pInfo->numType[c] = ADDR_U5FLOAT;
}
else
{
ADDR_ASSERT_ALWAYS();
}
break;
case ADDR_NUMBER_SINT:
pInfo->numType[c] = ADDR_SINT_BITS;
break;
case ADDR_NUMBER_UINT:
pInfo->numType[c] = ADDR_UINT_BITS;
break;
default:
ADDR_ASSERT(!"Invalid number type");
pInfo->numType[c] = ADDR_NO_NUMBER;
break;
}
}
}
}
/**
***************************************************************************************************
* AddrElemLib::GetCompSwap
*
* @brief
* Get components swapped for color surface
*
* @return
* N/A
*
***************************************************************************************************
*/
VOID AddrElemLib::GetCompSwap(
AddrSurfaceSwap swap, ///< [in] swap mode
ADDR_PIXEL_FORMATINFO* pInfo) ///< [in/out] output per component info
{
switch (pInfo->comps)
{
case 4:
switch (swap)
{
case ADDR_SWAP_ALT:
SwapComps( 0, 2, pInfo );
break; // BGRA
case ADDR_SWAP_STD_REV:
SwapComps( 0, 3, pInfo );
SwapComps( 1, 2, pInfo );
break; // ABGR
case ADDR_SWAP_ALT_REV:
SwapComps( 0, 3, pInfo );
SwapComps( 0, 2, pInfo );
SwapComps( 0, 1, pInfo );
break; // ARGB
default:
break;
}
break;
case 3:
switch (swap)
{
case ADDR_SWAP_ALT_REV:
SwapComps( 0, 3, pInfo );
SwapComps( 0, 2, pInfo );
break; // AGR
case ADDR_SWAP_STD_REV:
SwapComps( 0, 2, pInfo );
break; // BGR
case ADDR_SWAP_ALT:
SwapComps( 2, 3, pInfo );
break; // RGA
default:
break; // RGB
}
break;
case 2:
switch (swap)
{
case ADDR_SWAP_ALT_REV:
SwapComps( 0, 1, pInfo );
SwapComps( 1, 3, pInfo );
break; // AR
case ADDR_SWAP_STD_REV:
SwapComps( 0, 1, pInfo );
break; // GR
case ADDR_SWAP_ALT:
SwapComps( 1, 3, pInfo );
break; // RA
default:
break; // RG
}
break;
case 1:
switch (swap)
{
case ADDR_SWAP_ALT_REV:
SwapComps( 0, 3, pInfo );
break; // A
case ADDR_SWAP_STD_REV:
SwapComps( 0, 2, pInfo );
break; // B
case ADDR_SWAP_ALT:
SwapComps( 0, 1, pInfo );
break; // G
default:
break; // R
}
break;
}
}
/**
***************************************************************************************************
* AddrElemLib::GetCompSwap
*
* @brief
* Get components swapped for color surface
*
* @return
* N/A
*
***************************************************************************************************
*/
VOID AddrElemLib::SwapComps(
UINT_32 c0, ///< [in] component index 0
UINT_32 c1, ///< [in] component index 1
ADDR_PIXEL_FORMATINFO* pInfo) ///< [in/out] output per component info
{
UINT_32 start;
UINT_32 bits;
start = pInfo->compStart[c0];
pInfo->compStart[c0] = pInfo->compStart[c1];
pInfo->compStart[c1] = start;
bits = pInfo->compBit[c0];
pInfo->compBit[c0] = pInfo->compBit[c1];
pInfo->compBit[c1] = bits;
}
/**
***************************************************************************************************
* AddrElemLib::PixGetColorCompInfo
*
* @brief
* Get per component info for color surface
*
* @return
* N/A
*
***************************************************************************************************
*/
VOID AddrElemLib::PixGetColorCompInfo(
AddrColorFormat format, ///< [in] surface format, read from register
AddrSurfaceNumber number, ///< [in] pixel number type
AddrSurfaceSwap swap, ///< [in] component swap mode
ADDR_PIXEL_FORMATINFO* pInfo ///< [out] output per component info
) const
{
// 1. Get componet bits
switch (format)
{
case ADDR_COLOR_8:
GetCompBits(8, 0, 0, 0, pInfo);
break;
case ADDR_COLOR_1_5_5_5:
GetCompBits(5, 5, 5, 1, pInfo);
break;
case ADDR_COLOR_5_6_5:
GetCompBits(8, 6, 5, 0, pInfo);
break;
case ADDR_COLOR_6_5_5:
GetCompBits(5, 5, 6, 0, pInfo);
break;
case ADDR_COLOR_8_8:
GetCompBits(8, 8, 0, 0, pInfo);
break;
case ADDR_COLOR_4_4_4_4:
GetCompBits(4, 4, 4, 4, pInfo);
break;
case ADDR_COLOR_16:
GetCompBits(16, 0, 0, 0, pInfo);
break;
case ADDR_COLOR_8_8_8_8:
GetCompBits(8, 8, 8, 8, pInfo);
break;
case ADDR_COLOR_2_10_10_10:
GetCompBits(10, 10, 10, 2, pInfo);
break;
case ADDR_COLOR_10_11_11:
GetCompBits(11, 11, 10, 0, pInfo);
break;
case ADDR_COLOR_11_11_10:
GetCompBits(10, 11, 11, 0, pInfo);
break;
case ADDR_COLOR_16_16:
GetCompBits(16, 16, 0, 0, pInfo);
break;
case ADDR_COLOR_16_16_16_16:
GetCompBits(16, 16, 16, 16, pInfo);
break;
case ADDR_COLOR_16_FLOAT:
GetCompBits(16, 0, 0, 0, pInfo);
break;
case ADDR_COLOR_16_16_FLOAT:
GetCompBits(16, 16, 0, 0, pInfo);
break;
case ADDR_COLOR_32_FLOAT:
GetCompBits(32, 0, 0, 0, pInfo);
break;
case ADDR_COLOR_32_32_FLOAT:
GetCompBits(32, 32, 0, 0, pInfo);
break;
case ADDR_COLOR_16_16_16_16_FLOAT:
GetCompBits(16, 16, 16, 16, pInfo);
break;
case ADDR_COLOR_32_32_32_32_FLOAT:
GetCompBits(32, 32, 32, 32, pInfo);
break;
case ADDR_COLOR_32:
GetCompBits(32, 0, 0, 0, pInfo);
break;
case ADDR_COLOR_32_32:
GetCompBits(32, 32, 0, 0, pInfo);
break;
case ADDR_COLOR_32_32_32_32:
GetCompBits(32, 32, 32, 32, pInfo);
break;
case ADDR_COLOR_10_10_10_2:
GetCompBits(2, 10, 10, 10, pInfo);
break;
case ADDR_COLOR_10_11_11_FLOAT:
GetCompBits(11, 11, 10, 0, pInfo);
break;
case ADDR_COLOR_11_11_10_FLOAT:
GetCompBits(10, 11, 11, 0, pInfo);
break;
case ADDR_COLOR_5_5_5_1:
GetCompBits(1, 5, 5, 5, pInfo);
break;
case ADDR_COLOR_3_3_2:
GetCompBits(2, 3, 3, 0, pInfo);
break;
case ADDR_COLOR_4_4:
GetCompBits(4, 4, 0, 0, pInfo);
break;
case ADDR_COLOR_8_24:
case ADDR_COLOR_8_24_FLOAT: // same bit count, fall through
GetCompBits(24, 8, 0, 0, pInfo);
break;
case ADDR_COLOR_24_8:
case ADDR_COLOR_24_8_FLOAT: // same bit count, fall through
GetCompBits(8, 24, 0, 0, pInfo);
break;
case ADDR_COLOR_X24_8_32_FLOAT:
GetCompBits(32, 8, 0, 0, pInfo);
break;
case ADDR_COLOR_INVALID:
GetCompBits(0, 0, 0, 0, pInfo);
break;
default:
ADDR_ASSERT(0);
GetCompBits(0, 0, 0, 0, pInfo);
break;
}
// 2. Get component number type
GetCompType(format, number, pInfo);
// 3. Swap components if needed
GetCompSwap(swap, pInfo);
}
/**
***************************************************************************************************
* AddrElemLib::PixGetDepthCompInfo
*
* @brief
* Get per component info for depth surface
*
* @return
* N/A
*
***************************************************************************************************
*/
VOID AddrElemLib::PixGetDepthCompInfo(
AddrDepthFormat format, ///< [in] surface format, read from register
ADDR_PIXEL_FORMATINFO* pInfo ///< [out] output per component bits and type
) const
{
if (m_depthPlanarType == ADDR_DEPTH_PLANAR_R800)
{
if (format == ADDR_DEPTH_8_24_FLOAT)
{
format = ADDR_DEPTH_X24_8_32_FLOAT; // Use this format to represent R800's D24FS8
}
if (format == ADDR_DEPTH_X8_24_FLOAT)
{
format = ADDR_DEPTH_32_FLOAT;
}
}
switch (format)
{
case ADDR_DEPTH_16:
GetCompBits(16, 0, 0, 0, pInfo);
break;
case ADDR_DEPTH_8_24:
case ADDR_DEPTH_8_24_FLOAT: // similar format, fall through
GetCompBits(24, 8, 0, 0, pInfo);
break;
case ADDR_DEPTH_X8_24:
case ADDR_DEPTH_X8_24_FLOAT: // similar format, fall through
GetCompBits(24, 0, 0, 0, pInfo);
break;
case ADDR_DEPTH_32_FLOAT:
GetCompBits(32, 0, 0, 0, pInfo);
break;
case ADDR_DEPTH_X24_8_32_FLOAT:
GetCompBits(32, 8, 0, 0, pInfo);
break;
case ADDR_DEPTH_INVALID:
GetCompBits(0, 0, 0, 0, pInfo);
break;
default:
ADDR_ASSERT(0);
GetCompBits(0, 0, 0, 0, pInfo);
break;
}
switch (format)
{
case ADDR_DEPTH_16:
pInfo->numType [0] = ADDR_UNORM_R6XX;
pInfo->numType [1] = ADDR_ZERO;
break;
case ADDR_DEPTH_8_24:
pInfo->numType [0] = ADDR_UNORM_R6XXDB;
pInfo->numType [1] = ADDR_UINT_BITS;
break;
case ADDR_DEPTH_8_24_FLOAT:
pInfo->numType [0] = ADDR_U4FLOATC;
pInfo->numType [1] = ADDR_UINT_BITS;
break;
case ADDR_DEPTH_X8_24:
pInfo->numType [0] = ADDR_UNORM_R6XXDB;
pInfo->numType [1] = ADDR_ZERO;
break;
case ADDR_DEPTH_X8_24_FLOAT:
pInfo->numType [0] = ADDR_U4FLOATC;
pInfo->numType [1] = ADDR_ZERO;
break;
case ADDR_DEPTH_32_FLOAT:
pInfo->numType [0] = ADDR_S8FLOAT32;
pInfo->numType [1] = ADDR_ZERO;
break;
case ADDR_DEPTH_X24_8_32_FLOAT:
pInfo->numType [0] = ADDR_S8FLOAT32;
pInfo->numType [1] = ADDR_UINT_BITS;
break;
default:
pInfo->numType [0] = ADDR_NO_NUMBER;
pInfo->numType [1] = ADDR_NO_NUMBER;
break;
}
pInfo->numType [2] = ADDR_NO_NUMBER;
pInfo->numType [3] = ADDR_NO_NUMBER;
}
/**
***************************************************************************************************
* AddrElemLib::PixGetExportNorm
*
* @brief
* Check if fp16 export norm can be enabled.
*
* @return
* TRUE if this can be enabled.
*
***************************************************************************************************
*/
BOOL_32 AddrElemLib::PixGetExportNorm(
AddrColorFormat colorFmt, ///< [in] surface format, read from register
AddrSurfaceNumber numberFmt, ///< [in] pixel number type
AddrSurfaceSwap swap ///< [in] components swap type
) const
{
BOOL_32 enabled = TRUE;
ADDR_PIXEL_FORMATINFO formatInfo;
PixGetColorCompInfo(colorFmt, numberFmt, swap, &formatInfo);
for (UINT_32 c = 0; c < 4; c++)
{
if (m_fp16ExportNorm)
{
if (((formatInfo.compBit[c] > 11) || (formatInfo.numType[c] > ADDR_USCALED)) &&
(formatInfo.numType[c] != ADDR_U4FLOATC) &&
(formatInfo.numType[c] != ADDR_S5FLOAT) &&
(formatInfo.numType[c] != ADDR_S5FLOATM) &&
(formatInfo.numType[c] != ADDR_U5FLOAT) &&
(formatInfo.numType[c] != ADDR_U3FLOATM))
{
enabled = FALSE;
break;
}
}
else
{
if ((formatInfo.compBit[c] > 11) || (formatInfo.numType[c] > ADDR_USCALED))
{
enabled = FALSE;
break;
}
}
}
return enabled;
}
/**
***************************************************************************************************
* AddrElemLib::AdjustSurfaceInfo
*
* @brief
* Adjust bpp/base pitch/width/height according to elemMode and expandX/Y
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::AdjustSurfaceInfo(
AddrElemMode elemMode, ///< [in] element mode
UINT_32 expandX, ///< [in] decompression expansion factor in X
UINT_32 expandY, ///< [in] decompression expansion factor in Y
UINT_32* pBpp, ///< [in/out] bpp
UINT_32* pBasePitch, ///< [in/out] base pitch
UINT_32* pWidth, ///< [in/out] width
UINT_32* pHeight) ///< [in/out] height
{
UINT_32 packedBits;
UINT_32 basePitch;
UINT_32 width;
UINT_32 height;
UINT_32 bpp;
BOOL_32 bBCnFormat = FALSE;
ADDR_ASSERT(pBpp != NULL);
ADDR_ASSERT(pWidth != NULL && pHeight != NULL && pBasePitch != NULL);
if (pBpp)
{
bpp = *pBpp;
switch (elemMode)
{
case ADDR_EXPANDED:
packedBits = bpp / expandX / expandY;
break;
case ADDR_PACKED_STD: // Different bit order
case ADDR_PACKED_REV:
packedBits = bpp * expandX * expandY;
break;
case ADDR_PACKED_GBGR:
case ADDR_PACKED_BGRG:
packedBits = bpp; // 32-bit packed ==> 2 32-bit result
break;
case ADDR_PACKED_BC1: // Fall through
case ADDR_PACKED_BC4:
packedBits = 64;
bBCnFormat = TRUE;
break;
case ADDR_PACKED_BC2: // Fall through
case ADDR_PACKED_BC3: // Fall through
case ADDR_PACKED_BC5: // Fall through
bBCnFormat = TRUE;
packedBits = 128;
break;
case ADDR_ROUND_BY_HALF: // Fall through
case ADDR_ROUND_TRUNCATE: // Fall through
case ADDR_ROUND_DITHER: // Fall through
case ADDR_UNCOMPRESSED:
packedBits = bpp;
break;
default:
packedBits = bpp;
ADDR_ASSERT_ALWAYS();
break;
}
*pBpp = packedBits;
}
if (pWidth && pHeight && pBasePitch)
{
basePitch = *pBasePitch;
width = *pWidth;
height = *pHeight;
if ((expandX > 1) || (expandY > 1))
{
if (elemMode == ADDR_EXPANDED)
{
basePitch *= expandX;
width *= expandX;
height *= expandY;
}
else
{
// Evergreen family workaround
if (bBCnFormat && (m_pAddrLib->GetAddrChipFamily() == ADDR_CHIP_FAMILY_R8XX))
{
// For BCn we now pad it to POW2 at the beginning so it is safe to
// divide by 4 directly
basePitch = basePitch / expandX;
width = width / expandX;
height = height / expandY;
#if DEBUG
width = (width == 0) ? 1 : width;
height = (height == 0) ? 1 : height;
if ((*pWidth > PowTwoAlign(width, 8) * expandX) ||
(*pHeight > PowTwoAlign(height, 8) * expandY)) // 8 is 1D tiling alignment
{
// if this assertion is hit we may have issues if app samples
// rightmost/bottommost pixels
ADDR_ASSERT_ALWAYS();
}
#endif
}
else // Not BCn format we still keep old way (FMT_1? No real test yet)
{
basePitch = (basePitch + expandX - 1) / expandX;
width = (width + expandX - 1) / expandX;
height = (height + expandY - 1) / expandY;
}
}
*pBasePitch = basePitch; // 0 is legal value for base pitch.
*pWidth = (width == 0) ? 1 : width;
*pHeight = (height == 0) ? 1 : height;
} //if (pWidth && pHeight && pBasePitch)
}
}
/**
***************************************************************************************************
* AddrElemLib::RestoreSurfaceInfo
*
* @brief
* Reverse operation of AdjustSurfaceInfo
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::RestoreSurfaceInfo(
AddrElemMode elemMode, ///< [in] element mode
UINT_32 expandX, ///< [in] decompression expansion factor in X
UINT_32 expandY, ///< [out] decompression expansion factor in Y
UINT_32* pBpp, ///< [in/out] bpp
UINT_32* pWidth, ///< [in/out] width
UINT_32* pHeight) ///< [in/out] height
{
UINT_32 originalBits;
UINT_32 width;
UINT_32 height;
UINT_32 bpp;
ADDR_ASSERT(pBpp != NULL);
ADDR_ASSERT(pWidth != NULL && pHeight != NULL);
if (pBpp)
{
bpp = *pBpp;
switch (elemMode)
{
case ADDR_EXPANDED:
originalBits = bpp * expandX * expandY;
break;
case ADDR_PACKED_STD: // Different bit order
case ADDR_PACKED_REV:
originalBits = bpp / expandX / expandY;
break;
case ADDR_PACKED_GBGR:
case ADDR_PACKED_BGRG:
originalBits = bpp; // 32-bit packed ==> 2 32-bit result
break;
case ADDR_PACKED_BC1: // Fall through
case ADDR_PACKED_BC4:
originalBits = 64;
break;
case ADDR_PACKED_BC2: // Fall through
case ADDR_PACKED_BC3: // Fall through
case ADDR_PACKED_BC5:
originalBits = 128;
break;
case ADDR_ROUND_BY_HALF: // Fall through
case ADDR_ROUND_TRUNCATE: // Fall through
case ADDR_ROUND_DITHER: // Fall through
case ADDR_UNCOMPRESSED:
originalBits = bpp;
break;
default:
originalBits = bpp;
ADDR_ASSERT_ALWAYS();
break;
}
*pBpp = originalBits;
}
if (pWidth && pHeight)
{
width = *pWidth;
height = *pHeight;
if ((expandX > 1) || (expandY > 1))
{
if (elemMode == ADDR_EXPANDED)
{
width /= expandX;
height /= expandY;
}
else
{
width *= expandX;
height *= expandY;
}
}
*pWidth = (width == 0) ? 1 : width;
*pHeight = (height == 0) ? 1 : height;
}
}
/**
***************************************************************************************************
* AddrElemLib::GetBitsPerPixel
*
* @brief
* Compute the total bits per element according to a format
* code. For compressed formats, this is not the same as
* the number of bits per decompressed element.
*
* @return
* Bits per pixel
***************************************************************************************************
*/
UINT_32 AddrElemLib::GetBitsPerPixel(
AddrFormat format, ///< [in] surface format code
AddrElemMode* pElemMode, ///< [out] element mode
UINT_32* pExpandX, ///< [out] decompression expansion factor in X
UINT_32* pExpandY, ///< [out] decompression expansion factor in Y
UINT_32* pUnusedBits) ///< [out] bits unused
{
UINT_32 bpp;
UINT_32 expandX = 1;
UINT_32 expandY = 1;
UINT_32 bitUnused = 0;
AddrElemMode elemMode = ADDR_UNCOMPRESSED; // default value
switch (format)
{
case ADDR_FMT_8:
bpp = 8;
break;
case ADDR_FMT_1_5_5_5:
case ADDR_FMT_5_6_5:
case ADDR_FMT_6_5_5:
case ADDR_FMT_8_8:
case ADDR_FMT_4_4_4_4:
case ADDR_FMT_16:
case ADDR_FMT_16_FLOAT:
bpp = 16;
break;
case ADDR_FMT_GB_GR: // treat as FMT_8_8
elemMode = ADDR_PACKED_GBGR;
bpp = 16;
break;
case ADDR_FMT_BG_RG: // treat as FMT_8_8
elemMode = ADDR_PACKED_BGRG;
bpp = 16;
break;
case ADDR_FMT_8_8_8_8:
case ADDR_FMT_2_10_10_10:
case ADDR_FMT_10_11_11:
case ADDR_FMT_11_11_10:
case ADDR_FMT_16_16:
case ADDR_FMT_16_16_FLOAT:
case ADDR_FMT_32:
case ADDR_FMT_32_FLOAT:
case ADDR_FMT_24_8:
case ADDR_FMT_24_8_FLOAT:
bpp = 32;
break;
case ADDR_FMT_16_16_16_16:
case ADDR_FMT_16_16_16_16_FLOAT:
case ADDR_FMT_32_32:
case ADDR_FMT_32_32_FLOAT:
case ADDR_FMT_CTX1:
bpp = 64;
break;
case ADDR_FMT_32_32_32_32:
case ADDR_FMT_32_32_32_32_FLOAT:
bpp = 128;
break;
case ADDR_FMT_INVALID:
bpp = 0;
break;
case ADDR_FMT_1_REVERSED:
elemMode = ADDR_PACKED_REV;
expandX = 8;
bpp = 1;
break;
case ADDR_FMT_1:
elemMode = ADDR_PACKED_STD;
expandX = 8;
bpp = 1;
break;
case ADDR_FMT_4_4:
case ADDR_FMT_3_3_2:
bpp = 8;
break;
case ADDR_FMT_5_5_5_1:
bpp = 16;
break;
case ADDR_FMT_32_AS_8:
case ADDR_FMT_32_AS_8_8:
case ADDR_FMT_8_24:
case ADDR_FMT_8_24_FLOAT:
case ADDR_FMT_10_10_10_2:
case ADDR_FMT_10_11_11_FLOAT:
case ADDR_FMT_11_11_10_FLOAT:
case ADDR_FMT_5_9_9_9_SHAREDEXP:
bpp = 32;
break;
case ADDR_FMT_X24_8_32_FLOAT:
bpp = 64;
bitUnused = 24;
break;
case ADDR_FMT_8_8_8:
elemMode = ADDR_EXPANDED;
bpp = 24;//@@ 8; // read 3 elements per pixel
expandX = 3;
break;
case ADDR_FMT_16_16_16:
case ADDR_FMT_16_16_16_FLOAT:
elemMode = ADDR_EXPANDED;
bpp = 48;//@@ 16; // read 3 elements per pixel
expandX = 3;
break;
case ADDR_FMT_32_32_32_FLOAT:
case ADDR_FMT_32_32_32:
elemMode = ADDR_EXPANDED;
expandX = 3;
bpp = 96;//@@ 32; // read 3 elements per pixel
break;
case ADDR_FMT_BC1:
elemMode = ADDR_PACKED_BC1;
expandX = 4;
expandY = 4;
bpp = 64;
break;
case ADDR_FMT_BC4:
elemMode = ADDR_PACKED_BC4;
expandX = 4;
expandY = 4;
bpp = 64;
break;
case ADDR_FMT_BC2:
elemMode = ADDR_PACKED_BC2;
expandX = 4;
expandY = 4;
bpp = 128;
break;
case ADDR_FMT_BC3:
elemMode = ADDR_PACKED_BC3;
expandX = 4;
expandY = 4;
bpp = 128;
break;
case ADDR_FMT_BC5:
case ADDR_FMT_BC6: // reuse ADDR_PACKED_BC5
case ADDR_FMT_BC7: // reuse ADDR_PACKED_BC5
elemMode = ADDR_PACKED_BC5;
expandX = 4;
expandY = 4;
bpp = 128;
break;
default:
bpp = 0;
ADDR_ASSERT_ALWAYS();
break;
// @@ or should this be an error?
}
SafeAssign(pExpandX, expandX);
SafeAssign(pExpandY, expandY);
SafeAssign(pUnusedBits, bitUnused);
SafeAssign(reinterpret_cast<UINT_32*>(pElemMode), elemMode);
return bpp;
}
/**
***************************************************************************************************
* AddrElemLib::GetCompBits
*
* @brief
* Set each component's bit size and bit start. And set element mode and number type
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::GetCompBits(
UINT_32 c0, ///< [in] bits of component 0
UINT_32 c1, ///< [in] bits of component 1
UINT_32 c2, ///< [in] bits of component 2
UINT_32 c3, ///< [in] bits of component 3
ADDR_PIXEL_FORMATINFO* pInfo, ///< [out] per component info out
AddrElemMode elemMode) ///< [in] element mode
{
pInfo->comps = 0;
pInfo->compBit[0] = c0;
pInfo->compBit[1] = c1;
pInfo->compBit[2] = c2;
pInfo->compBit[3] = c3;
pInfo->compStart[0] = 0;
pInfo->compStart[1] = c0;
pInfo->compStart[2] = c0+c1;
pInfo->compStart[3] = c0+c1+c2;
pInfo->elemMode = elemMode;
// still needed since component swap may depend on number of components
for (INT i=0; i<4; i++)
{
if (pInfo->compBit[i] == 0)
{
pInfo->compStart[i] = 0; // all null components start at bit 0
pInfo->numType[i] = ADDR_NO_NUMBER; // and have no number type
}
else
{
pInfo->comps++;
}
}
}
/**
***************************************************************************************************
* AddrElemLib::GetCompBits
*
* @brief
* Set the clear color (or clear depth/stencil) for a surface
*
* @note
* If clearColor is zero, a default clear value is used in place of comps[4].
* If float32 is set, full precision is used, else the mantissa is reduced to 12-bits
*
* @return
* N/A
***************************************************************************************************
*/
VOID AddrElemLib::SetClearComps(
ADDR_FLT_32 comps[4], ///< [in/out] components
BOOL_32 clearColor, ///< [in] TRUE if clear color is set (CLEAR_COLOR)
BOOL_32 float32) ///< [in] TRUE if float32 component (BLEND_FLOAT32)
{
INT_32 i;
// Use default clearvalues if clearColor is disabled
if (clearColor == FALSE)
{
for (i=0; i<3; i++)
{
comps[i].f = 0.0;
}
comps[3].f = 1.0;
}
// Otherwise use the (modified) clear value
else
{
for (i=0; i<4; i++)
{ // If full precision, use clear value unchanged
if (float32)
{
// Do nothing
//comps[i] = comps[i];
}
// Else if it is a NaN, use the standard NaN value
else if ((comps[i].u & 0x7FFFFFFF) > 0x7F800000)
{
comps[i].u = 0xFFC00000;
}
// Else reduce the mantissa precision
else
{
comps[i].u = comps[i].u & 0xFFFFF000;
}
}
}
}
/**
***************************************************************************************************
* AddrElemLib::IsBlockCompressed
*
* @brief
* TRUE if this is block compressed format
*
* @note
*
* @return
* BOOL_32
***************************************************************************************************
*/
BOOL_32 AddrElemLib::IsBlockCompressed(
AddrFormat format) ///< [in] Format
{
return format >= ADDR_FMT_BC1 && format <= ADDR_FMT_BC7;
}
/**
***************************************************************************************************
* AddrElemLib::IsCompressed
*
* @brief
* TRUE if this is block compressed format or 1 bit format
*
* @note
*
* @return
* BOOL_32
***************************************************************************************************
*/
BOOL_32 AddrElemLib::IsCompressed(
AddrFormat format) ///< [in] Format
{
return IsBlockCompressed(format) || format == ADDR_FMT_BC1 || format == ADDR_FMT_BC7;
}
/**
***************************************************************************************************
* AddrElemLib::IsExpand3x
*
* @brief
* TRUE if this is 3x expand format
*
* @note
*
* @return
* BOOL_32
***************************************************************************************************
*/
BOOL_32 AddrElemLib::IsExpand3x(
AddrFormat format) ///< [in] Format
{
BOOL_32 is3x = FALSE;
switch (format)
{
case ADDR_FMT_8_8_8:
case ADDR_FMT_16_16_16:
case ADDR_FMT_16_16_16_FLOAT:
case ADDR_FMT_32_32_32:
case ADDR_FMT_32_32_32_FLOAT:
is3x = TRUE;
break;
default:
break;
}
return is3x;
}