xref: /aosp_15_r20/external/gmmlib/Source/GmmLib/Texture/GmmTextureSpecialCases.cpp (revision 35ffd701415c9e32e53136d61a677a8d0a8fc4a5)
1 /*==============================================================================
2 Copyright(c) 2017 Intel Corporation
3 
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files(the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and / or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 ============================================================================*/
22 
23 #include "Internal/Common/GmmLibInc.h"
24 
25 /////////////////////////////////////////////////////////////////////////////////////
26 /// This function does any special-case conversion from client-provided pseudo creation
27 /// parameters to actual parameters for Hiz, CCS, SeparateStencil and Depth buffers.
28 ///
29 /// @param[in]  pTexInfo: Reference to ::GMM_TEXTURE_INFO
30 ///
31 /////////////////////////////////////////////////////////////////////////////////////
PreProcessTexSpecialCases(GMM_TEXTURE_INFO * pTexInfo)32 GMM_STATUS GmmLib::GmmTextureCalc::PreProcessTexSpecialCases(GMM_TEXTURE_INFO *pTexInfo)
33 {
34     GMM_STATUS               Status    = GMM_SUCCESS;
35     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
36 
37     if(!pTexInfo->Flags.Gpu.CCS &&
38        !pTexInfo->Flags.Gpu.MCS &&
39        !pTexInfo->Flags.Gpu.HiZ &&
40        !pTexInfo->Flags.Gpu.SeparateStencil &&
41        !pTexInfo->Flags.Gpu.MMC)
42     {
43         // Fast-out for non-special-cases.
44     }
45     else if(pTexInfo->Flags.Gpu.HiZ) // ######################################
46     {
47         // With HiZ surface creation, clients send the size/etc. parameters of
48         // the associated Depth Buffer--and here we convert to the appropriate
49         // HiZ creation parameters...
50 
51         if((pTexInfo->BaseWidth > 0) &&
52            (pTexInfo->BaseWidth <= pPlatform->HiZ.MaxWidth) &&
53            (pTexInfo->BaseHeight > 0) &&
54            (pTexInfo->BaseHeight <= pPlatform->HiZ.MaxHeight) &&
55            (pTexInfo->Depth <= ((pTexInfo->Type == RESOURCE_3D) ?
56                                 pPlatform->HiZ.MaxDepth :
57                                 1)) &&
58            (pTexInfo->ArraySize <= ((pTexInfo->Type == RESOURCE_3D) ?
59                                     1 :
60                                     (pTexInfo->Type == RESOURCE_CUBE) ?
61                                     pPlatform->HiZ.MaxArraySize / 6 :
62                                     pPlatform->HiZ.MaxArraySize)) &&
63            // SKL+ does not support HiZ surfaces for 1D and 3D surfaces
64            ((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN9_CORE) ||
65             (pTexInfo->Type != RESOURCE_1D && pTexInfo->Type != RESOURCE_3D)))
66         {
67             uint32_t Z_Width, Z_Height, Z_Depth;
68 
69             // Latch Z_[Width/Height/Depth]...
70             Z_Width  = GFX_ULONG_CAST(pTexInfo->BaseWidth);
71             Z_Height = pTexInfo->BaseHeight;
72             if((pTexInfo->Type == RESOURCE_1D) ||
73                (pTexInfo->Type == RESOURCE_2D))
74             {
75                 Z_Depth = GFX_MAX(pTexInfo->ArraySize, 1);
76             }
77             else if(pTexInfo->Type == RESOURCE_3D)
78             {
79                 Z_Depth = pTexInfo->Depth;
80             }
81             else if(pTexInfo->Type == RESOURCE_CUBE)
82             {
83                 // HW doesn't allow HiZ cube arrays, but GMM is allowing because
84                 // clients will redescribe depth/HiZ cube arrays as 2D arrays.
85                 Z_Depth = 6 * GFX_MAX(pTexInfo->ArraySize, 1);
86             }
87             else
88             {
89                 __GMM_ASSERT(0); // Illegal--Should have caught at upper IF check.
90                 Z_Depth = 0;
91             }
92 
93             // HZ_[Width/Height/QPitch] Calculation...
94             {
95                 uint32_t h0, h1, hL, i, NumSamples, QPitch, Z_HeightL;
96                 uint32_t HZ_HAlign = 16, HZ_VAlign = 8;
97                 uint8_t  HZ_DepthRows = pPlatform->HiZPixelsPerByte;
98 
99                 // HZ operates in pixel space starting from SKL. So, it does not care
100                 // whether the depth buffer is in MSAA mode or not.
101                 NumSamples =
102                 (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) ?
103                 1 :
104                 pTexInfo->MSAA.NumSamples;
105 
106                 pTexInfo->BaseWidth = ExpandWidth(Z_Width, HZ_HAlign, NumSamples);
107 
108                 h0 = ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
109 
110                 Z_Height = GmmTexGetMipHeight(pTexInfo, 1);
111                 h1       = ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
112 
113                 if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE)
114                 {
115                     if(pTexInfo->Type == RESOURCE_3D)
116                     {
117                         for(i = 0, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++)
118                         {
119                             Z_Height = GmmTexGetMipHeight(pTexInfo, i);
120                             hL       = ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
121                             Z_HeightL += (hL * GFX_MAX(1, (Z_Depth / GFX_2_TO_POWER_OF(i))));
122                         }
123 
124                         pTexInfo->ArraySize  = 0;
125                         pTexInfo->BaseHeight = Z_HeightL / 2;
126                     }
127                     else
128                     {
129                         for(i = 2, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++)
130                         {
131                             Z_Height = GmmTexGetMipHeight(pTexInfo, i);
132                             Z_HeightL += ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
133                         }
134 
135                         QPitch =
136                         (pTexInfo->MaxLod > 0) ?
137                         (h0 + GFX_MAX(h1, Z_HeightL)) :
138                         h0;
139                         QPitch /= HZ_DepthRows;
140                         pTexInfo->ArraySize  = Z_Depth;
141                         pTexInfo->BaseHeight = QPitch;
142                     }
143 
144                     pTexInfo->Alignment.HAlign = HZ_HAlign;
145                     pTexInfo->Alignment.VAlign = HZ_VAlign / HZ_DepthRows;
146                 }
147                 else //if (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN7_CORE)
148                 {
149                     if(pTexInfo->Type == RESOURCE_3D)
150                     {
151                         for(i = 0, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++)
152                         {
153                             hL = ExpandHeight(Z_Height >> i, HZ_VAlign, NumSamples);
154                             Z_HeightL += (hL * GFX_MAX(1, (Z_Depth / GFX_2_TO_POWER_OF(i))));
155                         }
156 
157                         pTexInfo->BaseHeight = Z_HeightL / 2;
158                     }
159                     else
160                     {
161                         QPitch = h0 + h1 + 12 * HZ_VAlign;
162 
163                         pTexInfo->BaseHeight = GFX_CEIL_DIV((QPitch * Z_Depth / 2), 8) * 8;
164                     }
165 
166                     pTexInfo->ArraySize = 1;
167                 }
168             }
169 
170             /// Native HZ Params //////////////////////////////////////////////////
171             pTexInfo->BitsPerPixel       = 8;
172             pTexInfo->Depth              = 1;
173             pTexInfo->Format             = GMM_FORMAT_GENERIC_8BIT;
174             pTexInfo->MaxLod             = 0;
175             pTexInfo->MSAA.NumSamples    = 1;
176             pTexInfo->MSAA.SamplePattern = GMM_MSAA_DISABLED;
177             pTexInfo->Type               = RESOURCE_2D;
178 
179             // HiZ Always Tile-Y
180             pTexInfo->Flags.Info.Linear  = 0;
181             pTexInfo->Flags.Info.TiledW  = 0;
182             pTexInfo->Flags.Info.TiledX  = 0;
183             pTexInfo->Flags.Info.TiledYf = 0;
184             GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
185             GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext);
186 
187         }
188         else
189         {
190             GMM_ASSERTDPF(0, "Illegal HiZ creation parameters!");
191             Status = GMM_ERROR;
192         }
193     } // HiZ
194     else if(pTexInfo->Flags.Gpu.CCS ||
195             pTexInfo->Flags.Gpu.MCS) // ######################################
196     {
197         // With CCS surface creation, clients send height, width, depth, etc. of
198         // the associated RenderTarget--and here we convert to the appropriate CCS
199         // creation parameters...
200         __GMM_ASSERT((!pGmmLibContext->GetSkuTable().FtrTileY ||
201                       (pTexInfo->Flags.Info.Linear + pTexInfo->Flags.Info.TiledW + pTexInfo->Flags.Info.TiledX + pTexInfo->Flags.Info.TiledY)) == 1);
202 
203         __GMM_ASSERT((pGmmLibContext->GetSkuTable().FtrTileY || (pTexInfo->Flags.Info.Linear + pTexInfo->Flags.Info.Tile4 + pTexInfo->Flags.Info.Tile64)) == 1);
204 
205         __GMM_ASSERT((pTexInfo->MSAA.NumSamples == 1) || (pTexInfo->MSAA.NumSamples == 2) || (pTexInfo->MSAA.NumSamples == 4) ||
206                      (pTexInfo->MSAA.NumSamples == 8) || (pTexInfo->MSAA.NumSamples == 16));
207 
208         Status = pGmmLibContext->GetTextureCalc()->MSAACCSUsage(pTexInfo);
209 
210         if(!pTexInfo->Flags.Gpu.__NonMsaaLinearCCS)
211         {
212             // CCS Always Tile-Y (Even for Non-MSAA FastClear.)
213             pTexInfo->Flags.Info.Linear  = 0;
214             pTexInfo->Flags.Info.TiledW  = 0;
215             pTexInfo->Flags.Info.TiledX  = 0;
216             pTexInfo->Flags.Info.TiledYf = 0;
217 
218             GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
219             GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext);
220 
221             //Clear compression request in CCS
222             pTexInfo->Flags.Info.RenderCompressed = 0;
223             pTexInfo->Flags.Info.MediaCompressed  = 0;
224         }
225 
226     }                                            // CCS
227     else if(pTexInfo->Flags.Gpu.SeparateStencil) // ##########################
228     {
229         // Seperate stencil sizing is based on the associated depth buffer
230         // size, however UMD manages this sizing, and GMM will allocate any
231         // arbitrarily sized stencil. Stencils do have specific tiling
232         // requirements however, which is handled below.
233 
234         if((pTexInfo->BaseWidth > 0) &&
235            (pTexInfo->BaseHeight > 0))
236         {
237             __GMM_ASSERT(pTexInfo->BitsPerPixel == 8);
238 
239             if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN7_CORE)
240             {
241                 GMM_ASSERTDPF((pTexInfo->MaxLod == 0), "Stencil Buffer LOD's not supported!");
242             }
243 
244             if(pGmmLibContext->GetSkuTable().FtrTileY)
245             {
246                 // Separate Stencil Tile-W Gen8-Gen11, otherwise Tile-Y
247                 pTexInfo->Flags.Info.Linear  = 0;
248                 pTexInfo->Flags.Info.TiledX  = 0;
249                 pTexInfo->Flags.Info.TiledYf = 0;
250                 pTexInfo->Flags.Info.TiledW  = 0;
251                 GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
252                 GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
253 
254                 if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE &&
255                    GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN11_CORE)
256                 {
257                     pTexInfo->Flags.Info.TiledW = 1;
258                 }
259                 else
260                 {
261                     GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext);
262                 }
263             }
264             else
265             {
266                 __GMM_ASSERT(pTexInfo->Flags.Info.Tile4 + pTexInfo->Flags.Info.Tile64 == 1);
267             }
268         }
269         else
270         {
271             GMM_ASSERTDPF(0, "Illegal Separate Stencil creation parameters!");
272             Status = GMM_ERROR;
273         }
274     } // Separate Stencil
275     else if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface)
276     {
277         pTexInfo->Flags.Gpu.__NonMsaaLinearCCS = 1;
278         pTexInfo->Flags.Info.Linear            = 1;
279     }
280 
281     return Status;
282 }
283 
284 /////////////////////////////////////////////////////////////////////////////////////
285 /// This function performs rough estimate of memory requirement between 4KB Tile vs
286 /// 64KB Tile surfaces and if the memory wastage due to padding/alignment exceeds
287 /// configured threshold, then optimize to demote the surface to 4KB Tile.
288 ///
289 /// @param[in]  pTexInfo: Reference to ::GMM_TEXTURE_INFO
290 ///             returns 1 if optimization to demote to 4KB tile is required otherwise 0
291 ///
292 /////////////////////////////////////////////////////////////////////////////////////
SurfaceRequires64KBTileOptimization(GMM_TEXTURE_INFO * pTexInfo)293 uint8_t GmmLib::GmmTextureCalc::SurfaceRequires64KBTileOptimization(GMM_TEXTURE_INFO *pTexInfo)
294 {
295     GMM_STATUS               Status    = GMM_SUCCESS;
296     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
297     uint32_t                 Size4KbTile, Size64KbTile;
298 
299     // Discard the surface if not eligible for 4KB Tile.
300     // All YUV formats restricted with default Tile64 across clients
301     if((pTexInfo->MSAA.NumSamples > 1) ||
302        pTexInfo->Flags.Gpu.TiledResource ||
303        pTexInfo->Flags.Gpu.HiZ ||
304        (!pTexInfo->Flags.Info.Tile64))
305     {
306         return 0;
307     }
308 
309     // Calc Surf size for 64KB Tile.
310     // Ignoring the CCS/AuxSurf dimensions since its proportional to main surface size
311     {
312         GMM_TEXTURE_INFO Surf = {};
313         uint32_t         ExpandedArraySize, BitsPerPixel;
314         uint32_t         SliceHeight, SliceWidth, Pitch;
315         uint32_t         BlockHeight = 0;
316         uint32_t         HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
317 
318         Surf = *pTexInfo;
319 
320         //Get HAlign/VAlign
321         if((Status = __GmmTexFillHAlignVAlign(&Surf, pGmmLibContext)) != GMM_SUCCESS)
322         {
323             __GMM_ASSERT(0);
324             return 0;
325         }
326 
327         HAlign = Surf.Alignment.HAlign;
328         VAlign = Surf.Alignment.VAlign;
329         DAlign = Surf.Alignment.DAlign;
330 
331         // Set Tile Mode
332         SetTileMode(&Surf);
333         BitsPerPixel = Surf.BitsPerPixel;
334 
335         ExpandedArraySize =
336         GFX_MAX(Surf.ArraySize, 1) *
337         ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) *                   // Cubemaps simply 6-element, 2D arrays.
338         ((Surf.Type == RESOURCE_3D) ? GFX_MAX(Surf.Depth, 1) : 1); // 3D's simply 2D arrays for sizing.
339 
340         if(GMM_IS_64KB_TILE(Surf.Flags))
341         {
342             ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth);
343         }
344 
345         // For Mipped Surface, Approx SliceHeight = VAlign(Lod0Height) * Mipped ? 1.5 : 1;
346         SliceHeight = GFX_ALIGN(Surf.BaseHeight, VAlign);
347 
348         if(Surf.MaxLod > 1)
349         {
350             SliceHeight = (GFX_ALIGN(Surf.BaseHeight, VAlign) * 3) / 2;
351         }
352 
353         uint8_t Compress = GmmIsCompressed(pGmmLibContext, Surf.Format);
354         GetCompressionBlockDimensions(Surf.Format, &CompressWidth, &CompressHeight, &CompressDepth);
355 
356 
357         SliceWidth  = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(Surf.BaseWidth), HAlign, &Surf);
358         BlockHeight = SliceHeight * ExpandedArraySize;
359 
360         if(Compress)
361         {
362             SliceWidth  = GFX_CEIL_DIV(SliceWidth, CompressWidth);
363             BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
364         }
365 
366         // Default pitch
367         Pitch = SliceWidth * BitsPerPixel >> 3;
368 
369         if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode]))
370         {
371             Pitch       = GFX_ALIGN(Pitch, pPlatform->TileInfo[Surf.TileMode].LogicalTileWidth);
372             BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight);
373         }
374 
375         // Calculate Tile aligned size.
376         Size64KbTile = BlockHeight * Pitch;
377 
378 	if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear)
379         {
380             Size64KbTile *= pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth;
381         }
382     }
383 
384     // Calc Surf size for 4KB Tile
385     // Ignoring the CCS/AuxSurf dimensions since its proportional to main surface size
386     {
387         GMM_TEXTURE_INFO Surf = {};
388         uint32_t         ExpandedArraySize, BitsPerPixel;
389         uint32_t         SliceHeight, SliceWidth, Pitch;
390         uint32_t         BlockHeight = 0;
391         uint32_t         HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
392 
393         Surf                   = *pTexInfo;
394         Surf.Flags.Info.Tile4  = 1;
395         Surf.Flags.Info.Tile64 = 0;
396 
397         //Get HAlign/VAlign
398         if((Status = __GmmTexFillHAlignVAlign(&Surf, pGmmLibContext)) != GMM_SUCCESS)
399         {
400             Status = GMM_ERROR;
401             return Status;
402         }
403 
404         HAlign = Surf.Alignment.HAlign;
405         VAlign = Surf.Alignment.VAlign;
406         DAlign = Surf.Alignment.DAlign;
407 
408         // Set Tile Mode
409         SetTileMode(&Surf);
410         BitsPerPixel = Surf.BitsPerPixel;
411 
412         ExpandedArraySize =
413         GFX_MAX(Surf.ArraySize, 1) *
414         ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) *                   // Cubemaps simply 6-element, 2D arrays.
415         ((Surf.Type == RESOURCE_3D) ? GFX_MAX(Surf.Depth, 1) : 1); // 3D's simply 2D arrays for sizing.
416 
417         if(GMM_IS_64KB_TILE(Surf.Flags))
418         {
419             ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth);
420         }
421 
422         // For Mipped Surface, Approx SliceHeight = VAlign(Lod0Height) * Mipped ? 1.5 : 1;
423         SliceHeight = GFX_ALIGN(Surf.BaseHeight, VAlign);
424 
425         if(Surf.MaxLod > 1)
426         {
427             SliceHeight = (GFX_ALIGN(Surf.BaseHeight, VAlign) * 3) / 2;
428         }
429 
430         uint8_t Compress = GmmIsCompressed(pGmmLibContext, Surf.Format);
431         GetCompressionBlockDimensions(Surf.Format, &CompressWidth, &CompressHeight, &CompressDepth);
432 
433         SliceWidth  = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(Surf.BaseWidth), HAlign, &Surf);
434         BlockHeight = SliceHeight * ExpandedArraySize;
435 
436         if(Compress)
437         {
438             SliceWidth  = GFX_CEIL_DIV(SliceWidth, CompressWidth);
439             BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
440         }
441 
442         // Default pitch
443         Pitch = SliceWidth * BitsPerPixel >> 3;
444 
445         if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode]))
446         {
447             Pitch       = GFX_ALIGN(Pitch, pPlatform->TileInfo[Surf.TileMode].LogicalTileWidth);
448             BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight);
449         }
450 
451         // Calculate Tile aligned size.
452         Size4KbTile = BlockHeight * Pitch;
453     }
454 
455     // check if 64KB tiled resource size exceeds memory wastage threshold.
456     if(((Size4KbTile * (100 + (GMM_GFX_SIZE_T)pGmmLibContext->GetAllowedPaddingFor64KBTileSurf())) / 100) < Size64KbTile)
457     {
458         return 1;
459     }
460 
461     return 0;
462 }
463