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 
24 #include "Internal/Common/GmmLibInc.h"
25 #include "Internal/Common/Texture/GmmGen10TextureCalc.h"
26 
27 /////////////////////////////////////////////////////////////////////////////////////
28 /// Returns the mip offset of given LOD in Mip Tail
29 ///
30 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
31 ///             MipLevel: given LOD #
32 ///
33 /// @return     offset value of LOD in bytes
34 /////////////////////////////////////////////////////////////////////////////////////
GetMipTailByteOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)35 uint32_t GmmLib::GmmGen10TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo,
36                                                            uint32_t          MipLevel)
37 {
38     uint32_t ByteOffset = 0, Slot = 0xff;
39 
40     GMM_DPF_ENTER;
41 
42     // 3D textures follow the Gen9 mip tail format
43     if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat || pTexInfo->Type == RESOURCE_3D)
44     {
45         return GmmGen9TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel);
46     }
47 
48 
49     if(pTexInfo->Type == RESOURCE_1D)
50     {
51         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
52                (pTexInfo->Flags.Info.TiledYf ? 4 : 0);
53     }
54     else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
55     {
56         // clang-format off
57         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
58                     // TileYs
59                    ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 :
60                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  8) ? 3 :
61                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  4) ? 2 :
62                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  2) ? 1 :
63                     (pTexInfo->Flags.Info.TiledYs                                   ) ? 0 :
64                     // TileYf
65                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11:
66                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples ==  8) ? 10:
67                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples ==  4) ?  8:
68                     (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples ==  2) ?  5:
69                     (pTexInfo->Flags.Info.TiledYf                                   ) ?  4: 0);
70         // clang-format on
71     }
72 
73     switch(Slot)
74     {
75         case 0:
76             ByteOffset = GMM_KBYTE(32);
77             break;
78         case 1:
79             ByteOffset = GMM_KBYTE(16);
80             break;
81         case 2:
82             ByteOffset = GMM_KBYTE(8);
83             break;
84         case 3:
85             ByteOffset = GMM_KBYTE(4);
86             break;
87         case 4:
88             ByteOffset = GMM_KBYTE(2);
89             break;
90         case 5:
91             ByteOffset = GMM_BYTES(1536);
92             break;
93         case 6:
94             ByteOffset = GMM_BYTES(1280);
95             break;
96         case 7:
97             ByteOffset = GMM_BYTES(1024);
98             break;
99         case 8:
100             ByteOffset = GMM_BYTES(768);
101             break;
102         case 9:
103             ByteOffset = GMM_BYTES(512);
104             break;
105         case 10:
106             ByteOffset = GMM_BYTES(256);
107             break;
108         case 11:
109             ByteOffset = GMM_BYTES(192);
110             break;
111         case 12:
112             ByteOffset = GMM_BYTES(128);
113             break;
114         case 13:
115             ByteOffset = GMM_BYTES(64);
116             break;
117         case 14:
118             ByteOffset = GMM_BYTES(0);
119             break;
120         default:
121             __GMM_ASSERT(0);
122     }
123 
124     GMM_DPF_EXIT;
125 
126     return (ByteOffset);
127 }
128 
129 GMM_MIPTAIL_SLOT_OFFSET Gen10MipTailSlotOffset1DSurface[15][5] = GEN10_MIPTAIL_SLOT_OFFSET_1D_SURFACE;
130 GMM_MIPTAIL_SLOT_OFFSET Gen10MipTailSlotOffset2DSurface[15][5] = GEN10_MIPTAIL_SLOT_OFFSET_2D_SURFACE;
131 GMM_MIPTAIL_SLOT_OFFSET Gen10MipTailSlotOffset3DSurface[15][5] = GEN10_MIPTAIL_SLOT_OFFSET_3D_SURFACE;
132 /////////////////////////////////////////////////////////////////////////////////////
133 /// Returns the mip-map offset in geometric OffsetX, Y, Z for a given LOD in Mip Tail.
134 ///
135 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
136 ///             MipLevel: mip-map level
137 ///             OffsetX: ptr to Offset in X direction (in bytes)
138 ///             OffsetY: ptr to Offset in Y direction (in pixels)
139 ///             OffsetZ: ptr to Offset in Z direction (in pixels)
140 ///
141 /////////////////////////////////////////////////////////////////////////////////////
GetMipTailGeometryOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel,uint32_t * OffsetX,uint32_t * OffsetY,uint32_t * OffsetZ)142 void GmmLib::GmmGen10TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo,
143                                                            uint32_t          MipLevel,
144                                                            uint32_t *        OffsetX,
145                                                            uint32_t *        OffsetY,
146                                                            uint32_t *        OffsetZ)
147 {
148     uint32_t ArrayIndex = 0;
149     uint32_t Slot       = 0;
150 
151     GMM_DPF_ENTER;
152 
153     // 3D textures follow the Gen9 mip tail format
154     if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat ||
155        pTexInfo->Type == RESOURCE_3D)
156     {
157         return GmmGen9TextureCalc::GetMipTailGeometryOffset(pTexInfo, MipLevel, OffsetX, OffsetY, OffsetZ);
158     }
159 
160     switch(pTexInfo->BitsPerPixel)
161     {
162         case 128:
163             ArrayIndex = 0;
164             break;
165         case 64:
166             ArrayIndex = 1;
167             break;
168         case 32:
169             ArrayIndex = 2;
170             break;
171         case 16:
172             ArrayIndex = 3;
173             break;
174         case 8:
175             ArrayIndex = 4;
176             break;
177         default:
178             __GMM_ASSERT(0);
179             break;
180     }
181 
182     if(pTexInfo->Type == RESOURCE_1D)
183     {
184         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
185                (pTexInfo->Flags.Info.TiledYf ? 4 : 0);
186 
187         *OffsetX = Gen10MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
188         *OffsetY = Gen10MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y;
189         *OffsetZ = Gen10MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z;
190     }
191     else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
192     {
193         // clang-format off
194         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
195                // TileYs
196                ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 :
197                (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 :
198                (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 :
199                (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 :
200                (pTexInfo->Flags.Info.TiledYs) ? 0 :
201                // TileYf
202                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11 :
203                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 8) ? 10 :
204                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 4) ? 8 :
205                (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 2) ? 5 :
206                (pTexInfo->Flags.Info.TiledYf) ? 4 : 0);
207         // clang-format on
208 
209         *OffsetX = Gen10MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
210         *OffsetY = Gen10MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y;
211         *OffsetZ = Gen10MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z;
212     }
213 
214     GMM_DPF_EXIT;
215     return;
216 }
217 
218 /////////////////////////////////////////////////////////////////////////////////////
219 /// Returns the aligned block height of the 3D surface on Gen9
220 ///
221 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
222 ///             BlockHeight:
223 ///             ExpandedArraySize:  adjusted array size for MSAA, cube faces, etc.
224 ///
225 /// @return     BlockHeight
226 /////////////////////////////////////////////////////////////////////////////////////
GetAligned3DBlockHeight(GMM_TEXTURE_INFO * pTexInfo,uint32_t BlockHeight,uint32_t ExpandedArraySize)227 uint32_t GmmLib::GmmGen10TextureCalc::GetAligned3DBlockHeight(GMM_TEXTURE_INFO *pTexInfo,
228                                                               uint32_t          BlockHeight,
229                                                               uint32_t          ExpandedArraySize)
230 {
231     uint32_t DAlign, CompressHeight, CompressWidth, CompressDepth;
232     GMM_DPF_ENTER;
233 
234     __GMM_ASSERTPTR(pTexInfo, 0);
235 
236     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
237 
238     DAlign = pTexInfo->Alignment.DAlign;
239 
240     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
241 
242     if(pTexInfo->Type == RESOURCE_3D)
243     {
244         ExpandedArraySize = GFX_ALIGN_NP2(ExpandedArraySize, DAlign) / CompressDepth;
245 
246         if(!pTexInfo->Flags.Info.Linear)
247         {
248             BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
249         }
250     }
251 
252     GMM_DPF_EXIT;
253 
254     return BlockHeight;
255 }
256 
257 /////////////////////////////////////////////////////////////////////////////////////
258 /// Allocates the 2D mip layout for surface state programming.
259 ///
260 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
261 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
262 ///
263 /// @return     ::GMM_STATUS
264 /////////////////////////////////////////////////////////////////////////////////////
FillTex2D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)265 GMM_STATUS GMM_STDCALL GmmLib::GmmGen10TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo,
266                                                               __GMM_BUFFER_TYPE *pRestrictions)
267 {
268     uint32_t   Width, Height, BitsPerPixel;
269     uint32_t   HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
270     uint32_t   AlignedWidth, BlockHeight, ExpandedArraySize, Pitch;
271     uint8_t    Compress = 0;
272     GMM_STATUS Status;
273 
274     GMM_DPF_ENTER;
275 
276     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
277     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
278 
279     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
280 
281     BitsPerPixel = pTexInfo->BitsPerPixel;
282     if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
283     {
284         // Aux Surfaces are 8bpp.
285         BitsPerPixel = 8;
286     }
287 
288     Height = pTexInfo->BaseHeight;
289     Width  = GFX_ULONG_CAST(pTexInfo->BaseWidth);
290 
291     pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1);
292 
293     if(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)
294     {
295         FindMipTailStartLod(pTexInfo);
296     }
297 
298     ExpandedArraySize =
299     GFX_MAX(pTexInfo->ArraySize, 1) *
300     ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) *             // Cubemaps simply 6-element, 2D arrays.
301     ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays.
302     ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil ||
303       (pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys samples are NOT stored as array planes.
304      1 :
305      pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes.
306 
307     if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)
308     {
309         ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth);
310     }
311 
312     //
313     // Check for color separation
314     //
315     if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)
316     {
317         bool csRestrictionsMet = (((ExpandedArraySize <= 2) &&
318                                    (ExpandedArraySize == pTexInfo->ArraySize) &&
319                                    ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) ||
320                                     (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) ||
321                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) ||
322                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) ||
323                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) ||
324                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) &&
325                                    ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) ||
326                                     (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0))));
327 
328         if(csRestrictionsMet)
329         {
330             ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE;
331         }
332         else
333         {
334             pTexInfo->Flags.Gpu.ColorSeparation     = false;
335             pTexInfo->Flags.Gpu.ColorSeparationRGBX = false;
336         }
337     }
338 
339     HAlign = pTexInfo->Alignment.HAlign;
340     VAlign = pTexInfo->Alignment.VAlign;
341     DAlign = pTexInfo->Alignment.DAlign;
342     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
343 
344     Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
345 
346     /////////////////////////////////
347     // Calculate Block Surface Height
348     /////////////////////////////////
349 
350     if(ExpandedArraySize > 1)
351     {
352         uint32_t Alignment = VAlign;
353         if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) ||
354            (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) ||
355 	   (pTexInfo->Flags.Wa.MediaPipeUsage))
356         {
357             Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
358 	    //Gmm uses TileY for Stencil allocations, having half TileW height (TileY width compensates)
359             if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
360             {
361                 Alignment *= 2;
362             }
363         }
364 
365         // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight)
366         BlockHeight = Get2DMipMapTotalHeight(pTexInfo);
367         BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment);
368 
369         // GMM internally uses QPitch as the logical distance between slices, but translates
370         // as appropriate to service client queries in GmmResGetQPitch.
371         pTexInfo->Alignment.QPitch = BlockHeight;
372 
373         if(Compress)
374         {
375             BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
376 
377             BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize);
378         }
379         else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
380         {
381             BlockHeight /= 2;
382         }
383         else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
384         {
385             BlockHeight /= 16;
386         }
387 
388         BlockHeight *= ExpandedArraySize;
389     }
390     else
391     {
392         pTexInfo->Alignment.QPitch = 0;
393 
394         BlockHeight = Get2DMipMapHeight(pTexInfo);
395     }
396 
397     ///////////////////////////////////
398     // Calculate Pitch
399     ///////////////////////////////////
400 
401     AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo);
402 
403     // For Non - planar surfaces, the alignment is done on the entire height of the allocation
404     if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU &&
405        GmmIsYUVFormatLCUAligned(pTexInfo->Format))
406     {
407         AlignedWidth = GFX_ALIGN(AlignedWidth, GMM_SCANLINES(GMM_MAX_LCU_SIZE));
408     }
409 
410     // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths
411     // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1
412     if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) &&
413        (pTexInfo->Alignment.MipTailStartLod < 2))
414     {
415         // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned.
416     }
417     else if(pTexInfo->MaxLod >= 2)
418     {
419         uint32_t AlignedWidthLod1, AlignedWidthLod2;
420 
421         AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo);
422         AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo);
423 
424         AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2);
425     }
426 
427     if(Compress)
428     {
429         AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth);
430     }
431     else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
432     {
433         AlignedWidth *= 2;
434     }
435     else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
436     {
437         switch(pTexInfo->BitsPerPixel)
438         {
439             case 32:
440                 AlignedWidth /= 8;
441                 break;
442             case 64:
443                 AlignedWidth /= 4;
444                 break;
445             case 128:
446                 AlignedWidth /= 2;
447                 break;
448             default:
449                 __GMM_ASSERT(0);
450         }
451     }
452     else if(pTexInfo->Flags.Gpu.ColorSeparation)
453     {
454         AlignedWidth *= pTexInfo->ArraySize;
455         __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION));
456         AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION;
457     }
458     else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX)
459     {
460         AlignedWidth *= pTexInfo->ArraySize;
461         __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION));
462         AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION;
463     }
464 
465     // Default pitch
466     Pitch = AlignedWidth * BitsPerPixel >> 3;
467 
468     // Make sure the pitch satisfy linear min pitch requirment
469     Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch);
470 
471     // Make sure pitch satisfy alignment restriction
472     Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment);
473 
474     ////////////////////
475     // Adjust for Tiling
476     ////////////////////
477 
478     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
479     {
480         Pitch       = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
481         BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
482     }
483 
484     GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!");
485     pTexInfo->Flags.Info.LayoutBelow = 1;
486     pTexInfo->Flags.Info.LayoutRight = 0;
487 
488     // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
489     // padding needs to be added. Since this will create a none pitch aligned
490     // surface the padding is aligned to the next row
491     if(GmmIsYUVPacked(pTexInfo->Format) ||
492        (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
493        (pTexInfo->BitsPerPixel == GMM_BITS(48)))
494     {
495         BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch);
496     }
497 
498     // For Non-planar surfaces, the alignment is done on the entire height of the allocation
499     if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU &&
500         GmmIsYUVFormatLCUAligned(pTexInfo->Format) &&
501        !GmmIsPlanar(pTexInfo->Format))
502     {
503         BlockHeight = GFX_ALIGN(BlockHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE));
504     }
505 
506     // Align height to even row to cover for HW over-fetch
507     BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW);
508 
509     if((Status = // <-- Note assignment.
510         FillTexPitchAndSize(
511         pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS)
512     {
513         Fill2DTexOffsetAddress(pTexInfo);
514     }
515 
516     GMM_DPF_EXIT;
517 
518     return (Status);
519 }
520 
521 /////////////////////////////////////////////////////////////////////////////////////
522 /// This function will Setup a planar surface allocation.
523 ///
524 /// @param[in]  pTexInfo: Reference to ::GMM_TEXTURE_INFO
525 /// @param[in]  pRestrictions: Reference to surface alignment and size restrictions.
526 ///
527 /// @return     ::GMM_STATUS
528 /////////////////////////////////////////////////////////////////////////////////////
FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)529 GMM_STATUS GMM_STDCALL GmmLib::GmmGen10TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo,
530                                                                   __GMM_BUFFER_TYPE *pRestrictions)
531 {
532     uint32_t   WidthBytesPhysical, Height, YHeight, VHeight;
533     uint32_t   AdjustedVHeight = 0;
534     GMM_STATUS Status;
535     bool       UVPacked = false;
536 
537     GMM_DPF_ENTER;
538 
539     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
540     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
541     __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW);
542     pTexInfo->TileMode = TILE_NONE;
543 
544     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
545 
546     WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3;
547     Height = VHeight = 0;
548 
549     YHeight = pTexInfo->BaseHeight;
550 
551     switch(pTexInfo->Format)
552     {
553         case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V
554         case GMM_FORMAT_IMC3:
555         case GMM_FORMAT_MFX_JPEG_YUV420:  // Same as IMC3.
556                                           // YYYYYYYY
557                                           // YYYYYYYY
558                                           // YYYYYYYY
559                                           // YYYYYYYY
560                                           // UUUU
561                                           // UUUU
562                                           // VVVV
563                                           // VVVV
564         case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width.
565                                           // YYYYYYYY
566                                           // YYYYYYYY
567                                           // YYYYYYYY
568                                           // YYYYYYYY
569                                           // UUUUUUUU
570                                           // UUUUUUUU
571                                           // VVVVVVVV
572                                           // VVVVVVVV
573             {
574                 VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
575 
576                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
577 
578                 Height = YHeight + 2 * VHeight; // One VHeight for V and one for U.
579 
580                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
581 
582                 break;
583             }
584         case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width.
585                                                //YYYYYYYY
586                                                //YYYYYYYY
587                                                //YYYYYYYY
588                                                //YYYYYYYY
589                                                //UUUUUUUU
590                                                //VVVVVVVV
591             {
592                 VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
593 
594                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
595 
596                 Height = YHeight + 2 * VHeight;
597 
598                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
599 
600                 break;
601             }
602         case GMM_FORMAT_MFX_JPEG_YUV411:  // Similar to IMC3 but U/V are quarter width and full height.
603                                           // YYYYYYYY
604                                           // YYYYYYYY
605                                           // YYYYYYYY
606                                           // YYYYYYYY
607                                           // UU
608                                           // UU
609                                           // UU
610                                           // UU
611                                           // VV
612                                           // VV
613                                           // VV
614                                           // VV
615         case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height.
616                                           // YYYYYYYY
617                                           // YYYYYYYY
618                                           // YYYYYYYY
619                                           // YYYYYYYY
620                                           // UUUU
621                                           // UUUU
622                                           // UUUU
623                                           // UUUU
624                                           // VVVV
625                                           // VVVV
626                                           // VVVV
627                                           // VVVV
628         case GMM_FORMAT_BGRP:
629         case GMM_FORMAT_RGBP:
630         case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size.
631             // YYYYYYYY
632             // YYYYYYYY
633             // YYYYYYYY
634             // YYYYYYYY
635             // UUUUUUUU
636             // UUUUUUUU
637             // UUUUUUUU
638             // UUUUUUUU
639             // VVVVVVVV
640             // VVVVVVVV
641             // VVVVVVVV
642             // VVVVVVVV
643             {
644                 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
645                 VHeight = YHeight;
646 
647                 Height = YHeight + 2 * VHeight;
648 
649                 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
650 
651                 break;
652             }
653         case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V
654         case GMM_FORMAT_IMC4:
655         {
656             // YYYYYYYY
657             // YYYYYYYY
658             // YYYYYYYY
659             // YYYYYYYY
660             // UUUUVVVV
661             // UUUUVVVV
662 
663             YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
664             VHeight = GFX_CEIL_DIV(YHeight, 2);
665 
666             WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes.
667 
668             Height = YHeight + VHeight;
669 
670             // With SURFACE_STATE.XOffset support, the U-V interface has
671             // much lighter restrictions--which will be naturally met by
672             // surface pitch restrictions (i.e. dividing an IMC2/4 pitch
673             // by 2--to get the U/V interface--will always produce a safe
674             // XOffset value).
675 
676             // Not technically UV packed but sizing works out the same
677             // if the resource is std swizzled
678             UVPacked                              = true;
679             pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2;
680 
681             break;
682         }
683         case GMM_FORMAT_NV12:
684         case GMM_FORMAT_NV21:
685         case GMM_FORMAT_NV11:
686         case GMM_FORMAT_P010:
687         case GMM_FORMAT_P012:
688         case GMM_FORMAT_P016:
689         case GMM_FORMAT_P208:
690         case GMM_FORMAT_P216:
691         {
692             // YYYYYYYY
693             // YYYYYYYY
694             // YYYYYYYY
695             // YYYYYYYY
696             // [UV-Packing]
697 
698             if((pTexInfo->Format == GMM_FORMAT_NV12) ||
699                (pTexInfo->Format == GMM_FORMAT_NV21) ||
700                (pTexInfo->Format == GMM_FORMAT_P010) ||
701                (pTexInfo->Format == GMM_FORMAT_P012) ||
702                (pTexInfo->Format == GMM_FORMAT_P016))
703             {
704                 VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y
705                 Height  = YHeight + VHeight;
706             }
707             else
708             {
709                 VHeight = YHeight; // U/V plane is same as Y
710                 Height  = YHeight + VHeight;
711             }
712 
713             if((pTexInfo->Format == GMM_FORMAT_NV12) ||
714                (pTexInfo->Format == GMM_FORMAT_NV21) ||
715                (pTexInfo->Format == GMM_FORMAT_P010) ||
716                (pTexInfo->Format == GMM_FORMAT_P012) ||
717                (pTexInfo->Format == GMM_FORMAT_P016) ||
718                (pTexInfo->Format == GMM_FORMAT_P208) ||
719                (pTexInfo->Format == GMM_FORMAT_P216))
720             {
721                 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes.
722             }
723             else //if(pTexInfo->Format == GMM_FORMAT_NV11)
724             {
725                 // Tiling not supported, since YPitch != UVPitch...
726                 pTexInfo->Flags.Info.TiledY  = 0;
727                 pTexInfo->Flags.Info.TiledYf = 0;
728                 pTexInfo->Flags.Info.TiledYs = 0;
729                 pTexInfo->Flags.Info.TiledX  = 0;
730                 pTexInfo->Flags.Info.Linear  = 1;
731             }
732 
733             UVPacked                              = true;
734             pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2;
735             break;
736         }
737         case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except,
738         case GMM_FORMAT_IYUV: // U & V pl.s are reversed.
739         case GMM_FORMAT_YV12:
740         case GMM_FORMAT_YVU9:
741         {
742             // YYYYYYYY
743             // YYYYYYYY
744             // YYYYYYYY
745             // YYYYYYYY
746             // VVVVVV..  <-- V and U planes follow the Y plane, as linear
747             // ..UUUUUU      arrays--without respect to pitch.
748 
749             uint32_t YSize, UVSize, YVSizeRShift;
750             uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment;
751 
752             YSize = WidthBytesPhysical * YHeight;
753 
754             // YVU9 has one U/V pixel for each 4x4 Y block.
755             // The others have one U/V pixel for each 2x2 Y block.
756 
757             // YVU9 has a Y:V size ratio of 16 (4x4 --> 1).
758             // The others have a ratio of 4 (2x2 --> 1).
759             YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
760 
761             // If a Y plane isn't fully-aligned to its Y-->U/V block size, the
762             // extra/unaligned Y pixels still need corresponding U/V pixels--So
763             // for the purpose of computing the UVSize, we must consider a
764             // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would
765             // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.)
766             YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
767             YSizeForUVPurposes =
768             GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) *
769             GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment);
770 
771             UVSize = 2 * // <-- U + V
772                      (YSizeForUVPurposes >> YVSizeRShift);
773 
774             Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical);
775 
776             // Tiling not supported, since YPitch != UVPitch...
777             pTexInfo->Flags.Info.TiledY  = 0;
778             pTexInfo->Flags.Info.TiledYf = 0;
779             pTexInfo->Flags.Info.TiledYs = 0;
780             pTexInfo->Flags.Info.TiledX  = 0;
781             pTexInfo->Flags.Info.Linear  = 1;
782 
783             pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1;
784             break;
785         }
786         default:
787         {
788             GMM_ASSERTDPF(0, "Unexpected format");
789             return GMM_ERROR;
790         }
791     }
792 
793     // Align Height to even row to avoid hang if HW over-fetch
794     Height = GFX_ALIGN(Height, __GMM_EVEN_ROW);
795 
796     SetTileMode(pTexInfo);
797 
798     // MMC is not supported for linear formats.
799     if(pTexInfo->Flags.Gpu.MMC)
800     {
801         if(!(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs))
802         {
803             pTexInfo->Flags.Gpu.MMC = 0;
804         }
805     }
806 
807     // Legacy Planar "Linear Video" Restrictions...
808     if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions)
809     {
810         pRestrictions->LockPitchAlignment   = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64));
811         pRestrictions->MinPitch             = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64));
812         pRestrictions->PitchAlignment       = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64));
813         pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64));
814     }
815 
816     // Multiply overall pitch alignment for surfaces whose U/V planes have a
817     // pitch down-scaled from that of Y--Since the U/V pitches must meet the
818     // original restriction, the Y pitch must meet a scaled-up multiple.
819     if((pTexInfo->Format == GMM_FORMAT_I420) ||
820        (pTexInfo->Format == GMM_FORMAT_IYUV) ||
821        (pTexInfo->Format == GMM_FORMAT_NV11) ||
822        (pTexInfo->Format == GMM_FORMAT_YV12) ||
823        (pTexInfo->Format == GMM_FORMAT_YVU9))
824     {
825         uint32_t LShift =
826         (pTexInfo->Format != GMM_FORMAT_YVU9) ?
827         1 : // UVPitch = 1/2 YPitch
828         2;  // UVPitch = 1/4 YPitch
829 
830         pRestrictions->LockPitchAlignment <<= LShift;
831         pRestrictions->MinPitch <<= LShift;
832         pRestrictions->PitchAlignment <<= LShift;
833         pRestrictions->RenderPitchAlignment <<= LShift;
834     }
835 
836     AdjustedVHeight = VHeight;
837     // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access
838     if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0)
839     {
840         AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE));
841         Height += AdjustedVHeight - VHeight;
842     }
843 
844     // For Tiled Planar surfaces, the planes must be tile-boundary aligned.
845     // Actual alignment is handled in FillPlanarOffsetAddress, but height
846     // and width must be adjusted for correct size calculation
847     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
848     {
849         uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
850         uint32_t TileWidth  = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth;
851 
852         pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true;
853 
854         //for separate U and V planes, use U plane unaligned and V plane aligned
855         Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) :
856                                                               (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight)));
857 
858         if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns
859            pTexInfo->Format == GMM_FORMAT_IMC4)
860         {
861             // If the U & V planes are side-by-side then the surface pitch must be
862             // padded out so that U and V planes will being on a tile boundary.
863             // This means that an odd Y plane width must be padded out
864             // with an additional tile. Even widths do not need padding
865             uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth);
866             if(TileCols % 2)
867             {
868                 WidthBytesPhysical = (TileCols + 1) * TileWidth;
869             }
870         }
871 
872         if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)
873         {
874             pTexInfo->Flags.Info.RedecribedPlanes = true;
875         }
876     }
877 
878     // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support
879     //Special case LKF MMC compressed surfaces
880     if(pTexInfo->Flags.Gpu.MMC &&
881        pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
882        pTexInfo->Flags.Info.TiledY)
883     {
884         uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
885 
886         Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight);
887     }
888 
889     // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support
890     // MMC above 16k bytes wide, while Yf NV12 does not support above 8k - 128 bytes.
891     if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN10_CORE) &&
892        (pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs))
893     {
894         if(((pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= GMM_KBYTE(16)) ||
895            (pTexInfo->Format == GMM_FORMAT_NV12 && pTexInfo->Flags.Info.TiledYf &&
896             (pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= (GMM_KBYTE(8) - 128)))
897         {
898             pTexInfo->Flags.Gpu.MMC = 0;
899         }
900     }
901 
902     if(pTexInfo->Flags.Info.RedecribedPlanes)
903     {
904         if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical))
905         {
906             __GMM_ASSERT(FALSE);
907         }
908     }
909 
910     if((Status = // <-- Note assignment.
911         FillTexPitchAndSize(
912         pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS)
913     {
914         FillPlanarOffsetAddress(pTexInfo);
915     }
916 
917     // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout
918     // is defined by SW requirements; Y plane must be 4KB aligned.
919     if(pTexInfo->ArraySize > 1)
920     {
921         GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size;
922         int64_t        LargeSize;
923 
924         // Size should always be page aligned.
925         __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0);
926 
927         if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize)
928         {
929             pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes;
930             pTexInfo->Size                         = LargeSize;
931         }
932         else
933         {
934             GMM_ASSERTDPF(0, "Surface too large!");
935             Status = GMM_ERROR;
936         }
937     }
938 
939     GMM_DPF_EXIT;
940     return (Status);
941 } // FillTexPlanar
942