1 /*==============================================================================
2 Copyright(c) 2019 Intel Corporation
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files(the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and / or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 ============================================================================*/
22
23
24 #include "Internal/Common/GmmLibInc.h"
25 #include "Internal/Common/Texture/GmmGen10TextureCalc.h"
26 #include "Internal/Common/Texture/GmmGen11TextureCalc.h"
27 #include "Internal/Common/Texture/GmmGen12TextureCalc.h"
28
29 GMM_MIPTAIL_SLOT_OFFSET MipTailSlotOffset1DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_1D_SURFACE;
30 GMM_MIPTAIL_SLOT_OFFSET MipTailSlotOffset2DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_2D_SURFACE;
31 GMM_MIPTAIL_SLOT_OFFSET MipTailSlotOffset3DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_3D_SURFACE;
32
33 /////////////////////////////////////////////////////////////////////////////////////
34 /// Calculates height of the 2D mip layout on Gen9
35 ///
36 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
37 ///
38 /// @return height of 2D mip layout
39 /////////////////////////////////////////////////////////////////////////////////////
Get2DMipMapHeight(GMM_TEXTURE_INFO * pTexInfo)40 uint32_t GmmLib::GmmGen12TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo)
41 {
42 uint32_t BlockHeight, MipHeight;
43 uint32_t HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2;
44 uint32_t i, MipLevel, VAlign, CompressHeight, CompressWidth, CompressDepth;
45 uint8_t Compressed;
46 GMM_DPF_ENTER;
47
48 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
49
50 Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
51 MipHeight = pTexInfo->BaseHeight;
52 MipLevel = pTexInfo->MaxLod;
53 VAlign = pTexInfo->Alignment.VAlign;
54 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
55
56 HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo);
57
58 if(Compressed)
59 {
60 HeightLinesLevel0 /= CompressHeight;
61 }
62
63 // Mip0 height...
64 BlockHeight = HeightLinesLevel0;
65
66 if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
67 ((pTexInfo->Alignment.MipTailStartLod == 0) || (pTexInfo->MaxLod == 0)))
68 {
69 // Do nothing. Height is already aligned.
70 }
71 else
72 {
73 // Height of Mip1 and Mip2..n needed later...
74 HeightLinesLevel1 = HeightLinesLevel2 = 0;
75 for(i = 1; i <= MipLevel; i++)
76 {
77 uint32_t AlignedHeightLines;
78
79 if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
80 (i == pTexInfo->Alignment.MipTailStartLod))
81 {
82 AlignedHeightLines = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
83
84 if(i == 1)
85 {
86 HeightLinesLevel1 = AlignedHeightLines;
87 }
88 else
89 {
90 HeightLinesLevel2 += AlignedHeightLines;
91 }
92
93 break;
94 }
95 else
96 {
97 MipHeight = GmmTexGetMipHeight(pTexInfo, i);
98
99 AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo);
100
101 if(Compressed)
102 {
103 AlignedHeightLines /= CompressHeight;
104 }
105
106 if(i == 1)
107 {
108 HeightLinesLevel1 = AlignedHeightLines;
109 }
110 else
111 {
112 HeightLinesLevel2 += AlignedHeightLines;
113 }
114 }
115 }
116
117 // If Mip1 height covers all others, then that is all we need...
118 if(!(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)))
119 {
120 if(HeightLinesLevel1 >= HeightLinesLevel2)
121 {
122 BlockHeight += GFX_ALIGN(HeightLinesLevel1, VAlign);
123 }
124 else
125 {
126 BlockHeight += GFX_ALIGN(HeightLinesLevel2, VAlign);
127 }
128 }
129 else
130 {
131 //TR mode- requires TileMode height alignment
132 BlockHeight += (HeightLinesLevel1 >= HeightLinesLevel2) ? HeightLinesLevel1 : HeightLinesLevel2;
133 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
134 }
135 }
136
137 GMM_DPF_EXIT;
138
139 return (BlockHeight);
140 }
141
142 /////////////////////////////////////////////////////////////////////////////////////
143 /// Calculates Linear CCS size from main surface size
144 ///
145 /// @param[in] pSurf: ptr to ::GMM_TEXTURE_INFO of main surface
146 /// @param[in] pAuxTexInfo: ptr to ::GMM_TEXTURE_INFO of Aux surface
147 ///
148 /////////////////////////////////////////////////////////////////////////////////////
FillTexCCS(GMM_TEXTURE_INFO * pSurf,GMM_TEXTURE_INFO * pAuxTexInfo)149 GMM_STATUS GmmLib::GmmGen12TextureCalc::FillTexCCS(GMM_TEXTURE_INFO *pSurf,
150 GMM_TEXTURE_INFO *pAuxTexInfo)
151 {
152 if(pGmmLibContext->GetSkuTable().FtrFlatPhysCCS && !pSurf->Flags.Gpu.ProceduralTexture)
153 {
154 //No CCS allocation for lossless compression (exclude AMFS CCS).
155 return GMM_SUCCESS;
156 }
157 else if(pAuxTexInfo->Flags.Gpu.__NonMsaaLinearCCS)
158 {
159 GMM_TEXTURE_INFO Surf = *pSurf;
160 uint32_t Depth;
161 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pSurf, pGmmLibContext);
162 pAuxTexInfo->Flags.Info.TiledW = 0;
163 pAuxTexInfo->Flags.Info.TiledYf = 0;
164 pAuxTexInfo->Flags.Info.TiledX = 0;
165 pAuxTexInfo->Flags.Info.Linear = 1;
166 GMM_SET_64KB_TILE(pAuxTexInfo->Flags, 0, pGmmLibContext);
167 GMM_SET_4KB_TILE(pAuxTexInfo->Flags, 0, pGmmLibContext);
168
169 pAuxTexInfo->ArraySize = Surf.ArraySize;
170 pAuxTexInfo->Alignment = {0};
171 pAuxTexInfo->BitsPerPixel = 8;
172 Depth = (Surf.Depth > 0) ? Surf.Depth : 1; // Depth = 0 needs to be handled gracefully
173 uint32_t ExpandedArraySize =
174 GFX_MAX(Surf.ArraySize, 1) *
175 ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
176 ((Surf.Type == RESOURCE_3D) ? Depth : 1) * // 3D's simply 2D arrays for sizing.
177 ((Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil ||
178 GMM_IS_64KB_TILE(Surf.Flags) || Surf.Flags.Info.TiledYf) ?
179 1 :
180 Surf.MSAA.NumSamples) * // MSAA (non-Depth/Stencil) RT samples stored as array planes.
181 ((GMM_IS_64KB_TILE(Surf.Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (Surf.MSAA.NumSamples == 16)) ? 4 : // MSAA x8/x16 stored as pseudo array planes each with 4x samples
182 (GMM_IS_64KB_TILE(Surf.Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (Surf.MSAA.NumSamples == 8)) ? 2 :
183 1);
184
185 if(GMM_IS_64KB_TILE(Surf.Flags) || Surf.Flags.Info.TiledYf)
186 {
187 ExpandedArraySize = GFX_ALIGN(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth);
188 }
189
190 if(GmmIsUVPacked(Surf.Format))
191 {
192 uint64_t YCcsSize = GFX_ALIGN((Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] * Surf.Pitch), GMM_KBYTE(16)) >> 8;
193 YCcsSize = GFX_ALIGN(YCcsSize, PAGE_SIZE);
194
195 uint64_t PlanarSize = (Surf.ArraySize > 1) ? (Surf.OffsetInfo.Plane.ArrayQPitch) : Surf.Size;
196
197 uint64_t UVCcsSize = GFX_ALIGN(PlanarSize - (Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] * Surf.Pitch), GMM_KBYTE(16)) >> 8;
198 if(UVCcsSize == 0)
199 {
200 //GMM_ASSERTDPF(UVCcsSize != 0, "Incorrect Planar Surface Size"); //Redescription of Yf/Ys planar surface P010 hits it (debug required?)
201 UVCcsSize = 1;
202 }
203 UVCcsSize = GFX_ALIGN_NP2(UVCcsSize, PAGE_SIZE);
204
205 pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0;
206 pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0;
207 pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U] = YCcsSize; //Being Linear CCS, fill X-offset - Test GetAuxOffset UV_CCS is proper
208 pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] = 0;
209 pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V] = YCcsSize; //Being Linear CCS, fill X-offset
210 pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] = 0;
211
212 pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch = YCcsSize + UVCcsSize;
213 pAuxTexInfo->Size = pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch * ((Surf.ArraySize > 1) ? (Surf.ArraySize) : 1);
214 pAuxTexInfo->Alignment.QPitch = GFX_ULONG_CAST(pAuxTexInfo->Size) / ExpandedArraySize;
215 }
216 else if(GmmIsPlanar(Surf.Format))
217 {
218 //Doesn't require separate Aux surfaces since not displayable. Page-alignment ensures
219 //each hybrid plane is 4k-aligned, hence gets unique AuxT.L1e
220 uint64_t PlanarSize = (Surf.ArraySize > 1) ? (Surf.OffsetInfo.Plane.ArrayQPitch) : Surf.Size;
221 uint64_t CcsSize = GFX_ALIGN(PlanarSize, GMM_KBYTE(16)) >> 8;
222 CcsSize = GFX_ALIGN(CcsSize, PAGE_SIZE);
223
224 pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0;
225 pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0;
226 pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U] = GFX_ALIGN(Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] * Surf.Pitch, GMM_KBYTE(16)) >> 8; //Being Linear CCS, fill X-offset - Test GetAuxOffset UV_CCS is proper
227 pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] = 0;
228 pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V] = GFX_ALIGN(Surf.OffsetInfo.Plane.Y[GMM_PLANE_V] * Surf.Pitch, GMM_KBYTE(16)) >> 8; //Being Linear CCS, fill X-offset
229 pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] = 0;
230
231 pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch = CcsSize;
232 pAuxTexInfo->Size = pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch *
233 ((Surf.ArraySize > 1) ? (Surf.ArraySize) : 1);
234 pAuxTexInfo->Alignment.QPitch = GFX_ULONG_CAST(pAuxTexInfo->Size) / ExpandedArraySize;
235 }
236 else
237 {
238 pAuxTexInfo->Size = (GFX_ALIGN(Surf.Size, GMM_KBYTE(16)) >> 8);
239
240 uint32_t qPitch;
241 if(ExpandedArraySize > 1)
242 {
243 uint64_t sliceSize = ((GFX_ALIGN(Surf.Pitch * Surf.Alignment.QPitch, GMM_KBYTE(16)) >> 8));
244 qPitch = GFX_ULONG_CAST(sliceSize); //HW doesn't use QPitch for Aux except MCS, how'd AMFS get sw-filled non-zero QPitch?
245
246
247 if(Surf.MSAA.NumSamples && !pGmmLibContext->GetSkuTable().FtrTileY)
248 {
249 //MSAA Qpitch is sample-distance, multiply NumSamples in a tile
250 qPitch *= (pGmmLibContext->GetSkuTable().FtrXe2PlusTiling ? Surf.MSAA.NumSamples : GFX_MIN(Surf.MSAA.NumSamples, 4));
251 }
252 }
253 else
254 {
255 qPitch = GFX_ULONG_CAST(pAuxTexInfo->Size);
256 }
257
258 pAuxTexInfo->Alignment.QPitch = qPitch;
259 }
260 __GMM_ASSERT(ExpandedArraySize || (pAuxTexInfo->Size == 0));
261 pAuxTexInfo->Pitch = 0;
262 pAuxTexInfo->Type = RESOURCE_BUFFER;
263 pAuxTexInfo->Alignment.BaseAlignment = GMM_KBYTE(4); //TODO: TiledResource?
264 pAuxTexInfo->Size = GFX_ALIGN(pAuxTexInfo->Size, PAGE_SIZE); //page-align final size
265
266 if(pAuxTexInfo->Flags.Gpu.TiledResource)
267 {
268 pAuxTexInfo->Alignment.BaseAlignment = GMM_KBYTE(64); //TODO: TiledResource?
269 pAuxTexInfo->Size = GFX_ALIGN(pAuxTexInfo->Size, GMM_KBYTE(64)); //page-align final size
270 }
271
272 //Clear compression request in CCS
273 pAuxTexInfo->Flags.Info.RenderCompressed = 0;
274 pAuxTexInfo->Flags.Info.MediaCompressed = 0;
275 pAuxTexInfo->Flags.Info.NotCompressed = 1;
276 pAuxTexInfo->Flags.Info.RedecribedPlanes = 0;
277 SetTileMode(pAuxTexInfo);
278
279 return GMM_SUCCESS;
280 }
281 return GMM_SUCCESS;
282 }
283
284 /////////////////////////////////////////////////////////////////////////////////////
285 /// Allocates the 2D mip layout for surface state programming.
286 ///
287 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
288 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
289 ///
290 /// @return ::GMM_STATUS
291 /////////////////////////////////////////////////////////////////////////////////////
FillTex2D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)292 GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo,
293 __GMM_BUFFER_TYPE *pRestrictions)
294 {
295 uint32_t Width, Height, BitsPerPixel;
296 uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
297 uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch;
298 uint8_t Compress = 0;
299 GMM_STATUS Status;
300
301 GMM_DPF_ENTER;
302
303 __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
304 __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
305
306 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
307
308 BitsPerPixel = pTexInfo->BitsPerPixel;
309 //TODO: Deprecate TileY usage
310 if((pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs))
311 {
312 // Aux Surfaces are 8bpp.
313 BitsPerPixel = 8;
314 }
315
316 Height = pTexInfo->BaseHeight;
317 Width = GFX_ULONG_CAST(pTexInfo->BaseWidth);
318
319 pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1);
320
321 if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags))
322 {
323 FindMipTailStartLod(pTexInfo);
324 }
325
326 ExpandedArraySize =
327 GFX_MAX(pTexInfo->ArraySize, 1) *
328 ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
329 ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays for sizing.
330 ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil ||
331 (GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys/Yf samples are ALSO stored as array planes, calculate size for single sample and expand it later.
332 1 :
333 pTexInfo->MSAA.NumSamples) * // MSAA (non-Depth/Stencil) RT samples stored as array planes.
334 ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ? // Depth/Stencil MSAA surface is expanded through Width and Depth
335 1 :
336 ((GMM_IS_64KB_TILE(pTexInfo->Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (pTexInfo->MSAA.NumSamples == 16)) ? 4 : // MSAA x8/x16 stored as pseudo array planes each with 4x samples
337 (GMM_IS_64KB_TILE(pTexInfo->Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (pTexInfo->MSAA.NumSamples == 8)) ? 2 :
338 1));
339 if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf)
340 {
341 ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth);
342 }
343
344 //
345 // Check for color separation
346 //
347 if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)
348 {
349 bool csRestrictionsMet = (((ExpandedArraySize <= 2) &&
350 (ExpandedArraySize == pTexInfo->ArraySize) &&
351 ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) ||
352 (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) ||
353 (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) ||
354 (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) ||
355 (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) ||
356 (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) &&
357 ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) ||
358 (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0))));
359
360 if(csRestrictionsMet)
361 {
362 ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE;
363 }
364 else
365 {
366 pTexInfo->Flags.Gpu.ColorSeparation = 0;
367 pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0;
368 }
369 }
370
371 HAlign = pTexInfo->Alignment.HAlign;
372 VAlign = pTexInfo->Alignment.VAlign;
373 DAlign = pTexInfo->Alignment.DAlign;
374
375 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
376
377 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
378
379 /////////////////////////////////
380 // Calculate Block Surface Height
381 /////////////////////////////////
382
383 if(ExpandedArraySize > 1)
384 {
385 uint32_t Alignment = VAlign;
386 if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) ||
387 (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) ||
388 (pTexInfo->Flags.Wa.MediaPipeUsage))
389 {
390 Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
391 }
392
393 // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight)
394 BlockHeight = Get2DMipMapTotalHeight(pTexInfo);
395 BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment);
396
397 // GMM internally uses QPitch as the logical distance between slices, but translates
398 // as appropriate to service client queries in GmmResGetQPitch.
399 pTexInfo->Alignment.QPitch = BlockHeight;
400
401 if(Compress)
402 {
403 BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
404
405 BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize);
406 }
407 else
408 {
409 BlockHeight = ScaleTextureHeight(pTexInfo, BlockHeight);
410 }
411
412 BlockHeight *= ExpandedArraySize;
413 }
414 else
415 {
416 pTexInfo->Alignment.QPitch = 0;
417
418 BlockHeight = Get2DMipMapHeight(pTexInfo);
419 BlockHeight = ScaleTextureHeight(pTexInfo, BlockHeight);
420 }
421
422 ///////////////////////////////////
423 // Calculate Pitch
424 ///////////////////////////////////
425
426 AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo);
427
428 // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths
429 // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1
430 if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
431 (pTexInfo->Alignment.MipTailStartLod < 2))
432 {
433 // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned.
434 }
435 else if(pTexInfo->MaxLod >= 2)
436 {
437 uint32_t AlignedWidthLod1, AlignedWidthLod2;
438
439 AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo);
440 AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo);
441
442 AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2);
443 }
444
445 if(Compress)
446 {
447 AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth);
448 }
449 else
450 {
451 AlignedWidth = ScaleTextureWidth(pTexInfo, AlignedWidth);
452 }
453
454 // Default pitch
455 Pitch = AlignedWidth * BitsPerPixel >> 3;
456
457 // Make sure the pitch satisfy linear min pitch requirment
458 Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch);
459
460 // Make sure pitch satisfy alignment restriction
461 Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment);
462
463 ////////////////////
464 // Adjust for Tiling
465 ////////////////////
466
467 if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
468 {
469 Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
470 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
471 }
472
473 GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!");
474 pTexInfo->Flags.Info.LayoutBelow = 1;
475 pTexInfo->Flags.Info.LayoutRight = 0;
476
477 // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
478 // padding needs to be added. Since this will create a none pitch aligned
479 // surface the padding is aligned to the next row
480 if(GmmIsYUVPacked(pTexInfo->Format) ||
481 (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
482 (pTexInfo->BitsPerPixel == GMM_BITS(48)))
483 {
484 BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch);
485 }
486
487 // For Non-planar surfaces, the alignment is done on the entire height of the allocation
488 if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU &&
489 GmmIsYUVFormatLCUAligned(pTexInfo->Format) &&
490 !GmmIsPlanar(pTexInfo->Format))
491 {
492 BlockHeight = GFX_ALIGN(BlockHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE));
493 }
494
495 // Align height to even row to avoid hang if HW over-fetch
496 BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW);
497
498 if((Status = // <-- Note assignment.
499 FillTexPitchAndSize(
500 pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS)
501 {
502 Fill2DTexOffsetAddress(pTexInfo);
503 }
504 GMM_DPF_EXIT;
505
506 return (Status);
507 }
508
509 /////////////////////////////////////////////////////////////////////////////////////
510 /// This function will Setup a planar surface allocation.
511 ///
512 /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO
513 /// @param[in] pRestrictions: Reference to surface alignment and size restrictions.
514 ///
515 /// @return ::GMM_STATUS
516 /////////////////////////////////////////////////////////////////////////////////////
FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)517 GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo,
518 __GMM_BUFFER_TYPE *pRestrictions)
519 {
520 uint32_t WidthBytesPhysical, Height, YHeight, VHeight;
521 uint32_t AdjustedVHeight = 0;
522 GMM_STATUS Status;
523 bool UVPacked = false;
524 uint32_t BitsPerPixel, AlignedWidth;
525
526 GMM_DPF_ENTER;
527
528 __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
529 __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
530 __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW);
531 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
532
533 BitsPerPixel = pTexInfo->BitsPerPixel;
534 AlignedWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth);
535 if(!pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
536 {
537 pTexInfo->TileMode = TILE_NONE;
538 }
539 else
540 {
541 pTexInfo->TileMode = LEGACY_TILE_Y;
542 }
543
544 WidthBytesPhysical = AlignedWidth * BitsPerPixel >> 3;
545 Height = VHeight = 0;
546
547 YHeight = pTexInfo->BaseHeight;
548
549 switch(pTexInfo->Format)
550 {
551 case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V
552 case GMM_FORMAT_IMC3:
553 case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3.
554 // YYYYYYYY
555 // YYYYYYYY
556 // YYYYYYYY
557 // YYYYYYYY
558 // UUUU
559 // UUUU
560 // VVVV
561 // VVVV
562 case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width.
563 // YYYYYYYY
564 // YYYYYYYY
565 // YYYYYYYY
566 // YYYYYYYY
567 // UUUUUUUU
568 // UUUUUUUU
569 // VVVVVVVV
570 // VVVVVVVV
571 {
572 VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
573
574 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
575
576 Height = YHeight + 2 * VHeight; // One VHeight for V and one for U.
577 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
578 break;
579 }
580 case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width.
581 //YYYYYYYY
582 //YYYYYYYY
583 //YYYYYYYY
584 //YYYYYYYY
585 //UUUUUUUU
586 //VVVVVVVV
587 {
588 VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
589
590 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
591
592 Height = YHeight + 2 * VHeight;
593 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
594 break;
595 }
596 case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height.
597 // YYYYYYYY
598 // YYYYYYYY
599 // YYYYYYYY
600 // YYYYYYYY
601 // UU
602 // UU
603 // UU
604 // UU
605 // VV
606 // VV
607 // VV
608 // VV
609 case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height.
610 // YYYYYYYY
611 // YYYYYYYY
612 // YYYYYYYY
613 // YYYYYYYY
614 // UUUU
615 // UUUU
616 // UUUU
617 // UUUU
618 // VVVV
619 // VVVV
620 // VVVV
621 // VVVV
622 case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size.
623 #if _WIN32
624 case GMM_FORMAT_WGBOX_YUV444:
625 case GMM_FORMAT_WGBOX_PLANAR_YUV444:
626 #endif
627 // YYYYYYYY
628 // YYYYYYYY
629 // YYYYYYYY
630 // YYYYYYYY
631 // UUUUUUUU
632 // UUUUUUUU
633 // UUUUUUUU
634 // UUUUUUUU
635 // VVVVVVVV
636 // VVVVVVVV
637 // VVVVVVVV
638 // VVVVVVVV
639 {
640 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
641 VHeight = YHeight;
642
643 Height = YHeight + 2 * VHeight;
644 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
645 break;
646 }
647 case GMM_FORMAT_BGRP:
648 case GMM_FORMAT_RGBP:
649 {
650 //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned
651 if(pTexInfo->Flags.Info.Linear)
652 {
653 VHeight = YHeight;
654
655 Height = YHeight + 2 * VHeight;
656 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
657 }
658 else
659 {
660 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
661 VHeight = YHeight;
662
663 Height = YHeight + 2 * VHeight;
664 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3;
665 }
666 break;
667 }
668 case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V
669 case GMM_FORMAT_IMC4:
670 {
671 // YYYYYYYY
672 // YYYYYYYY
673 // YYYYYYYY
674 // YYYYYYYY
675 // UUUUVVVV
676 // UUUUVVVV
677
678 YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
679 VHeight = GFX_CEIL_DIV(YHeight, 2);
680
681 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes.
682
683 Height = YHeight + VHeight;
684
685 // With SURFACE_STATE.XOffset support, the U-V interface has
686 // much lighter restrictions--which will be naturally met by
687 // surface pitch restrictions (i.e. dividing an IMC2/4 pitch
688 // by 2--to get the U/V interface--will always produce a safe
689 // XOffset value).
690 // Not technically UV packed but sizing works out the same
691 // if the resource is std swizzled
692 UVPacked = true;
693 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2;
694 break;
695 }
696 case GMM_FORMAT_NV12:
697 case GMM_FORMAT_NV21:
698 case GMM_FORMAT_NV11:
699 case GMM_FORMAT_P010:
700 case GMM_FORMAT_P012:
701 case GMM_FORMAT_P016:
702 case GMM_FORMAT_P208:
703 case GMM_FORMAT_P216:
704 {
705 // YYYYYYYY
706 // YYYYYYYY
707 // YYYYYYYY
708 // YYYYYYYY
709 // [UV-Packing]
710
711 if((pTexInfo->Format == GMM_FORMAT_NV12) ||
712 (pTexInfo->Format == GMM_FORMAT_NV21) ||
713 (pTexInfo->Format == GMM_FORMAT_P010) ||
714 (pTexInfo->Format == GMM_FORMAT_P012) ||
715 (pTexInfo->Format == GMM_FORMAT_P016))
716 {
717 VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y
718 Height = YHeight + VHeight;
719 }
720 else
721 {
722 VHeight = YHeight; // U/V plane is same as Y
723 Height = YHeight + VHeight;
724 }
725
726 if((pTexInfo->Format == GMM_FORMAT_NV12) ||
727 (pTexInfo->Format == GMM_FORMAT_NV21) ||
728 (pTexInfo->Format == GMM_FORMAT_P010) ||
729 (pTexInfo->Format == GMM_FORMAT_P012) ||
730 (pTexInfo->Format == GMM_FORMAT_P016) ||
731 (pTexInfo->Format == GMM_FORMAT_P208) ||
732 (pTexInfo->Format == GMM_FORMAT_P216))
733 {
734 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes.
735 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2;
736 }
737 else //if(pTexInfo->Format == GMM_FORMAT_NV11)
738 {
739 // Tiling not supported, since YPitch != UVPitch...
740 pTexInfo->Flags.Info.TiledYf = 0;
741 pTexInfo->Flags.Info.TiledX = 0;
742 pTexInfo->Flags.Info.Linear = 1;
743 GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
744 GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
745 }
746
747 UVPacked = true;
748 break;
749 }
750 case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except,
751 case GMM_FORMAT_IYUV: // U & V pl.s are reversed.
752 case GMM_FORMAT_YV12:
753 case GMM_FORMAT_YVU9:
754 {
755 // YYYYYYYY
756 // YYYYYYYY
757 // YYYYYYYY
758 // YYYYYYYY
759 // VVVVVV.. <-- V and U planes follow the Y plane, as linear
760 // ..UUUUUU arrays--without respect to pitch.
761
762 uint32_t YSize, UVSize, YVSizeRShift;
763 uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment;
764
765 YSize = WidthBytesPhysical * YHeight;
766
767 // YVU9 has one U/V pixel for each 4x4 Y block.
768 // The others have one U/V pixel for each 2x2 Y block.
769
770 // YVU9 has a Y:V size ratio of 16 (4x4 --> 1).
771 // The others have a ratio of 4 (2x2 --> 1).
772 YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
773
774 // If a Y plane isn't fully-aligned to its Y-->U/V block size, the
775 // extra/unaligned Y pixels still need corresponding U/V pixels--So
776 // for the purpose of computing the UVSize, we must consider a
777 // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would
778 // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.)
779 YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4;
780 YSizeForUVPurposes =
781 GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) *
782 GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment);
783
784 UVSize = 2 * // <-- U + V
785 (YSizeForUVPurposes >> YVSizeRShift);
786
787 Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical);
788
789 // Tiling not supported, since YPitch != UVPitch...
790 pTexInfo->Flags.Info.TiledYf = 0;
791 pTexInfo->Flags.Info.TiledX = 0;
792 pTexInfo->Flags.Info.Linear = 1;
793 pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1;
794 GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
795 GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
796
797 break;
798 }
799 default:
800 {
801 GMM_ASSERTDPF(0, "Unexpected format");
802 return GMM_ERROR;
803 }
804 }
805
806 // Align Height to even row to avoid hang if HW over-fetch
807 Height = GFX_ALIGN(Height, __GMM_EVEN_ROW);
808
809 SetTileMode(pTexInfo);
810
811 // If the Surface has Odd height dimension, we will fall back to Linear Format.
812 // If MMC is enabled, disable MMC during such cases.
813 if(pTexInfo->Flags.Gpu.MMC)
814 {
815 if(!(GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags)))
816 {
817 pTexInfo->Flags.Gpu.MMC = 0;
818 }
819 }
820
821 // If the Surface has Odd height dimension, we will fall back to Linear Format.
822 // If MMC is enabled, disable .CCS/UnifiedAuxSurface during such cases.
823 if(pTexInfo->Flags.Gpu.CCS)
824 {
825 if(!(GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
826 !(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && GMM_IS_4KB_TILE(pTexInfo->Flags)))
827 {
828 pTexInfo->Flags.Gpu.MMC = 0;
829 pTexInfo->Flags.Gpu.CCS = 0;
830 pTexInfo->Flags.Gpu.UnifiedAuxSurface = 0;
831 pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = 0;
832 }
833 }
834
835 // Legacy Planar "Linear Video" Restrictions...
836 if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions)
837 {
838 pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64));
839 pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64));
840 pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64));
841 pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64));
842 }
843
844 // Multiply overall pitch alignment for surfaces whose U/V planes have a
845 // pitch down-scaled from that of Y--Since the U/V pitches must meet the
846 // original restriction, the Y pitch must meet a scaled-up multiple.
847 if((pTexInfo->Format == GMM_FORMAT_I420) ||
848 (pTexInfo->Format == GMM_FORMAT_IYUV) ||
849 (pTexInfo->Format == GMM_FORMAT_NV11) ||
850 (pTexInfo->Format == GMM_FORMAT_YV12) ||
851 (pTexInfo->Format == GMM_FORMAT_YVU9))
852 {
853 uint32_t LShift =
854 (pTexInfo->Format != GMM_FORMAT_YVU9) ?
855 1 : // UVPitch = 1/2 YPitch
856 2; // UVPitch = 1/4 YPitch
857
858 pRestrictions->LockPitchAlignment <<= LShift;
859 pRestrictions->MinPitch <<= LShift;
860 pRestrictions->PitchAlignment <<= LShift;
861 pRestrictions->RenderPitchAlignment <<= LShift;
862 }
863
864 AdjustedVHeight = VHeight;
865
866 FindMipTailStartLod(pTexInfo);
867
868 // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access
869 if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0)
870 {
871 AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE));
872 Height += AdjustedVHeight - VHeight;
873 }
874
875 // For std swizzled and UV packed tile Ys/Yf cases, the planes
876 // must be tile-boundary aligned. Actual alignment is handled
877 // in FillPlanarOffsetAddress, but height and width must
878 // be adjusted for correct size calculation
879 if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) &&
880 !pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
881 {
882 uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
883 uint32_t TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth;
884
885 pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true;
886
887 if(pTexInfo->Flags.Gpu.CCS && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) // alignment adjustment needed only for aux tables
888 {
889 if(GMM_IS_64KB_TILE(pTexInfo->Flags))
890 {
891 TileHeight *= (!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) ? 16 : 1; // For 64Kb Tile mode: Multiply TileHeight by 16 for 1 MB alignment
892 }
893 else
894 {
895 TileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64); // For 4k Tile: Multiply TileHeight by 4 and Pitch by 4 for 64kb alignment, multiply TileHeight by 64 and Pitch by 4 for 1 MB alignment
896 }
897 }
898
899 if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns
900 pTexInfo->Format == GMM_FORMAT_IMC4)
901 {
902 // If the U & V planes are side-by-side then the surface pitch must be
903 // padded out so that U and V planes will being on a tile boundary.
904 // This means that an odd Y plane width must be padded out
905 // with an additional tile. Even widths do not need padding
906 uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth);
907 if(TileCols % 2)
908 {
909 WidthBytesPhysical = (TileCols + 1) * TileWidth;
910 }
911 }
912
913 Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) :
914 (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight)));
915
916 if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf)
917 {
918 pTexInfo->Flags.Info.RedecribedPlanes = true;
919 }
920 }
921 else if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
922 {
923 uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight;
924
925 BitsPerPixel = 8;
926
927 if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns
928 pTexInfo->Format == GMM_FORMAT_IMC4)
929 {
930 // If the U & V planes are side-by-side then the surface pitch must be
931 // padded out so that U and V planes will being on a tile boundary.
932 // This means that an odd Y plane width must be padded out
933 // with an additional tile. Even widths do not need padding
934
935 // CCS must use padded main surface width, so get main surface TileWidth
936 #define CCSMODE_TO_TILEMODE(y) ((y + TILE_YF_2D_8bpe) < TILE_YS_1D_8bpe) ? (y + TILE_YF_2D_8bpe) : \
937 ((y + TILE_YF_2D_8bpe + 5) >= TILE_YS_1D_128bpe) ? (y + TILE_YF_2D_8bpe + 5) : TILE_NONE
938
939 uint32_t BaseTileWidth = pPlatform->TileInfo[CCSMODE_TO_TILEMODE(pTexInfo->CCSModeAlign)].LogicalTileWidth;
940 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2 * BaseTileWidth);
941 }
942
943 AlignedWidth = GFX_ULONG_CAST(WidthBytesPhysical / (pTexInfo->BitsPerPixel >> 3));
944
945 WidthBytesPhysical = __GMM_EXPAND_WIDTH(this, AlignedWidth, pTexInfo->Alignment.HAlign, pTexInfo);
946 WidthBytesPhysical = ScaleTextureWidth(pTexInfo, WidthBytesPhysical); //Should both YAux and UVAux use same CCModeALign (ie using common bpe?)
947 //If different, then copy Aux info from per-plane Aux? HW has separate bpe or common?
948 YHeight = __GMM_EXPAND_HEIGHT(this, YHeight, pTexInfo->Alignment.VAlign, pTexInfo);
949 YHeight = ScaleTextureHeight(pTexInfo, YHeight);
950 YHeight = GFX_ALIGN(YHeight, TileHeight);
951
952 VHeight = __GMM_EXPAND_HEIGHT(this, VHeight, pTexInfo->Alignment.VAlign, pTexInfo);
953 VHeight = ScaleTextureHeight(pTexInfo, VHeight);
954 VHeight = GFX_ALIGN(VHeight, TileHeight);
955
956 Height = YHeight + VHeight;
957 }
958
959 if(pTexInfo->Flags.Info.RedecribedPlanes)
960 {
961 if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical))
962 {
963 __GMM_ASSERT(false);
964 }
965 }
966
967 if((Status = // <-- Note assignment.
968 FillTexPitchAndSize(
969 pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS)
970 {
971 FillPlanarOffsetAddress(pTexInfo);
972 }
973
974 // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout
975 // is defined by SW requirements; Y plane must be 4KB aligned.
976 if(pTexInfo->ArraySize > 1)
977 {
978 GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size;
979 int64_t LargeSize;
980
981 // Size should always be page aligned.
982 __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0);
983
984 if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize)
985 {
986 pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes;
987 pTexInfo->Size = LargeSize;
988 }
989 else
990 {
991 GMM_ASSERTDPF(0, "Surface too large!");
992 Status = GMM_ERROR;
993 }
994 }
995
996 GMM_DPF_EXIT;
997 return (Status);
998 } // FillTexPlanar
999
GetCCSScaleFactor(GMM_TEXTURE_INFO * pTexInfo,CCS_UNIT & ScaleFactor)1000 GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::GetCCSScaleFactor(GMM_TEXTURE_INFO *pTexInfo,
1001 CCS_UNIT & ScaleFactor)
1002 {
1003 GMM_STATUS Status = GMM_SUCCESS;
1004 GMM_TEXTURE_ALIGN_EX TexAlignEx = static_cast<PlatformInfoGen12 *>(pGmmLibContext->GetPlatformInfoObj())->GetExTextureAlign();
1005 uint32_t CCSModeIdx = 0;
1006
1007 if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) //pTexInfo is RT Surf
1008 {
1009 CCSModeIdx = CCS_MODE(pTexInfo->TileMode);
1010 __GMM_ASSERT(pTexInfo->TileMode < GMM_TILE_MODES);
1011 }
1012 else //pTexInfo is CCS Surf
1013 {
1014 CCSModeIdx = pTexInfo->CCSModeAlign;
1015 }
1016
1017 if(!(CCSModeIdx < CCS_MODES))
1018 {
1019 __GMM_ASSERT(0); //indicates something wrong w/ H/V/D Align Filling function or Wrong TileMode set
1020 return GMM_ERROR;
1021 }
1022
1023 ScaleFactor = TexAlignEx.CCSEx[CCSModeIdx];
1024
1025 return (Status);
1026 }
1027
GetCCSExMode(GMM_TEXTURE_INFO * AuxSurf)1028 GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::GetCCSExMode(GMM_TEXTURE_INFO *AuxSurf)
1029 {
1030 if(GMM_IS_4KB_TILE(AuxSurf->Flags) || GMM_IS_64KB_TILE(AuxSurf->Flags) || AuxSurf->Flags.Info.Linear)
1031 {
1032 if(pGmmLibContext->GetSkuTable().FtrLinearCCS)
1033 {
1034 AuxSurf->Flags.Gpu.__NonMsaaLinearCCS = 1;
1035 }
1036 else
1037 {
1038 AuxSurf->Flags.Gpu.__NonMsaaTileYCcs = 1;
1039 //CCS is always 2D, even for 3D surface
1040 if(AuxSurf->Type == RESOURCE_CUBE)
1041 {
1042 AuxSurf->ArraySize = 6;
1043 }
1044 AuxSurf->Type = RESOURCE_2D;
1045 }
1046 if(AuxSurf->Flags.Gpu.__NonMsaaTileYCcs)
1047 {
1048 AuxSurf->CCSModeAlign = 0;
1049 SetTileMode(AuxSurf);
1050 /*if (AuxSurf->Flags.Gpu.UnifiedAuxSurface)*/
1051 {
1052 AuxSurf->CCSModeAlign = CCS_MODE(AuxSurf->TileMode);
1053 }
1054 AuxSurf->TileMode = TILE_NONE;
1055
1056 __GMM_ASSERT(AuxSurf->CCSModeAlign < CCS_MODES);
1057 return (AuxSurf->CCSModeAlign < CCS_MODES) ? GMM_SUCCESS : GMM_INVALIDPARAM;
1058 }
1059 }
1060 return GMM_SUCCESS;
1061 }
1062
ScaleTextureHeight(GMM_TEXTURE_INFO * pTexInfo,uint32_t Height)1063 uint32_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleTextureHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height)
1064 {
1065 uint32_t ScaledHeight = Height;
1066 if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
1067 {
1068 CCS_UNIT ScaleFactor;
1069 GetCCSScaleFactor(pTexInfo, ScaleFactor);
1070
1071 ScaledHeight /= ScaleFactor.Downscale.Height;
1072 }
1073
1074 return ScaledHeight;
1075 }
1076
ScaleTextureWidth(GMM_TEXTURE_INFO * pTexInfo,uint32_t Width)1077 uint32_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleTextureWidth(GMM_TEXTURE_INFO *pTexInfo, uint32_t Width)
1078 {
1079 uint32_t ScaledWidth = Width;
1080
1081 if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
1082 {
1083 CCS_UNIT ScaleFactor;
1084 GetCCSScaleFactor(pTexInfo, ScaleFactor);
1085
1086
1087 if(ScaleFactor.Downscale.Width < 0)
1088 {
1089 ScaledWidth *= ((-1) * ScaleFactor.Downscale.Width);
1090 }
1091 else
1092 {
1093 ScaledWidth /= ScaleFactor.Downscale.Width;
1094 }
1095 }
1096 else if(pTexInfo->Flags.Gpu.ColorSeparation)
1097 {
1098 ScaledWidth *= pTexInfo->ArraySize;
1099 __GMM_ASSERT(0 == (ScaledWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION));
1100 ScaledWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION;
1101 }
1102 else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX)
1103 {
1104 ScaledWidth *= pTexInfo->ArraySize;
1105 __GMM_ASSERT(0 == (ScaledWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION));
1106 ScaledWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION;
1107 }
1108
1109 return ScaledWidth;
1110 }
1111
ScaleFCRectHeight(GMM_TEXTURE_INFO * pTexInfo,uint32_t Height)1112 uint32_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleFCRectHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height)
1113 {
1114 uint32_t ScaledHeight = Height;
1115 if(pTexInfo->Flags.Gpu.CCS)
1116 {
1117 CCS_UNIT *FCRectAlign = static_cast<PlatformInfoGen12 *>(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign();
1118 uint8_t index = FCMaxModes;
1119 if((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes)
1120 {
1121 ScaledHeight = GFX_ALIGN(ScaledHeight, FCRectAlign[index].Align.Height);
1122 ScaledHeight /= FCRectAlign[index].Downscale.Height;
1123 }
1124 else
1125 {
1126 __GMM_ASSERT(0);
1127 }
1128 }
1129
1130 return ScaledHeight;
1131 }
1132
ScaleFCRectWidth(GMM_TEXTURE_INFO * pTexInfo,uint64_t Width)1133 uint64_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleFCRectWidth(GMM_TEXTURE_INFO *pTexInfo, uint64_t Width)
1134 {
1135 uint64_t ScaledWidth = Width;
1136 if(pTexInfo->Flags.Gpu.CCS)
1137 {
1138 CCS_UNIT *FCRectAlign = static_cast<PlatformInfoGen12 *>(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign();
1139 uint8_t index = FCMaxModes;
1140 if((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes)
1141 {
1142 ScaledWidth = GFX_ALIGN(ScaledWidth, FCRectAlign[index].Align.Width);
1143 ScaledWidth /= FCRectAlign[index].Downscale.Width;
1144 }
1145 else
1146 {
1147 //Unsupported tiling-type for FastClear
1148 __GMM_ASSERT(0);
1149 }
1150 }
1151
1152 return ScaledWidth;
1153 }
1154
1155
Get2DFCSurfaceWidthFor3DSurface(GMM_TEXTURE_INFO * pTexInfo,uint64_t Width)1156 uint64_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::Get2DFCSurfaceWidthFor3DSurface(GMM_TEXTURE_INFO *pTexInfo,
1157 uint64_t Width)
1158 {
1159 uint64_t Width2D = Width;
1160 if (pTexInfo->Flags.Gpu.CCS)
1161 {
1162 CCS_UNIT *FCRectAlign = static_cast<PlatformInfoGen12 *>(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign();
1163 uint8_t index = FCMaxModes;
1164 if ((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes)
1165 {
1166 Width2D = GFX_ALIGN(Width2D, FCRectAlign[index].Align.Width);
1167 Width2D *= FCRectAlign[index].Downscale.Width;
1168 }
1169 else
1170 {
1171
1172 __GMM_ASSERT(0);
1173 }
1174 }
1175 return Width2D;
1176 }
Get2DFCSurfaceHeightFor3DSurface(GMM_TEXTURE_INFO * pTexInfo,uint32_t Height,uint32_t Depth)1177 uint64_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::Get2DFCSurfaceHeightFor3DSurface(GMM_TEXTURE_INFO *pTexInfo,
1178 uint32_t Height,
1179 uint32_t Depth)
1180 {
1181 uint64_t Height2D = Height;
1182 uint32_t Depth3D = Depth;
1183
1184 if (pTexInfo->Flags.Gpu.CCS && (Depth > 1))
1185 {
1186 CCS_UNIT *FCRectAlign = static_cast<PlatformInfoGen12 *>(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign();
1187 uint8_t index = FCMaxModes;
1188 if ((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes)
1189 {
1190 Height2D = GFX_ALIGN(Height2D, FCRectAlign[index].Align.Height);
1191 Height2D *= FCRectAlign[index].Downscale.Height;
1192 Depth3D = GFX_ALIGN(Depth3D, FCRectAlign[index].Align.Depth) / FCRectAlign[index].Align.Depth;
1193 Height2D *= Depth3D;
1194 }
1195 else
1196 {
1197
1198 __GMM_ASSERT(0);
1199 }
1200 }
1201 return Height2D;
1202 }
1203
1204 /////////////////////////////////////////////////////////////////////////////////////
1205 /// This function does any special-case conversion from client-provided pseudo creation
1206 /// parameters to actual parameters for CCS.
1207 ///
1208 /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO
1209 ///
1210 /// @return ::GMM_STATUS
1211 /////////////////////////////////////////////////////////////////////////////////////
MSAACCSUsage(GMM_TEXTURE_INFO * pTexInfo)1212 GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo)
1213 {
1214 GMM_STATUS Status = GMM_SUCCESS;
1215
1216 if(pTexInfo->MSAA.NumSamples > 1 && (pTexInfo->Flags.Gpu.MCS)) // CCS for MSAA Compression
1217 {
1218 Status = MSAACompression(pTexInfo);
1219 }
1220 else // Non-MSAA CCS Use (i.e. Render Target Fast Clear)
1221 {
1222 if(!pTexInfo->Flags.Info.TiledW &&
1223 (!pTexInfo->Flags.Info.TiledX) &&
1224 ((GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) ||
1225 (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear)))) //!Yf - deprecate Yf)
1226 {
1227 // For non-MSAA CCS usage, the Doc has four tables of
1228 // requirements:
1229 // (1) RT Alignment (GMM Don't Care: Occurs Naturally)
1230 // (2) ClearRect Alignment
1231 // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter)
1232 // (4) Non-MSAA CCS Sizing
1233
1234 // Gen8+:
1235 // Since mip-mapped and arrayed surfaces are supported, we
1236 // deal with alignment later at per mip level. Here, we set
1237 // tiling type only. TileX is not supported on Gen9+.
1238 // Pre-Gen8:
1239 // (!) For all the above, the doc has separate entries for
1240 // 32/64/128bpp--and then deals with PIXEL widths--Here,
1241 // though, we will unify by considering 8bpp table entries
1242 // (unlisted--i.e. do the math)--and deal with BYTE widths.
1243
1244 // (1) RT Alignment -- The surface width and height don't
1245 // need to be padded to RT CL granularity. On HSW, all tiled
1246 // RT's will have appropriate alignment (given 4KB surface
1247 // base and no mip-map support) and appropriate padding
1248 // (due to tile padding). On BDW+, GMM uses H/VALIGN that
1249 // will guarantee the MCS RT alignment for all subresources.
1250
1251 // (2) ClearRect Alignment -- I.e. FastClears must be done
1252 // with certain granularity:
1253 // TileY: 512 Bytes x 128 Lines
1254 // TileX: 1024 Bytes x 64 Lines
1255 // So a CCS must be sized to match that granularity (though
1256 // the RT itself need not be fully padded to that
1257 // granularity to use FastClear).
1258
1259 // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the
1260 // size of the FastClear (with granularity padding) for the
1261 // paired RT. CCS's (byte widths and heights) are scaled
1262 // down from their RT's by:
1263 // TileY: 32 x 32
1264 // TileX: 64 x 16
1265
1266 // ### Example #############################################
1267 // RT: 800x600, 32bpp, TileY
1268 // 8bpp: 3200x600
1269 // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128)
1270 // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32)
1271
1272 GetCCSExMode(pTexInfo);
1273 }
1274 else
1275 {
1276 GMM_ASSERTDPF(0, "Illegal CCS creation parameters!");
1277 Status = GMM_ERROR;
1278 }
1279 }
1280 return Status;
1281 }
1282
1283
1284 /////////////////////////////////////////////////////////////////////////////////////
1285 /// Returns the mip offset of given LOD in Mip Tail
1286 ///
1287 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
1288 /// MipLevel: mip-map level
1289 ///
1290 /// @return offset value of LOD in bytes
1291 /////////////////////////////////////////////////////////////////////////////////////
GetMipTailByteOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)1292 uint32_t GmmLib::GmmGen12TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo,
1293 uint32_t MipLevel)
1294 {
1295 uint32_t ByteOffset = 0, Slot = 0xff;
1296
1297 GMM_DPF_ENTER;
1298
1299 if(pGmmLibContext->GetSkuTable().FtrTileY)
1300 {
1301 return GmmGen11TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel);
1302 }
1303 // 3D textures follow the Gen10 mip tail format
1304 if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat)
1305 {
1306 return GmmGen9TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel);
1307 }
1308
1309 // Til64 is the only format which supports MipTail on FtrTileY disabled platforms
1310 __GMM_ASSERT(pTexInfo->Flags.Info.Tile64);
1311 // Mipped MSAA is not supported for Tile64
1312 __GMM_ASSERT(pTexInfo->MSAA.NumSamples <= 1);
1313
1314 if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_3D) || (pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE))
1315 {
1316 Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod;
1317 }
1318
1319 // Miptail Slot layout in Tile64: as per specifications
1320 // Byteoffset varies based on bpp for tile64 format, so any caller who needs to use byteoffset needs to call cpuswizzle with corresponding geomteric offsets
1321 // Returning ByteOffset as 0 for Tile64 always
1322
1323 // GMM_DPF_CRITICAL("Miptail byte offset requested for Tile64 \r\n");
1324 GMM_DPF_EXIT;
1325
1326 // return ByteOffset=0, i.e return start of miptail for any address within packed miptail
1327 return (ByteOffset);
1328 }
1329
GetMipTailGeometryOffset(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel,uint32_t * OffsetX,uint32_t * OffsetY,uint32_t * OffsetZ)1330 void GmmLib::GmmGen12TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo,
1331 uint32_t MipLevel,
1332 uint32_t * OffsetX,
1333 uint32_t * OffsetY,
1334 uint32_t * OffsetZ)
1335 {
1336 uint32_t ArrayIndex = 0;
1337 uint32_t Slot = 0;
1338
1339 GMM_DPF_ENTER;
1340
1341 if(pGmmLibContext->GetSkuTable().FtrTileY)
1342 {
1343 return GmmGen11TextureCalc::GetMipTailGeometryOffset(pTexInfo, MipLevel, OffsetX, OffsetY, OffsetZ);
1344 }
1345
1346 // Til64 is the only format which supports MipTail on FtrTileY disabled platforms
1347 __GMM_ASSERT(pTexInfo->Flags.Info.Tile64);
1348 // Mipped MSAA is not supported for Tile64
1349 __GMM_ASSERT(pTexInfo->MSAA.NumSamples <= 1);
1350
1351 switch(pTexInfo->BitsPerPixel)
1352 {
1353 case 128:
1354 ArrayIndex = 0;
1355 break;
1356 case 64:
1357 ArrayIndex = 1;
1358 break;
1359 case 32:
1360 ArrayIndex = 2;
1361 break;
1362 case 16:
1363 ArrayIndex = 3;
1364 break;
1365 case 8:
1366 ArrayIndex = 4;
1367 break;
1368 default:
1369 __GMM_ASSERT(0);
1370 break;
1371 }
1372
1373
1374 // FtrTileY disabled platforms: platforms which support Tile4/Tile64 tiled formats
1375 if(pTexInfo->Type == RESOURCE_1D)
1376 {
1377 Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod;
1378
1379 *OffsetX = MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
1380 *OffsetY = MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y;
1381 *OffsetZ = MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z;
1382 }
1383 else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)
1384 {
1385 // Mipped MSAA is not supported on Tile64, so need not account for MSAA here
1386 Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod;
1387
1388 *OffsetX = MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
1389 *OffsetY = MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y;
1390 *OffsetZ = MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z;
1391 }
1392 else if(pTexInfo->Type == RESOURCE_3D)
1393 {
1394 Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod;
1395
1396 *OffsetX = MipTailSlotOffset3DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8;
1397 *OffsetY = MipTailSlotOffset3DSurface[Slot][ArrayIndex].Y;
1398 *OffsetZ = MipTailSlotOffset3DSurface[Slot][ArrayIndex].Z;
1399 }
1400
1401 GMM_DPF_EXIT;
1402 return;
1403 }
1404
1405