xref: /aosp_15_r20/external/gmmlib/Source/GmmLib/Texture/GmmGen11Texture.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 #include "Internal/Common/Texture/GmmGen10TextureCalc.h"
25 #include "Internal/Common/Texture/GmmGen11TextureCalc.h"
26 
27 /////////////////////////////////////////////////////////////////////////////////////
28 /// This function calculates the (X,Y) address of each given plane. X is in bytes
29 /// and Y is in scanlines.
30 ///
31 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
32 ///
33 /////////////////////////////////////////////////////////////////////////////////////
FillPlanarOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)34 void GmmLib::GmmGen11TextureCalc::FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
35 {
36     GMM_GFX_SIZE_T *pUOffsetX, *pUOffsetY;
37     GMM_GFX_SIZE_T *pVOffsetX, *pVOffsetY;
38     uint32_t        YHeight = 0, VHeight = 0;
39     bool            UVPacked = false;
40     uint32_t        Height;
41     uint32_t        WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3;
42 
43 #define SWAP_UV()              \
44     {                          \
45         GMM_GFX_SIZE_T *pTemp; \
46                                \
47         pTemp     = pUOffsetX; \
48         pUOffsetX = pVOffsetX; \
49         pVOffsetX = pTemp;     \
50                                \
51         pTemp     = pUOffsetY; \
52         pUOffsetY = pVOffsetY; \
53         pVOffsetY = pTemp;     \
54     }
55 
56     __GMM_ASSERTPTR(pTexInfo, VOIDRETURN);
57     __GMM_ASSERTPTR(((pTexInfo->TileMode < GMM_TILE_MODES) && (pTexInfo->TileMode >= TILE_NONE)), VOIDRETURN);
58     GMM_DPF_ENTER;
59 
60     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
61 
62     // GMM_PLANE_Y always at (0, 0)...
63     pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0;
64     pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0;
65 
66     pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = 0;
67     pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = 0;
68 
69     Height = pTexInfo->BaseHeight;
70     if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
71     {
72         Height = __GMM_EXPAND_HEIGHT(this, Height, pTexInfo->Alignment.VAlign, pTexInfo);
73         Height = ScaleTextureHeight(pTexInfo, Height);
74         if(pTexInfo->Flags.Gpu.UnifiedAuxSurface)
75         {
76             pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0;
77         }
78     }
79 
80     // GMM_PLANE_U/V Planes...
81     pUOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U];
82     pUOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U];
83     pVOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V];
84     pVOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V];
85 
86     switch(pTexInfo->Format)
87     {
88         case GMM_FORMAT_IMC1:
89             SWAP_UV(); // IMC1 = IMC3 with Swapped U/V
90         case GMM_FORMAT_IMC3:
91         case GMM_FORMAT_MFX_JPEG_YUV420:  // Same as IMC3.
92                                           // YYYYYYYY
93                                           // YYYYYYYY
94                                           // YYYYYYYY
95                                           // YYYYYYYY
96                                           // UUUU
97                                           // UUUU
98                                           // VVVV
99                                           // VVVV
100         case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width.
101                                           // YYYYYYYY
102                                           // YYYYYYYY
103                                           // YYYYYYYY
104                                           // YYYYYYYY
105                                           // UUUUUUUU
106                                           // UUUUUUUU
107                                           // VVVVVVVV
108                                           // VVVVVVVV
109             {
110                 *pUOffsetX = 0;
111                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
112                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
113 
114                 *pVOffsetX = 0;
115                 VHeight    = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
116                 *pVOffsetY =
117                 GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) +
118                 GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
119 
120                 break;
121             }
122         case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width.
123                                                //YYYYYYYY
124                                                //YYYYYYYY
125                                                //YYYYYYYY
126                                                //YYYYYYYY
127                                                //UUUUUUUU
128                                                //VVVVVVVV
129             {
130                 *pUOffsetX = 0;
131                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
132                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
133 
134                 *pVOffsetX = 0;
135                 VHeight    = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
136                 *pVOffsetY =
137                 GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) +
138                 GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
139 
140                 break;
141             }
142         case GMM_FORMAT_MFX_JPEG_YUV411:  // Similar to IMC3 but U/V are quarter width and full height.
143                                           // YYYYYYYY
144                                           // YYYYYYYY
145                                           // YYYYYYYY
146                                           // YYYYYYYY
147                                           // UU
148                                           // UU
149                                           // UU
150                                           // UU
151                                           // VV
152                                           // VV
153                                           // VV
154                                           // VV
155         case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height.
156                                           // YYYYYYYY
157                                           // YYYYYYYY
158                                           // YYYYYYYY
159                                           // YYYYYYYY
160                                           // UUUU
161                                           // UUUU
162                                           // UUUU
163                                           // UUUU
164                                           // VVVV
165                                           // VVVV
166                                           // VVVV
167                                           // VVVV
168         case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size.
169                                          // YYYYYYYY
170                                          // YYYYYYYY
171                                          // YYYYYYYY
172                                          // YYYYYYYY
173                                          // UUUUUUUU
174                                          // UUUUUUUU
175                                          // UUUUUUUU
176                                          // UUUUUUUU
177                                          // VVVVVVVV
178                                          // VVVVVVVV
179                                          // VVVVVVVV
180                                          // VVVVVVVV
181             {
182                 *pUOffsetX = 0;
183                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
184                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
185 
186                 *pVOffsetX = 0;
187                 VHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
188                 *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2;
189 
190                 break;
191             }
192         case GMM_FORMAT_BGRP:
193         case GMM_FORMAT_RGBP:
194         {
195             //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned
196             if(pTexInfo->Flags.Info.Linear)
197             {
198                 *pUOffsetX = 0;
199                 YHeight    = pTexInfo->BaseHeight;
200                 *pUOffsetY = pTexInfo->BaseHeight;
201 
202                 *pVOffsetX = 0;
203                 VHeight    = pTexInfo->BaseHeight;
204                 *pVOffsetY = (GMM_GFX_SIZE_T)pTexInfo->BaseHeight * 2;
205             }
206             else //Tiled
207             {
208                 *pUOffsetX = 0;
209                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
210                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
211 
212                 *pVOffsetX = 0;
213                 VHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
214                 *pVOffsetY = (GMM_GFX_SIZE_T)GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2;
215             }
216             break;
217         }
218         case GMM_FORMAT_IMC2:
219             SWAP_UV(); // IMC2 = IMC4 with Swapped U/V
220         case GMM_FORMAT_IMC4:
221         {
222             // YYYYYYYY
223             // YYYYYYYY
224             // YYYYYYYY
225             // YYYYYYYY
226             // UUUUVVVV
227             // UUUUVVVV
228 
229             __GMM_ASSERT((pTexInfo->Pitch & 1) == 0);
230 
231             *pUOffsetX = 0;
232             YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
233             *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
234 
235             *pVOffsetX = pTexInfo->Pitch / 2;
236             VHeight    = GFX_CEIL_DIV(YHeight, 2);
237             *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
238 
239             // Not technically UV packed but sizing works out the same
240             UVPacked = true;
241 
242             break;
243         }
244         case GMM_FORMAT_I420: // I420 = IYUV
245         case GMM_FORMAT_IYUV:
246             SWAP_UV(); // I420/IYUV = YV12 with Swapped U/V
247         case GMM_FORMAT_YV12:
248         case GMM_FORMAT_YVU9:
249         {
250             // YYYYYYYY
251             // YYYYYYYY
252             // YYYYYYYY
253             // YYYYYYYY
254             // VVVVVV..  <-- V and U planes follow the Y plane, as linear
255             // ..UUUUUU      arrays--without respect to pitch.
256 
257             uint32_t YSize, YVSizeRShift, VSize, UOffset;
258             uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment;
259 
260             YSize = GFX_ULONG_CAST(pTexInfo->Pitch) * pTexInfo->BaseHeight;
261 
262             // YVU9 has one U/V pixel for each 4x4 Y block.
263             // The others have one U/V pixel for each 2x2 Y block.
264 
265             // YVU9 has a Y:V size ratio of 16 (4x4 --> 1).
266             // The others have a ratio of 4 (2x2 --> 1).
267             YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
268 
269             // If a Y plane isn't fully-aligned to its Y-->U/V block size, the
270             // extra/unaligned Y pixels still need corresponding U/V pixels--So
271             // for the purpose of computing the UVSize, we must consider a
272             // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would
273             // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.)
274             YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
275             YSizeForUVPurposes =
276             GFX_ALIGN(GFX_ULONG_CAST(pTexInfo->Pitch), YSizeForUVPurposesDimensionalAlignment) *
277             GFX_ALIGN(pTexInfo->BaseHeight, YSizeForUVPurposesDimensionalAlignment);
278 
279             VSize   = (YSizeForUVPurposes >> YVSizeRShift);
280             UOffset = YSize + VSize;
281 
282             *pVOffsetX = 0;
283             *pVOffsetY = pTexInfo->BaseHeight;
284 
285             *pUOffsetX = UOffset % pTexInfo->Pitch;
286             *pUOffsetY = UOffset / pTexInfo->Pitch;
287 
288             YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical);
289 
290             break;
291         }
292         case GMM_FORMAT_NV12:
293         case GMM_FORMAT_NV21:
294         case GMM_FORMAT_NV11:
295         case GMM_FORMAT_P010:
296         case GMM_FORMAT_P012:
297         case GMM_FORMAT_P016:
298         case GMM_FORMAT_P208:
299         case GMM_FORMAT_P216:
300         {
301             // YYYYYYYY
302             // YYYYYYYY
303             // YYYYYYYY
304             // YYYYYYYY
305             // [UV-Packing]
306             *pUOffsetX = *pVOffsetX = 0;
307             YHeight                 = GFX_ALIGN(Height, __GMM_EVEN_ROW);
308             *pUOffsetY = *pVOffsetY = YHeight;
309 
310             if((pTexInfo->Format == GMM_FORMAT_NV12) ||
311                (pTexInfo->Format == GMM_FORMAT_NV21) ||
312                (pTexInfo->Format == GMM_FORMAT_P010) ||
313                (pTexInfo->Format == GMM_FORMAT_P012) ||
314                (pTexInfo->Format == GMM_FORMAT_P016))
315             {
316                 VHeight = GFX_CEIL_DIV(Height, 2);
317             }
318             else
319             {
320                 VHeight = YHeight; // U/V plane is same as Y
321             }
322 
323             UVPacked = true;
324             break;
325         }
326         default:
327         {
328             GMM_ASSERTDPF(0, "Unknown Video Format U\n");
329             break;
330         }
331     }
332 
333     pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = YHeight;
334     if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2)
335     {
336         pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = VHeight;
337     }
338     else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3)
339     {
340         pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] =
341         pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V] = VHeight;
342     }
343 
344     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) || pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
345     {
346         GMM_GFX_SIZE_T TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
347         GMM_GFX_SIZE_T TileWidth  = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth;
348         GMM_GFX_SIZE_T PhysicalTileHeight = TileHeight;
349         if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) > IGFX_GEN11LP_CORE)
350         {
351             if(pTexInfo->Flags.Gpu.CCS && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS)
352             {
353                 //U/V must be aligned to AuxT granularity, 4x pitchalign enforces 16K-align for 4KB tile,
354                 //add extra padding for 64K AuxT, 1MB AuxT
355                 if(GMM_IS_64KB_TILE(pTexInfo->Flags))
356                 {
357                     TileHeight *= (!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) ? 16 : 1; // For 64Kb Tile mode: Multiply TileHeight by 16 for 1 MB alignment
358                 }
359                 else
360                 {
361                     PhysicalTileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 1); //  for 1 MB AuxT granularity, we do 1 MB alignment only in VA space and not in physical space, so do not multiply PhysicalTileHeight with 64 here
362                     TileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64);        // For 4k Tile:  Multiply TileHeight by 4 and Pitch by 4 for 64kb alignment, multiply TileHeight by 64 and Pitch by 4 for 1 MB alignment
363                 }
364             }
365         }
366 
367         *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth);
368         *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight);
369         *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth);
370         *pVOffsetY = UVPacked ?
371                      GFX_ALIGN(*pVOffsetY, TileHeight) :
372                      GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight);
373 
374         if(pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
375         {
376             *pUOffsetY += pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y];
377             *pVOffsetY = *pUOffsetY;
378         }
379 
380         // This is needed for FtrDisplayPageTables
381         if(pGmmLibContext->GetSkuTable().FtrDisplayPageTables)
382         {
383             pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_Y] = GFX_ALIGN(YHeight, TileHeight);
384             if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2)
385             {
386                 pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_U] = GFX_ALIGN(VHeight, TileHeight);
387             }
388             else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3)
389             {
390                 pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_U] =
391                 pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_V] = GFX_ALIGN(VHeight, TileHeight);
392             }
393         }
394     }
395 
396     //Special case LKF MMC compressed surfaces
397     if(pTexInfo->Flags.Gpu.MMC &&
398        pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
399        pTexInfo->Flags.Info.TiledY)
400     {
401         GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
402         GMM_GFX_SIZE_T TileWidth  = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth;
403 
404         *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth);
405         *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight);
406         *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth);
407         *pVOffsetY = GFX_ALIGN(*pVOffsetY, TileHeight);
408     }
409 
410     GMM_DPF_EXIT;
411 
412 #undef SWAP_UV
413 }
414 
415 /////////////////////////////////////////////////////////////////////////////////////
416 /// Returns the mip offset of given LOD in Mip Tail
417 ///
418 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
419 ///             MipLevel: mip-map level
420 ///
421 /// @return     offset value of LOD in bytes
422 /////////////////////////////////////////////////////////////////////////////////////
GetMipTailByteOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)423 uint32_t GmmLib::GmmGen11TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo,
424                                                            uint32_t          MipLevel)
425 {
426     uint32_t ByteOffset = 0, Slot = 0xff;
427 
428     GMM_DPF_ENTER;
429 
430     // 3D textures follow the Gen10 mip tail format
431     if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat)
432     {
433         return GmmGen9TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel);
434     }
435 
436     if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_3D))
437     {
438         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
439                (pTexInfo->Flags.Info.TiledYf ? 4 : 0);
440     }
441     else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
442     {
443         // clang-format off
444         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
445                     // TileYs
446                    ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 :
447                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  8) ? 3 :
448                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  4) ? 2 :
449                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  2) ? 1 :
450                     (pTexInfo->Flags.Info.TiledYs                                   ) ? 0 :
451                     // TileYf
452                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11:
453                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples ==  8) ? 10:
454                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples ==  4) ?  8:
455                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples ==  2) ?  5:
456                     (pTexInfo->Flags.Info.TiledYf                                   ) ?  4: 0);
457         // clang-format on
458     }
459 
460     switch(Slot)
461     {
462         case 0:
463             ByteOffset = GMM_KBYTE(32);
464             break;
465         case 1:
466             ByteOffset = GMM_KBYTE(16);
467             break;
468         case 2:
469             ByteOffset = GMM_KBYTE(8);
470             break;
471         case 3:
472             ByteOffset = GMM_KBYTE(4);
473             break;
474         case 4:
475             ByteOffset = GMM_KBYTE(2);
476             break;
477         case 5:
478             ByteOffset = GMM_BYTES(1536);
479             break;
480         case 6:
481             ByteOffset = GMM_BYTES(1280);
482             break;
483         case 7:
484             ByteOffset = GMM_BYTES(1024);
485             break;
486         case 8:
487             ByteOffset = GMM_BYTES(768);
488             break;
489         case 9:
490             ByteOffset = GMM_BYTES(512);
491             break;
492         case 10:
493             ByteOffset = GMM_BYTES(256);
494             break;
495         case 11:
496             ByteOffset = GMM_BYTES(0);
497             break;
498         case 12:
499             ByteOffset = GMM_BYTES(64);
500             break;
501         case 13:
502             ByteOffset = GMM_BYTES(128);
503             break;
504         case 14:
505             ByteOffset = GMM_BYTES(196);
506             break;
507         default:
508             __GMM_ASSERT(0);
509     }
510 
511     GMM_DPF_EXIT;
512 
513     return (ByteOffset);
514 }
515 
516 
517 /////////////////////////////////////////////////////////////////////////////////////
518 /// Returns the mip-map offset in geometric OffsetX, Y, Z for a given LOD in Mip Tail on Gen11.
519 ///
520 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
521 ///             MipLevel: mip-map level
522 ///             OffsetX: ptr to Offset in X direction (in bytes)
523 ///             OffsetY: ptr to Offset in Y direction (in pixels)
524 ///             OffsetZ: ptr to Offset in Z direction (in pixels)
525 ///
526 /////////////////////////////////////////////////////////////////////////////////////
527 
528 GMM_MIPTAIL_SLOT_OFFSET Gen11MipTailSlotOffset1DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_1D_SURFACE;
529 GMM_MIPTAIL_SLOT_OFFSET Gen11MipTailSlotOffset2DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_2D_SURFACE;
530 GMM_MIPTAIL_SLOT_OFFSET Gen11MipTailSlotOffset3DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_3D_SURFACE;
531 
GetMipTailGeometryOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel,uint32_t * OffsetX,uint32_t * OffsetY,uint32_t * OffsetZ)532 void GmmLib::GmmGen11TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo,
533                                                            uint32_t          MipLevel,
534                                                            uint32_t *        OffsetX,
535                                                            uint32_t *        OffsetY,
536                                                            uint32_t *        OffsetZ)
537 {
538     uint32_t ArrayIndex = 0;
539     uint32_t Slot       = 0;
540 
541     GMM_DPF_ENTER;
542 
543     switch(pTexInfo->BitsPerPixel)
544     {
545         case 128:
546             ArrayIndex = 0;
547             break;
548         case 64:
549             ArrayIndex = 1;
550             break;
551         case 32:
552             ArrayIndex = 2;
553             break;
554         case 16:
555             ArrayIndex = 3;
556             break;
557         case 8:
558             ArrayIndex = 4;
559             break;
560         default:
561             __GMM_ASSERT(0);
562             break;
563     }
564 
565     if(pTexInfo->Type == RESOURCE_1D)
566     {
567         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod;
568 
569         *OffsetX = Gen11MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
570         *OffsetY = Gen11MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y;
571         *OffsetZ = Gen11MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z;
572     }
573     else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
574     {
575         // clang-format off
576         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
577                // TileYs
578                ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 :
579                (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 :
580                (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 :
581                (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 :
582                (pTexInfo->Flags.Info.TiledYs) ? 0 :
583                // TileYf
584                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11 :
585                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 8) ? 10 :
586                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 4) ? 8 :
587                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 2) ? 5 :
588                (pTexInfo->Flags.Info.TiledYf) ? 4 : 0);
589         // clang-format on
590 
591         *OffsetX = Gen11MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
592         *OffsetY = Gen11MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y;
593         *OffsetZ = Gen11MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z;
594     }
595     else if(pTexInfo->Type == RESOURCE_3D)
596     {
597         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod;
598 
599         *OffsetX = Gen11MipTailSlotOffset3DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
600         *OffsetY = Gen11MipTailSlotOffset3DSurface[Slot][ArrayIndex].Y;
601         *OffsetZ = Gen11MipTailSlotOffset3DSurface[Slot][ArrayIndex].Z;
602     }
603 
604     GMM_DPF_EXIT;
605     return;
606 }
607 
FillLinearCCS(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)608 GMM_STATUS GmmLib::GmmGen11TextureCalc::FillLinearCCS(GMM_TEXTURE_INFO * pTexInfo,
609                                                       __GMM_BUFFER_TYPE *pRestrictions)
610 {
611     GMM_GFX_SIZE_T           PaddedSize;
612     uint32_t                 TileHeight;
613     GMM_GFX_SIZE_T           YCcsSize    = 0;
614     GMM_GFX_SIZE_T           UVCcsSize   = 0;
615     GMM_GFX_SIZE_T           TotalHeight = 0;
616     const GMM_PLATFORM_INFO *pPlatform   = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
617     GMM_DPF_ENTER;
618 
619 
620     __GMM_ASSERT(pTexInfo->Flags.Gpu.MMC &&
621                  pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
622                  pTexInfo->Flags.Gpu.__NonMsaaLinearCCS);
623 
624     __GMM_ASSERT(pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] > 0);
625     TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
626 
627     // Vinante : CCS or Tile status buffer is computed by giving 2bit for every 256bytes of origional pixel data.
628     // For YUV Planar surfaces, UV Plane follow immediately after Y plane. Y and UV surfaces have their own
629     // control surfaces. So AuxSurf will be linear buffer with CCS for Y plane followed by CCS for UV plane.
630     // Y and UV control surface must be 4kb base aligned and they store the control data for full tiles covering Y and UV
631     // planes respectively.
632     // GMM will also allocate cacheline aligned 64-byte to hold the LKF's software controlled media compression state.
633     // GMM will calculate YAuxOffset, UVAuxOffset and MediaCompression State offset on the fly. Refer GmmResGetAuxSurfaceOffset().
634 
635     YCcsSize = pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] * pTexInfo->Pitch / 1024;
636     YCcsSize = GFX_ALIGN(YCcsSize, PAGE_SIZE);
637 
638     if(pTexInfo->ArraySize > 1)
639     {
640         TotalHeight = pTexInfo->OffsetInfo.Plane.ArrayQPitch / pTexInfo->Pitch;
641     }
642     else
643     {
644         TotalHeight = pTexInfo->Size / pTexInfo->Pitch;
645     }
646 
647     UVCcsSize = (TotalHeight - pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) * pTexInfo->Pitch / 1024;
648     UVCcsSize = GFX_ALIGN(UVCcsSize, PAGE_SIZE);
649 
650     pTexInfo->Size  = GFX_ALIGN(YCcsSize + UVCcsSize + GMM_MEDIA_COMPRESSION_STATE_SIZE, pRestrictions->MinAllocationSize);
651     pTexInfo->Pitch = 0;
652 
653     //Store the dimension of linear surface in OffsetInfo.Plane.X.
654     pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = YCcsSize;
655     pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U] =
656     pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V] = UVCcsSize;
657 
658     pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] =
659     pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] =
660     pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] = 0;
661 
662     // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout
663     // is defined by SW requirements; Y plane must be 4KB aligned.
664     if(pTexInfo->ArraySize > 1)
665     {
666         GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size;
667         int64_t        LargeSize;
668 
669         // Size should always be page aligned.
670         __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0);
671 
672         if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize)
673         {
674             pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes;
675             pTexInfo->Size                         = LargeSize;
676         }
677         else
678         {
679             GMM_ASSERTDPF(0, "Surface too large!");
680             return GMM_ERROR;
681         }
682     }
683 
684     return GMM_SUCCESS;
685     GMM_DPF_EXIT;
686 }
687 
688 /////////////////////////////////////////////////////////////////////////////////////
689 /// This function will Setup a planar surface allocation.
690 ///
691 /// @param[in]  pTexInfo: Reference to ::GMM_TEXTURE_INFO
692 /// @param[in]  pRestrictions: Reference to surface alignment and size restrictions.
693 ///
694 /// @return     ::GMM_STATUS
695 /////////////////////////////////////////////////////////////////////////////////////
FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)696 GMM_STATUS GMM_STDCALL GmmLib::GmmGen11TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo,
697                                                                   __GMM_BUFFER_TYPE *pRestrictions)
698 {
699     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
700 
701     GMM_DPF_ENTER;
702     uint32_t   WidthBytesPhysical, Height, YHeight, VHeight;
703     uint32_t   AdjustedVHeight = 0;
704     GMM_STATUS Status;
705     bool       UVPacked = false;
706 
707     GMM_DPF_ENTER;
708 
709     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
710     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
711     __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW);
712 
713     pTexInfo->TileMode = TILE_NONE;
714 
715     WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3;
716     Height = VHeight = 0;
717 
718     YHeight = pTexInfo->BaseHeight;
719 
720     //[History]
721     // When planar surfaces are tiled, there are HW alignment
722     // restrictions about where the U and V planes can be located.
723     // Prior to SURFACE_STATE.X/YOffset support, planes needed to start
724     // on tile boundaries; with X/YOffset support, the alignment
725     // restrictions were reduced (but not eliminated).
726     //
727     // Horizontal alignment is only an issue for IMC2/4 surfaces, since
728     // the planes of all other formats are always on the left-edge.
729     //
730     // For IMC1/3 surfaces, we must ensure that both the U/V planes are
731     // properly aligned--That is, both the YHeight and VHeight must be
732     // properly aligned. For all other surfaces (since the U/V data
733     // starts at a common vertical location) only YHeight must be
734     // properly aligned.
735 
736     // [Current] :
737     // For Tiled surfaces, even though h/w supports U and V plane alignment
738     // at lower granularities GMM will align all the planes at Tiled boundary
739     // to unify the implementation across all platforms and GMM will add
740     // handling for removing the extra padding when UMDs request for ResCpuBlt
741     // operations.
742     // For Linear surfaces, GMM will continue to support minimal aligment restrictions
743 
744     switch(pTexInfo->Format)
745     {
746         case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V
747         case GMM_FORMAT_IMC3:
748         case GMM_FORMAT_MFX_JPEG_YUV420:  // Same as IMC3.
749                                           // YYYYYYYY
750                                           // YYYYYYYY
751                                           // YYYYYYYY
752                                           // YYYYYYYY
753                                           // UUUU
754                                           // UUUU
755                                           // VVVV
756                                           // VVVV
757         case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width.
758                                           // YYYYYYYY
759                                           // YYYYYYYY
760                                           // YYYYYYYY
761                                           // YYYYYYYY
762                                           // UUUUUUUU
763                                           // UUUUUUUU
764                                           // VVVVVVVV
765                                           // VVVVVVVV
766             {
767                 VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
768                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
769 
770                 Height                                = YHeight + 2 * VHeight; // One VHeight for V and one for U.
771                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
772                 break;
773             }
774         case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width.
775                                                //YYYYYYYY
776                                                //YYYYYYYY
777                                                //YYYYYYYY
778                                                //YYYYYYYY
779                                                //UUUUUUUU
780                                                //VVVVVVVV
781             {
782                 VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
783 
784                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
785 
786                 Height                                = YHeight + 2 * VHeight;
787                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
788                 break;
789             }
790         case GMM_FORMAT_MFX_JPEG_YUV411:  // Similar to IMC3 but U/V are quarter width and full height.
791                                           // YYYYYYYY
792                                           // YYYYYYYY
793                                           // YYYYYYYY
794                                           // YYYYYYYY
795                                           // UU
796                                           // UU
797                                           // UU
798                                           // UU
799                                           // VV
800                                           // VV
801                                           // VV
802                                           // VV
803         case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height.
804                                           // YYYYYYYY
805                                           // YYYYYYYY
806                                           // YYYYYYYY
807                                           // YYYYYYYY
808                                           // UUUU
809                                           // UUUU
810                                           // UUUU
811                                           // UUUU
812                                           // VVVV
813                                           // VVVV
814                                           // VVVV
815                                           // VVVV
816         case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size.
817 #if _WIN32
818         case GMM_FORMAT_WGBOX_YUV444:
819         case GMM_FORMAT_WGBOX_PLANAR_YUV444:
820 #endif
821             // YYYYYYYY
822             // YYYYYYYY
823             // YYYYYYYY
824             // YYYYYYYY
825             // UUUUUUUU
826             // UUUUUUUU
827             // UUUUUUUU
828             // UUUUUUUU
829             // VVVVVVVV
830             // VVVVVVVV
831             // VVVVVVVV
832             // VVVVVVVV
833             {
834                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
835                 VHeight = YHeight;
836 
837                 Height                                = YHeight + 2 * VHeight;
838                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
839                 break;
840             }
841         case GMM_FORMAT_BGRP:
842         case GMM_FORMAT_RGBP:
843         {
844             //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned
845             if(pTexInfo->Flags.Info.Linear)
846             {
847                 VHeight = YHeight;
848 
849                 Height                                = YHeight + 2 * VHeight;
850                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
851             }
852             else //Tiled
853             {
854                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
855                 VHeight = YHeight;
856 
857                 Height                                = YHeight + 2 * VHeight;
858                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
859             }
860             break;
861         }
862         case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V
863         case GMM_FORMAT_IMC4:
864         {
865             // YYYYYYYY
866             // YYYYYYYY
867             // YYYYYYYY
868             // YYYYYYYY
869             // UUUUVVVV
870             // UUUUVVVV
871 
872             YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
873             VHeight = GFX_CEIL_DIV(YHeight, 2);
874 
875             WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes.
876 
877             Height = YHeight + VHeight;
878 
879             // With SURFACE_STATE.XOffset support, the U-V interface has
880             // much lighter restrictions--which will be naturally met by
881             // surface pitch restrictions (i.e. dividing an IMC2/4 pitch
882             // by 2--to get the U/V interface--will always produce a safe
883             // XOffset value).
884 
885             // Not technically UV packed but sizing works out the same
886             // if the resource is std swizzled
887             UVPacked                              = true;
888             pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2;
889 
890             break;
891         }
892         case GMM_FORMAT_NV12:
893         case GMM_FORMAT_NV21:
894         case GMM_FORMAT_NV11:
895         case GMM_FORMAT_P010:
896         case GMM_FORMAT_P012:
897         case GMM_FORMAT_P016:
898         case GMM_FORMAT_P208:
899         case GMM_FORMAT_P216:
900         {
901             // YYYYYYYY
902             // YYYYYYYY
903             // YYYYYYYY
904             // YYYYYYYY
905             // [UV-Packing]
906 
907             if((pTexInfo->Format == GMM_FORMAT_NV12) ||
908                (pTexInfo->Format == GMM_FORMAT_NV21) ||
909                (pTexInfo->Format == GMM_FORMAT_P010) ||
910                (pTexInfo->Format == GMM_FORMAT_P012) ||
911                (pTexInfo->Format == GMM_FORMAT_P016))
912             {
913                 VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y
914                 Height  = YHeight + VHeight;
915             }
916             else
917             {
918                 VHeight = YHeight; // U/V plane is same as Y
919                 Height  = YHeight + VHeight;
920             }
921 
922             if((pTexInfo->Format == GMM_FORMAT_NV12) ||
923                (pTexInfo->Format == GMM_FORMAT_NV21) ||
924                (pTexInfo->Format == GMM_FORMAT_P010) ||
925                (pTexInfo->Format == GMM_FORMAT_P012) ||
926                (pTexInfo->Format == GMM_FORMAT_P016) ||
927                (pTexInfo->Format == GMM_FORMAT_P208) ||
928                (pTexInfo->Format == GMM_FORMAT_P216))
929             {
930                 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes.
931                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2;
932             }
933             else //if(pTexInfo->Format == GMM_FORMAT_NV11)
934             {
935                 // Tiling not supported, since YPitch != UVPitch...
936                 pTexInfo->Flags.Info.TiledY  = 0;
937                 pTexInfo->Flags.Info.TiledYf = 0;
938                 pTexInfo->Flags.Info.TiledYs = 0;
939                 pTexInfo->Flags.Info.TiledX  = 0;
940                 pTexInfo->Flags.Info.Linear  = 1;
941             }
942 
943             UVPacked                              = true;
944             break;
945         }
946         case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except,
947         case GMM_FORMAT_IYUV: // U & V pl.s are reversed.
948         case GMM_FORMAT_YV12:
949         case GMM_FORMAT_YVU9:
950         {
951             // YYYYYYYY
952             // YYYYYYYY
953             // YYYYYYYY
954             // YYYYYYYY
955             // VVVVVV..  <-- V and U planes follow the Y plane, as linear
956             // ..UUUUUU      arrays--without respect to pitch.
957 
958             uint32_t YSize, UVSize, YVSizeRShift;
959             uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment;
960 
961             YSize = WidthBytesPhysical * YHeight;
962 
963             // YVU9 has one U/V pixel for each 4x4 Y block.
964             // The others have one U/V pixel for each 2x2 Y block.
965 
966             // YVU9 has a Y:V size ratio of 16 (4x4 --> 1).
967             // The others have a ratio of 4 (2x2 --> 1).
968             YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
969 
970             // If a Y plane isn't fully-aligned to its Y-->U/V block size, the
971             // extra/unaligned Y pixels still need corresponding U/V pixels--So
972             // for the purpose of computing the UVSize, we must consider a
973             // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would
974             // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.)
975             YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
976             YSizeForUVPurposes =
977             GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) *
978             GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment);
979 
980             UVSize = 2 * // <-- U + V
981                      (YSizeForUVPurposes >> YVSizeRShift);
982 
983             Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical);
984 
985             // Tiling not supported, since YPitch != UVPitch...
986             pTexInfo->Flags.Info.TiledY  = 0;
987             pTexInfo->Flags.Info.TiledYf = 0;
988             pTexInfo->Flags.Info.TiledYs = 0;
989             pTexInfo->Flags.Info.TiledX  = 0;
990             pTexInfo->Flags.Info.Linear  = 1;
991 
992             pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1;
993             break;
994         }
995         default:
996         {
997             GMM_ASSERTDPF(0, "Unexpected format");
998             return GMM_ERROR;
999         }
1000     }
1001 
1002     // Align Height to even row to avoid hang if HW over-fetch
1003     Height = GFX_ALIGN(Height, __GMM_EVEN_ROW);
1004 
1005     SetTileMode(pTexInfo);
1006 
1007     // MMC is not supported for linear formats.
1008     if(pTexInfo->Flags.Gpu.MMC)
1009     {
1010         if(!(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs))
1011         {
1012             pTexInfo->Flags.Gpu.MMC = 0;
1013         }
1014     }
1015 
1016     // Legacy Planar "Linear Video" Restrictions...
1017     if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions)
1018     {
1019         pRestrictions->LockPitchAlignment   = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64));
1020         pRestrictions->MinPitch             = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64));
1021         pRestrictions->PitchAlignment       = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64));
1022         pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64));
1023     }
1024 
1025     // Multiply overall pitch alignment for surfaces whose U/V planes have a
1026     // pitch down-scaled from that of Y--Since the U/V pitches must meet the
1027     // original restriction, the Y pitch must meet a scaled-up multiple.
1028     if((pTexInfo->Format == GMM_FORMAT_I420) ||
1029        (pTexInfo->Format == GMM_FORMAT_IYUV) ||
1030        (pTexInfo->Format == GMM_FORMAT_NV11) ||
1031        (pTexInfo->Format == GMM_FORMAT_YV12) ||
1032        (pTexInfo->Format == GMM_FORMAT_YVU9))
1033     {
1034         uint32_t LShift =
1035         (pTexInfo->Format != GMM_FORMAT_YVU9) ?
1036         1 : // UVPitch = 1/2 YPitch
1037         2;  // UVPitch = 1/4 YPitch
1038 
1039         pRestrictions->LockPitchAlignment <<= LShift;
1040         pRestrictions->MinPitch <<= LShift;
1041         pRestrictions->PitchAlignment <<= LShift;
1042         pRestrictions->RenderPitchAlignment <<= LShift;
1043     }
1044 
1045     AdjustedVHeight = VHeight;
1046     // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access
1047     if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0)
1048     {
1049         AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE));
1050         Height += AdjustedVHeight - VHeight;
1051     }
1052 
1053     // For Tiled Planar surfaces, the planes must be tile-boundary aligned.
1054     // Actual alignment is handled in FillPlanarOffsetAddress, but height
1055     // and width must be adjusted for correct size calculation
1056     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
1057     {
1058         uint32_t TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
1059         uint32_t TileWidth  = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth;
1060 
1061         pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true;
1062 
1063         //for separate U and V planes, use U plane unaligned and V plane aligned
1064         Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) :
1065                                                               (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight)));
1066 
1067         if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns
1068            pTexInfo->Format == GMM_FORMAT_IMC4)
1069         {
1070             // If the U & V planes are side-by-side then the surface pitch must be
1071             // padded out so that U and V planes will being on a tile boundary.
1072             // This means that an odd Y plane width must be padded out
1073             // with an additional tile. Even widths do not need padding
1074             uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth);
1075             if(TileCols % 2)
1076             {
1077                 WidthBytesPhysical = (TileCols + 1) * TileWidth;
1078             }
1079         }
1080 
1081         if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)
1082         {
1083             pTexInfo->Flags.Info.RedecribedPlanes = 1;
1084         }
1085     }
1086 
1087     // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support
1088     //Special case LKF MMC compressed surfaces
1089     if(pTexInfo->Flags.Gpu.MMC &&
1090        pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
1091        pTexInfo->Flags.Info.TiledY)
1092     {
1093         uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
1094 
1095         Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight);
1096     }
1097 
1098     // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support
1099     // Very wide planar tiled planar formats do not support MMC pre gen11. All formats do not support
1100     // MMC above 16k bytes wide, while Yf NV12 does not support above 8k - 128 bytes.
1101     if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN10_CORE) &&
1102        (pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs))
1103     {
1104         if(((pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= GMM_KBYTE(16)) ||
1105            (pTexInfo->Format == GMM_FORMAT_NV12 && pTexInfo->Flags.Info.TiledYf &&
1106             (pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= (GMM_KBYTE(8) - 128)))
1107         {
1108             pTexInfo->Flags.Gpu.MMC = 0;
1109         }
1110     }
1111 
1112     if(pTexInfo->Flags.Info.RedecribedPlanes)
1113     {
1114         if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical))
1115         {
1116             __GMM_ASSERT(false);
1117         }
1118     }
1119 
1120     if((Status = // <-- Note assignment.
1121         FillTexPitchAndSize(
1122         pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS)
1123     {
1124         FillPlanarOffsetAddress(pTexInfo);
1125     }
1126 
1127     // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout
1128     // is defined by SW requirements; Y plane must be 4KB aligned.
1129     if(pTexInfo->ArraySize > 1)
1130     {
1131         GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size;
1132         int64_t        LargeSize;
1133 
1134         // Size should always be page aligned.
1135         __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0);
1136 
1137         if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize)
1138         {
1139             pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes;
1140             pTexInfo->Size                         = LargeSize;
1141         }
1142         else
1143         {
1144             GMM_ASSERTDPF(0, "Surface too large!");
1145             Status = GMM_ERROR;
1146         }
1147     }
1148 
1149     //LKF specific Restrictions
1150     if(GFX_GET_CURRENT_PRODUCT(pPlatform->Platform) == IGFX_LAKEFIELD)
1151     {
1152         // If GMM fall backs TileY to Linear then reset the UnifiedAuxSurface flag.
1153         if(!pTexInfo->Flags.Gpu.MMC &&
1154            pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
1155            !pTexInfo->Flags.Gpu.__NonMsaaLinearCCS)
1156         {
1157             GMM_ASSERTDPF(0, "MMC TileY is fallback to Linear surface!");
1158             pTexInfo->Flags.Gpu.UnifiedAuxSurface = 0;
1159         }
1160 
1161         if(pTexInfo->Flags.Gpu.MMC &&
1162            pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
1163            pTexInfo->Flags.Gpu.__NonMsaaLinearCCS)
1164         {
1165             FillLinearCCS(pTexInfo, pRestrictions);
1166         }
1167     }
1168 
1169     GMM_DPF_EXIT;
1170 
1171     return GMM_SUCCESS;
1172 }
1173