1 /*==============================================================================
2 Copyright(c) 2017 Intel Corporation
3 
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files(the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and / or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 ============================================================================*/
22 
23 #include "Internal/Common/GmmLibInc.h"
24 
25 
26 /////////////////////////////////////////////////////////////////////////////////////
27 /// Calculates the mip offset of given LOD in 1D mip layout
28 ///
29 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
30 ///
31 /// @return     offset value in bytes
32 /////////////////////////////////////////////////////////////////////////////////////
Get1DTexOffsetAddressPerMip(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)33 GMM_GFX_SIZE_T GmmLib::GmmGen9TextureCalc::Get1DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo,
34                                                                        uint32_t          MipLevel)
35 {
36     uint32_t       AlignedMipWidth, MipWidth, __MipLevel;
37     uint32_t       i, HAlign;
38     GMM_GFX_SIZE_T MipOffset = 0;
39     uint8_t        Compressed;
40     uint32_t       CompressHeight, CompressWidth, CompressDepth;
41 
42     GMM_DPF_ENTER;
43 
44     HAlign   = pTexInfo->Alignment.HAlign;
45     MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth);
46 
47     __MipLevel =
48     (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ?
49     GFX_MIN(MipLevel, pTexInfo->Alignment.MipTailStartLod) :
50     MipLevel;
51 
52     Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
53     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
54 
55     for(i = 1; i <= __MipLevel; i++)
56     {
57         AlignedMipWidth = __GMM_EXPAND_WIDTH(this, MipWidth, HAlign, pTexInfo);
58 
59         if(Compressed)
60         {
61             AlignedMipWidth /= CompressWidth;
62         }
63 
64         MipOffset += AlignedMipWidth;
65 
66         MipWidth = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, i));
67     }
68 
69     MipOffset *= (pTexInfo->BitsPerPixel >> 3);
70 
71     if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
72        (MipLevel >= pTexInfo->Alignment.MipTailStartLod))
73     {
74         MipOffset += GetMipTailByteOffset(pTexInfo, MipLevel);
75     }
76 
77     GMM_DPF_EXIT;
78 
79     return (MipOffset);
80 }
81 
82 
83 /////////////////////////////////////////////////////////////////////////////////////
84 /// Calculates the address offset for each mip map of 1D texture and store them into
85 /// the GMM_TEXTURE_INFO for surf state programming.
86 ///
87 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
88 ///
89 /////////////////////////////////////////////////////////////////////////////////////
Fill1DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)90 void GmmLib::GmmGen9TextureCalc::Fill1DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
91 {
92     uint32_t i;
93 
94     GMM_DPF_ENTER;
95 
96     pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender =
97     pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock =
98     pTexInfo->Alignment.QPitch * pTexInfo->BitsPerPixel >> 3;
99 
100     for(i = 0; i <= pTexInfo->MaxLod; i++)
101     {
102         pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get1DTexOffsetAddressPerMip(pTexInfo, i);
103     }
104 
105     GMM_DPF_EXIT;
106 }
107 
108 
109 /////////////////////////////////////////////////////////////////////////////////////
110 /// Allocates the 1D mip layout for surface state programming.
111 ///
112 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
113 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
114 ///
115 /// @return     ::GMM_STATUS
116 /////////////////////////////////////////////////////////////////////////////////////
FillTex1D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)117 GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo,
118                                                              __GMM_BUFFER_TYPE *pRestrictions)
119 {
120     uint32_t   ArraySize, BitsPerPixel, HAlign, i, Width, MipWidth;
121     int64_t    Size;
122     GMM_STATUS Status = GMM_SUCCESS;
123     uint8_t    Compressed;
124     uint32_t   CompressHeight, CompressWidth, CompressDepth;
125 
126     GMM_DPF_ENTER;
127 
128     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
129     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
130     __GMM_ASSERT(pTexInfo->Flags.Info.Linear ||
131                  pTexInfo->Flags.Info.TiledYf ||
132                  GMM_IS_64KB_TILE(pTexInfo->Flags));
133 
134     pTexInfo->Flags.Info.Linear = 1;
135     pTexInfo->Flags.Info.TiledW = 0;
136     pTexInfo->Flags.Info.TiledX = 0;
137     GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
138 
139     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
140 
141     ArraySize    = GFX_MAX(pTexInfo->ArraySize, 1);
142     BitsPerPixel = pTexInfo->BitsPerPixel;
143     HAlign       = pTexInfo->Alignment.HAlign;
144 
145     Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
146     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
147 
148     if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags))
149     {
150         FindMipTailStartLod(pTexInfo);
151     }
152 
153     /////////////////////////////
154     // Calculate Surface QPitch
155     /////////////////////////////
156 
157     Width    = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(pTexInfo->BaseWidth), HAlign, pTexInfo);
158     MipWidth = Width;
159 
160     if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
161        ((pTexInfo->Alignment.MipTailStartLod == 0) || (pTexInfo->MaxLod == 0)))
162     {
163         // Do nothing. Width is already aligned.
164     }
165     else
166     {
167         for(i = 1; i <= pTexInfo->MaxLod; i++)
168         {
169             uint32_t AlignedMipWidth;
170 
171             if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
172                (i == pTexInfo->Alignment.MipTailStartLod))
173             {
174                 Width += pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth;
175                 break;
176             }
177             else
178             {
179                 MipWidth = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, i));
180 
181                 AlignedMipWidth = __GMM_EXPAND_WIDTH(this, MipWidth, HAlign, pTexInfo);
182 
183                 if(Compressed)
184                 {
185                     AlignedMipWidth /= CompressWidth;
186                 }
187 
188                 Width += AlignedMipWidth;
189             }
190         }
191     }
192 
193     pTexInfo->Alignment.QPitch = GFX_ALIGN((ArraySize > 1) ? Width : 0, HAlign); // in pixels
194 
195     pTexInfo->Pitch = 0;
196 
197     ///////////////////////////
198     // Calculate Surface Size
199     ///////////////////////////
200 
201     Width *= BitsPerPixel >> 3;
202 
203     Size = GFX_ALIGN((uint64_t)Width * ArraySize, PAGE_SIZE);
204 
205     if(Size <= pPlatform->SurfaceMaxSize)
206     {
207         pTexInfo->Size = Size;
208 
209         Fill1DTexOffsetAddress(pTexInfo);
210     }
211     else
212     {
213         GMM_ASSERTDPF(0, "Surface too large!");
214         Status = GMM_ERROR;
215     }
216 
217     //////////////////////
218     // Surface Alignment
219     //////////////////////
220 
221     if(!pTexInfo->Alignment.BaseAlignment || __GMM_IS_ALIGN(pRestrictions->Alignment, pTexInfo->Alignment.BaseAlignment))
222     {
223         pTexInfo->Alignment.BaseAlignment = pRestrictions->Alignment;
224     }
225     else if(__GMM_IS_ALIGN(pTexInfo->Alignment.BaseAlignment, pRestrictions->Alignment))
226     {
227         // Do nothing: pTexInfo->Alignment.BaseAlignment is properly aligned
228     }
229     else
230     {
231         pTexInfo->Alignment.BaseAlignment = pTexInfo->Alignment.BaseAlignment * pRestrictions->Alignment;
232         GMM_ASSERTDPF(0,
233                       "Client requested alignment that is not properly aligned to HW requirements."
234                       "Alignment is going to be much higher to match both client and HW requirements.\r\n");
235     }
236 
237     GMM_DPF_EXIT;
238 
239     return (Status);
240 }
241 
242 
243 /////////////////////////////////////////////////////////////////////////////////////
244 /// Calculates height of the 2D mip layout on Gen9
245 ///
246 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
247 ///
248 /// @return     height of 2D mip layout
249 /////////////////////////////////////////////////////////////////////////////////////
Get2DMipMapHeight(GMM_TEXTURE_INFO * pTexInfo)250 uint32_t GmmLib::GmmGen9TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo)
251 {
252     uint32_t BlockHeight, MipHeight;
253     uint32_t HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2;
254     uint32_t i, MipLevel, VAlign, CompressHeight, CompressWidth, CompressDepth;
255     uint8_t  Compressed;
256     GMM_DPF_ENTER;
257 
258     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
259 
260     Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
261     MipHeight  = pTexInfo->BaseHeight;
262     MipLevel   = pTexInfo->MaxLod;
263     VAlign     = pTexInfo->Alignment.VAlign;
264     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
265 
266     HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo);
267 
268     if(Compressed)
269     {
270         HeightLinesLevel0 /= CompressHeight;
271     }
272     else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
273     {
274         HeightLinesLevel0 /= 2;
275     }
276     else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
277     {
278         HeightLinesLevel0 /= 16;
279     }
280 
281     // Mip0 height...
282     BlockHeight = HeightLinesLevel0;
283 
284     if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) &&
285        ((pTexInfo->Alignment.MipTailStartLod == 0) || (pTexInfo->MaxLod == 0)))
286     {
287         // Do nothing. Height is already aligned.
288     }
289     else
290     {
291         // Height of Mip1 and Mip2..n needed later...
292         HeightLinesLevel1 = HeightLinesLevel2 = 0;
293         for(i = 1; i <= MipLevel; i++)
294         {
295             uint32_t AlignedHeightLines;
296 
297             if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) &&
298                (i == pTexInfo->Alignment.MipTailStartLod))
299             {
300                 AlignedHeightLines = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
301 
302                 if(i == 1)
303                 {
304                     HeightLinesLevel1 = AlignedHeightLines;
305                 }
306                 else
307                 {
308                     HeightLinesLevel2 += AlignedHeightLines;
309                 }
310 
311                 break;
312             }
313             else
314             {
315                 MipHeight = GmmTexGetMipHeight(pTexInfo, i);
316 
317                 AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo);
318 
319                 if(Compressed)
320                 {
321                     AlignedHeightLines /= CompressHeight;
322                 }
323                 else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
324                 {
325                     AlignedHeightLines /= 2;
326                 }
327                 else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
328                 {
329                     AlignedHeightLines /= 16;
330                 }
331 
332                 if(i == 1)
333                 {
334                     HeightLinesLevel1 = AlignedHeightLines;
335                 }
336                 else
337                 {
338                     HeightLinesLevel2 += AlignedHeightLines;
339                 }
340             }
341         }
342 
343         // If Mip1 height covers all others, then that is all we need...
344         if(!(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs))
345         {
346             if(HeightLinesLevel1 >= HeightLinesLevel2)
347             {
348                 BlockHeight += GFX_ALIGN(HeightLinesLevel1, VAlign);
349             }
350             else
351             {
352                 BlockHeight += GFX_ALIGN(HeightLinesLevel2, VAlign);
353             }
354         }
355         else
356         {
357             //TR mode- requires TileMode height alignment
358             BlockHeight += (HeightLinesLevel1 >= HeightLinesLevel2) ? HeightLinesLevel1 : HeightLinesLevel2;
359             BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
360         }
361     }
362 
363     GMM_DPF_EXIT;
364 
365     return (BlockHeight);
366 }
367 
368 
369 /////////////////////////////////////////////////////////////////////////////////////
370 /// Calculates total height of an arrayed 2D/3D mip layout
371 ///
372 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
373 ///
374 /// @return     height of arrayed 2D/3D  mip layout
375 /////////////////////////////////////////////////////////////////////////////////////
Get2DMipMapTotalHeight(GMM_TEXTURE_INFO * pTexInfo)376 uint32_t GmmLib::GmmGen9TextureCalc::Get2DMipMapTotalHeight(GMM_TEXTURE_INFO *pTexInfo)
377 {
378     uint32_t BlockHeight, MipHeight;
379     uint32_t HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2;
380     uint32_t i, MipLevel, VAlign;
381     uint32_t AlignedHeightLines;
382 
383     GMM_DPF_ENTER;
384 
385     MipHeight = pTexInfo->BaseHeight;
386     MipLevel  = pTexInfo->MaxLod;
387     VAlign    = pTexInfo->Alignment.VAlign;
388 
389     MipLevel =
390     (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ?
391     GFX_MIN(MipLevel, pTexInfo->Alignment.MipTailStartLod) :
392     MipLevel;
393 
394 
395     HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo);
396 
397     // Mip0 height...
398     BlockHeight = HeightLinesLevel0;
399 
400     // Height of Mip1 and Mip2..n needed later...
401     HeightLinesLevel1 = HeightLinesLevel2 = 0;
402     for(i = 1; i <= MipLevel; i++)
403     {
404         MipHeight = GmmTexGetMipHeight(pTexInfo, i);
405 
406         AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo);
407 
408         if(i == 1)
409         {
410             HeightLinesLevel1 = AlignedHeightLines;
411         }
412         else
413         {
414             HeightLinesLevel2 += AlignedHeightLines;
415         }
416     }
417 
418     // If Mip1 height covers all others, then that is all we need...
419     if(HeightLinesLevel1 >= HeightLinesLevel2)
420     {
421         BlockHeight += HeightLinesLevel1;
422     }
423     else
424     {
425         BlockHeight += HeightLinesLevel2;
426     }
427 
428     GMM_DPF_EXIT;
429 
430     return (BlockHeight);
431 }
432 
433 
434 /////////////////////////////////////////////////////////////////////////////////////
435 /// Calculates the mip offset of given LOD in 2D/3D mip layout
436 ///
437 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
438 ///
439 /// @return     ::GMM_GFX_SIZE_T  offset value in bytes
440 /////////////////////////////////////////////////////////////////////////////////////
Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)441 GMM_GFX_SIZE_T GmmLib::GmmGen9TextureCalc::Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo,
442                                                                        uint32_t          MipLevel)
443 {
444     uint32_t       AlignedMipHeight, i, OffsetHeight;
445     uint8_t        Compressed;
446     uint32_t       HAlign, VAlign, __MipLevel;
447     uint32_t       CompressHeight, CompressWidth, CompressDepth;
448     uint32_t       MipHeight;
449     GMM_GFX_SIZE_T MipOffset;
450 
451     GMM_DPF_ENTER;
452 
453     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
454 
455     HAlign     = pTexInfo->Alignment.HAlign;
456     VAlign     = pTexInfo->Alignment.VAlign;
457     Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
458 
459     MipHeight    = pTexInfo->BaseHeight;
460     OffsetHeight = 0;
461 
462     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
463 
464     __MipLevel =
465     (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ?
466     GFX_MIN(MipLevel, pTexInfo->Alignment.MipTailStartLod) :
467     MipLevel;
468 
469     if(__MipLevel < 2) // LOD0 and LOD1 are on the left edge...
470     {
471         MipOffset = 0;
472     }
473     else // LOD2 and beyond are to the right of LOD1...
474     {
475         uint32_t MipWidth     = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, 1));
476         uint32_t BitsPerPixel = pTexInfo->BitsPerPixel;
477 
478         MipWidth = __GMM_EXPAND_WIDTH(this, MipWidth, HAlign, pTexInfo);
479 
480         if(Compressed)
481         {
482             MipWidth /= CompressWidth;
483         }
484         else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
485         {
486 	    //Expt: Stencil Row interleaving, where Rowheight = VALign=8
487             //XOffset on interleaved row not different than w/o interleave.
488             //MipWidth *= 2;
489 	}
490         else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
491         {
492             BitsPerPixel = 8; // Aux Surfaces are 8bpp
493 
494             switch(pTexInfo->BitsPerPixel)
495             {
496                 case 32:
497                     MipWidth /= 8;
498                     break;
499                 case 64:
500                     MipWidth /= 4;
501                     break;
502                 case 128:
503                     MipWidth /= 2;
504                     break;
505                 default:
506                     __GMM_ASSERT(0);
507             }
508         }
509 
510         MipOffset = (GMM_GFX_SIZE_T)MipWidth * BitsPerPixel >> 3;
511     }
512 
513     for(i = 1; i <= __MipLevel; i++)
514     {
515         AlignedMipHeight = GFX_ULONG_CAST(__GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo));
516 
517         if(Compressed)
518         {
519             AlignedMipHeight /= CompressHeight;
520         }
521         else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
522         {
523             AlignedMipHeight /= 2;
524         }
525         else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
526         {
527             AlignedMipHeight /= 16;
528         }
529 
530         OffsetHeight += ((i != 2) ? AlignedMipHeight : 0);
531 
532         MipHeight = GmmTexGetMipHeight(pTexInfo, i);
533     }
534     OffsetHeight *= GFX_MAX(pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth, 1);
535 
536     MipOffset += OffsetHeight * GFX_ULONG_CAST(pTexInfo->Pitch);
537 
538     if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
539        (MipLevel >= pTexInfo->Alignment.MipTailStartLod))
540     {
541         MipOffset += GetMipTailByteOffset(pTexInfo, MipLevel);
542     }
543 
544     GMM_DPF_EXIT;
545     return (MipOffset);
546 }
547 
548 
549 /////////////////////////////////////////////////////////////////////////////////////
550 /// Calculates the address offset for each mip map of 2D texture and store them into
551 /// the GMM_TEXTURE_INFO for surf state programming.
552 ///
553 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
554 ///
555 /////////////////////////////////////////////////////////////////////////////////////
Fill2DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)556 void GmmLib::GmmGen9TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
557 {
558     uint32_t i;
559     GMM_DPF_ENTER;
560 
561     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
562 
563     // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch...
564     if((pTexInfo->ArraySize <= 1) &&
565        (pTexInfo->Type != RESOURCE_3D) &&
566        (pTexInfo->Type != RESOURCE_CUBE) &&
567        !(pTexInfo->Flags.Gpu.ColorSeparation ||
568          pTexInfo->Flags.Gpu.ColorSeparationRGBX))
569     {
570         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender =
571         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = 0;
572     }
573     else
574     {
575         uint32_t ArrayQPitch, Alignment;
576 
577         Alignment = pTexInfo->Alignment.VAlign;
578         if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) ||
579            (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) ||
580 	   (pTexInfo->Flags.Wa.MediaPipeUsage))
581          {
582             Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
583 	    //Gmm uses TileY for Stencil allocations, having half TileW height (TileY width compensates)
584             if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
585             {
586                 Alignment *= 2;
587             }
588 	}
589 
590         // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight)
591         ArrayQPitch = Get2DMipMapTotalHeight(pTexInfo);
592         ArrayQPitch = GFX_ALIGN_NP2(ArrayQPitch, Alignment);
593 
594 	// Color Surf with MSAA Enabled Mutiply 4
595         if(GMM_IS_64KB_TILE(pTexInfo->Flags) && (!pGmmLibContext->GetSkuTable().FtrTileY) &&
596            ((pTexInfo->MSAA.NumSamples == 8) || (pTexInfo->MSAA.NumSamples == 16)) &&
597            ((pTexInfo->Flags.Gpu.Depth == 0) && (pTexInfo->Flags.Gpu.SeparateStencil == 0)))
598         {
599             ArrayQPitch *= 4; /* Aligned height of 4 samples */
600         }
601 
602         pTexInfo->Alignment.QPitch = ArrayQPitch;
603 
604         if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format))
605         {
606             uint32_t CompressWidth, CompressHeight, CompressDepth;
607 
608             GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
609 
610             ArrayQPitch /= CompressHeight;
611 
612             if((pTexInfo->Type == RESOURCE_3D) && !pTexInfo->Flags.Info.Linear)
613             {
614                 ArrayQPitch = GFX_ALIGN(ArrayQPitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
615             }
616         }
617         else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
618         {
619             ArrayQPitch /= 2;
620 	    if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear)
621             {
622                 pTexInfo->Alignment.QPitch = ArrayQPitch;
623             }
624         }
625         else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
626         {
627             ArrayQPitch /= 16;
628         }
629 
630         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender =
631         pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = ArrayQPitch * pTexInfo->Pitch;
632     }
633 
634     for(i = 0; i <= pTexInfo->MaxLod; i++)
635     {
636         pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i);
637     }
638 
639     GMM_DPF_EXIT;
640 }
641 
642 /////////////////////////////////////////////////////////////////////////////////////
643 /// Returns the aligned block height of the 3D surface on Gen9
644 ///
645 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
646 ///             BlockHeight: Unaligned block height
647 ///             ExpandedArraySize:  adjusted array size for MSAA, cube faces, etc.
648 ///
649 /// @return     Aligned BlockHeight
650 /////////////////////////////////////////////////////////////////////////////////////
GetAligned3DBlockHeight(GMM_TEXTURE_INFO * pTexInfo,uint32_t BlockHeight,uint32_t ExpandedArraySize)651 uint32_t GmmLib::GmmGen9TextureCalc::GetAligned3DBlockHeight(GMM_TEXTURE_INFO *pTexInfo,
652                                                              uint32_t          BlockHeight,
653                                                              uint32_t          ExpandedArraySize)
654 {
655     GMM_DPF_ENTER;
656 
657     GMM_UNREFERENCED_PARAMETER(ExpandedArraySize);
658     __GMM_ASSERTPTR(pTexInfo, 0);
659 
660     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
661 
662     if((pTexInfo->Type == RESOURCE_3D) && !pTexInfo->Flags.Info.Linear)
663     {
664         BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
665     }
666 
667     GMM_DPF_EXIT;
668 
669     return BlockHeight;
670 }
671 
672 /////////////////////////////////////////////////////////////////////////////////////
673 /// Allocates the 2D mip layout for surface state programming.
674 ///
675 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
676 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
677 ///
678 /// @return     ::GMM_STATUS
679 /////////////////////////////////////////////////////////////////////////////////////
FillTex2D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)680 GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo,
681                                                              __GMM_BUFFER_TYPE *pRestrictions)
682 {
683     uint32_t   Width, Height, BitsPerPixel;
684     uint32_t   HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
685     uint32_t   AlignedWidth, BlockHeight, ExpandedArraySize, Pitch;
686     uint8_t    Compress = 0;
687     GMM_STATUS Status;
688 
689     GMM_DPF_ENTER;
690 
691     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
692     __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
693 
694     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
695 
696     BitsPerPixel = pTexInfo->BitsPerPixel;
697     if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
698     {
699         // Aux Surfaces are 8bpp.
700         BitsPerPixel = 8;
701     }
702 
703     Height = pTexInfo->BaseHeight;
704     Width  = GFX_ULONG_CAST(pTexInfo->BaseWidth);
705 
706     pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1);
707 
708     if(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)
709     {
710         FindMipTailStartLod(pTexInfo);
711     }
712 
713     ExpandedArraySize =
714     GFX_MAX(pTexInfo->ArraySize, 1) *
715     ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) *             // Cubemaps simply 6-element, 2D arrays.
716     ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays.
717     ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil ||
718       (pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys samples are NOT stored as array planes.
719      1 :
720      pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes.
721 
722     if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)
723     {
724         ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth);
725     }
726 
727     //
728     // Check for color separation
729     //
730     if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)
731     {
732         bool csRestrictionsMet = (((ExpandedArraySize <= 2) &&
733                                    (ExpandedArraySize == pTexInfo->ArraySize) &&
734                                    ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) ||
735                                     (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) ||
736                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) ||
737                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) ||
738                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) ||
739                                     (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) &&
740                                    ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) ||
741                                     (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0))));
742 
743         if(csRestrictionsMet)
744         {
745             ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE;
746         }
747         else
748         {
749             pTexInfo->Flags.Gpu.ColorSeparation     = false;
750             pTexInfo->Flags.Gpu.ColorSeparationRGBX = false;
751         }
752     }
753 
754     HAlign = pTexInfo->Alignment.HAlign;
755     VAlign = pTexInfo->Alignment.VAlign;
756     DAlign = pTexInfo->Alignment.DAlign;
757     GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
758 
759     Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
760 
761     /////////////////////////////////
762     // Calculate Block Surface Height
763     /////////////////////////////////
764 
765     if(ExpandedArraySize > 1)
766     {
767         uint32_t Alignment = VAlign;
768         if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) ||
769            (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) ||
770            (pTexInfo->Flags.Wa.MediaPipeUsage))
771         {
772             Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
773 	    //Gmm uses TileY for Stencil allocations, having half TileW height (TileY width compensates)
774             if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
775             {
776                 Alignment *= 2;
777             }
778 	}
779 
780         // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight)
781         BlockHeight = Get2DMipMapTotalHeight(pTexInfo);
782         BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment);
783 
784         // GMM internally uses QPitch as the logical distance between slices, but translates
785         // as appropriate to service client queries in GmmResGetQPitch.
786         pTexInfo->Alignment.QPitch = BlockHeight;
787 
788         if(Compress)
789         {
790             BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
791 
792             BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize);
793         }
794         else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
795         {
796             BlockHeight /= 2;
797         }
798         else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
799         {
800             BlockHeight /= 16;
801         }
802 
803         BlockHeight *= ExpandedArraySize;
804     }
805     else
806     {
807         pTexInfo->Alignment.QPitch = 0;
808 
809         BlockHeight = Get2DMipMapHeight(pTexInfo);
810     }
811 
812     ///////////////////////////////////
813     // Calculate Pitch
814     ///////////////////////////////////
815 
816     AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo);
817 
818     // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths
819     // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1
820     if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) &&
821        (pTexInfo->Alignment.MipTailStartLod < 2))
822     {
823         // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned.
824     }
825     else if(pTexInfo->MaxLod >= 2)
826     {
827         uint32_t AlignedWidthLod1, AlignedWidthLod2;
828 
829         AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo);
830         AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo);
831 
832         AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2);
833     }
834 
835     if(Compress)
836     {
837         AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth);
838     }
839     else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
840     {
841         AlignedWidth *= 2;
842     }
843     else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
844     {
845         switch(pTexInfo->BitsPerPixel)
846         {
847             case 32:
848                 AlignedWidth /= 8;
849                 break;
850             case 64:
851                 AlignedWidth /= 4;
852                 break;
853             case 128:
854                 AlignedWidth /= 2;
855                 break;
856             default:
857                 __GMM_ASSERT(0);
858         }
859     }
860     else if(pTexInfo->Flags.Gpu.ColorSeparation)
861     {
862         AlignedWidth *= pTexInfo->ArraySize;
863         __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION));
864         AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION;
865     }
866     else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX)
867     {
868         AlignedWidth *= pTexInfo->ArraySize;
869         __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION));
870         AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION;
871     }
872 
873     // Default pitch
874     Pitch = AlignedWidth * BitsPerPixel >> 3;
875 
876     // Make sure the pitch satisfy linear min pitch requirment
877     Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch);
878 
879     // Make sure pitch satisfy alignment restriction
880     Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment);
881 
882     ////////////////////
883     // Adjust for Tiling
884     ////////////////////
885 
886     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
887     {
888         Pitch       = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
889         BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
890     }
891 
892     GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!");
893     pTexInfo->Flags.Info.LayoutBelow = 1;
894     pTexInfo->Flags.Info.LayoutRight = 0;
895 
896     // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
897     // padding needs to be added. Since this will create a none pitch aligned
898     // surface the padding is aligned to the next row
899     if(GmmIsYUVPacked(pTexInfo->Format) ||
900        (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
901        (pTexInfo->BitsPerPixel == GMM_BITS(48)))
902     {
903         BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch);
904     }
905 
906     // Align height to even row to cover for HW over-fetch
907     BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW);
908 
909     if((Status = // <-- Note assignment.
910         FillTexPitchAndSize(
911         pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS)
912     {
913         Fill2DTexOffsetAddress(pTexInfo);
914     }
915 
916     GMM_DPF_EXIT;
917 
918     return (Status);
919 }
920 
921 
922 /////////////////////////////////////////////////////////////////////////////////////
923 /// Returns the mip offset of given LOD in Mip Tail
924 ///
925 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
926 ///             MipLevel: given LOD #
927 ///
928 /// @return     offset value of LOD in bytes
929 /////////////////////////////////////////////////////////////////////////////////////
GetMipTailByteOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)930 uint32_t GmmLib::GmmGen9TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo,
931                                                           uint32_t          MipLevel)
932 {
933     uint32_t ByteOffset = 0, Slot;
934 
935     GMM_DPF_ENTER;
936 
937     if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_3D))
938     {
939         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
940                (pTexInfo->Flags.Info.TiledYf ? 4 : 0);
941 
942         switch(Slot)
943         {
944             case 0:
945                 ByteOffset = GMM_KBYTE(32);
946                 break;
947             case 1:
948                 ByteOffset = GMM_KBYTE(16);
949                 break;
950             case 2:
951                 ByteOffset = GMM_KBYTE(8);
952                 break;
953             case 3:
954                 ByteOffset = GMM_KBYTE(4);
955                 break;
956             case 4:
957                 ByteOffset = GMM_KBYTE(2);
958                 break;
959             case 5:
960                 ByteOffset = GMM_KBYTE(1);
961                 break;
962             case 6:
963                 ByteOffset = GMM_BYTES(768);
964                 break;
965             case 7:
966                 ByteOffset = GMM_BYTES(512);
967                 break;
968             case 8:
969                 ByteOffset = GMM_BYTES(448);
970                 break;
971             case 9:
972                 ByteOffset = GMM_BYTES(384);
973                 break;
974             case 10:
975                 ByteOffset = GMM_BYTES(320);
976                 break;
977             case 11:
978                 ByteOffset = GMM_BYTES(256);
979                 break;
980             case 12:
981                 ByteOffset = GMM_BYTES(192);
982                 break;
983             case 13:
984                 ByteOffset = GMM_BYTES(128);
985                 break;
986             case 14:
987                 ByteOffset = GMM_BYTES(64);
988                 break;
989             case 15:
990                 ByteOffset = GMM_BYTES(0);
991                 break;
992             default:
993                 __GMM_ASSERT(0);
994         }
995     }
996     else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
997     {
998         // clang-format off
999         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
1000                     // TileYs
1001                    ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 :
1002                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  8) ? 3 :
1003                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  4) ? 2 :
1004                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  2) ? 1 :
1005                     (pTexInfo->Flags.Info.TiledYs                                   ) ? 0 :
1006                     // TileYf
1007                     (pTexInfo->Flags.Info.TiledYf                                   ) ?  4: 0);
1008         // clang-format on
1009 
1010         switch(Slot)
1011         {
1012             case 0:
1013                 ByteOffset = GMM_KBYTE(32);
1014                 break;
1015             case 1:
1016                 ByteOffset = GMM_KBYTE(16);
1017                 break;
1018             case 2:
1019                 ByteOffset = GMM_KBYTE(8);
1020                 break;
1021             case 3:
1022                 ByteOffset = GMM_KBYTE(4);
1023                 break;
1024             case 4:
1025                 ByteOffset = GMM_KBYTE(2);
1026                 break;
1027             case 5:
1028                 ByteOffset = GMM_BYTES(1536);
1029                 break;
1030             case 6:
1031                 ByteOffset = GMM_BYTES(1280);
1032                 break;
1033             case 7:
1034                 ByteOffset = GMM_BYTES(1024);
1035                 break;
1036             case 8:
1037                 ByteOffset = GMM_BYTES(768);
1038                 break;
1039             case 9:
1040                 ByteOffset = GMM_BYTES(512);
1041                 break;
1042             case 10:
1043                 ByteOffset = GMM_BYTES(256);
1044                 break;
1045             case 11:
1046                 ByteOffset = GMM_BYTES(192);
1047                 break;
1048             case 12:
1049                 ByteOffset = GMM_BYTES(128);
1050                 break;
1051             case 13:
1052                 ByteOffset = GMM_BYTES(64);
1053                 break;
1054             case 14:
1055                 ByteOffset = GMM_BYTES(0);
1056                 break;
1057             default:
1058                 __GMM_ASSERT(0);
1059         }
1060     }
1061 
1062     GMM_DPF_EXIT;
1063 
1064     return (ByteOffset);
1065 }
1066 
1067 GMM_MIPTAIL_SLOT_OFFSET Gen9MipTailSlotOffset1DSurface[16][5] = GEN9_MIPTAIL_SLOT_OFFSET_1D_SURFACE;
1068 GMM_MIPTAIL_SLOT_OFFSET Gen9MipTailSlotOffset2DSurface[15][5] = GEN9_MIPTAIL_SLOT_OFFSET_2D_SURFACE;
1069 GMM_MIPTAIL_SLOT_OFFSET Gen9MipTailSlotOffset3DSurface[16][5] = GEN9_MIPTAIL_SLOT_OFFSET_3D_SURFACE;
1070 /////////////////////////////////////////////////////////////////////////////////////
1071 /// Returns the mip-map offset in geometric OffsetX, Y, Z
1072 //  for a given LOD in Mip Tail.
1073 ///
1074 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
1075 ///             MipLevel: mip-map level
1076 ///             OffsetX: ptr to Offset in X direction (in bytes)
1077 ///             OffsetY: ptr to Offset in Y direction (in pixels)
1078 ///             OffsetZ: ptr to Offset in Z direction (in pixels)
1079 ///
1080 /////////////////////////////////////////////////////////////////////////////////////
GetMipTailGeometryOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel,uint32_t * OffsetX,uint32_t * OffsetY,uint32_t * OffsetZ)1081 void GmmLib::GmmGen9TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo,
1082                                                           uint32_t          MipLevel,
1083                                                           uint32_t *        OffsetX,
1084                                                           uint32_t *        OffsetY,
1085                                                           uint32_t *        OffsetZ)
1086 {
1087     uint32_t ArrayIndex = 0;
1088     uint32_t Slot       = 0;
1089 
1090     GMM_DPF_ENTER;
1091 
1092     switch(pTexInfo->BitsPerPixel)
1093     {
1094         case 128:
1095             ArrayIndex = 0;
1096             break;
1097         case 64:
1098             ArrayIndex = 1;
1099             break;
1100         case 32:
1101             ArrayIndex = 2;
1102             break;
1103         case 16:
1104             ArrayIndex = 3;
1105             break;
1106         case 8:
1107             ArrayIndex = 4;
1108             break;
1109         default:
1110             __GMM_ASSERT(0);
1111             break;
1112     }
1113 
1114     if(pTexInfo->Type == RESOURCE_1D)
1115     {
1116         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
1117                (pTexInfo->Flags.Info.TiledYf ? 4 : 0);
1118 
1119         *OffsetX = Gen9MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
1120         *OffsetY = Gen9MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y;
1121         *OffsetZ = Gen9MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z;
1122     }
1123     else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
1124     {
1125         // clang-format off
1126         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
1127                     // TileYs
1128                    ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 :
1129                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  8) ? 3 :
1130                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  4) ? 2 :
1131                     (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples ==  2) ? 1 :
1132                     (pTexInfo->Flags.Info.TiledYs                                   ) ? 0 :
1133                     // TileYf
1134                     (pTexInfo->Flags.Info.TiledYf                                   ) ?  4: 0);
1135         // clang-format on
1136 
1137         *OffsetX = Gen9MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
1138         *OffsetY = Gen9MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y;
1139         *OffsetZ = Gen9MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z;
1140     }
1141     else if(pTexInfo->Type == RESOURCE_3D)
1142     {
1143         Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod +
1144                (pTexInfo->Flags.Info.TiledYf ? 4 : 0);
1145 
1146         *OffsetX = Gen9MipTailSlotOffset3DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
1147         *OffsetY = Gen9MipTailSlotOffset3DSurface[Slot][ArrayIndex].Y;
1148         *OffsetZ = Gen9MipTailSlotOffset3DSurface[Slot][ArrayIndex].Z;
1149     }
1150 
1151     GMM_DPF_EXIT;
1152     return;
1153 }
1154 
1155 
1156 /////////////////////////////////////////////////////////////////////////////////////
1157 /// Allocates the 3D mip layout for surface state programming.
1158 ///
1159 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
1160 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
1161 ///
1162 /// @return     ::GMM_STATUS
1163 /////////////////////////////////////////////////////////////////////////////////////
FillTex3D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)1164 GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTex3D(GMM_TEXTURE_INFO * pTexInfo,
1165                                                              __GMM_BUFFER_TYPE *pRestrictions)
1166 {
1167     return FillTex2D(pTexInfo, pRestrictions);
1168 }
1169 
1170 
1171 /////////////////////////////////////////////////////////////////////////////////////
1172 /// Calculates the cube layout for surface state programming.
1173 ///
1174 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO,
1175 /// @param[in]  pRestrictions: ptr to surface alignment and size restrictions
1176 ///
1177 /// @return     ::GMM_STATUS
1178 /////////////////////////////////////////////////////////////////////////////////////
FillTexCube(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)1179 GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo,
1180                                                                __GMM_BUFFER_TYPE *pRestrictions)
1181 {
1182     return FillTex2D(pTexInfo, pRestrictions);
1183 }
1184 
1185 /////////////////////////////////////////////////////////////////////////////////////
1186 /// This function does any special-case conversion from client-provided pseudo creation
1187 /// parameters to actual parameters for CCS.
1188 ///
1189 /// @param[in]  pTexInfo: Reference to ::GMM_TEXTURE_INFO
1190 ///
1191 /// @return     ::GMM_STATUS
1192 /////////////////////////////////////////////////////////////////////////////////////
MSAACCSUsage(GMM_TEXTURE_INFO * pTexInfo)1193 GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo)
1194 {
1195     GMM_STATUS Status = GMM_SUCCESS;
1196 
1197     if(pTexInfo->MSAA.NumSamples > 1) // CCS for MSAA Compression
1198     {
1199         Status = MSAACompression(pTexInfo);
1200     }
1201     else // Non-MSAA CCS Use (i.e. Render Target Fast Clear)
1202     {
1203         if(!pTexInfo->Flags.Info.TiledW &&
1204            (!pTexInfo->Flags.Info.TiledX) &&
1205            ((!pTexInfo->Flags.Info.Linear) ||
1206             (GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) ||
1207              (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear))) && //!Yf - deprecate Yf
1208            ((pTexInfo->BitsPerPixel == 32) ||
1209             (pTexInfo->BitsPerPixel == 64) ||
1210             (pTexInfo->BitsPerPixel == 128)))
1211         {
1212             // For non-MSAA CCS usage, the four tables of
1213             // requirements:
1214             // (1) RT Alignment (GMM Don't Care: Occurs Naturally)
1215             // (2) ClearRect Alignment
1216             // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter)
1217             // (4) Non-MSAA CCS Sizing
1218 
1219             // Gen8+:
1220             // Since mip-mapped and arrayed surfaces are supported, we
1221             // deal with alignment later at per mip level. Here, we set
1222             // tiling type only. TileX is not supported on Gen9+.
1223             // Pre-Gen8:
1224             // (!) For all the above, there are separate entries for
1225             // 32/64/128bpp--and then deals with PIXEL widths--Here,
1226             // though, we will unify by considering 8bpp table entries
1227             // (unlisted--i.e. do the math)--and deal with BYTE widths.
1228 
1229             // (1) RT Alignment -- The surface width and height don't
1230             // need to be padded to RT CL granularity. On HSW, all tiled
1231             // RT's will have appropriate alignment (given 4KB surface
1232             // base and no mip-map support) and appropriate padding
1233             // (due to tile padding). On BDW+, GMM uses H/VALIGN that
1234             // will guarantee the MCS RT alignment for all subresources.
1235 
1236             // (2) ClearRect Alignment -- I.e. FastClears must be done
1237             // with certain granularity:
1238             //  TileY:  512 Bytes x 128 Lines
1239             //  TileX: 1024 Bytes x  64 Lines
1240             // So a CCS must be sized to match that granularity (though
1241             // the RT itself need not be fully padded to that
1242             // granularity to use FastClear).
1243 
1244             // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the
1245             // size of the FastClear (with granularity padding) for the
1246             // paired RT. CCS's (byte widths and heights) are scaled
1247             // down from their RT's by:
1248             //  TileY: 32 x 32
1249             //  TileX: 64 x 16
1250 
1251             // ### Example #############################################
1252             // RT:         800x600, 32bpp, TileY
1253             // 8bpp:      3200x600
1254             // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128)
1255             // CCS:       112x20 (for TileY RT:CCS Sizing Downscale of 32x32)
1256 
1257             pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs;
1258             pTexInfo->Flags.Gpu.__NonMsaaTileXCcs = pTexInfo->Flags.Info.TiledX;
1259         }
1260         else
1261         {
1262             GMM_ASSERTDPF(0, "Illegal CCS creation parameters!");
1263             Status = GMM_ERROR;
1264         }
1265     }
1266     return Status;
1267 }
1268