text: /*
   * Copyright © 2007-2019 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  addrlib.cpp
  * @brief Contains the implementation for the Addr::Lib class.
  ****************************************************************************************************
  */
  
  #include "addrinterface.h"
  #include "addrlib.h"
  #include "addrcommon.h"
  
  #if defined(__APPLE__)
  
  UINT_32 div64_32(UINT_64 n, UINT_32 base)
  {
      UINT_64 rem = n;
      UINT_64 b = base;
      UINT_64 res, d = 1;
      UINT_32 high = rem >> 32;
  
      res = 0;
      if (high >= base)
      {
          high /= base;
          res = (UINT_64) high << 32;
          rem -= (UINT_64) (high * base) << 32;
      }
  
      while (((INT_64)b > 0) && (b < rem))
      {
          b = b + b;
          d = d + d;
      }
  
      do
      {
          if (rem >= b)
          {
              rem -= b;
              res += d;
          }
          b >>= 1;
          d >>= 1;
      } while (d);
  
      n = res;
      return rem;
  }
  
  extern "C"
  UINT_32 __umoddi3(UINT_64 n, UINT_32 base)
  {
      return div64_32(n, base);
  }
  
  #endif // __APPLE__
  
  namespace rocr {
  namespace Addr
  {
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //                               Constructor/Destructor
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  
  /**
  ****************************************************************************************************
  *   Lib::Lib
  *
  *   @brief
  *       Constructor for the AddrLib class
  *
  ****************************************************************************************************
  */
  Lib::Lib() :
      m_class(BASE_ADDRLIB),
      m_chipFamily(ADDR_CHIP_FAMILY_IVLD),
      m_chipRevision(0),
      m_version(ADDRLIB_VERSION),
      m_pipes(0),
      m_banks(0),
      m_pipeInterleaveBytes(0),
      m_rowSize(0),
      m_minPitchAlignPixels(1),
      m_maxSamples(8),
      m_pElemLib(NULL)
  {
      m_configFlags.value = 0;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::Lib
  *
  *   @brief
  *       Constructor for the AddrLib class with hClient as parameter
  *
  ****************************************************************************************************
  */
  Lib::Lib(const Client* pClient) :
      Object(pClient),
      m_class(BASE_ADDRLIB),
      m_chipFamily(ADDR_CHIP_FAMILY_IVLD),
      m_chipRevision(0),
      m_version(ADDRLIB_VERSION),
      m_pipes(0),
      m_banks(0),
      m_pipeInterleaveBytes(0),
      m_rowSize(0),
      m_minPitchAlignPixels(1),
      m_maxSamples(8),
      m_pElemLib(NULL)
  {
      m_configFlags.value = 0;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::~AddrLib
  *
  *   @brief
  *       Destructor for the AddrLib class
  *
  ****************************************************************************************************
  */
  Lib::~Lib()
  {
      if (m_pElemLib)
      {
          delete m_pElemLib;
          m_pElemLib = NULL;
      }
  }
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //                               Initialization/Helper
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  
  /**
  ****************************************************************************************************
  *   Lib::Create
  *
  *   @brief
  *       Creates and initializes AddrLib object.
  *
  *   @return
  *       ADDR_E_RETURNCODE
  ****************************************************************************************************
  */
  ADDR_E_RETURNCODE Lib::Create(
      const ADDR_CREATE_INPUT* pCreateIn,     ///< [in] pointer to ADDR_CREATE_INPUT
      ADDR_CREATE_OUTPUT*      pCreateOut)    ///< [out] pointer to ADDR_CREATE_OUTPUT
  {
      Lib* pLib = NULL;
      ADDR_E_RETURNCODE returnCode = ADDR_OK;
  
      if (pCreateIn->createFlags.fillSizeFields == TRUE)
      {
          if ((pCreateIn->size != sizeof(ADDR_CREATE_INPUT)) ||
              (pCreateOut->size != sizeof(ADDR_CREATE_OUTPUT)))
          {
              returnCode = ADDR_PARAMSIZEMISMATCH;
          }
      }
  
      if ((returnCode == ADDR_OK)                    &&
          (pCreateIn->callbacks.allocSysMem != NULL) &&
          (pCreateIn->callbacks.freeSysMem != NULL))
      {
          Client client = {
              pCreateIn->hClient,
              pCreateIn->callbacks
          };
  
          switch (pCreateIn->chipEngine)
          {
              case CIASICIDGFXENGINE_SOUTHERNISLAND:
                  switch (pCreateIn->chipFamily)
                  {
                      case FAMILY_SI:
                          pLib = SiHwlInit(&client);
                          break;
                      case FAMILY_VI:
                      case FAMILY_CZ:
                      case FAMILY_CI:
                      case FAMILY_KV: // CI based fusion
                          pLib = CiHwlInit(&client);
                          break;
                      default:
                          ADDR_ASSERT_ALWAYS();
                          break;
                  }
                  break;
              case CIASICIDGFXENGINE_ARCTICISLAND:
                  switch (pCreateIn->chipFamily)
                  {
                      case FAMILY_AI:
                      case FAMILY_RV:
                          pLib = Gfx9HwlInit(&client);
                          break;
                      case FAMILY_NV:
                          pLib = Gfx10HwlInit(&client);
                          break;
                      default:
                          ADDR_ASSERT_ALWAYS();
                          break;
                  }
                  break;
              default:
                  ADDR_ASSERT_ALWAYS();
                  break;
          }
      }
  
      if (pLib != NULL)
      {
          BOOL_32 initValid;
  
          // Pass createFlags to configFlags first since these flags may be overwritten
          pLib->m_configFlags.noCubeMipSlicesPad  = pCreateIn->createFlags.noCubeMipSlicesPad;
          pLib->m_configFlags.fillSizeFields      = pCreateIn->createFlags.fillSizeFields;
          pLib->m_configFlags.useTileIndex        = pCreateIn->createFlags.useTileIndex;
          pLib->m_configFlags.useCombinedSwizzle  = pCreateIn->createFlags.useCombinedSwizzle;
          pLib->m_configFlags.checkLast2DLevel    = pCreateIn->createFlags.checkLast2DLevel;
          pLib->m_configFlags.useHtileSliceAlign  = pCreateIn->createFlags.useHtileSliceAlign;
          pLib->m_configFlags.allowLargeThickTile = pCreateIn->createFlags.allowLargeThickTile;
          pLib->m_configFlags.forceDccAndTcCompat = pCreateIn->createFlags.forceDccAndTcCompat;
          pLib->m_configFlags.nonPower2MemConfig  = pCreateIn->createFlags.nonPower2MemConfig;
          pLib->m_configFlags.disableLinearOpt    = FALSE;
  
          pLib->SetChipFamily(pCreateIn->chipFamily, pCreateIn->chipRevision);
  
          pLib->SetMinPitchAlignPixels(pCreateIn->minPitchAlignPixels);
  
          // Global parameters initialized and remaining configFlags bits are set as well
          initValid = pLib->HwlInitGlobalParams(pCreateIn);
  
          if (initValid)
          {
              pLib->m_pElemLib = ElemLib::Create(pLib);
          }
          else
          {
              pLib->m_pElemLib = NULL; // Don't go on allocating element lib
              returnCode = ADDR_INVALIDGBREGVALUES;
          }
  
          if (pLib->m_pElemLib == NULL)
          {
              delete pLib;
              pLib = NULL;
              ADDR_ASSERT_ALWAYS();
          }
          else
          {
              pLib->m_pElemLib->SetConfigFlags(pLib->m_configFlags);
          }
      }
  
      pCreateOut->hLib = pLib;
  
      if ((pLib != NULL) &&
          (returnCode == ADDR_OK))
      {
          pCreateOut->numEquations =
              pLib->HwlGetEquationTableInfo(&pCreateOut->pEquationTable);
  
          pLib->SetMaxAlignments();
  
      }
      else if ((pLib == NULL) &&
               (returnCode == ADDR_OK))
      {
          // Unknown failures, we return the general error code
          returnCode = ADDR_ERROR;
      }
  
      return returnCode;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::SetChipFamily
  *
  *   @brief
  *       Convert familyID defined in atiid.h to ChipFamily and set m_chipFamily/m_chipRevision
  *   @return
  *      N/A
  ****************************************************************************************************
  */
  VOID Lib::SetChipFamily(
      UINT_32 uChipFamily,        ///< [in] chip family defined in atiih.h
      UINT_32 uChipRevision)      ///< [in] chip revision defined in "asic_family"_id.h
  {
      ChipFamily family = HwlConvertChipFamily(uChipFamily, uChipRevision);
  
      ADDR_ASSERT(family != ADDR_CHIP_FAMILY_IVLD);
  
      m_chipFamily   = family;
      m_chipRevision = uChipRevision;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::SetMinPitchAlignPixels
  *
  *   @brief
  *       Set m_minPitchAlignPixels with input param
  *
  *   @return
  *      N/A
  ****************************************************************************************************
  */
  VOID Lib::SetMinPitchAlignPixels(
      UINT_32 minPitchAlignPixels)    ///< [in] minmum pitch alignment in pixels
  {
      m_minPitchAlignPixels = (minPitchAlignPixels == 0) ? 1 : minPitchAlignPixels;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::SetMaxAlignments
  *
  *   @brief
  *       Set max alignments
  *
  *   @return
  *      N/A
  ****************************************************************************************************
  */
  VOID Lib::SetMaxAlignments()
  {
      m_maxBaseAlign     = HwlComputeMaxBaseAlignments();
      m_maxMetaBaseAlign = HwlComputeMaxMetaBaseAlignments();
  }
  
  /**
  ****************************************************************************************************
  *   Lib::GetLib
  *
  *   @brief
  *       Get AddrLib pointer
  *
  *   @return
  *      An AddrLib class pointer
  ****************************************************************************************************
  */
  Lib* Lib::GetLib(
      ADDR_HANDLE hLib)   ///< [in] handle of ADDR_HANDLE
  {
      return static_cast<Addr::Lib*>(hLib);
  }
  
  /**
  ****************************************************************************************************
  *   Lib::GetMaxAlignments
  *
  *   @brief
  *       Gets maximum alignments for data surface (include FMask)
  *
  *   @return
  *       ADDR_E_RETURNCODE
  ****************************************************************************************************
  */
  ADDR_E_RETURNCODE Lib::GetMaxAlignments(
      ADDR_GET_MAX_ALIGNMENTS_OUTPUT* pOut    ///< [out] output structure
      ) const
  {
      ADDR_E_RETURNCODE returnCode = ADDR_OK;
  
      if (GetFillSizeFieldsFlags() == TRUE)
      {
          if (pOut->size != sizeof(ADDR_GET_MAX_ALIGNMENTS_OUTPUT))
          {
              returnCode = ADDR_PARAMSIZEMISMATCH;
          }
      }
  
      if (returnCode == ADDR_OK)
      {
          if (m_maxBaseAlign != 0)
          {
              pOut->baseAlign = m_maxBaseAlign;
          }
          else
          {
              returnCode = ADDR_NOTIMPLEMENTED;
          }
      }
  
      return returnCode;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::GetMaxMetaAlignments
  *
  *   @brief
  *       Gets maximum alignments for metadata (CMask, DCC and HTile)
  *
  *   @return
  *       ADDR_E_RETURNCODE
  ****************************************************************************************************
  */
  ADDR_E_RETURNCODE Lib::GetMaxMetaAlignments(
      ADDR_GET_MAX_ALIGNMENTS_OUTPUT* pOut    ///< [out] output structure
      ) const
  {
      ADDR_E_RETURNCODE returnCode = ADDR_OK;
  
      if (GetFillSizeFieldsFlags() == TRUE)
      {
          if (pOut->size != sizeof(ADDR_GET_MAX_ALIGNMENTS_OUTPUT))
          {
              returnCode = ADDR_PARAMSIZEMISMATCH;
          }
      }
  
      if (returnCode == ADDR_OK)
      {
          if (m_maxMetaBaseAlign != 0)
          {
              pOut->baseAlign = m_maxMetaBaseAlign;
          }
          else
          {
              returnCode = ADDR_NOTIMPLEMENTED;
          }
      }
  
      return returnCode;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::Bits2Number
  *
  *   @brief
  *       Cat a array of binary bit to a number
  *
  *   @return
  *       The number combined with the array of bits
  ****************************************************************************************************
  */
  UINT_32 Lib::Bits2Number(
      UINT_32 bitNum,     ///< [in] how many bits
      ...)                ///< [in] varaible bits value starting from MSB
  {
      UINT_32 number = 0;
      UINT_32 i;
      va_list bits_ptr;
  
      va_start(bits_ptr, bitNum);
  
      for(i = 0; i < bitNum; i++)
      {
          number |= va_arg(bits_ptr, UINT_32);
          number <<= 1;
      }
  
      number >>= 1;
  
      va_end(bits_ptr);
  
      return number;
  }
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //                               Element lib
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  
  /**
  ****************************************************************************************************
  *   Lib::Flt32ToColorPixel
  *
  *   @brief
  *       Convert a FLT_32 value to a depth/stencil pixel value
  *   @return
  *       ADDR_E_RETURNCODE
  ****************************************************************************************************
  */
  ADDR_E_RETURNCODE Lib::Flt32ToDepthPixel(
      const ELEM_FLT32TODEPTHPIXEL_INPUT* pIn,
      ELEM_FLT32TODEPTHPIXEL_OUTPUT* pOut) const
  {
      ADDR_E_RETURNCODE returnCode = ADDR_OK;
  
      if (GetFillSizeFieldsFlags() == TRUE)
      {
          if ((pIn->size != sizeof(ELEM_FLT32TODEPTHPIXEL_INPUT)) ||
              (pOut->size != sizeof(ELEM_FLT32TODEPTHPIXEL_OUTPUT)))
          {
              returnCode = ADDR_PARAMSIZEMISMATCH;
          }
      }
  
      if (returnCode == ADDR_OK)
      {
          GetElemLib()->Flt32ToDepthPixel(pIn->format, pIn->comps, pOut->pPixel);
  
          UINT_32 depthBase = 0;
          UINT_32 stencilBase = 0;
          UINT_32 depthBits = 0;
          UINT_32 stencilBits = 0;
  
          switch (pIn->format)
          {
              case ADDR_DEPTH_16:
                  depthBits = 16;
                  break;
              case ADDR_DEPTH_X8_24:
              case ADDR_DEPTH_8_24:
              case ADDR_DEPTH_X8_24_FLOAT:
              case ADDR_DEPTH_8_24_FLOAT:
                  depthBase = 8;
                  depthBits = 24;
                  stencilBits = 8;
                  break;
              case ADDR_DEPTH_32_FLOAT:
                  depthBits = 32;
                  break;
              case ADDR_DEPTH_X24_8_32_FLOAT:
                  depthBase = 8;
                  depthBits = 32;
                  stencilBits = 8;
                  break;
              default:
                  break;
          }
  
          // Overwrite base since R800 has no "tileBase"
          if (GetElemLib()->IsDepthStencilTilePlanar() == FALSE)
          {
              depthBase = 0;
              stencilBase = 0;
          }
  
          depthBase *= 64;
          stencilBase *= 64;
  
          pOut->stencilBase = stencilBase;
          pOut->depthBase = depthBase;
          pOut->depthBits = depthBits;
          pOut->stencilBits = stencilBits;
      }
  
      return returnCode;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::Flt32ToColorPixel
  *
  *   @brief
  *       Convert a FLT_32 value to a red/green/blue/alpha pixel value
  *   @return
  *       ADDR_E_RETURNCODE
  ****************************************************************************************************
  */
  ADDR_E_RETURNCODE Lib::Flt32ToColorPixel(
      const ELEM_FLT32TOCOLORPIXEL_INPUT* pIn,
      ELEM_FLT32TOCOLORPIXEL_OUTPUT* pOut) const
  {
      ADDR_E_RETURNCODE returnCode = ADDR_OK;
  
      if (GetFillSizeFieldsFlags() == TRUE)
      {
          if ((pIn->size != sizeof(ELEM_FLT32TOCOLORPIXEL_INPUT)) ||
              (pOut->size != sizeof(ELEM_FLT32TOCOLORPIXEL_OUTPUT)))
          {
              returnCode = ADDR_PARAMSIZEMISMATCH;
          }
      }
  
      if (returnCode == ADDR_OK)
      {
          GetElemLib()->Flt32ToColorPixel(pIn->format,
                                          pIn->surfNum,
                                          pIn->surfSwap,
                                          pIn->comps,
                                          pOut->pPixel);
      }
  
      return returnCode;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::GetExportNorm
  *
  *   @brief
  *       Check one format can be EXPORT_NUM
  *   @return
  *       TRUE if EXPORT_NORM can be used
  ****************************************************************************************************
  */
  BOOL_32 Lib::GetExportNorm(
      const ELEM_GETEXPORTNORM_INPUT* pIn) const
  {
      ADDR_E_RETURNCODE returnCode = ADDR_OK;
  
      BOOL_32 enabled = FALSE;
  
      if (GetFillSizeFieldsFlags() == TRUE)
      {
          if (pIn->size != sizeof(ELEM_GETEXPORTNORM_INPUT))
          {
              returnCode = ADDR_PARAMSIZEMISMATCH;
          }
      }
  
      if (returnCode == ADDR_OK)
      {
          enabled = GetElemLib()->PixGetExportNorm(pIn->format, pIn->num, pIn->swap);
      }
  
      return enabled;
  }
  
  /**
  ****************************************************************************************************
  *   Lib::GetBpe
  *
  *   @brief
  *       Get bits-per-element for specified format
  *   @return
  *       bits-per-element of specified format
  ****************************************************************************************************
  */
  UINT_32 Lib::GetBpe(AddrFormat format) const
  {
      return GetElemLib()->GetBitsPerPixel(format);
  }
  
  } // Addr
  } // rocr
  
  