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 /// GMM Interface to return lock or render aligned offset to a mip map
28 ///
29 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
30 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info
31 ///
32 /// @return     ::GMM_STATUS
33 /////////////////////////////////////////////////////////////////////////////////////
GmmTexGetMipMapOffset(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo,GMM_LIB_CONTEXT * pGmmLibContext)34 GMM_STATUS GmmTexGetMipMapOffset(GMM_TEXTURE_INFO *   pTexInfo,
35                                  GMM_REQ_OFFSET_INFO *pReqInfo,
36                                  GMM_LIB_CONTEXT *    pGmmLibContext)
37 {
38     GMM_STATUS        Status           = GMM_SUCCESS;
39     bool              RestoreRenderReq = false;
40     GMM_TEXTURE_CALC *pTextureCalc;
41 
42     GMM_DPF_ENTER;
43     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
44     __GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
45     __GMM_ASSERT(pReqInfo->CubeFace <= __GMM_NO_CUBE_MAP);
46 
47     pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext);
48 
49     if((pReqInfo->Plane >= GMM_MAX_PLANE) ||
50        (pReqInfo->Plane < GMM_NO_PLANE) ||
51        (pReqInfo->MipLevel >= GMM_MAX_MIPMAP))
52     {
53         GMM_ASSERTDPF(0, "Invalid parameter!");
54         return GMM_ERROR;
55     }
56 
57     if((pTexInfo->TileMode >= GMM_TILE_MODES) ||
58        (pTexInfo->TileMode < TILE_NONE))
59     {
60         GMM_ASSERTDPF(0, "Invalid parameter!");
61         return GMM_ERROR;
62     }
63 
64     // Retrieve offset info at pReqInfo->MipLevel
65     if(pReqInfo->ReqLock)
66     {
67         if(pReqInfo->ReqRender)
68         {
69             pReqInfo->ReqRender = 0;
70             RestoreRenderReq    = true;
71         }
72 
73         if(pTextureCalc->GetTexLockOffset(pTexInfo, pReqInfo) != GMM_SUCCESS)
74         {
75             GMM_ASSERTDPF(0, "ReqLock failed!");
76             Status = GMM_ERROR;
77         }
78     }
79 
80     if(RestoreRenderReq == true)
81         pReqInfo->ReqRender = 1;
82 
83     if(pReqInfo->ReqRender)
84     {
85         if(pTextureCalc->GetTexRenderOffset(pTexInfo, pReqInfo) != GMM_SUCCESS)
86         {
87             GMM_ASSERTDPF(0, "ReqRender failed!");
88             Status = GMM_ERROR;
89         }
90     }
91 
92     if(pReqInfo->ReqStdLayout)
93     {
94         if(pTextureCalc->GetTexStdLayoutOffset(pTexInfo, pReqInfo) != GMM_SUCCESS)
95         {
96             GMM_ASSERTDPF(0, "ReqStdLayout failed!");
97             Status = GMM_ERROR;
98         }
99     }
100 
101     GMM_DPF_EXIT;
102     return Status;
103 }
104 
105 
106 /////////////////////////////////////////////////////////////////////////////////////
107 /// Calculates StdLayout offsets and related pitches of
108 /// subresource..
109 ///
110 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
111 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info
112 ///
113 /// @return     ::GMM_STATUS
114 /////////////////////////////////////////////////////////////////////////////////////
GetTexStdLayoutOffset(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo)115 GMM_STATUS GmmLib::GmmTextureCalc::GetTexStdLayoutOffset(GMM_TEXTURE_INFO *   pTexInfo,
116                                                          GMM_REQ_OFFSET_INFO *pReqInfo)
117 {
118     uint32_t ReqArrayIndex;
119     bool     NeedSurfaceSize = false;
120 
121     __GMM_ASSERT(pTexInfo);
122     __GMM_ASSERT(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf);
123     __GMM_ASSERT(
124     (pTexInfo->Type == RESOURCE_2D) ||
125     (pTexInfo->Type == RESOURCE_3D) ||
126     (pTexInfo->Type == RESOURCE_CUBE));
127     __GMM_ASSERT(GmmIsPlanar(pTexInfo->Format) == false); // Planar not support
128 
129     if(pReqInfo->StdLayout.Offset == -1) // Special Req for Surface Size
130     {
131         NeedSurfaceSize = true;
132         ReqArrayIndex   = // TODO(Medium): Add planar support.
133         (pTexInfo->ArraySize * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1));
134     }
135     else
136     {
137         ReqArrayIndex =
138         (pReqInfo->ArrayIndex * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1));
139     }
140 
141     {
142         uint32_t TileSize = 0;
143 
144         if(pTexInfo->Flags.Info.TiledYs)
145         {
146             TileSize = GMM_KBYTE(64);
147         }
148         else if(pTexInfo->Flags.Info.TiledYf)
149         {
150             TileSize = GMM_KBYTE(4);
151         }
152 
153         const GMM_PLATFORM_INFO *pPlatform       = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
154         uint32_t                 BytesPerElement = pTexInfo->BitsPerPixel / CHAR_BIT;
155         GMM_TILE_MODE            TileMode        = pTexInfo->TileMode;
156         struct
157         {
158             uint32_t Width, Height, Depth;
159         } Element, Tile;
160 
161         __GMM_ASSERT(TileMode < GMM_TILE_MODES);
162 
163         GetCompressionBlockDimensions(
164         pTexInfo->Format,
165         &Element.Width,
166         &Element.Height,
167         &Element.Depth);
168 
169         Tile.Width =
170         (pPlatform->TileInfo[TileMode].LogicalTileWidth / BytesPerElement) *
171         Element.Width;
172 
173         Tile.Height =
174         pPlatform->TileInfo[TileMode].LogicalTileHeight *
175         Element.Height;
176 
177         Tile.Depth =
178         pPlatform->TileInfo[TileMode].LogicalTileDepth *
179         Element.Depth;
180 
181         {
182             GMM_GFX_ADDRESS TargetLodOffset = 0;
183             GMM_GFX_SIZE_T  PrevMipSize     = 0;
184             GMM_GFX_SIZE_T  SliceOffset     = 0;
185             GMM_GFX_SIZE_T  SlicePitch      = 0;
186             uint32_t        Lod;
187             uint32_t        EffectiveMaxLod =
188             (ReqArrayIndex == 0) ?
189             pReqInfo->MipLevel :
190             GFX_MIN(pTexInfo->MaxLod, pTexInfo->Alignment.MipTailStartLod);
191 
192             pReqInfo->StdLayout.Offset = 0;
193             for(Lod = 0; Lod <= EffectiveMaxLod; Lod++)
194             {
195                 GMM_GFX_SIZE_T MipWidth  = GmmTexGetMipWidth(pTexInfo, Lod);
196                 uint32_t       MipHeight = GmmTexGetMipHeight(pTexInfo, Lod);
197                 uint32_t       MipDepth  = GmmTexGetMipDepth(pTexInfo, Lod);
198 
199                 uint32_t MipCols = GFX_ULONG_CAST(
200                 GFX_CEIL_DIV(
201                 MipWidth,
202                 Tile.Width));
203                 uint32_t MipRows =
204                 GFX_CEIL_DIV(
205                 MipHeight,
206                 Tile.Height);
207                 uint32_t MipDepthTiles =
208                 GFX_CEIL_DIV(
209                 MipDepth,
210                 Tile.Depth);
211                 uint32_t RowPitch   = MipCols * TileSize; // Bytes from one tile row to the next.
212                 uint32_t DepthPitch = RowPitch * MipRows; // Bytes from one depth slice of tiles to the next.
213 
214                 if(Lod <= pTexInfo->Alignment.MipTailStartLod)
215                 {
216                     pReqInfo->StdLayout.Offset += PrevMipSize;
217                 }
218 
219                 if(Lod == pReqInfo->MipLevel)
220                 {
221                     TargetLodOffset = pReqInfo->StdLayout.Offset;
222 
223                     pReqInfo->StdLayout.TileRowPitch   = RowPitch;
224                     pReqInfo->StdLayout.TileDepthPitch = DepthPitch;
225                 }
226 
227                 PrevMipSize = DepthPitch * MipDepthTiles;
228                 SlicePitch += DepthPitch;
229             }
230 
231             if(pReqInfo->Slice > 0)
232             {
233                 SliceOffset = SlicePitch * pReqInfo->Slice;
234             }
235 
236             if(!NeedSurfaceSize && pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod)
237             {
238                 pReqInfo->StdLayout.Offset += (ReqArrayIndex * (pReqInfo->StdLayout.Offset + PrevMipSize)) +
239                                               GetMipTailByteOffset(pTexInfo, pReqInfo->MipLevel);
240             }
241             else
242             {
243                 pReqInfo->StdLayout.Offset = ReqArrayIndex * (pReqInfo->StdLayout.Offset + PrevMipSize) +
244                                              TargetLodOffset;
245             }
246 
247             pReqInfo->StdLayout.Offset += SliceOffset;
248         }
249     }
250 
251     return GMM_SUCCESS;
252 }
253 
254 
255 /////////////////////////////////////////////////////////////////////////////////////
256 /// Calculates offset address of a sub resource(i.e.  Mip Map, Cube face, volume texture)
257 ///
258 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
259 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info
260 ///
261 /// @return     ::GMM_STATUS
262 /////////////////////////////////////////////////////////////////////////////////////
GetTexLockOffset(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo)263 GMM_STATUS GmmLib::GmmTextureCalc::GetTexLockOffset(GMM_TEXTURE_INFO *   pTexInfo,
264                                                     GMM_REQ_OFFSET_INFO *pReqInfo)
265 {
266     GMM_STATUS     Result = GMM_SUCCESS;
267     GMM_GFX_SIZE_T AddressOffset;
268     uint32_t       Pitch, Slice;
269     uint32_t       MipHeight, MipWidth, MipLevel;
270     uint32_t       NumberOfMipsInSingleRow, SliceRow;
271 
272     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
273     __GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
274 
275     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
276 
277     // set default value
278     AddressOffset = 0;
279     Pitch         = GFX_ULONG_CAST(pTexInfo->Pitch);
280     MipLevel      = pReqInfo->MipLevel;
281     Slice         = pReqInfo->Slice;
282 
283     if(GmmIsPlanar(pTexInfo->Format))
284     {
285         AddressOffset           = GetMipMapByteAddress(pTexInfo, pReqInfo);
286         pReqInfo->Lock.Offset64 = AddressOffset;
287         pReqInfo->Lock.Pitch    = Pitch;
288 
289         // Adjust returned pitch for non-uniform-pitch U/V queries...
290         if((pReqInfo->Plane == GMM_PLANE_U) ||
291            (pReqInfo->Plane == GMM_PLANE_V))
292         {
293             switch(pTexInfo->Format)
294             {
295                 case GMM_FORMAT_I420:
296                 case GMM_FORMAT_IYUV:
297                 case GMM_FORMAT_YV12:
298                 case GMM_FORMAT_NV11:
299                     pReqInfo->Lock.Pitch /= 2;
300                     break;
301                 case GMM_FORMAT_YVU9:
302                     pReqInfo->Lock.Pitch /= 4;
303                     break;
304                 default:
305                     //Cool--Constant pitch across all planes.
306                     break;
307             }
308         }
309 
310         return Result;
311     }
312 
313     switch(pTexInfo->Type)
314     {
315         case RESOURCE_3D:
316         {
317             if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)
318             {
319                 AddressOffset = GFX_ULONG_CAST(GetMipMapByteAddress(pTexInfo, pReqInfo));
320 
321                 // Bytes from one slice to the next...
322                 pReqInfo->Lock.Gen9PlusSlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock);
323             }
324             else
325             {
326                 MipHeight = pTexInfo->BaseHeight >> MipLevel;
327                 MipWidth  = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> MipLevel;
328 
329                 AlignTexHeightWidth(pTexInfo, &MipHeight, &MipWidth);
330 
331                 // See how many mip can fit in one row
332                 NumberOfMipsInSingleRow = GFX_2_TO_POWER_OF(MipLevel);
333 
334                 SliceRow = Slice / NumberOfMipsInSingleRow;
335 
336                 // get the base address + Slice pitch
337                 AddressOffset = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel];
338 
339                 pReqInfo->Lock.Mip0SlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch);
340 
341                 // Actual address is offset based on requested slice
342                 AddressOffset += SliceRow * MipHeight * Pitch;
343 
344                 // Get to particular slice
345                 if(Slice % NumberOfMipsInSingleRow)
346                 {
347                     AddressOffset += (((Slice % NumberOfMipsInSingleRow) *
348                                        MipWidth * pTexInfo->BitsPerPixel) >>
349                                       3);
350                 }
351             }
352             break;
353         }
354         case RESOURCE_CUBE:
355         case RESOURCE_2D:
356         case RESOURCE_1D:
357         {
358             AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo);
359             break;
360         }
361         default:
362         { // These resources dont' have multiple levels of detail
363             AddressOffset = 0;
364             break;
365         }
366     }
367 
368     pReqInfo->Lock.Offset64 = AddressOffset;
369     pReqInfo->Lock.Pitch    = Pitch;
370 
371     return Result;
372 }
373 
374 
375 /////////////////////////////////////////////////////////////////////////////////////
376 /// Function used to align width and height of texture so that it satisfy our HW
377 /// restriction
378 ///
379 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
380 /// @param[in]  pHeight: ptr to height of mip
381 /// @param[in]  pWidth: ptr to width of mip
382 ///
383 /////////////////////////////////////////////////////////////////////////////////////
AlignTexHeightWidth(GMM_TEXTURE_INFO * pTexInfo,uint32_t * pHeight,uint32_t * pWidth)384 void GmmLib::GmmTextureCalc::AlignTexHeightWidth(GMM_TEXTURE_INFO *pTexInfo,
385                                                  uint32_t *        pHeight,
386                                                  uint32_t *        pWidth)
387 {
388     uint32_t MipWidth        = 0;
389     uint32_t MipHeight       = 0;
390     uint32_t UnitAlignHeight = 0;
391     uint32_t UnitAlignWidth  = 0;
392 
393     uint8_t Compress = 0;
394 
395     __GMM_ASSERTPTR(pTexInfo, VOIDRETURN);
396     __GMM_ASSERTPTR(pWidth, VOIDRETURN);
397     __GMM_ASSERTPTR(pHeight, VOIDRETURN);
398     __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN);
399 
400     MipWidth  = *pWidth;
401     MipHeight = *pHeight;
402 
403     UnitAlignWidth  = pTexInfo->Alignment.HAlign;
404     UnitAlignHeight = pTexInfo->Alignment.VAlign;
405     Compress        = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
406 
407     MipWidth  = GFX_MAX(MipWidth, UnitAlignWidth);
408     MipHeight = GFX_MAX(MipHeight, UnitAlignHeight);
409 
410     MipWidth  = GFX_ALIGN(MipWidth, UnitAlignWidth);
411     MipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
412 
413     if(Compress)
414     {
415         uint32_t CompressHeight, CompressWidth, CompressDepth;
416         GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
417         MipWidth /= CompressWidth;
418         MipHeight /= CompressHeight;
419     }
420     else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
421     {
422         MipWidth *= 2;
423         MipHeight /= 2;
424     }
425 
426     *pHeight = MipHeight;
427     *pWidth  = MipWidth;
428 }
429 
430 
431 /////////////////////////////////////////////////////////////////////////////////////
432 /// Function used to calculate the render aligned offset of a given surface
433 ///
434 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
435 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO
436 ///
437 /// @return     ::GMM_STATUS
438 /////////////////////////////////////////////////////////////////////////////////////
GetTexRenderOffset(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo)439 GMM_STATUS GmmLib::GmmTextureCalc::GetTexRenderOffset(GMM_TEXTURE_INFO *   pTexInfo,
440                                                       GMM_REQ_OFFSET_INFO *pReqInfo)
441 {
442 
443     const GMM_TILE_INFO *    pTileInfo         = NULL;
444     GMM_GFX_SIZE_T           AddressOffset     = 0;
445     GMM_GFX_SIZE_T           RenderAlignOffset = 0;
446     uint32_t                 OffsetX           = 0;
447     uint32_t                 OffsetY           = 0;
448     uint32_t                 OffsetZ           = 0;
449     const GMM_PLATFORM_INFO *pPlatform         = NULL;
450 
451     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
452     __GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
453 
454     pPlatform     = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
455     pTileInfo     = &pPlatform->TileInfo[pTexInfo->TileMode];
456     AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo);
457 
458     if(GMM_IS_TILED(*pTileInfo))
459     {
460         uint32_t       TileAlignedOffsetX = 0;
461         uint32_t       TileAlignedOffsetY = 0;
462         GMM_GFX_SIZE_T MipTailByteOffset  = 0;
463 
464         //--- Compute Tile-Aligned Offset, and Corresponding X/Y Offsets -------
465         // Render/Tiled-Aligned offsets and corresponding X/Y offsets are used
466         // to program the Surface Base Address and X/Y Offset fields of a
467         // SURFACE_STATE. For a given subresource, the tiled-aligned offset
468         // addresses the tile containing the base of the subresource; the X/Y
469         // offsets then give the additional offsets into the tile of the
470         // subresource base. (Though in SURFACE_STATE, X Offset is specified in
471         // pixels, this function will return the X Offset in bytes. Y Offset is
472         // in pixel rows.)
473 
474         if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
475            (pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod))
476         {
477             MipTailByteOffset = GetMipTailByteOffset(pTexInfo, pReqInfo->MipLevel);
478 
479             // For MipTail, Offset is really with respect to start of MipTail,
480             // so taking out individual Mipoffset within miptail region to get correct Tile aligned offset.
481             AddressOffset -= MipTailByteOffset;
482         }
483 
484         if(!pTexInfo->Flags.Info.RedecribedPlanes)
485         {
486             GMM_GFX_SIZE_T Pitch = pTexInfo->Pitch;
487             if(!pTexInfo->Pitch)
488             {
489                 // If no pitch exists, but the surface is still marked as tiled, then it is a 1D TileYf/Ys surface.
490                 // Technically no pitch exists for 1D surfaces, but we will fake it to make calculations work below.
491                 // Since 1D surfaces only have an X-dimension, this Pitch calculation is only used for OffsetX calculation.
492                 Pitch = pTexInfo->Size;
493             }
494 
495 	    if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
496             {
497                 OffsetX            = GFX_ULONG_CAST(AddressOffset % Pitch);
498                 TileAlignedOffsetX = GFX_ALIGN_FLOOR(OffsetX, pTileInfo->LogicalTileWidth / 2);
499                 OffsetX -= TileAlignedOffsetX;
500             }
501             else
502             {
503                 OffsetX            = GFX_ULONG_CAST(AddressOffset % Pitch);
504                 TileAlignedOffsetX = GFX_ALIGN_FLOOR(OffsetX, pTileInfo->LogicalTileWidth);
505                 OffsetX -= TileAlignedOffsetX;
506             }
507 
508             if(pTexInfo->Pitch)
509             {
510                 if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
511                 {
512                     //Expt: YOffset ignore row-interleave -- verify both 2d/3d mips
513                     OffsetY = GFX_ULONG_CAST(AddressOffset / pTexInfo->Pitch);
514                     OffsetY *= 2;
515                     TileAlignedOffsetY = GFX_ALIGN_FLOOR(OffsetY, pTileInfo->LogicalTileHeight * 2 * pTileInfo->LogicalTileDepth);
516                     OffsetY -= TileAlignedOffsetY;
517                     TileAlignedOffsetY /= 2;
518                 }
519                 else
520                 {
521                     OffsetY            = GFX_ULONG_CAST(AddressOffset / pTexInfo->Pitch);
522                     TileAlignedOffsetY = GFX_ALIGN_FLOOR(OffsetY, pTileInfo->LogicalTileHeight * pTileInfo->LogicalTileDepth);
523                     OffsetY -= TileAlignedOffsetY;
524                 }
525             }
526 
527             RenderAlignOffset =
528             TileAlignedOffsetY * pTexInfo->Pitch +
529             (TileAlignedOffsetX / pTileInfo->LogicalTileWidth) * pTileInfo->LogicalSize;
530 
531             // For Gen9+, Miptail Lods should be reported in a way that
532             //      - Base Address equals tile-aligned "Miptail start address"
533             //      - OffsetX equals to offset (in bytes) from "Miptail start Lod" to "current Lod" in geometric X direction
534             //      - OffsetY and OffsetZ are their pixel distance from "Miptail start Lod" to "current Lod" in geometric Y, Z directions
535             // Note: only Tile Yf and TileYs have Miptails and their Mips are always "tile aligned"
536 
537             if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
538                (pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod) &&
539                // Planar surfaces do not support MIPs
540                !GmmIsPlanar(pTexInfo->Format))
541             {
542                 GetMipTailGeometryOffset(pTexInfo, pReqInfo->MipLevel, &OffsetX, &OffsetY, &OffsetZ);
543             }
544         }
545         else
546         {
547             // Std swizzled and UV packed planes begin at tile-aligned
548             // offsets and do not support MIPs, so no adjustment is needed
549             RenderAlignOffset = AddressOffset;
550             OffsetX = OffsetY = OffsetZ = 0;
551         }
552     }
553     else
554     {
555         // Linear case make sure Render address is DWORD aligned.
556         RenderAlignOffset = GFX_ALIGN_FLOOR(AddressOffset, GMM_BYTES(4));
557 
558         if(pTexInfo->Pitch)
559         {
560             OffsetX = GFX_ULONG_CAST((AddressOffset - RenderAlignOffset) % pTexInfo->Pitch);
561             OffsetY = GFX_ULONG_CAST((AddressOffset - RenderAlignOffset) / pTexInfo->Pitch);
562         }
563         else
564         {
565             // One-dimensional textures (no height)
566             OffsetX = GFX_ULONG_CAST(AddressOffset - RenderAlignOffset);
567             OffsetY = 0;
568         }
569     }
570 
571     pReqInfo->Render.Offset64 = RenderAlignOffset;
572     pReqInfo->Render.XOffset  = GFX_ULONG_CAST(OffsetX);
573     pReqInfo->Render.YOffset  = GFX_ULONG_CAST(OffsetY);
574     pReqInfo->Render.ZOffset  = GFX_ULONG_CAST(OffsetZ);
575 
576     return GMM_SUCCESS;
577 } // __GmmGetRenderAlignAddress
578 
579 
580 /////////////////////////////////////////////////////////////////////////////////////
581 /// Function used to calculate byte address of a specified mip map
582 ///
583 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
584 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO
585 ///
586 /// @return     ::GMM_GFX_SIZE_T byte offset
587 /////////////////////////////////////////////////////////////////////////////////////
GetMipMapByteAddress(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo)588 GMM_GFX_SIZE_T GmmLib::GmmTextureCalc::GetMipMapByteAddress(GMM_TEXTURE_INFO *   pTexInfo,
589                                                             GMM_REQ_OFFSET_INFO *pReqInfo)
590 {
591     GMM_GFX_SIZE_T ArrayQPitch, MipMapByteAddress, Pitch;
592     uint32_t       MipLevel;
593 
594     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
595     __GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
596     __GMM_ASSERT(!(pTexInfo->Flags.Gpu.CCS && !pTexInfo->Flags.Gpu.UnifiedAuxSurface));
597     __GMM_ASSERT(pReqInfo->Plane < GMM_MAX_PLANE);
598 
599     MipLevel    = pReqInfo->MipLevel;
600     Pitch       = pTexInfo->Pitch;
601     ArrayQPitch = pReqInfo->ReqRender ?
602                   pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender :
603                   pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock;
604 
605     const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
606 
607     if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear)
608     {
609         ArrayQPitch *= pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth;
610     }
611 
612     if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) &&
613        ((pTexInfo->MSAA.NumSamples > 1) &&
614         !(pTexInfo->Flags.Gpu.Depth ||
615           pTexInfo->Flags.Gpu.SeparateStencil ||
616           GMM_IS_64KB_TILE(pTexInfo->Flags) ||
617           pTexInfo->Flags.Info.TiledYf)))
618     {
619         ArrayQPitch *= pTexInfo->MSAA.NumSamples;
620     }
621 
622     if(GmmIsPlanar(pTexInfo->Format))
623     {
624         uint32_t Plane = pReqInfo->Plane;
625 
626         uint32_t OffsetX = 0;
627         uint32_t OffsetY = 0;
628         if(Plane < GMM_MAX_PLANE)
629         {
630             OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.X[Plane]);
631             OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.Y[Plane]);
632         }
633         MipMapByteAddress = (OffsetY * Pitch) + OffsetX;
634 
635         __GMM_ASSERT(!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize));
636 
637         MipMapByteAddress += (pTexInfo->OffsetInfo.Plane.ArrayQPitch * pReqInfo->ArrayIndex);
638     }
639     else
640     {
641         switch(pTexInfo->Type)
642         {
643             case RESOURCE_CUBE:
644             {
645                 uint32_t CubeFace = pReqInfo->CubeFace;
646 
647                 GMM_ASSERTDPF( // Validate Cube Map Params...
648                 (!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize)) &&
649                 (pReqInfo->CubeFace < __GMM_MAX_CUBE_FACE) &&
650                 (pReqInfo->CubeFace != __GMM_NO_CUBE_MAP) &&
651                 (pReqInfo->Plane == GMM_NO_PLANE) &&
652                 (pReqInfo->Slice == 0),
653                 "Invalid parameter!");
654 
655                 // Support for CubeMap Arrays using 2D Arrays
656                 MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel];
657                 MipMapByteAddress += (ArrayQPitch * ((6 * pReqInfo->ArrayIndex) + CubeFace));
658                 break;
659             }
660             case RESOURCE_2D:
661             case RESOURCE_1D:
662             {
663                 MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel];
664 
665                 if(pReqInfo->ArrayIndex)
666                 {
667                     MipMapByteAddress += (ArrayQPitch * pReqInfo->ArrayIndex);
668                 }
669                 break;
670             }
671             case RESOURCE_3D:
672             {
673                 if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)
674                 {
675                     MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel];
676 
677                     if(pReqInfo->Slice)
678                     {
679                         MipMapByteAddress += (ArrayQPitch * pReqInfo->Slice);
680                     }
681                 }
682                 else
683                 {
684                     MipMapByteAddress = Get3DMipByteAddress(pTexInfo, pReqInfo);
685                 }
686                 break;
687             }
688             default:
689             { // These resources don't have multiple levels of detail
690                 MipMapByteAddress = 0;
691                 break;
692             }
693         }
694     }
695 
696     MipMapByteAddress += pTexInfo->Flags.Gpu.S3d ?
697                          GetDisplayFrameOffset(pTexInfo, pReqInfo) :
698                          0;
699 
700     return MipMapByteAddress;
701 }
702 
703 
704 /////////////////////////////////////////////////////////////////////////////////////
705 /// Utility function used to calculate byte address to a mip slice
706 ///
707 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
708 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO
709 ///
710 /// @return     byte offset
711 /////////////////////////////////////////////////////////////////////////////////////
Get3DMipByteAddress(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo)712 GMM_GFX_SIZE_T GmmLib::GmmTextureCalc::Get3DMipByteAddress(GMM_TEXTURE_INFO *   pTexInfo,
713                                                            GMM_REQ_OFFSET_INFO *pReqInfo)
714 {
715     uint32_t            MipsInThisRow, PlaneRows;
716     uint32_t            MipHeight, MipWidth;
717     uint32_t            UnitAlignHeight, UnitAlignWidth;
718     GMM_GFX_SIZE_T      MipMapByteAddress, ExtraBytes;
719     uint32_t            Slice, MipLevel, Pitch;
720     uint8_t             Compress;
721     GMM_RESOURCE_FORMAT GenericFormat;
722     uint32_t            CompressHeight, CompressWidth, CompressDepth;
723 
724     __GMM_ASSERTPTR(pGmmLibContext, 0);
725 
726     GenericFormat = pTexInfo->Format;
727     Slice         = pReqInfo->Slice;
728     MipLevel      = pReqInfo->MipLevel;
729     Pitch         = GFX_ULONG_CAST(pTexInfo->Pitch);
730 
731     // For slice 0 for any mip address is simple and stored in table
732     if(Slice == 0)
733     {
734         MipMapByteAddress = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel];
735     }
736     // For any slice
737     else
738     {
739         MipMapByteAddress = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel];
740 
741         // See how many mip can fit in one row
742         MipsInThisRow = GFX_2_TO_POWER_OF(MipLevel);
743 
744         PlaneRows = Slice / MipsInThisRow;
745 
746         // make sure we get the height and mip of base level
747         MipWidth  = GFX_ULONG_CAST(pTexInfo->BaseWidth);
748         MipHeight = pTexInfo->BaseHeight;
749 
750         MipWidth >>= MipLevel;
751         MipHeight >>= MipLevel;
752 
753         UnitAlignWidth  = pTexInfo->Alignment.HAlign;
754         UnitAlignHeight = pTexInfo->Alignment.VAlign;
755         Compress        = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
756         GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
757 
758         // clamp such that mip height is at least min height
759         MipHeight = GFX_MAX(MipHeight, UnitAlignHeight);
760         MipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
761 
762         // clamp such that mip width is at least min width
763         MipWidth = GFX_MAX(MipWidth, UnitAlignWidth);
764         MipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
765 
766         if(Compress)
767         {
768             MipWidth /= CompressWidth;
769             MipHeight /= CompressHeight;
770         }
771         else if(pTexInfo->Flags.Gpu.SeparateStencil)
772         {
773             MipWidth *= 2;
774             MipHeight /= 2;
775         }
776 
777         ExtraBytes = PlaneRows * MipHeight * Pitch;
778 
779         ExtraBytes += ((Slice % MipsInThisRow) *
780                        MipWidth * pTexInfo->BitsPerPixel) >>
781                       3;
782 
783         // get address offset
784         MipMapByteAddress += ExtraBytes;
785     }
786 
787     return MipMapByteAddress;
788 }
789 
790 
791 /////////////////////////////////////////////////////////////////////////////////////
792 /// Utility function calculates a byte offset from the base of the allocation
793 //  to L frame, R frame, or blank region.
794 ///
795 /// @param[in]  pTexInfo: ptr to ::GMM_TEXTURE_INFO
796 /// @param[in]  pReqInfo: ptr to GMM_REQ_OFFSET_INFO
797 ///
798 /// @return     byte offset
799 /////////////////////////////////////////////////////////////////////////////////////
GetDisplayFrameOffset(GMM_TEXTURE_INFO * pTexInfo,GMM_REQ_OFFSET_INFO * pReqInfo)800 uint32_t GmmLib::GmmTextureCalc::GetDisplayFrameOffset(GMM_TEXTURE_INFO *   pTexInfo,
801                                                        GMM_REQ_OFFSET_INFO *pReqInfo)
802 {
803     uint32_t Offset;
804 
805     __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
806     __GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
807 
808     switch(pReqInfo->Frame)
809     {
810         case GMM_DISPLAY_L:
811             Offset = 0;
812             break;
813         case GMM_DISPLAY_R:
814             Offset = pTexInfo->S3d.RFrameOffset;
815             break;
816         case GMM_DISPLAY_BLANK_AREA:
817             Offset = pTexInfo->S3d.BlankAreaOffset;
818             break;
819         default:
820             Offset = 0;
821             GMM_ASSERTDPF(0, "Unknown Frame Type!");
822             break;
823     }
824 
825     return Offset;
826 }
827