xref: /aosp_15_r20/external/gmmlib/Source/GmmLib/Texture/GmmGen7Texture.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 /// Allocates the 2D mip layout for surface state programming.
27 ///
28 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
29 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
30 ///
31 /// @return     ::GMM_STATUS
32 /////////////////////////////////////////////////////////////////////////////////////
FillTex2D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)33 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo,
34                                                              __GMM_BUFFER_TYPE *pRestrictions)
35 {
36     uint32_t   Width, Height, BitsPerPixel;
37     uint32_t   HAlign, VAlign;
38     uint32_t   CompressHeight, CompressWidth, CompressDepth;
39     uint32_t   AlignedWidth, BlockHeight, ExpandedArraySize, Pitch;
40     uint8_t    Compress = 0;
41     GMM_STATUS Status;
42 
43     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
44     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
45 
46     GMM_DPF_ENTER;
47 
48     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
49 
50     BitsPerPixel = pTexInfo->BitsPerPixel;
51     Height       = pTexInfo->BaseHeight;
52     Width        = GFX_ULONG_CAST(pTexInfo->BaseWidth);
53 
54     pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1);
55 
56     ExpandedArraySize =
57     GFX_MAX(pTexInfo->ArraySize, 1) *
58     ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
59     ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ?
60      1 :
61      pTexInfo->MSAA.NumSamples); // Gen7 MSAA (non-Depth/Stencil) RT samples stored as array planes.
62 
63     //
64     // Check for color separation
65     //
66     if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)
67     {
68         bool csRestrictionsMet = (((ExpandedArraySize <= 2) &&
69                                    (ExpandedArraySize == pTexInfo->ArraySize) &&
70                                    ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) ||
71                                     (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) ||
72                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) ||
73                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) ||
74                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) ||
75                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) &&
76                                    ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) ||
77                                     (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0))));
78 
79         if(csRestrictionsMet)
80         {
81             ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE;
82         }
83         else
84         {
85             pTexInfo->Flags.Gpu.ColorSeparation     = 0;
86             pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0;
87         }
88     }
89 
90     HAlign = pTexInfo->Alignment.HAlign;
91     VAlign = pTexInfo->Alignment.VAlign;
92     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
93 
94     Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
95 
96     /////////////////////////////////
97     // Calculate Block Surface Height
98     /////////////////////////////////
99 
100     // Adjust total height for arrayed 2D textures
101     if(ExpandedArraySize > 1)
102     {
103         uint32_t Height0, Height1;
104 
105         Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo);
106 
107         // If not ARYSPC_LOD0-eligible...
108         if((pTexInfo->MaxLod > 0) ||
109            pTexInfo->Flags.Gpu.Depth || // Depth/HiZ/Stencil buffers not ARYSPC_LOD0-compatible.
110            pTexInfo->Flags.Gpu.HiZ ||
111            pTexInfo->Flags.Gpu.SeparateStencil)
112         {
113             Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo);
114 
115             // QPitch = (h0 + h1 + 12j) * pitch
116             BlockHeight = Height0 + Height1 + 12 * VAlign;
117         }
118         else // SURFACE_STATE: Surface Array Spacing: ARYSPC_LOD0
119         {
120             // QPitch = h0 * pitch
121             BlockHeight                               = Height0;
122             pTexInfo->Alignment.ArraySpacingSingleLod = true;
123         }
124 
125         if(Compress)
126         {
127             BlockHeight /= CompressHeight;
128         }
129         else if(pTexInfo->Flags.Gpu.SeparateStencil)
130         {
131             BlockHeight /= 2;
132         }
133 
134         // Compute total array height
135         BlockHeight *= ExpandedArraySize;
136     }
137     else
138     {
139         BlockHeight = Get2DMipMapHeight(pTexInfo);
140     }
141 
142 
143     ///////////////////////////////////
144     // Calculate Pitch
145     ///////////////////////////////////
146 
147     AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo);
148 
149     // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths are greater
150     // than LOD0.  e.g. dimensions 4x4 and MinPitch == 1
151     if(pTexInfo->MaxLod >= 2)
152     {
153         uint32_t AlignedWidthLod1, AlignedWidthLod2;
154 
155         AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo);
156         AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo);
157 
158         AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2);
159     }
160 
161     if(Compress)
162     {
163         AlignedWidth /= CompressWidth;
164     }
165     else if(pTexInfo->Flags.Gpu.SeparateStencil)
166     {
167         AlignedWidth *= 2;
168     }
169     else if(pTexInfo->Flags.Gpu.ColorSeparation)
170     {
171         AlignedWidth *= pTexInfo->ArraySize;
172         __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION));
173         AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION;
174     }
175     else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX)
176     {
177         AlignedWidth *= pTexInfo->ArraySize;
178         __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION));
179         AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION;
180     }
181 
182     // Default pitch
183     Pitch = AlignedWidth * BitsPerPixel >> 3;
184 
185     // Make sure the pitch satisfy linear min pitch requirment
186     Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch);
187 
188     // Make sure pitch satisfy alignment restriction
189     Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment);
190 
191 
192     ////////////////////
193     // Adjust for Tiling
194     ////////////////////
195     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
196     {
197         Pitch       = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
198         BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
199 
200         // If Tiled Resource or Undefined64KBSwizzle resource, align to 64KB tile size
201         if((pTexInfo->Flags.Gpu.TiledResource || pTexInfo->Flags.Info.Undefined64KBSwizzle) &&
202            (pTexInfo->Flags.Info.TiledY))
203         {
204             uint32_t ColFactor = 0, RowFactor = 0;
205             uint32_t TRTileWidth = 0, TRTileHeight = 0;
206 
207             GmmGetD3DToHwTileConversion(pTexInfo, &ColFactor, &RowFactor);
208             TRTileWidth  = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * ColFactor;
209             TRTileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight * RowFactor;
210 
211             Pitch       = GFX_ALIGN(Pitch, TRTileWidth);
212             BlockHeight = GFX_ALIGN(BlockHeight, TRTileHeight);
213         }
214     }
215 
216     GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!");
217     pTexInfo->Flags.Info.LayoutBelow = 1;
218     pTexInfo->Flags.Info.LayoutRight = 0;
219 
220     // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
221     // padding needs to be added. Since this will create a none pitch aligned
222     // surface the padding is aligned to the next row
223     if(GmmIsYUVPacked(pTexInfo->Format) ||
224        (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
225        (pTexInfo->BitsPerPixel == GMM_BITS(48)))
226     {
227         BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch);
228     }
229 
230     // Align height to even row to cover for HW over - fetch
231     BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW);
232 
233     if((Status = // <-- Note assignment.
234         FillTexPitchAndSize(
235         pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS)
236     {
237         Fill2DTexOffsetAddress(pTexInfo);
238 
239         // Init to no-packed mips. It'll be initialized when app calls to get packed
240         // mips. Calculate packed mips here if there's a chance apps won't call to
241         // get packed mips.
242         pTexInfo->Alignment.PackedMipStartLod = GMM_TILED_RESOURCE_NO_PACKED_MIPS;
243     }
244 
245     GMM_DPF_EXIT;
246     return (Status);
247 }
248 
249 
250 /////////////////////////////////////////////////////////////////////////////////////
251 /// Calculates the mip offset of given LOD in 2D mip layout
252 ///
253 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
254 ///
255 /// @return     offset value in bytes
256 /////////////////////////////////////////////////////////////////////////////////////
Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)257 GMM_GFX_SIZE_T GmmLib::GmmGen7TextureCalc::Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo,
258                                                                        uint32_t          MipLevel)
259 {
260     GMM_GFX_SIZE_T MipOffset;
261     uint32_t       AlignedMipHeight, i, MipHeight, OffsetHeight;
262     uint32_t       HAlign, VAlign;
263     uint32_t       CompressHeight, CompressWidth, CompressDepth;
264     uint8_t        Compress;
265 
266     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
267     GMM_DPF_ENTER;
268 
269     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
270 
271     HAlign = pTexInfo->Alignment.HAlign;
272     VAlign = pTexInfo->Alignment.VAlign;
273 
274     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
275 
276     Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
277 
278     MipHeight    = pTexInfo->BaseHeight;
279     OffsetHeight = 0;
280 
281     // Mips 0 and 1 are on the left edge...
282     if(MipLevel < 2)
283     {
284         MipOffset = 0;
285     }
286     else // Mip2 and beyond are to the right of Mip1...
287     {
288         uint32_t Mip1Width = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> 1;
289 
290         Mip1Width = __GMM_EXPAND_WIDTH(this, Mip1Width, HAlign, pTexInfo);
291 
292         if(Compress)
293         {
294             Mip1Width /= CompressWidth;
295 
296 	    if((pGmmLibContext->GetWaTable().WaAstcCorruptionForOddCompressedBlockSizeX || pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) && pPlatform->FormatTable[pTexInfo->Format].ASTC && CompressWidth == 5)
297             {
298                 uint32_t Width1   = (pTexInfo->BaseWidth == 1) ? 1 : (GFX_ULONG_CAST(pTexInfo->BaseWidth) >> 1);
299                 uint32_t Modulo10 = Width1 % 10;
300                 if(Modulo10 >= 1 && Modulo10 <= CompressWidth)
301                 {
302                     Mip1Width += 3;
303                 }
304             }
305         }
306         else if(pTexInfo->Flags.Gpu.SeparateStencil)
307         {
308             Mip1Width *= 2;
309         }
310 
311         MipOffset = (GMM_GFX_SIZE_T)Mip1Width * pTexInfo->BitsPerPixel >> 3;
312     }
313 
314     for(i = 1; i <= MipLevel; i++)
315     {
316         AlignedMipHeight = GFX_ULONG_CAST(__GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo));
317 
318         if(Compress)
319         {
320             AlignedMipHeight /= CompressHeight;
321         }
322         else if(pTexInfo->Flags.Gpu.SeparateStencil)
323         {
324             AlignedMipHeight /= 2;
325         }
326 
327         OffsetHeight += ((i != 2) ? AlignedMipHeight : 0);
328 
329         MipHeight >>= 1;
330     }
331 
332     MipOffset += OffsetHeight * GFX_ULONG_CAST(pTexInfo->Pitch);
333 
334     GMM_DPF_EXIT;
335     return (MipOffset);
336 }
337 
338 
339 /////////////////////////////////////////////////////////////////////////////////////
340 /// Calculates height of the 2D mip layout
341 ///
342 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
343 ///
344 /// @return     Height of 2D mip layout
345 /////////////////////////////////////////////////////////////////////////////////////
Get2DMipMapHeight(GMM_TEXTURE_INFO * pTexInfo)346 uint32_t GmmLib::GmmGen7TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo)
347 {
348     uint32_t Height, BlockHeight, NumLevels; // Final height for 2D surface
349     uint32_t HeightLines, HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2;
350     uint32_t VAlign, CompressHeight, CompressWidth, CompressDepth;
351     uint32_t i;
352     uint8_t  Compress;
353 
354     GMM_DPF_ENTER;
355 
356     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
357 
358     // Mip 0 height is needed later
359     Height      = pTexInfo->BaseHeight;
360     Compress    = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
361     NumLevels   = pTexInfo->MaxLod;
362     HeightLines = Height;
363     VAlign      = pTexInfo->Alignment.VAlign;
364     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
365 
366     HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, HeightLines, VAlign, pTexInfo);
367 
368     if(Compress)
369     {
370         HeightLinesLevel0 /= CompressHeight;
371     }
372     else if(pTexInfo->Flags.Gpu.SeparateStencil)
373     {
374         HeightLinesLevel0 /= 2;
375     }
376 
377     // Start out with mip0
378     BlockHeight = HeightLinesLevel0;
379 
380     // Height of mip1 and height of all others mips(2,3,4,5,,) needed later
381     HeightLinesLevel1 = HeightLinesLevel2 = 0;
382     for(i = 1; i <= NumLevels; i++)
383     {
384         uint32_t AlignedHeightLines;
385 
386         HeightLines >>= 1;
387 
388         AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, HeightLines, VAlign, pTexInfo);
389 
390         if(Compress)
391         {
392             AlignedHeightLines /= CompressHeight;
393         }
394         else if(pTexInfo->Flags.Gpu.SeparateStencil)
395         {
396             AlignedHeightLines /= 2;
397         }
398 
399         if(i == 1)
400         {
401             HeightLinesLevel1 = AlignedHeightLines;
402         }
403         else
404         {
405             HeightLinesLevel2 += AlignedHeightLines;
406         }
407     }
408 
409     // If mip1 height covers all others then that is all we need
410     if(HeightLinesLevel1 >= HeightLinesLevel2)
411     {
412         BlockHeight += GFX_ALIGN_NP2(HeightLinesLevel1, VAlign);
413     }
414     else
415     {
416         BlockHeight += GFX_ALIGN_NP2(HeightLinesLevel2, VAlign);
417     }
418 
419     GMM_DPF_EXIT;
420     return (BlockHeight);
421 }
422 
423 
424 /////////////////////////////////////////////////////////////////////////////////////
425 /// Calculates the address offset for each mip map of 2D texture and store them
426 /// into the GMM_TEXTURE_INFO for surf state programming.
427 ///
428 /// @param[in]  pTexInfo: pointer to ::GMM_TEXTURE_INFO
429 ///
430 /////////////////////////////////////////////////////////////////////////////////////
Fill2DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)431 void GmmLib::GmmGen7TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
432 {
433     uint32_t i;
434 
435     __GMM_ASSERTPTR(pTexInfo, VOIDRETURN);
436 
437     GMM_DPF_ENTER;
438 
439     // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch...
440     // -------------------------------------------------------------------------
441     // Note: Gen7 MSAA RT samples stored as contiguous array planes--
442     // e.g. MSAA-4X'ed array elements A and B stored: A0 A1 A2 A3 B0 B1 B2 B3.
443     // However, for GMM's purposes QPitch is still the distance between
444     // elements--not the distance between samples.
445     // -------------------------------------------------------------------------
446     if((pTexInfo->ArraySize <= 1) &&
447        (pTexInfo->Type != RESOURCE_CUBE) &&
448        !(pTexInfo->Flags.Gpu.ColorSeparation ||
449          pTexInfo->Flags.Gpu.ColorSeparationRGBX))
450     {
451         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = 0;
452         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock   = 0;
453     }
454     else
455     {
456         uint32_t Height, Height0, Height1, ArrayQPitch, VAlign;
457 
458         Height = pTexInfo->BaseHeight;
459 
460         VAlign = pTexInfo->Alignment.VAlign;
461 
462         Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo);
463         Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo);
464 
465         if(!pTexInfo->Alignment.ArraySpacingSingleLod)
466         {
467             // QPitch = (h0 + h1 + 12j) * pitch
468             ArrayQPitch = Height0 + Height1 + 12 * VAlign;
469         }
470         else // SURFACE_STATE: Surface Array Spacing: ARYSPC_LOD0
471         {
472             // QPitch = h0 * pitch
473             ArrayQPitch = Height0;
474         }
475 
476         if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format))
477         {
478             uint32_t CompressHeight, CompressWidth, CompressDepth;
479 
480             GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
481 
482             ArrayQPitch /= CompressHeight;
483         }
484         else if(pTexInfo->Flags.Gpu.SeparateStencil)
485         {
486             ArrayQPitch /= 2;
487         }
488 
489         if((pTexInfo->MSAA.NumSamples > 1) && !(pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil))
490         {
491             // Gen7 MSAA (non-Depth/Stencil) RT samples stored as array planes;
492             // QPitch still element-to-element, not sample-to-sample.
493             ArrayQPitch *= pTexInfo->MSAA.NumSamples;
494         }
495 
496         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = ArrayQPitch * pTexInfo->Pitch;
497         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock   = ArrayQPitch * pTexInfo->Pitch;
498     }
499 
500     for(i = 0; i <= pTexInfo->MaxLod; i++)
501     {
502         pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i);
503     }
504 
505     GMM_DPF_EXIT;
506 }
507 
508 
509 /////////////////////////////////////////////////////////////////////////////////////
510 /// Calculates total height of an arrayed 3D mip layout
511 ///
512 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
513 ///
514 /// @return     height of arrayed 3D mip layout
515 /////////////////////////////////////////////////////////////////////////////////////
GetTotal3DHeight(GMM_TEXTURE_INFO * pTexInfo)516 uint32_t GmmLib::GmmGen7TextureCalc::GetTotal3DHeight(GMM_TEXTURE_INFO *pTexInfo)
517 {
518     uint32_t          AlignedHeight, BlockHeight, Depth;
519     uint8_t           Compressed;
520     uint32_t          i, MipsInThisRow, MipLevel, MipRows;
521     uint32_t          Total3DHeight = 0, UnitAlignHeight;
522     uint32_t          CompressHeight, CompressWidth, CompressDepth;
523     GMM_TEXTURE_CALC *pTextureCalc;
524 
525     GMM_DPF_ENTER;
526 
527     pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext);
528 
529     BlockHeight     = pTexInfo->BaseHeight;
530     Depth           = pTexInfo->Depth;
531     MipLevel        = pTexInfo->MaxLod;
532     UnitAlignHeight = pTexInfo->Alignment.VAlign;
533 
534     Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
535     pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
536 
537     // All mip0s of all planes are stacked together, then mip1s and so on...
538     for(i = 0; i <= MipLevel; i++)
539     {
540         BlockHeight   = GFX_MAX(BlockHeight, UnitAlignHeight);
541         AlignedHeight = GFX_ALIGN(BlockHeight, UnitAlignHeight);
542 
543         if(Compressed)
544         {
545             AlignedHeight /= CompressHeight;
546         }
547         else if(pTexInfo->Flags.Gpu.SeparateStencil)
548         {
549             AlignedHeight /= 2;
550         }
551         else if(pTexInfo->Flags.Gpu.CCS)
552         {
553             if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
554             {
555                 AlignedHeight /= 32;
556             }
557             else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
558             {
559                 AlignedHeight /= 16;
560             }
561         }
562 
563         // See how many mip can fit in one row
564         MipsInThisRow = GFX_2_TO_POWER_OF(i);
565 
566         // calculate if the mips will spill over to multiple rows
567         MipRows = GFX_CEIL_DIV(GFX_MAX(1, Depth >> i), MipsInThisRow);
568 
569         Total3DHeight += MipRows * AlignedHeight;
570 
571         // next level height
572         BlockHeight >>= 1;
573     }
574 
575     GMM_DPF_EXIT;
576     return Total3DHeight;
577 }
578 
579 
580 /////////////////////////////////////////////////////////////////////////////////////
581 /// Calculates the address offset for each mip map of 3D texture and store them
582 /// into the GMM_TEXTURE_INFO for surf state programming.
583 ///
584 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
585 ///
586 /////////////////////////////////////////////////////////////////////////////////////
Fill3DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)587 void GmmLib::GmmGen7TextureCalc::Fill3DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
588 {
589     uint32_t          AlignedMipHeight, AlignedMipWidth;
590     uint32_t          i, Depth;
591     uint32_t          MipsInThisRow, MipLevel, MipRows;
592     uint32_t          MipHeight, MipWidth;
593     uint32_t          UnitAlignHeight, UnitAlignWidth;
594     uint32_t          CompressHeight, CompressWidth, CompressDepth;
595     uint32_t          OffsetMipRows = 0;
596     GMM_GFX_SIZE_T    OffsetValue;
597     uint8_t           Compress;
598     GMM_TEXTURE_CALC *pTextureCalc;
599 
600     __GMM_ASSERT(pTexInfo);
601 
602     pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext);
603 
604     // Assign directly to unaligned MipMap dimension variables
605     // There isn't a need to save original dimensions
606     MipWidth  = GFX_ULONG_CAST(pTexInfo->BaseWidth);
607     MipHeight = pTexInfo->BaseHeight;
608 
609     // Align before we compress
610     UnitAlignWidth  = pTexInfo->Alignment.HAlign;
611     UnitAlignHeight = pTexInfo->Alignment.VAlign;
612     Compress        = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
613     pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
614 
615     // Aligned MipMap Dimensions
616     AlignedMipWidth  = GFX_ALIGN(MipWidth, UnitAlignWidth);
617     AlignedMipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
618 
619     Depth    = pTexInfo->Depth;
620     MipLevel = pTexInfo->MaxLod;
621 
622     // Start with base offset
623     OffsetValue = 0;
624 
625     // calculate the offset for each Mip level
626     for(i = 0; i <= MipLevel; i++)
627     {
628         // store the value in blockdesc
629         if(Compress)
630         {
631             // If there is compression, compress after the alignment at each level
632             AlignedMipWidth /= CompressWidth;
633             AlignedMipHeight /= CompressHeight;
634         }
635         else if(pTexInfo->Flags.Gpu.SeparateStencil)
636         {
637             AlignedMipWidth *= 2;
638             AlignedMipHeight /= 2;
639         }
640         else if(pTexInfo->Flags.Gpu.CCS)
641         {
642             if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
643             {
644                 switch(pTexInfo->BitsPerPixel)
645                 {
646                     case 32:
647                         AlignedMipWidth /= 8;
648                         break;
649                     case 64:
650                         AlignedMipWidth /= 4;
651                         break;
652                     case 128:
653                         AlignedMipWidth /= 2;
654                         break;
655                     default:
656                         __GMM_ASSERT(0);
657                 }
658 
659                 AlignedMipHeight /= 32;
660             }
661             else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
662             {
663                 switch(pTexInfo->BitsPerPixel)
664                 {
665                     case 32:
666                         AlignedMipWidth /= 16;
667                         break;
668                     case 64:
669                         AlignedMipWidth /= 8;
670                         break;
671                     case 128:
672                         AlignedMipWidth /= 4;
673                         break;
674                     default:
675                         __GMM_ASSERT(0);
676                 }
677 
678                 AlignedMipHeight /= 16;
679             }
680         }
681 
682         pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[i] = OffsetValue;
683 
684         // See how many mip can fit in one row
685         MipsInThisRow = GFX_2_TO_POWER_OF(i);
686 
687         // Slice pitch for LOD0
688         if(MipsInThisRow == 1)
689         {
690             pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch =
691             AlignedMipHeight * pTexInfo->Pitch;
692         }
693 
694         // calculate if the mips will spill over to multiple rows
695         MipRows = GFX_CEIL_DIV(GFX_MAX(1, Depth >> i), MipsInThisRow);
696 
697         // Offset in terms of height
698         OffsetMipRows += MipRows * AlignedMipHeight;
699 
700         // For a particular mip This is offset of a base slice (i.e. Slice 0)
701         OffsetValue = OffsetMipRows * pTexInfo->Pitch;
702 
703         // next level height
704         MipHeight >>= 1;
705         // Clamp such that mip height is at least1
706         MipHeight        = GFX_MAX(MipHeight, 1);
707         AlignedMipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
708 
709         MipWidth >>= 1;
710         // Clamp such that mip width is at least 1
711         MipWidth        = GFX_MAX(MipWidth, 1);
712         AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
713     }
714 }
715 
716 /////////////////////////////////////////////////////////////////////////////////////
717 /// Calculates the 3D offset and QPitch for surface state programming.
718 ///
719 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
720 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
721 ///
722 /// @return     ::GMM_STATUS
723 /////////////////////////////////////////////////////////////////////////////////////
FillTex3D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)724 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex3D(GMM_TEXTURE_INFO * pTexInfo,
725                                                              __GMM_BUFFER_TYPE *pRestrictions)
726 {
727     uint32_t   AlignedMipWidth;
728     uint32_t   BitsPerPixel;
729     uint32_t   Depth, Height, Width;
730     uint32_t   i, MipsInThisRow, MipWidth;
731     uint32_t   RenderPitch = 0, ThisRowPitch;
732     uint32_t   UnitAlignWidth;
733     uint32_t   Total3DHeight;
734     uint32_t   WidthBytesPhysical;
735     uint8_t    Compress;
736     uint32_t   CompressHeight, CompressWidth, CompressDepth;
737     bool       SeparateStencil;
738     GMM_STATUS Status;
739 
740     GMM_DPF_ENTER;
741 
742     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
743     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
744 
745     const __GMM_PLATFORM_RESOURCE *pPlatformResource = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
746 
747     BitsPerPixel = pTexInfo->BitsPerPixel;
748     Height       = pTexInfo->BaseHeight;
749     Width        = GFX_ULONG_CAST(pTexInfo->BaseWidth);
750     Depth        = pTexInfo->Depth;
751 
752     // Align before we compress
753     UnitAlignWidth = pTexInfo->Alignment.HAlign;
754     Compress       = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
755     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
756     SeparateStencil = pTexInfo->Flags.Gpu.SeparateStencil ? true : false;
757 
758     // Unaligned MipMap dimension variables
759     MipWidth = Width;
760 
761     // Aligned MipMap dimension variables
762     AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
763 
764     // Calculate the render pitch exactly the same way we do the
765     // offset for each Mip level
766     for(i = 0; i <= pTexInfo->MaxLod; i++)
767     {
768         if(Compress)
769         {
770             // If there is compression, compress after the alignment at each level
771             AlignedMipWidth /= CompressWidth;
772         }
773         else if(SeparateStencil)
774         {
775             AlignedMipWidth *= 2;
776         }
777         else if(pTexInfo->Flags.Gpu.CCS)
778         {
779             if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
780             {
781                 switch(BitsPerPixel)
782                 {
783                     case 32:
784                         AlignedMipWidth /= 8;
785                         break;
786                     case 64:
787                         AlignedMipWidth /= 4;
788                         break;
789                     case 128:
790                         AlignedMipWidth /= 2;
791                         break;
792                     default:
793                         __GMM_ASSERT(0);
794                 }
795             }
796             else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
797             {
798                 switch(BitsPerPixel)
799                 {
800                     case 32:
801                         AlignedMipWidth /= 16;
802                         break;
803                     case 64:
804                         AlignedMipWidth /= 8;
805                         break;
806                     case 128:
807                         AlignedMipWidth /= 4;
808                         break;
809                     default:
810                         __GMM_ASSERT(0);
811                 }
812             }
813         }
814 
815         // See how many mip can fit in one row
816         MipsInThisRow = GFX_2_TO_POWER_OF(i);
817 
818         // LOD planes may be less than MipsInThisRow, take the smaller value for pitch
819         MipsInThisRow = GFX_MIN(GFX_MAX(1, (Depth >> i)), MipsInThisRow);
820         ThisRowPitch  = AlignedMipWidth * MipsInThisRow;
821 
822         // Default pitch
823         WidthBytesPhysical = ThisRowPitch * BitsPerPixel >> 3;
824 
825         if(RenderPitch < WidthBytesPhysical)
826         {
827             RenderPitch = WidthBytesPhysical;
828         }
829 
830         MipWidth >>= 1;
831         // Clamp such that mip width is at least 1
832         MipWidth        = GFX_MAX(MipWidth, 1);
833         AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
834     }
835 
836     WidthBytesPhysical = RenderPitch;
837 
838     // Make sure the pitch satisfy linear min pitch requirment
839     WidthBytesPhysical = GFX_MAX(WidthBytesPhysical,
840                                  pRestrictions->MinPitch);
841 
842     // Make sure pitch satisfy alignment restriction
843     WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical,
844                                    pRestrictions->PitchAlignment);
845 
846     // Get Total height for the entire 3D texture
847     Total3DHeight = GetTotal3DHeight(pTexInfo);
848 
849     if(GMM_IS_TILED(pPlatformResource->TileInfo[pTexInfo->TileMode]))
850     {
851         // Align to tile boundary
852         Total3DHeight = GFX_ALIGN(Total3DHeight,
853                                   pPlatformResource->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
854         WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical,
855                                        pPlatformResource->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
856     }
857 
858     // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
859     // padding needs to be added. Since this will create a none pitch aligned
860     // surface the padding is aligned to the next row
861     if(GmmIsYUVPacked(pTexInfo->Format) ||
862        (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
863        (pTexInfo->BitsPerPixel == GMM_BITS(48)))
864     {
865         Total3DHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), WidthBytesPhysical);
866     }
867 
868     Total3DHeight = GFX_ALIGN(Total3DHeight, __GMM_EVEN_ROW);
869 
870     if((Status = // <-- Note assignment.
871         FillTexPitchAndSize(
872         pTexInfo, WidthBytesPhysical, Total3DHeight, pRestrictions)) == GMM_SUCCESS)
873     {
874         Fill3DTexOffsetAddress(pTexInfo);
875     }
876 
877     GMM_DPF_EXIT;
878     return (Status);
879 }
880 
881 /////////////////////////////////////////////////////////////////////////////////////
882 /// Allocates the 1D mip layout for surface state programming.
883 ///
884 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
885 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
886 ///
887 /// @return     ::GMM_STATUS
888 /////////////////////////////////////////////////////////////////////////////////////
FillTex1D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)889 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo,
890                                                              __GMM_BUFFER_TYPE *pRestrictions)
891 {
892     return FillTex2D(pTexInfo, pRestrictions);
893 }
894 
895 /////////////////////////////////////////////////////////////////////////////////////
896 /// Calculates the cube layout for surface state programming.
897 ///
898 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
899 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
900 ///
901 /// @return     ::GMM_STATUS
902 /////////////////////////////////////////////////////////////////////////////////////
FillTexCube(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)903 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo,
904                                                                __GMM_BUFFER_TYPE *pRestrictions)
905 {
906     return FillTex2D(pTexInfo, pRestrictions);
907 }
908