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