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