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_maxBaseAlign(0),
111     m_maxMetaBaseAlign(0),
112     m_pElemLib(NULL)
113 {
114     m_configFlags.value = 0;
115 }
116 
117 /**
118 ****************************************************************************************************
119 *   Lib::Lib
120 *
121 *   @brief
122 *       Constructor for the AddrLib class with hClient as parameter
123 *
124 ****************************************************************************************************
125 */
Lib(const Client * pClient)126 Lib::Lib(const Client* pClient) :
127     Object(pClient),
128     m_chipFamily(ADDR_CHIP_FAMILY_IVLD),
129     m_chipRevision(0),
130     m_version(ADDRLIB_VERSION),
131     m_pipes(0),
132     m_banks(0),
133     m_pipeInterleaveBytes(0),
134     m_rowSize(0),
135     m_minPitchAlignPixels(1),
136     m_maxSamples(8),
137     m_maxBaseAlign(0),
138     m_maxMetaBaseAlign(0),
139     m_pElemLib(NULL)
140 {
141     m_configFlags.value = 0;
142 }
143 
144 /**
145 ****************************************************************************************************
146 *   Lib::~AddrLib
147 *
148 *   @brief
149 *       Destructor for the AddrLib class
150 *
151 ****************************************************************************************************
152 */
~Lib()153 Lib::~Lib()
154 {
155     if (m_pElemLib)
156     {
157         delete m_pElemLib;
158         m_pElemLib = NULL;
159     }
160 }
161 
162 
163 ////////////////////////////////////////////////////////////////////////////////////////////////////
164 //                               Initialization/Helper
165 ////////////////////////////////////////////////////////////////////////////////////////////////////
166 
167 /**
168 ****************************************************************************************************
169 *   Lib::Create
170 *
171 *   @brief
172 *       Creates and initializes AddrLib object.
173 *
174 *   @return
175 *       ADDR_E_RETURNCODE
176 ****************************************************************************************************
177 */
Create(const ADDR_CREATE_INPUT * pCreateIn,ADDR_CREATE_OUTPUT * pCreateOut)178 ADDR_E_RETURNCODE Lib::Create(
179     const ADDR_CREATE_INPUT* pCreateIn,     ///< [in] pointer to ADDR_CREATE_INPUT
180     ADDR_CREATE_OUTPUT*      pCreateOut)    ///< [out] pointer to ADDR_CREATE_OUTPUT
181 {
182     Lib* pLib = NULL;
183     ADDR_E_RETURNCODE returnCode = ADDR_OK;
184 
185     if (pCreateIn->createFlags.fillSizeFields == TRUE)
186     {
187         if ((pCreateIn->size != sizeof(ADDR_CREATE_INPUT)) ||
188             (pCreateOut->size != sizeof(ADDR_CREATE_OUTPUT)))
189         {
190             returnCode = ADDR_PARAMSIZEMISMATCH;
191         }
192     }
193 
194     if ((returnCode == ADDR_OK)                    &&
195         (pCreateIn->callbacks.allocSysMem != NULL) &&
196         (pCreateIn->callbacks.freeSysMem != NULL))
197     {
198         Client client = {
199             pCreateIn->hClient,
200             pCreateIn->callbacks
201         };
202 
203         switch (pCreateIn->chipEngine)
204         {
205             case CIASICIDGFXENGINE_SOUTHERNISLAND:
206                 switch (pCreateIn->chipFamily)
207                 {
208                     case FAMILY_SI:
209                         pLib = SiHwlInit(&client);
210                         break;
211                     case FAMILY_VI:
212                     case FAMILY_CZ: // VI based fusion
213                     case FAMILY_CI:
214                     case FAMILY_KV: // CI based fusion
215                         pLib = CiHwlInit(&client);
216                         break;
217                     default:
218                         ADDR_ASSERT_ALWAYS();
219                         break;
220                 }
221                 break;
222             case CIASICIDGFXENGINE_ARCTICISLAND:
223                 switch (pCreateIn->chipFamily)
224                 {
225                     case FAMILY_AI:
226                     case FAMILY_RV:
227                         pLib = Gfx9HwlInit(&client);
228                         break;
229                     case FAMILY_NV:
230                     case FAMILY_VGH:
231                     case FAMILY_YC:
232                         pLib = Gfx10HwlInit(&client);
233                         break;
234                     default:
235                         ADDR_ASSERT_ALWAYS();
236                         break;
237                 }
238                 break;
239             default:
240                 ADDR_ASSERT_ALWAYS();
241                 break;
242         }
243     }
244 
245     if (pLib != NULL)
246     {
247         BOOL_32 initValid;
248 
249         // Pass createFlags to configFlags first since these flags may be overwritten
250         pLib->m_configFlags.noCubeMipSlicesPad  = pCreateIn->createFlags.noCubeMipSlicesPad;
251         pLib->m_configFlags.fillSizeFields      = pCreateIn->createFlags.fillSizeFields;
252         pLib->m_configFlags.useTileIndex        = pCreateIn->createFlags.useTileIndex;
253         pLib->m_configFlags.useCombinedSwizzle  = pCreateIn->createFlags.useCombinedSwizzle;
254         pLib->m_configFlags.checkLast2DLevel    = pCreateIn->createFlags.checkLast2DLevel;
255         pLib->m_configFlags.useHtileSliceAlign  = pCreateIn->createFlags.useHtileSliceAlign;
256         pLib->m_configFlags.allowLargeThickTile = pCreateIn->createFlags.allowLargeThickTile;
257         pLib->m_configFlags.forceDccAndTcCompat = pCreateIn->createFlags.forceDccAndTcCompat;
258         pLib->m_configFlags.nonPower2MemConfig  = pCreateIn->createFlags.nonPower2MemConfig;
259         pLib->m_configFlags.enableAltTiling     = pCreateIn->createFlags.enableAltTiling;
260         pLib->m_configFlags.disableLinearOpt    = FALSE;
261 
262         pLib->SetChipFamily(pCreateIn->chipFamily, pCreateIn->chipRevision);
263 
264         pLib->SetMinPitchAlignPixels(pCreateIn->minPitchAlignPixels);
265 
266         // Global parameters initialized and remaining configFlags bits are set as well
267         initValid = pLib->HwlInitGlobalParams(pCreateIn);
268 
269         if (initValid)
270         {
271             pLib->m_pElemLib = ElemLib::Create(pLib);
272         }
273         else
274         {
275             pLib->m_pElemLib = NULL; // Don't go on allocating element lib
276             returnCode = ADDR_INVALIDGBREGVALUES;
277         }
278 
279         if (pLib->m_pElemLib == NULL)
280         {
281             delete pLib;
282             pLib = NULL;
283             ADDR_ASSERT_ALWAYS();
284         }
285         else
286         {
287             pLib->m_pElemLib->SetConfigFlags(pLib->m_configFlags);
288         }
289     }
290 
291     pCreateOut->hLib = pLib;
292 
293     if ((pLib != NULL) &&
294         (returnCode == ADDR_OK))
295     {
296         pCreateOut->numEquations =
297             pLib->HwlGetEquationTableInfo(&pCreateOut->pEquationTable);
298 
299         pLib->SetMaxAlignments();
300 
301     }
302     else if ((pLib == NULL) &&
303              (returnCode == ADDR_OK))
304     {
305         // Unknown failures, we return the general error code
306         returnCode = ADDR_ERROR;
307     }
308 
309     return returnCode;
310 }
311 
312 /**
313 ****************************************************************************************************
314 *   Lib::SetChipFamily
315 *
316 *   @brief
317 *       Convert familyID defined in atiid.h to ChipFamily and set m_chipFamily/m_chipRevision
318 *   @return
319 *      N/A
320 ****************************************************************************************************
321 */
SetChipFamily(UINT_32 uChipFamily,UINT_32 uChipRevision)322 VOID Lib::SetChipFamily(
323     UINT_32 uChipFamily,        ///< [in] chip family defined in atiih.h
324     UINT_32 uChipRevision)      ///< [in] chip revision defined in "asic_family"_id.h
325 {
326     ChipFamily family = HwlConvertChipFamily(uChipFamily, uChipRevision);
327 
328     ADDR_ASSERT(family != ADDR_CHIP_FAMILY_IVLD);
329 
330     m_chipFamily   = family;
331     m_chipRevision = uChipRevision;
332 }
333 
334 /**
335 ****************************************************************************************************
336 *   Lib::SetMinPitchAlignPixels
337 *
338 *   @brief
339 *       Set m_minPitchAlignPixels with input param
340 *
341 *   @return
342 *      N/A
343 ****************************************************************************************************
344 */
SetMinPitchAlignPixels(UINT_32 minPitchAlignPixels)345 VOID Lib::SetMinPitchAlignPixels(
346     UINT_32 minPitchAlignPixels)    ///< [in] minmum pitch alignment in pixels
347 {
348     m_minPitchAlignPixels = (minPitchAlignPixels == 0) ? 1 : minPitchAlignPixels;
349 }
350 
351 /**
352 ****************************************************************************************************
353 *   Lib::SetMaxAlignments
354 *
355 *   @brief
356 *       Set max alignments
357 *
358 *   @return
359 *      N/A
360 ****************************************************************************************************
361 */
SetMaxAlignments()362 VOID Lib::SetMaxAlignments()
363 {
364     m_maxBaseAlign     = HwlComputeMaxBaseAlignments();
365     m_maxMetaBaseAlign = HwlComputeMaxMetaBaseAlignments();
366 }
367 
368 /**
369 ****************************************************************************************************
370 *   Lib::GetLib
371 *
372 *   @brief
373 *       Get AddrLib pointer
374 *
375 *   @return
376 *      An AddrLib class pointer
377 ****************************************************************************************************
378 */
GetLib(ADDR_HANDLE hLib)379 Lib* Lib::GetLib(
380     ADDR_HANDLE hLib)   ///< [in] handle of ADDR_HANDLE
381 {
382     return static_cast<Addr::Lib*>(hLib);
383 }
384 
385 /**
386 ****************************************************************************************************
387 *   Lib::GetMaxAlignments
388 *
389 *   @brief
390 *       Gets maximum alignments for data surface (include FMask)
391 *
392 *   @return
393 *       ADDR_E_RETURNCODE
394 ****************************************************************************************************
395 */
GetMaxAlignments(ADDR_GET_MAX_ALIGNMENTS_OUTPUT * pOut) const396 ADDR_E_RETURNCODE Lib::GetMaxAlignments(
397     ADDR_GET_MAX_ALIGNMENTS_OUTPUT* pOut    ///< [out] output structure
398     ) const
399 {
400     ADDR_E_RETURNCODE returnCode = ADDR_OK;
401 
402     if (GetFillSizeFieldsFlags() == TRUE)
403     {
404         if (pOut->size != sizeof(ADDR_GET_MAX_ALIGNMENTS_OUTPUT))
405         {
406             returnCode = ADDR_PARAMSIZEMISMATCH;
407         }
408     }
409 
410     if (returnCode == ADDR_OK)
411     {
412         if (m_maxBaseAlign != 0)
413         {
414             pOut->baseAlign = m_maxBaseAlign;
415         }
416         else
417         {
418             returnCode = ADDR_NOTIMPLEMENTED;
419         }
420     }
421 
422     return returnCode;
423 }
424 
425 /**
426 ****************************************************************************************************
427 *   Lib::GetMaxMetaAlignments
428 *
429 *   @brief
430 *       Gets maximum alignments for metadata (CMask, DCC and HTile)
431 *
432 *   @return
433 *       ADDR_E_RETURNCODE
434 ****************************************************************************************************
435 */
GetMaxMetaAlignments(ADDR_GET_MAX_ALIGNMENTS_OUTPUT * pOut) const436 ADDR_E_RETURNCODE Lib::GetMaxMetaAlignments(
437     ADDR_GET_MAX_ALIGNMENTS_OUTPUT* pOut    ///< [out] output structure
438     ) const
439 {
440     ADDR_E_RETURNCODE returnCode = ADDR_OK;
441 
442     if (GetFillSizeFieldsFlags() == TRUE)
443     {
444         if (pOut->size != sizeof(ADDR_GET_MAX_ALIGNMENTS_OUTPUT))
445         {
446             returnCode = ADDR_PARAMSIZEMISMATCH;
447         }
448     }
449 
450     if (returnCode == ADDR_OK)
451     {
452         if (m_maxMetaBaseAlign != 0)
453         {
454             pOut->baseAlign = m_maxMetaBaseAlign;
455         }
456         else
457         {
458             returnCode = ADDR_NOTIMPLEMENTED;
459         }
460     }
461 
462     return returnCode;
463 }
464 
465 /**
466 ****************************************************************************************************
467 *   Lib::Bits2Number
468 *
469 *   @brief
470 *       Cat a array of binary bit to a number
471 *
472 *   @return
473 *       The number combined with the array of bits
474 ****************************************************************************************************
475 */
Bits2Number(UINT_32 bitNum,...)476 UINT_32 Lib::Bits2Number(
477     UINT_32 bitNum,     ///< [in] how many bits
478     ...)                ///< [in] varaible bits value starting from MSB
479 {
480     UINT_32 number = 0;
481     UINT_32 i;
482     va_list bits_ptr;
483 
484     va_start(bits_ptr, bitNum);
485 
486     for(i = 0; i < bitNum; i++)
487     {
488         number |= va_arg(bits_ptr, UINT_32);
489         number <<= 1;
490     }
491 
492     number >>= 1;
493 
494     va_end(bits_ptr);
495 
496     return number;
497 }
498 
499 
500 ////////////////////////////////////////////////////////////////////////////////////////////////////
501 //                               Element lib
502 ////////////////////////////////////////////////////////////////////////////////////////////////////
503 
504 
505 /**
506 ****************************************************************************************************
507 *   Lib::Flt32ToColorPixel
508 *
509 *   @brief
510 *       Convert a FLT_32 value to a depth/stencil pixel value
511 *   @return
512 *       ADDR_E_RETURNCODE
513 ****************************************************************************************************
514 */
Flt32ToDepthPixel(const ELEM_FLT32TODEPTHPIXEL_INPUT * pIn,ELEM_FLT32TODEPTHPIXEL_OUTPUT * pOut) const515 ADDR_E_RETURNCODE Lib::Flt32ToDepthPixel(
516     const ELEM_FLT32TODEPTHPIXEL_INPUT* pIn,
517     ELEM_FLT32TODEPTHPIXEL_OUTPUT* pOut) const
518 {
519     ADDR_E_RETURNCODE returnCode = ADDR_OK;
520 
521     if (GetFillSizeFieldsFlags() == TRUE)
522     {
523         if ((pIn->size != sizeof(ELEM_FLT32TODEPTHPIXEL_INPUT)) ||
524             (pOut->size != sizeof(ELEM_FLT32TODEPTHPIXEL_OUTPUT)))
525         {
526             returnCode = ADDR_PARAMSIZEMISMATCH;
527         }
528     }
529 
530     if (returnCode == ADDR_OK)
531     {
532         GetElemLib()->Flt32ToDepthPixel(pIn->format, pIn->comps, pOut->pPixel);
533 
534         UINT_32 depthBase = 0;
535         UINT_32 stencilBase = 0;
536         UINT_32 depthBits = 0;
537         UINT_32 stencilBits = 0;
538 
539         switch (pIn->format)
540         {
541             case ADDR_DEPTH_16:
542                 depthBits = 16;
543                 break;
544             case ADDR_DEPTH_X8_24:
545             case ADDR_DEPTH_8_24:
546             case ADDR_DEPTH_X8_24_FLOAT:
547             case ADDR_DEPTH_8_24_FLOAT:
548                 depthBase = 8;
549                 depthBits = 24;
550                 stencilBits = 8;
551                 break;
552             case ADDR_DEPTH_32_FLOAT:
553                 depthBits = 32;
554                 break;
555             case ADDR_DEPTH_X24_8_32_FLOAT:
556                 depthBase = 8;
557                 depthBits = 32;
558                 stencilBits = 8;
559                 break;
560             default:
561                 break;
562         }
563 
564         // Overwrite base since R800 has no "tileBase"
565         if (GetElemLib()->IsDepthStencilTilePlanar() == FALSE)
566         {
567             depthBase = 0;
568             stencilBase = 0;
569         }
570 
571         depthBase *= 64;
572         stencilBase *= 64;
573 
574         pOut->stencilBase = stencilBase;
575         pOut->depthBase = depthBase;
576         pOut->depthBits = depthBits;
577         pOut->stencilBits = stencilBits;
578     }
579 
580     return returnCode;
581 }
582 
583 /**
584 ****************************************************************************************************
585 *   Lib::Flt32ToColorPixel
586 *
587 *   @brief
588 *       Convert a FLT_32 value to a red/green/blue/alpha pixel value
589 *   @return
590 *       ADDR_E_RETURNCODE
591 ****************************************************************************************************
592 */
Flt32ToColorPixel(const ELEM_FLT32TOCOLORPIXEL_INPUT * pIn,ELEM_FLT32TOCOLORPIXEL_OUTPUT * pOut) const593 ADDR_E_RETURNCODE Lib::Flt32ToColorPixel(
594     const ELEM_FLT32TOCOLORPIXEL_INPUT* pIn,
595     ELEM_FLT32TOCOLORPIXEL_OUTPUT* pOut) const
596 {
597     ADDR_E_RETURNCODE returnCode = ADDR_OK;
598 
599     if (GetFillSizeFieldsFlags() == TRUE)
600     {
601         if ((pIn->size != sizeof(ELEM_FLT32TOCOLORPIXEL_INPUT)) ||
602             (pOut->size != sizeof(ELEM_FLT32TOCOLORPIXEL_OUTPUT)))
603         {
604             returnCode = ADDR_PARAMSIZEMISMATCH;
605         }
606     }
607 
608     if (returnCode == ADDR_OK)
609     {
610         GetElemLib()->Flt32ToColorPixel(pIn->format,
611                                         pIn->surfNum,
612                                         pIn->surfSwap,
613                                         pIn->comps,
614                                         pOut->pPixel);
615     }
616 
617     return returnCode;
618 }
619 
620 
621 /**
622 ****************************************************************************************************
623 *   Lib::GetExportNorm
624 *
625 *   @brief
626 *       Check one format can be EXPORT_NUM
627 *   @return
628 *       TRUE if EXPORT_NORM can be used
629 ****************************************************************************************************
630 */
GetExportNorm(const ELEM_GETEXPORTNORM_INPUT * pIn) const631 BOOL_32 Lib::GetExportNorm(
632     const ELEM_GETEXPORTNORM_INPUT* pIn) const
633 {
634     ADDR_E_RETURNCODE returnCode = ADDR_OK;
635 
636     BOOL_32 enabled = FALSE;
637 
638     if (GetFillSizeFieldsFlags() == TRUE)
639     {
640         if (pIn->size != sizeof(ELEM_GETEXPORTNORM_INPUT))
641         {
642             returnCode = ADDR_PARAMSIZEMISMATCH;
643         }
644     }
645 
646     if (returnCode == ADDR_OK)
647     {
648         enabled = GetElemLib()->PixGetExportNorm(pIn->format, pIn->num, pIn->swap);
649     }
650 
651     return enabled;
652 }
653 
654 /**
655 ****************************************************************************************************
656 *   Lib::GetBpe
657 *
658 *   @brief
659 *       Get bits-per-element for specified format
660 *   @return
661 *       bits-per-element of specified format
662 ****************************************************************************************************
663 */
GetBpe(AddrFormat format) const664 UINT_32 Lib::GetBpe(AddrFormat format) const
665 {
666     return GetElemLib()->GetBitsPerPixel(format);
667 }
668 
669 } // Addr
670