1 /*
2  * Copyright © 2007-2019 Advanced Micro Devices, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
17  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  */
26 
27 /**
28 ****************************************************************************************************
29 * @file  addrlib.cpp
30 * @brief Contains the implementation for the Addr::Lib class.
31 ****************************************************************************************************
32 */
33 
34 #include "addrinterface.h"
35 #include "addrlib.h"
36 #include "addrcommon.h"
37 
38 #if defined(__APPLE__)
39 
div64_32(UINT_64 n,UINT_32 base)40 UINT_32 div64_32(UINT_64 n, UINT_32 base)
41 {
42     UINT_64 rem = n;
43     UINT_64 b = base;
44     UINT_64 res, d = 1;
45     UINT_32 high = rem >> 32;
46 
47     res = 0;
48     if (high >= base)
49     {
50         high /= base;
51         res = (UINT_64) high << 32;
52         rem -= (UINT_64) (high * base) << 32;
53     }
54 
55     while (((INT_64)b > 0) && (b < rem))
56     {
57         b = b + b;
58         d = d + d;
59     }
60 
61     do
62     {
63         if (rem >= b)
64         {
65             rem -= b;
66             res += d;
67         }
68         b >>= 1;
69         d >>= 1;
70     } while (d);
71 
72     n = res;
73     return rem;
74 }
75 
76 extern "C"
__umoddi3(UINT_64 n,UINT_32 base)77 UINT_32 __umoddi3(UINT_64 n, UINT_32 base)
78 {
79     return div64_32(n, base);
80 }
81 
82 #endif // __APPLE__
83 
84 namespace Addr
85 {
86 
87 ////////////////////////////////////////////////////////////////////////////////////////////////////
88 //                               Constructor/Destructor
89 ////////////////////////////////////////////////////////////////////////////////////////////////////
90 
91 /**
92 ****************************************************************************************************
93 *   Lib::Lib
94 *
95 *   @brief
96 *       Constructor for the AddrLib class
97 *
98 ****************************************************************************************************
99 */
Lib()100 Lib::Lib() :
101     m_chipFamily(ADDR_CHIP_FAMILY_IVLD),
102     m_chipRevision(0),
103     m_version(ADDRLIB_VERSION),
104     m_pipes(0),
105     m_banks(0),
106     m_pipeInterleaveBytes(0),
107     m_rowSize(0),
108     m_minPitchAlignPixels(1),
109     m_maxSamples(8),
110     m_pElemLib(NULL)
111 {
112     m_configFlags.value = 0;
113 }
114 
115 /**
116 ****************************************************************************************************
117 *   Lib::Lib
118 *
119 *   @brief
120 *       Constructor for the AddrLib class with hClient as parameter
121 *
122 ****************************************************************************************************
123 */
Lib(const Client * pClient)124 Lib::Lib(const Client* pClient) :
125     Object(pClient),
126     m_chipFamily(ADDR_CHIP_FAMILY_IVLD),
127     m_chipRevision(0),
128     m_version(ADDRLIB_VERSION),
129     m_pipes(0),
130     m_banks(0),
131     m_pipeInterleaveBytes(0),
132     m_rowSize(0),
133     m_minPitchAlignPixels(1),
134     m_maxSamples(8),
135     m_pElemLib(NULL)
136 {
137     m_configFlags.value = 0;
138 }
139 
140 /**
141 ****************************************************************************************************
142 *   Lib::~AddrLib
143 *
144 *   @brief
145 *       Destructor for the AddrLib class
146 *
147 ****************************************************************************************************
148 */
~Lib()149 Lib::~Lib()
150 {
151     if (m_pElemLib)
152     {
153         delete m_pElemLib;
154         m_pElemLib = NULL;
155     }
156 }
157 
158 
159 ////////////////////////////////////////////////////////////////////////////////////////////////////
160 //                               Initialization/Helper
161 ////////////////////////////////////////////////////////////////////////////////////////////////////
162 
163 /**
164 ****************************************************************************************************
165 *   Lib::Create
166 *
167 *   @brief
168 *       Creates and initializes AddrLib object.
169 *
170 *   @return
171 *       ADDR_E_RETURNCODE
172 ****************************************************************************************************
173 */
Create(const ADDR_CREATE_INPUT * pCreateIn,ADDR_CREATE_OUTPUT * pCreateOut)174 ADDR_E_RETURNCODE Lib::Create(
175     const ADDR_CREATE_INPUT* pCreateIn,     ///< [in] pointer to ADDR_CREATE_INPUT
176     ADDR_CREATE_OUTPUT*      pCreateOut)    ///< [out] pointer to ADDR_CREATE_OUTPUT
177 {
178     Lib* pLib = NULL;
179     ADDR_E_RETURNCODE returnCode = ADDR_OK;
180 
181     if (pCreateIn->createFlags.fillSizeFields == TRUE)
182     {
183         if ((pCreateIn->size != sizeof(ADDR_CREATE_INPUT)) ||
184             (pCreateOut->size != sizeof(ADDR_CREATE_OUTPUT)))
185         {
186             returnCode = ADDR_PARAMSIZEMISMATCH;
187         }
188     }
189 
190     if ((returnCode == ADDR_OK)                    &&
191         (pCreateIn->callbacks.allocSysMem != NULL) &&
192         (pCreateIn->callbacks.freeSysMem != NULL))
193     {
194         Client client = {
195             pCreateIn->hClient,
196             pCreateIn->callbacks
197         };
198 
199         switch (pCreateIn->chipEngine)
200         {
201             case CIASICIDGFXENGINE_SOUTHERNISLAND:
202                 switch (pCreateIn->chipFamily)
203                 {
204                     case FAMILY_SI:
205                         pLib = SiHwlInit(&client);
206                         break;
207                     case FAMILY_VI:
208                     case FAMILY_CZ:
209                     case FAMILY_CI:
210                     case FAMILY_KV: // CI based fusion
211                         pLib = CiHwlInit(&client);
212                         break;
213                     default:
214                         ADDR_ASSERT_ALWAYS();
215                         break;
216                 }
217                 break;
218             case CIASICIDGFXENGINE_ARCTICISLAND:
219                 switch (pCreateIn->chipFamily)
220                 {
221                     case FAMILY_AI:
222                     case FAMILY_RV:
223                         pLib = Gfx9HwlInit(&client);
224                         break;
225                     case FAMILY_NV:
226                     case FAMILY_VGH:
227                         pLib = Gfx10HwlInit(&client);
228                         break;
229                     default:
230                         ADDR_ASSERT_ALWAYS();
231                         break;
232                 }
233                 break;
234             default:
235                 ADDR_ASSERT_ALWAYS();
236                 break;
237         }
238     }
239 
240     if (pLib != NULL)
241     {
242         BOOL_32 initValid;
243 
244         // Pass createFlags to configFlags first since these flags may be overwritten
245         pLib->m_configFlags.noCubeMipSlicesPad  = pCreateIn->createFlags.noCubeMipSlicesPad;
246         pLib->m_configFlags.fillSizeFields      = pCreateIn->createFlags.fillSizeFields;
247         pLib->m_configFlags.useTileIndex        = pCreateIn->createFlags.useTileIndex;
248         pLib->m_configFlags.useCombinedSwizzle  = pCreateIn->createFlags.useCombinedSwizzle;
249         pLib->m_configFlags.checkLast2DLevel    = pCreateIn->createFlags.checkLast2DLevel;
250         pLib->m_configFlags.useHtileSliceAlign  = pCreateIn->createFlags.useHtileSliceAlign;
251         pLib->m_configFlags.allowLargeThickTile = pCreateIn->createFlags.allowLargeThickTile;
252         pLib->m_configFlags.forceDccAndTcCompat = pCreateIn->createFlags.forceDccAndTcCompat;
253         pLib->m_configFlags.nonPower2MemConfig  = pCreateIn->createFlags.nonPower2MemConfig;
254         pLib->m_configFlags.enableAltTiling     = pCreateIn->createFlags.enableAltTiling;
255         pLib->m_configFlags.disableLinearOpt    = FALSE;
256 
257         pLib->SetChipFamily(pCreateIn->chipFamily, pCreateIn->chipRevision);
258 
259         pLib->SetMinPitchAlignPixels(pCreateIn->minPitchAlignPixels);
260 
261         // Global parameters initialized and remaining configFlags bits are set as well
262         initValid = pLib->HwlInitGlobalParams(pCreateIn);
263 
264         if (initValid)
265         {
266             pLib->m_pElemLib = ElemLib::Create(pLib);
267         }
268         else
269         {
270             pLib->m_pElemLib = NULL; // Don't go on allocating element lib
271             returnCode = ADDR_INVALIDGBREGVALUES;
272         }
273 
274         if (pLib->m_pElemLib == NULL)
275         {
276             delete pLib;
277             pLib = NULL;
278             ADDR_ASSERT_ALWAYS();
279         }
280         else
281         {
282             pLib->m_pElemLib->SetConfigFlags(pLib->m_configFlags);
283         }
284     }
285 
286     pCreateOut->hLib = pLib;
287 
288     if ((pLib != NULL) &&
289         (returnCode == ADDR_OK))
290     {
291         pCreateOut->numEquations =
292             pLib->HwlGetEquationTableInfo(&pCreateOut->pEquationTable);
293 
294         pLib->SetMaxAlignments();
295 
296     }
297     else if ((pLib == NULL) &&
298              (returnCode == ADDR_OK))
299     {
300         // Unknown failures, we return the general error code
301         returnCode = ADDR_ERROR;
302     }
303 
304     return returnCode;
305 }
306 
307 /**
308 ****************************************************************************************************
309 *   Lib::SetChipFamily
310 *
311 *   @brief
312 *       Convert familyID defined in atiid.h to ChipFamily and set m_chipFamily/m_chipRevision
313 *   @return
314 *      N/A
315 ****************************************************************************************************
316 */
SetChipFamily(UINT_32 uChipFamily,UINT_32 uChipRevision)317 VOID Lib::SetChipFamily(
318     UINT_32 uChipFamily,        ///< [in] chip family defined in atiih.h
319     UINT_32 uChipRevision)      ///< [in] chip revision defined in "asic_family"_id.h
320 {
321     ChipFamily family = HwlConvertChipFamily(uChipFamily, uChipRevision);
322 
323     ADDR_ASSERT(family != ADDR_CHIP_FAMILY_IVLD);
324 
325     m_chipFamily   = family;
326     m_chipRevision = uChipRevision;
327 }
328 
329 /**
330 ****************************************************************************************************
331 *   Lib::SetMinPitchAlignPixels
332 *
333 *   @brief
334 *       Set m_minPitchAlignPixels with input param
335 *
336 *   @return
337 *      N/A
338 ****************************************************************************************************
339 */
SetMinPitchAlignPixels(UINT_32 minPitchAlignPixels)340 VOID Lib::SetMinPitchAlignPixels(
341     UINT_32 minPitchAlignPixels)    ///< [in] minmum pitch alignment in pixels
342 {
343     m_minPitchAlignPixels = (minPitchAlignPixels == 0) ? 1 : minPitchAlignPixels;
344 }
345 
346 /**
347 ****************************************************************************************************
348 *   Lib::SetMaxAlignments
349 *
350 *   @brief
351 *       Set max alignments
352 *
353 *   @return
354 *      N/A
355 ****************************************************************************************************
356 */
SetMaxAlignments()357 VOID Lib::SetMaxAlignments()
358 {
359     m_maxBaseAlign     = HwlComputeMaxBaseAlignments();
360     m_maxMetaBaseAlign = HwlComputeMaxMetaBaseAlignments();
361 }
362 
363 /**
364 ****************************************************************************************************
365 *   Lib::GetLib
366 *
367 *   @brief
368 *       Get AddrLib pointer
369 *
370 *   @return
371 *      An AddrLib class pointer
372 ****************************************************************************************************
373 */
GetLib(ADDR_HANDLE hLib)374 Lib* Lib::GetLib(
375     ADDR_HANDLE hLib)   ///< [in] handle of ADDR_HANDLE
376 {
377     return static_cast<Addr::Lib*>(hLib);
378 }
379 
380 /**
381 ****************************************************************************************************
382 *   Lib::GetMaxAlignments
383 *
384 *   @brief
385 *       Gets maximum alignments for data surface (include FMask)
386 *
387 *   @return
388 *       ADDR_E_RETURNCODE
389 ****************************************************************************************************
390 */
GetMaxAlignments(ADDR_GET_MAX_ALIGNMENTS_OUTPUT * pOut) const391 ADDR_E_RETURNCODE Lib::GetMaxAlignments(
392     ADDR_GET_MAX_ALIGNMENTS_OUTPUT* pOut    ///< [out] output structure
393     ) const
394 {
395     ADDR_E_RETURNCODE returnCode = ADDR_OK;
396 
397     if (GetFillSizeFieldsFlags() == TRUE)
398     {
399         if (pOut->size != sizeof(ADDR_GET_MAX_ALIGNMENTS_OUTPUT))
400         {
401             returnCode = ADDR_PARAMSIZEMISMATCH;
402         }
403     }
404 
405     if (returnCode == ADDR_OK)
406     {
407         if (m_maxBaseAlign != 0)
408         {
409             pOut->baseAlign = m_maxBaseAlign;
410         }
411         else
412         {
413             returnCode = ADDR_NOTIMPLEMENTED;
414         }
415     }
416 
417     return returnCode;
418 }
419 
420 /**
421 ****************************************************************************************************
422 *   Lib::GetMaxMetaAlignments
423 *
424 *   @brief
425 *       Gets maximum alignments for metadata (CMask, DCC and HTile)
426 *
427 *   @return
428 *       ADDR_E_RETURNCODE
429 ****************************************************************************************************
430 */
GetMaxMetaAlignments(ADDR_GET_MAX_ALIGNMENTS_OUTPUT * pOut) const431 ADDR_E_RETURNCODE Lib::GetMaxMetaAlignments(
432     ADDR_GET_MAX_ALIGNMENTS_OUTPUT* pOut    ///< [out] output structure
433     ) const
434 {
435     ADDR_E_RETURNCODE returnCode = ADDR_OK;
436 
437     if (GetFillSizeFieldsFlags() == TRUE)
438     {
439         if (pOut->size != sizeof(ADDR_GET_MAX_ALIGNMENTS_OUTPUT))
440         {
441             returnCode = ADDR_PARAMSIZEMISMATCH;
442         }
443     }
444 
445     if (returnCode == ADDR_OK)
446     {
447         if (m_maxMetaBaseAlign != 0)
448         {
449             pOut->baseAlign = m_maxMetaBaseAlign;
450         }
451         else
452         {
453             returnCode = ADDR_NOTIMPLEMENTED;
454         }
455     }
456 
457     return returnCode;
458 }
459 
460 /**
461 ****************************************************************************************************
462 *   Lib::Bits2Number
463 *
464 *   @brief
465 *       Cat a array of binary bit to a number
466 *
467 *   @return
468 *       The number combined with the array of bits
469 ****************************************************************************************************
470 */
Bits2Number(UINT_32 bitNum,...)471 UINT_32 Lib::Bits2Number(
472     UINT_32 bitNum,     ///< [in] how many bits
473     ...)                ///< [in] varaible bits value starting from MSB
474 {
475     UINT_32 number = 0;
476     UINT_32 i;
477     va_list bits_ptr;
478 
479     va_start(bits_ptr, bitNum);
480 
481     for(i = 0; i < bitNum; i++)
482     {
483         number |= va_arg(bits_ptr, UINT_32);
484         number <<= 1;
485     }
486 
487     number >>= 1;
488 
489     va_end(bits_ptr);
490 
491     return number;
492 }
493 
494 
495 ////////////////////////////////////////////////////////////////////////////////////////////////////
496 //                               Element lib
497 ////////////////////////////////////////////////////////////////////////////////////////////////////
498 
499 
500 /**
501 ****************************************************************************************************
502 *   Lib::Flt32ToColorPixel
503 *
504 *   @brief
505 *       Convert a FLT_32 value to a depth/stencil pixel value
506 *   @return
507 *       ADDR_E_RETURNCODE
508 ****************************************************************************************************
509 */
Flt32ToDepthPixel(const ELEM_FLT32TODEPTHPIXEL_INPUT * pIn,ELEM_FLT32TODEPTHPIXEL_OUTPUT * pOut) const510 ADDR_E_RETURNCODE Lib::Flt32ToDepthPixel(
511     const ELEM_FLT32TODEPTHPIXEL_INPUT* pIn,
512     ELEM_FLT32TODEPTHPIXEL_OUTPUT* pOut) const
513 {
514     ADDR_E_RETURNCODE returnCode = ADDR_OK;
515 
516     if (GetFillSizeFieldsFlags() == TRUE)
517     {
518         if ((pIn->size != sizeof(ELEM_FLT32TODEPTHPIXEL_INPUT)) ||
519             (pOut->size != sizeof(ELEM_FLT32TODEPTHPIXEL_OUTPUT)))
520         {
521             returnCode = ADDR_PARAMSIZEMISMATCH;
522         }
523     }
524 
525     if (returnCode == ADDR_OK)
526     {
527         GetElemLib()->Flt32ToDepthPixel(pIn->format, pIn->comps, pOut->pPixel);
528 
529         UINT_32 depthBase = 0;
530         UINT_32 stencilBase = 0;
531         UINT_32 depthBits = 0;
532         UINT_32 stencilBits = 0;
533 
534         switch (pIn->format)
535         {
536             case ADDR_DEPTH_16:
537                 depthBits = 16;
538                 break;
539             case ADDR_DEPTH_X8_24:
540             case ADDR_DEPTH_8_24:
541             case ADDR_DEPTH_X8_24_FLOAT:
542             case ADDR_DEPTH_8_24_FLOAT:
543                 depthBase = 8;
544                 depthBits = 24;
545                 stencilBits = 8;
546                 break;
547             case ADDR_DEPTH_32_FLOAT:
548                 depthBits = 32;
549                 break;
550             case ADDR_DEPTH_X24_8_32_FLOAT:
551                 depthBase = 8;
552                 depthBits = 32;
553                 stencilBits = 8;
554                 break;
555             default:
556                 break;
557         }
558 
559         // Overwrite base since R800 has no "tileBase"
560         if (GetElemLib()->IsDepthStencilTilePlanar() == FALSE)
561         {
562             depthBase = 0;
563             stencilBase = 0;
564         }
565 
566         depthBase *= 64;
567         stencilBase *= 64;
568 
569         pOut->stencilBase = stencilBase;
570         pOut->depthBase = depthBase;
571         pOut->depthBits = depthBits;
572         pOut->stencilBits = stencilBits;
573     }
574 
575     return returnCode;
576 }
577 
578 /**
579 ****************************************************************************************************
580 *   Lib::Flt32ToColorPixel
581 *
582 *   @brief
583 *       Convert a FLT_32 value to a red/green/blue/alpha pixel value
584 *   @return
585 *       ADDR_E_RETURNCODE
586 ****************************************************************************************************
587 */
Flt32ToColorPixel(const ELEM_FLT32TOCOLORPIXEL_INPUT * pIn,ELEM_FLT32TOCOLORPIXEL_OUTPUT * pOut) const588 ADDR_E_RETURNCODE Lib::Flt32ToColorPixel(
589     const ELEM_FLT32TOCOLORPIXEL_INPUT* pIn,
590     ELEM_FLT32TOCOLORPIXEL_OUTPUT* pOut) const
591 {
592     ADDR_E_RETURNCODE returnCode = ADDR_OK;
593 
594     if (GetFillSizeFieldsFlags() == TRUE)
595     {
596         if ((pIn->size != sizeof(ELEM_FLT32TOCOLORPIXEL_INPUT)) ||
597             (pOut->size != sizeof(ELEM_FLT32TOCOLORPIXEL_OUTPUT)))
598         {
599             returnCode = ADDR_PARAMSIZEMISMATCH;
600         }
601     }
602 
603     if (returnCode == ADDR_OK)
604     {
605         GetElemLib()->Flt32ToColorPixel(pIn->format,
606                                         pIn->surfNum,
607                                         pIn->surfSwap,
608                                         pIn->comps,
609                                         pOut->pPixel);
610     }
611 
612     return returnCode;
613 }
614 
615 
616 /**
617 ****************************************************************************************************
618 *   Lib::GetExportNorm
619 *
620 *   @brief
621 *       Check one format can be EXPORT_NUM
622 *   @return
623 *       TRUE if EXPORT_NORM can be used
624 ****************************************************************************************************
625 */
GetExportNorm(const ELEM_GETEXPORTNORM_INPUT * pIn) const626 BOOL_32 Lib::GetExportNorm(
627     const ELEM_GETEXPORTNORM_INPUT* pIn) const
628 {
629     ADDR_E_RETURNCODE returnCode = ADDR_OK;
630 
631     BOOL_32 enabled = FALSE;
632 
633     if (GetFillSizeFieldsFlags() == TRUE)
634     {
635         if (pIn->size != sizeof(ELEM_GETEXPORTNORM_INPUT))
636         {
637             returnCode = ADDR_PARAMSIZEMISMATCH;
638         }
639     }
640 
641     if (returnCode == ADDR_OK)
642     {
643         enabled = GetElemLib()->PixGetExportNorm(pIn->format, pIn->num, pIn->swap);
644     }
645 
646     return enabled;
647 }
648 
649 /**
650 ****************************************************************************************************
651 *   Lib::GetBpe
652 *
653 *   @brief
654 *       Get bits-per-element for specified format
655 *   @return
656 *       bits-per-element of specified format
657 ****************************************************************************************************
658 */
GetBpe(AddrFormat format) const659 UINT_32 Lib::GetBpe(AddrFormat format) const
660 {
661     return GetElemLib()->GetBitsPerPixel(format);
662 }
663 
664 } // Addr
665