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 /// This function calculates the (X,Y) address of each given plane. X is in bytes
28 /// and Y is in scanlines.
29 ///
30 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
31 ///
32 /////////////////////////////////////////////////////////////////////////////////////
FillPlanarOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)33 void GmmLib::GmmTextureCalc::FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
34 {
35     GMM_GFX_SIZE_T *pUOffsetX, *pUOffsetY;
36     GMM_GFX_SIZE_T *pVOffsetX, *pVOffsetY;
37     uint32_t        YHeight = 0, VHeight = 0;
38     bool            UVPacked = false;
39     uint32_t        Height;
40     uint32_t        WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3;
41 
42 #define SWAP_UV()              \
43     {                          \
44         GMM_GFX_SIZE_T *pTemp; \
45                                \
46         pTemp     = pUOffsetX; \
47         pUOffsetX = pVOffsetX; \
48         pVOffsetX = pTemp;     \
49                                \
50         pTemp     = pUOffsetY; \
51         pUOffsetY = pVOffsetY; \
52         pVOffsetY = pTemp;     \
53     }
54 
55     __GMM_ASSERTPTR(pTexInfo, VOIDRETURN);
56     __GMM_ASSERTPTR(((pTexInfo->TileMode < GMM_TILE_MODES) && (pTexInfo->TileMode >= TILE_NONE)), VOIDRETURN);
57     GMM_DPF_ENTER;
58 
59     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
60 
61     // GMM_PLANE_Y always at (0, 0)...
62     pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0;
63     pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0;
64 
65     Height = pTexInfo->BaseHeight;
66     if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
67     {
68         Height = __GMM_EXPAND_HEIGHT(this, Height, pTexInfo->Alignment.VAlign, pTexInfo);
69         Height = ScaleTextureHeight(pTexInfo, Height);
70         if(pTexInfo->Flags.Gpu.UnifiedAuxSurface)
71         {
72             pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0;
73         }
74     }
75 
76     // GMM_PLANE_U/V Planes...
77     pUOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U];
78     pUOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U];
79     pVOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V];
80     pVOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V];
81 
82     switch(pTexInfo->Format)
83     {
84         case GMM_FORMAT_IMC1:
85             SWAP_UV(); // IMC1 = IMC3 with Swapped U/V
86         case GMM_FORMAT_IMC3:
87         case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3.
88         // YYYYYYYY
89         // YYYYYYYY
90         // YYYYYYYY
91         // YYYYYYYY
92         // UUUU
93         // UUUU
94         // VVVV
95         // VVVV
96         case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width.
97             // YYYYYYYY
98             // YYYYYYYY
99             // YYYYYYYY
100             // YYYYYYYY
101             // UUUUUUUU
102             // UUUUUUUU
103             // VVVVVVVV
104             // VVVVVVVV
105             {
106                 *pUOffsetX = 0;
107                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
108                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
109 
110                 *pVOffsetX = 0;
111                 VHeight    = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
112                 *pVOffsetY =
113                 GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) +
114                 GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
115 
116                 break;
117             }
118         case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width.
119             //YYYYYYYY
120             //YYYYYYYY
121             //YYYYYYYY
122             //YYYYYYYY
123             //UUUUUUUU
124             //VVVVVVVV
125             {
126                 *pUOffsetX = 0;
127                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
128                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
129 
130                 *pVOffsetX = 0;
131                 VHeight    = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
132                 *pVOffsetY =
133                 GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) +
134                 GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
135 
136                 break;
137             }
138         case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height.
139         // YYYYYYYY
140         // YYYYYYYY
141         // YYYYYYYY
142         // YYYYYYYY
143         // UU
144         // UU
145         // UU
146         // UU
147         // VV
148         // VV
149         // VV
150         // VV
151         case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height.
152         // YYYYYYYY
153         // YYYYYYYY
154         // YYYYYYYY
155         // YYYYYYYY
156         // UUUU
157         // UUUU
158         // UUUU
159         // UUUU
160         // VVVV
161         // VVVV
162         // VVVV
163         // VVVV
164         case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size.
165             // YYYYYYYY
166             // YYYYYYYY
167             // YYYYYYYY
168             // YYYYYYYY
169             // UUUUUUUU
170             // UUUUUUUU
171             // UUUUUUUU
172             // UUUUUUUU
173             // VVVVVVVV
174             // VVVVVVVV
175             // VVVVVVVV
176             // VVVVVVVV
177             {
178                 *pUOffsetX = 0;
179                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
180                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
181 
182                 *pVOffsetX = 0;
183                 VHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
184                 *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2;
185 
186                 break;
187             }
188         case GMM_FORMAT_BGRP:
189         case GMM_FORMAT_RGBP:
190         {
191             //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned
192             if(pTexInfo->Flags.Info.Linear)
193             {
194                 *pUOffsetX = 0;
195                 YHeight    = pTexInfo->BaseHeight;
196                 *pUOffsetY = pTexInfo->BaseHeight;
197 
198                 *pVOffsetX = 0;
199                 VHeight    = pTexInfo->BaseHeight;
200                 *pVOffsetY = (GMM_GFX_SIZE_T)pTexInfo->BaseHeight * 2;
201             }
202             else // Tiled
203             {
204                 *pUOffsetX = 0;
205                 YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
206                 *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
207 
208                 *pVOffsetX = 0;
209                 VHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
210                 *pVOffsetY = (GMM_GFX_SIZE_T)GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2;
211             }
212             break;
213         }
214         case GMM_FORMAT_IMC2:
215             SWAP_UV(); // IMC2 = IMC4 with Swapped U/V
216         case GMM_FORMAT_IMC4:
217         {
218             // YYYYYYYY
219             // YYYYYYYY
220             // YYYYYYYY
221             // YYYYYYYY
222             // UUUUVVVV
223             // UUUUVVVV
224 
225             __GMM_ASSERT((pTexInfo->Pitch & 1) == 0);
226 
227             *pUOffsetX = 0;
228             YHeight    = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
229             *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
230 
231             *pVOffsetX = pTexInfo->Pitch / 2;
232             VHeight    = GFX_CEIL_DIV(YHeight, 2);
233             *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
234 
235             // Not technically UV packed but sizing works out the same
236             UVPacked = true;
237 
238             break;
239         }
240         case GMM_FORMAT_I420: // I420 = IYUV
241         case GMM_FORMAT_IYUV:
242             SWAP_UV(); // I420/IYUV = YV12 with Swapped U/V
243         case GMM_FORMAT_YV12:
244         case GMM_FORMAT_YVU9:
245         {
246             // YYYYYYYY
247             // YYYYYYYY
248             // YYYYYYYY
249             // YYYYYYYY
250             // VVVVVV..  <-- V and U planes follow the Y plane, as linear
251             // ..UUUUUU      arrays--without respect to pitch.
252 
253             uint32_t YSize, YVSizeRShift, VSize, UOffset;
254             uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment;
255 
256             YSize = GFX_ULONG_CAST(pTexInfo->Pitch) * pTexInfo->BaseHeight;
257 
258             // YVU9 has one U/V pixel for each 4x4 Y block.
259             // The others have one U/V pixel for each 2x2 Y block.
260 
261             // YVU9 has a Y:V size ratio of 16 (4x4 --> 1).
262             // The others have a ratio of 4 (2x2 --> 1).
263             YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
264 
265             // If a Y plane isn't fully-aligned to its Y-->U/V block size, the
266             // extra/unaligned Y pixels still need corresponding U/V pixels--So
267             // for the purpose of computing the UVSize, we must consider a
268             // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would
269             // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.)
270             YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
271             YSizeForUVPurposes =
272             GFX_ALIGN(GFX_ULONG_CAST(pTexInfo->Pitch), YSizeForUVPurposesDimensionalAlignment) *
273             GFX_ALIGN(pTexInfo->BaseHeight, YSizeForUVPurposesDimensionalAlignment);
274 
275             VSize   = (YSizeForUVPurposes >> YVSizeRShift);
276             UOffset = YSize + VSize;
277 
278             *pVOffsetX = 0;
279             *pVOffsetY = pTexInfo->BaseHeight;
280 
281             *pUOffsetX = UOffset % pTexInfo->Pitch;
282             *pUOffsetY = UOffset / pTexInfo->Pitch;
283 
284             YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical);
285 
286             break;
287         }
288         case GMM_FORMAT_NV12:
289         case GMM_FORMAT_NV21:
290         case GMM_FORMAT_NV11:
291         case GMM_FORMAT_P010:
292         case GMM_FORMAT_P012:
293         case GMM_FORMAT_P016:
294         case GMM_FORMAT_P208:
295         case GMM_FORMAT_P216:
296         {
297             // YYYYYYYY
298             // YYYYYYYY
299             // YYYYYYYY
300             // YYYYYYYY
301             // [UV-Packing]
302             *pUOffsetX = *pVOffsetX = 0;
303             YHeight                 = GFX_ALIGN(Height, __GMM_EVEN_ROW);
304             *pUOffsetY = *pVOffsetY = YHeight;
305 
306             if((pTexInfo->Format == GMM_FORMAT_NV12) ||
307                (pTexInfo->Format == GMM_FORMAT_NV21) ||
308                (pTexInfo->Format == GMM_FORMAT_P010) ||
309                (pTexInfo->Format == GMM_FORMAT_P012) ||
310                (pTexInfo->Format == GMM_FORMAT_P016))
311             {
312                 VHeight = GFX_CEIL_DIV(Height, 2);
313             }
314             else
315             {
316                 VHeight = YHeight; // U/V plane is same as Y
317             }
318 
319             UVPacked = true;
320             break;
321         }
322         default:
323         {
324             GMM_ASSERTDPF(0, "Unknown Video Format U\n");
325             break;
326         }
327     }
328 
329     pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = YHeight;
330     if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2)
331     {
332         pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = VHeight;
333     }
334     else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3)
335     {
336         pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] =
337         pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V] = VHeight;
338     }
339 
340 
341     if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) || pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
342     {
343         GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
344         GMM_GFX_SIZE_T TileWidth  = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth;
345 
346         *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth);
347         *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight);
348         *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth);
349         *pVOffsetY = UVPacked ?
350                      GFX_ALIGN(*pVOffsetY, TileHeight) :
351                      GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight);
352 
353         if(pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
354         {
355             *pUOffsetY += pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y];
356             *pVOffsetY = *pUOffsetY;
357         }
358     }
359 
360     //Special case LKF MMC compressed surfaces
361     if(pTexInfo->Flags.Gpu.MMC &&
362        pTexInfo->Flags.Gpu.UnifiedAuxSurface &&
363        GMM_IS_4KB_TILE(pTexInfo->Flags))
364     {
365         GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
366         GMM_GFX_SIZE_T TileWidth  = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth;
367 
368         *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth);
369         *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight);
370         *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth);
371         *pVOffsetY = GFX_ALIGN(*pVOffsetY, TileHeight);
372     }
373 
374     GMM_DPF_EXIT;
375 
376 #undef SWAP_UV
377 }
378 
379 
380 /////////////////////////////////////////////////////////////////////////////////////
381 /// Sibling function of GmmLib::GmmTextureCalc::ExpandWidth. it returns the given
382 /// Width, as appropriately scaled by the MSAA NumSamples parameter and aligned to the
383 /// given UnitAlignment.
384 ///
385 /// @param[in]  Height: Height of the surface
386 /// @param[in]  UnitAlignment: Unit alignment factor
387 /// @param[in]  NumSamples: No of MSAA samples
388 ///
389 /// @return     scaled height
390 /////////////////////////////////////////////////////////////////////////////////////
ExpandHeight(uint32_t Height,uint32_t UnitAlignment,uint32_t NumSamples)391 uint32_t GmmLib::GmmTextureCalc::ExpandHeight(uint32_t Height, uint32_t UnitAlignment, uint32_t NumSamples)
392 {
393     // Implemented as separate function (instead of as a single function with a
394     // Width/Height parameter) so both functions can be later implemented without
395     // branches, if need be.
396 
397     return (
398     GmmLib::GmmTextureCalc::ExpandWidth(
399     Height, UnitAlignment,
400     (NumSamples == 2) ? 1 :                 // MSAA_2X: No height adjustment
401     ((NumSamples == 8) ? 4 : NumSamples))); // <-- MSAA_8X:Height = MSAA_4X:Height.
402 }
403 
404 
405 /////////////////////////////////////////////////////////////////////////////////////
406 /// This function returns the given Width, as appropriately scaled by the MSAA
407 /// NumSamples parameter and aligned to the given UnitAlignment.
408 ///
409 /// @param[in]  Width: Height of the surface
410 /// @param[in]  UnitAlignment: Unit alignment factor
411 /// @param[in]  NumSamples: No of MSAA samples
412 ///
413 /// @return     scaled width
414 /////////////////////////////////////////////////////////////////////////////////////
ExpandWidth(uint32_t Width,uint32_t UnitAlignment,uint32_t NumSamples)415 uint32_t GmmLib::GmmTextureCalc::ExpandWidth(uint32_t Width, uint32_t UnitAlignment, uint32_t NumSamples)
416 {
417     uint32_t ExpandedWidth;
418 
419     switch(NumSamples)
420     {
421         case 1:
422             ExpandedWidth = Width;
423             break;
424         case 2: // Same as 4x...
425         case 4:
426             ExpandedWidth = GFX_CEIL_DIV(GFX_MAX(Width, 1), 2) * 4;
427             break;
428         case 8: // Same as 16x...
429         case 16:
430             ExpandedWidth = GFX_CEIL_DIV(GFX_MAX(Width, 1), 2) * 8;
431             break;
432         default:
433             ExpandedWidth = Width;
434             __GMM_ASSERT(0);
435     }
436 
437     ExpandedWidth = GFX_MAX(ExpandedWidth, UnitAlignment);
438     ExpandedWidth = GFX_ALIGN_NP2(ExpandedWidth, UnitAlignment);
439 
440     return (ExpandedWidth);
441 }
442 
443 
444 /////////////////////////////////////////////////////////////////////////////////////
445 /// This function calculates Mip Tail Start LOD using max mip tail dimensions and
446 /// populates pTexInfo->Alignment.MipTailStartLod
447 ///
448 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
449 ///
450 /////////////////////////////////////////////////////////////////////////////////////
FindMipTailStartLod(GMM_TEXTURE_INFO * pTexInfo)451 void GmmLib::GmmTextureCalc::FindMipTailStartLod(GMM_TEXTURE_INFO *pTexInfo)
452 {
453     GMM_DPF_ENTER;
454 
455     if(!(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ||
456        (pTexInfo->MaxLod == 0) ||
457        (pTexInfo->Flags.Wa.DisablePackedMipTail))
458     {
459         // HW never ignores MipTailStartLod for Yf/Ys surfaces. If we do not
460         // want a mip tail, we set MipTailStartLod to be greater than MaxLod.
461         pTexInfo->Alignment.MipTailStartLod = GMM_TILED_RESOURCE_NO_MIP_TAIL;
462     }
463     else
464     {
465         uint32_t                 MipDepth, MipHeight, MipWidth, CompressWidth, CompressHeight, CompressDepth;
466         uint32_t                 Level     = 0;
467         const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
468 
469         MipDepth  = pTexInfo->Depth;
470         MipHeight = pTexInfo->BaseHeight;
471         MipWidth  = GFX_ULONG_CAST(pTexInfo->BaseWidth);
472 
473         //if compressed texture format, use compressed height, width
474         GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
475 
476         if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format))
477         {
478             MipWidth  = GFX_CEIL_DIV(MipWidth, CompressWidth);
479             MipHeight = GFX_CEIL_DIV(MipHeight, CompressHeight);
480             MipDepth  = GFX_CEIL_DIV(MipDepth, CompressDepth);
481         }
482 
483         while((Level < pTexInfo->MaxLod) &&
484               (((pTexInfo->Type == RESOURCE_1D) &&
485                 !(MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth)) ||
486                (((pTexInfo->Type == RESOURCE_2D) || (pTexInfo->Type == RESOURCE_CUBE)) &&
487                 !((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) &&
488                   (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight))) ||
489                ((pTexInfo->Type == RESOURCE_3D) &&
490                 !((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) &&
491                   (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight) &&
492                   (MipDepth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartDepth)))))
493         {
494             Level++;
495 
496             MipWidth  = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, Level));
497             MipHeight = GmmTexGetMipHeight(pTexInfo, Level);
498             MipDepth  = GmmTexGetMipDepth(pTexInfo, Level);
499 
500             MipWidth  = GFX_CEIL_DIV(MipWidth, CompressWidth);
501             MipHeight = GFX_CEIL_DIV(MipHeight, CompressHeight);
502             MipDepth  = GFX_CEIL_DIV(MipDepth, CompressDepth);
503         }
504 
505         if(((pTexInfo->Type == RESOURCE_1D) &&
506             (MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth)) ||
507            (((pTexInfo->Type == RESOURCE_2D) || (pTexInfo->Type == RESOURCE_CUBE)) &&
508             ((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) &&
509              (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight))) ||
510            ((pTexInfo->Type == RESOURCE_3D) &&
511             ((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) &&
512              (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight) &&
513              (MipDepth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartDepth))))
514         {
515             pTexInfo->Alignment.MipTailStartLod = Level;
516         }
517         else
518         {
519             pTexInfo->Alignment.MipTailStartLod = GMM_TILED_RESOURCE_NO_MIP_TAIL;
520         }
521     }
522 
523     GMM_DPF_EXIT;
524 }
525 
526 
527 /////////////////////////////////////////////////////////////////////////////////////
528 /// This function returns the height, width and depth of the compression block for a
529 /// given surface format.
530 ///
531 /// @param[in]  Format: ::GMM_RESOURCE_FORMAT
532 /// @param[in]  pWidth: populates Width
533 /// @param[in]  pHeight: populates Height
534 /// @param[in]  pDepth: populates Depth
535 ///
536 /////////////////////////////////////////////////////////////////////////////////////
GetCompressionBlockDimensions(GMM_RESOURCE_FORMAT Format,uint32_t * pWidth,uint32_t * pHeight,uint32_t * pDepth)537 void GmmLib::GmmTextureCalc::GetCompressionBlockDimensions(GMM_RESOURCE_FORMAT Format,
538                                                            uint32_t *          pWidth,
539                                                            uint32_t *          pHeight,
540                                                            uint32_t *          pDepth)
541 {
542 
543     GMM_DPF_ENTER;
544     __GMM_ASSERT(pWidth && pHeight && pDepth);
545 
546     if(pWidth && pHeight && pDepth)
547     {
548         if((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS))
549         {
550             *pWidth  = pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.Width;
551             *pHeight = pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.Height;
552             *pDepth  = pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.Depth;
553         }
554         else
555         {
556             *pWidth  = 1;
557             *pHeight = 1;
558             *pDepth  = 1;
559         }
560     }
561     GMM_DPF_EXIT;
562 }
563 
564 /////////////////////////////////////////////////////////////////////////////////////
565 /// This function Convert from d3d tile (64KB) to h/w tile
566 ///
567 /// @param[in]  pTexInfo: ::GMM_TEXTURE_INFO
568 /// @param[in/out]  pColFactor: populates Width
569 /// @param[in/out]  pRowFactor: populates Height
570 /// @param[out]  true on Success else false
571 ///
572 /////////////////////////////////////////////////////////////////////////////////////
GmmGetD3DToHwTileConversion(GMM_TEXTURE_INFO * pTexInfo,uint32_t * pColFactor,uint32_t * pRowFactor)573 bool GmmLib::GmmTextureCalc::GmmGetD3DToHwTileConversion(GMM_TEXTURE_INFO *pTexInfo,
574                                                          uint32_t *        pColFactor,
575                                                          uint32_t *        pRowFactor)
576 {
577     uint32_t i   = 0;
578     uint32_t Bpp = pTexInfo->BitsPerPixel;
579 
580     // check for  unsupported bpp
581     if(!(Bpp == 8 || Bpp == 16 || Bpp == 32 || Bpp == 64 || Bpp == 128))
582     {
583         __GMM_ASSERT(false);
584         goto EXIT_ERROR;
585     }
586 
587     // for TileYS, no conversion
588     if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.Linear)
589     {
590         *pColFactor = 1;
591         *pRowFactor = 1;
592     }
593     else if(GMM_IS_4KB_TILE(pTexInfo->Flags))
594     {
595         // Logic for non-MSAA
596         {
597             //      Bpp = 8      => i = 0           , Bpp = 16 => i = 1, ...
598             // Log2(Bpp = 8) = 3 => i = Log2(8) - 3.
599 
600             i           = __GmmLog2(Bpp) - 3;
601             *pColFactor = __GmmTileYConversionTable[i][0];
602             *pRowFactor = __GmmTileYConversionTable[i][1];
603         }
604 
605         // Logic for MSAA
606         if(pTexInfo->MSAA.NumSamples > 1)
607         {
608 
609             // For MSAA, the DirectX tile dimensions change, using the table __GmmMSAAConversion.
610             uint32_t W = __GmmMSAAConversion[__GmmLog2(pTexInfo->MSAA.NumSamples)][0];
611             uint32_t H = __GmmMSAAConversion[__GmmLog2(pTexInfo->MSAA.NumSamples)][1];
612 
613             // For the new DirectX tile dimensions the new Col and Row conversion factors are:
614             *pColFactor /= W;
615             *pRowFactor /= H;
616         }
617     }
618     else
619     {
620         // unsupported format.
621         __GMM_ASSERT(false);
622         goto EXIT_ERROR;
623     }
624 
625     return true;
626 
627 EXIT_ERROR:
628     *pColFactor = 0;
629     *pRowFactor = 0;
630     return false;
631 }
632 
633 /////////////////////////////////////////////////////////////////////////////////////
634 /// This function redescribes WidthBytesPhysical of main surface as per UV plane bpp and tilemode
635 ///
636 /// @return     ::bool
637 /////////////////////////////////////////////////////////////////////////////////////
RedescribeTexturePlanes(GMM_TEXTURE_INFO * pTexInfo,uint32_t * pWidthBytesPhysical)638 bool GmmLib::GmmTextureCalc::RedescribeTexturePlanes(GMM_TEXTURE_INFO *pTexInfo, uint32_t *pWidthBytesPhysical)
639 {
640     GMM_STATUS               Status = GMM_SUCCESS;
641     GMM_TEXTURE_INFO         TexInfoUVPlane;
642     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
643 
644     __GMM_ASSERT(pTexInfo);
645     __GMM_ASSERT(pTexInfo->Flags.Info.RedecribedPlanes);
646     __GMM_ASSERT(pWidthBytesPhysical);
647 
648     TexInfoUVPlane = *pTexInfo;
649 #ifdef _WIN32
650     memcpy_s(&TexInfoUVPlane, sizeof(GMM_TEXTURE_INFO), pTexInfo, sizeof(GMM_TEXTURE_INFO));
651 #else
652     memcpy(&TexInfoUVPlane, pTexInfo, sizeof(GMM_TEXTURE_INFO));
653 #endif // _WIN32
654 
655 
656     if(GmmIsUVPacked(pTexInfo->Format))
657     {
658         // UV packed resources must have two seperate
659         // tiling modes per plane, due to the packed
660         // UV plane having twice the bits per pixel
661         // as the Y plane.
662         switch(pTexInfo->Format)
663         {
664             case GMM_FORMAT_NV12:
665             case GMM_FORMAT_NV21:
666             case GMM_FORMAT_P208:
667                 TexInfoUVPlane.BitsPerPixel = 16; // Redescribe bpp to 16 from 8
668                 break;
669             case GMM_FORMAT_P010:
670             case GMM_FORMAT_P012:
671             case GMM_FORMAT_P016:
672             case GMM_FORMAT_P216:
673                 TexInfoUVPlane.BitsPerPixel = 32;
674                 break;
675             default:
676                 GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!");
677                 Status = GMM_INVALIDPARAM;
678                 goto ERROR_CASE;
679                 break;
680         }
681     }
682     else
683     {
684         // Non-UV packed surfaces, TileMode and bpp of each plane is same as that of pTexInfo
685     }
686 
687     SetTileMode(&TexInfoUVPlane);
688     *pWidthBytesPhysical = GFX_ALIGN(*pWidthBytesPhysical, pPlatform->TileInfo[TexInfoUVPlane.TileMode].LogicalTileWidth);
689 
690 ERROR_CASE:
691     return (Status == GMM_SUCCESS) ? true : false;
692 }
693 
694 /////////////////////////////////////////////////////////////////////////////////////
695 /// This function returns per plane redescribed parameters (pRedescribedTexInfo: fmt, tilemode,bpp, width, height, size) when main surface pTexInfo is passed
696 ///
697 /// @return     ::bool
698 /////////////////////////////////////////////////////////////////////////////////////
GetRedescribedPlaneParams(GMM_TEXTURE_INFO * pTexInfo,GMM_YUV_PLANE PlaneType,GMM_TEXTURE_INFO * pRedescribedTexInfo)699 bool GmmLib::GmmTextureCalc::GetRedescribedPlaneParams(GMM_TEXTURE_INFO *pTexInfo, GMM_YUV_PLANE PlaneType, GMM_TEXTURE_INFO *pRedescribedTexInfo)
700 {
701     GMM_STATUS               Status = GMM_SUCCESS;
702     GMM_TEXTURE_INFO         TexInfoUVPlane;
703     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
704 
705     __GMM_ASSERT(pTexInfo);
706     __GMM_ASSERT(pTexInfo->Flags.Info.RedecribedPlanes);
707     __GMM_ASSERT(pRedescribedTexInfo);
708 
709     *pRedescribedTexInfo                             = *pTexInfo;
710     pRedescribedTexInfo->Flags.Info.RedecribedPlanes = 0;
711 #ifdef _WIN32
712     memcpy_s(&TexInfoUVPlane, sizeof(GMM_TEXTURE_INFO), pTexInfo, sizeof(GMM_TEXTURE_INFO));
713 #else
714     memcpy(&TexInfoUVPlane, pTexInfo, sizeof(GMM_TEXTURE_INFO));
715 #endif // _WIN32
716 
717     if(GmmIsUVPacked(pTexInfo->Format))
718     {
719         // UV packed resources must have two seperate
720         // tiling modes per plane, due to the packed
721         // UV plane having twice the bits per pixel
722         // as the Y plane.
723         if((PlaneType == GMM_PLANE_U) || (PlaneType == GMM_PLANE_V))
724         {
725             switch(pTexInfo->Format)
726             {
727                 // GMM_FORMAT_NV11  :                               linear format, no tiling supported, hence no redescription supported
728                 case GMM_FORMAT_NV12:
729                 case GMM_FORMAT_NV21:
730                     pRedescribedTexInfo->BitsPerPixel = 16;
731                     pRedescribedTexInfo->BaseWidth    = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2);
732                     pRedescribedTexInfo->BaseHeight   = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2);
733                     break;
734                 case GMM_FORMAT_P208:
735                     pRedescribedTexInfo->BitsPerPixel = 16;
736                     pRedescribedTexInfo->BaseWidth    = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2);
737                     // same base height as main surface
738                     break;
739                 case GMM_FORMAT_P010:
740                 case GMM_FORMAT_P012:
741                 case GMM_FORMAT_P016:
742                     pRedescribedTexInfo->BitsPerPixel = 32;
743                     pRedescribedTexInfo->BaseWidth    = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2);
744                     pRedescribedTexInfo->BaseHeight   = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2);
745                     break;
746                 case GMM_FORMAT_P216:
747                     pRedescribedTexInfo->BitsPerPixel = 32;
748                     pRedescribedTexInfo->BaseWidth    = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2);
749                     // same base height as main surface
750                     break;
751                 default:
752                     GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!");
753                     Status = GMM_INVALIDPARAM;
754                     goto ERROR_CASE;
755                     break;
756             }
757         }
758     }
759     else
760     {
761         // Non-UV packed surfaces TileMode of each plane is same as that of pTexInfo
762         if((PlaneType == GMM_PLANE_U) || (PlaneType == GMM_PLANE_V))
763         { // Non-UV packed surfaces only require the plane descriptors have proper height and width for each plane
764             switch(pTexInfo->Format)
765             {
766                 case GMM_FORMAT_IMC1:
767                 case GMM_FORMAT_IMC2:
768                 case GMM_FORMAT_IMC3:
769                 case GMM_FORMAT_IMC4:
770                 case GMM_FORMAT_MFX_JPEG_YUV420:
771                     pRedescribedTexInfo->BaseWidth  = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2);
772                     pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2);
773                     break;
774                 case GMM_FORMAT_MFX_JPEG_YUV422V:
775                     pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2);
776                     break;
777                 case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE:
778                     pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 4);
779                     break;
780                 case GMM_FORMAT_MFX_JPEG_YUV411:
781                     pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 4);
782                     break;
783                 case GMM_FORMAT_MFX_JPEG_YUV422H:
784                     pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2);
785                     break;
786                 default:
787                     GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!");
788                     Status = GMM_INVALIDPARAM;
789                     goto ERROR_CASE;
790                     break;
791             }
792         }
793     }
794 
795     SetTileMode(pRedescribedTexInfo);
796     switch(pRedescribedTexInfo->BitsPerPixel)
797     {
798         case 8:
799             pRedescribedTexInfo->Format = GMM_FORMAT_R8_UINT;
800             break;
801         case 16:
802             pRedescribedTexInfo->Format = GMM_FORMAT_R16_UINT;
803             break;
804         case 32:
805             pRedescribedTexInfo->Format = GMM_FORMAT_R32_UINT;
806             break;
807         default:
808             GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!");
809             Status = GMM_INVALIDPARAM;
810             goto ERROR_CASE;
811             break;
812     }
813     if(pTexInfo->ArraySize > 1)
814     {
815         pRedescribedTexInfo->OffsetInfo.Plane.ArrayQPitch = 0; // no longer a planar format on redescription
816         pRedescribedTexInfo->Alignment.QPitch             = GFX_ALIGN(pRedescribedTexInfo->BaseHeight, pTexInfo->Alignment.VAlign);
817         pRedescribedTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender =
818         pRedescribedTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = pRedescribedTexInfo->Alignment.QPitch * pTexInfo->Pitch;
819         pRedescribedTexInfo->Size                                           = pRedescribedTexInfo->Alignment.QPitch * pTexInfo->Pitch * pTexInfo->ArraySize;
820     }
821     else
822     {
823         pRedescribedTexInfo->Size = (GFX_ALIGN(pRedescribedTexInfo->BaseHeight, pTexInfo->Alignment.VAlign)) * pTexInfo->Pitch;
824     }
825 
826 ERROR_CASE:
827     return (Status == GMM_SUCCESS) ? true : false;
828 }
829