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 /// Allocates the 2D mip layout for surface state programming.
27 ///
28 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
29 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
30 ///
31 /// @return ::GMM_STATUS
32 /////////////////////////////////////////////////////////////////////////////////////
FillTex2D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)33 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo,
34 __GMM_BUFFER_TYPE *pRestrictions)
35 {
36 uint32_t Width, Height, BitsPerPixel;
37 uint32_t HAlign, VAlign;
38 uint32_t CompressHeight, CompressWidth, CompressDepth;
39 uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch;
40 uint8_t Compress = 0;
41 GMM_STATUS Status;
42
43 __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
44 __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
45
46 GMM_DPF_ENTER;
47
48 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
49
50 BitsPerPixel = pTexInfo->BitsPerPixel;
51 Height = pTexInfo->BaseHeight;
52 Width = GFX_ULONG_CAST(pTexInfo->BaseWidth);
53
54 pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1);
55
56 ExpandedArraySize =
57 GFX_MAX(pTexInfo->ArraySize, 1) *
58 ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
59 ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ?
60 1 :
61 pTexInfo->MSAA.NumSamples); // Gen7 MSAA (non-Depth/Stencil) RT samples stored as array planes.
62
63 //
64 // Check for color separation
65 //
66 if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)
67 {
68 bool csRestrictionsMet = (((ExpandedArraySize <= 2) &&
69 (ExpandedArraySize == pTexInfo->ArraySize) &&
70 ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) ||
71 (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) ||
72 (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) ||
73 (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) ||
74 (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) ||
75 (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) &&
76 ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) ||
77 (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0))));
78
79 if(csRestrictionsMet)
80 {
81 ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE;
82 }
83 else
84 {
85 pTexInfo->Flags.Gpu.ColorSeparation = 0;
86 pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0;
87 }
88 }
89
90 HAlign = pTexInfo->Alignment.HAlign;
91 VAlign = pTexInfo->Alignment.VAlign;
92 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
93
94 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
95
96 /////////////////////////////////
97 // Calculate Block Surface Height
98 /////////////////////////////////
99
100 // Adjust total height for arrayed 2D textures
101 if(ExpandedArraySize > 1)
102 {
103 uint32_t Height0, Height1;
104
105 Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo);
106
107 // If not ARYSPC_LOD0-eligible...
108 if((pTexInfo->MaxLod > 0) ||
109 pTexInfo->Flags.Gpu.Depth || // Depth/HiZ/Stencil buffers not ARYSPC_LOD0-compatible.
110 pTexInfo->Flags.Gpu.HiZ ||
111 pTexInfo->Flags.Gpu.SeparateStencil)
112 {
113 Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo);
114
115 // QPitch = (h0 + h1 + 12j) * pitch
116 BlockHeight = Height0 + Height1 + 12 * VAlign;
117 }
118 else // SURFACE_STATE: Surface Array Spacing: ARYSPC_LOD0
119 {
120 // QPitch = h0 * pitch
121 BlockHeight = Height0;
122 pTexInfo->Alignment.ArraySpacingSingleLod = true;
123 }
124
125 if(Compress)
126 {
127 BlockHeight /= CompressHeight;
128 }
129 else if(pTexInfo->Flags.Gpu.SeparateStencil)
130 {
131 BlockHeight /= 2;
132 }
133
134 // Compute total array height
135 BlockHeight *= ExpandedArraySize;
136 }
137 else
138 {
139 BlockHeight = Get2DMipMapHeight(pTexInfo);
140 }
141
142
143 ///////////////////////////////////
144 // Calculate Pitch
145 ///////////////////////////////////
146
147 AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo);
148
149 // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths are greater
150 // than LOD0. e.g. dimensions 4x4 and MinPitch == 1
151 if(pTexInfo->MaxLod >= 2)
152 {
153 uint32_t AlignedWidthLod1, AlignedWidthLod2;
154
155 AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo);
156 AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo);
157
158 AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2);
159 }
160
161 if(Compress)
162 {
163 AlignedWidth /= CompressWidth;
164 }
165 else if(pTexInfo->Flags.Gpu.SeparateStencil)
166 {
167 AlignedWidth *= 2;
168 }
169 else if(pTexInfo->Flags.Gpu.ColorSeparation)
170 {
171 AlignedWidth *= pTexInfo->ArraySize;
172 __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION));
173 AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION;
174 }
175 else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX)
176 {
177 AlignedWidth *= pTexInfo->ArraySize;
178 __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION));
179 AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION;
180 }
181
182 // Default pitch
183 Pitch = AlignedWidth * BitsPerPixel >> 3;
184
185 // Make sure the pitch satisfy linear min pitch requirment
186 Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch);
187
188 // Make sure pitch satisfy alignment restriction
189 Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment);
190
191
192 ////////////////////
193 // Adjust for Tiling
194 ////////////////////
195 if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
196 {
197 Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
198 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
199
200 // If Tiled Resource or Undefined64KBSwizzle resource, align to 64KB tile size
201 if((pTexInfo->Flags.Gpu.TiledResource || pTexInfo->Flags.Info.Undefined64KBSwizzle) &&
202 (pTexInfo->Flags.Info.TiledY))
203 {
204 uint32_t ColFactor = 0, RowFactor = 0;
205 uint32_t TRTileWidth = 0, TRTileHeight = 0;
206
207 GmmGetD3DToHwTileConversion(pTexInfo, &ColFactor, &RowFactor);
208 TRTileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * ColFactor;
209 TRTileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight * RowFactor;
210
211 Pitch = GFX_ALIGN(Pitch, TRTileWidth);
212 BlockHeight = GFX_ALIGN(BlockHeight, TRTileHeight);
213 }
214 }
215
216 GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!");
217 pTexInfo->Flags.Info.LayoutBelow = 1;
218 pTexInfo->Flags.Info.LayoutRight = 0;
219
220 // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
221 // padding needs to be added. Since this will create a none pitch aligned
222 // surface the padding is aligned to the next row
223 if(GmmIsYUVPacked(pTexInfo->Format) ||
224 (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
225 (pTexInfo->BitsPerPixel == GMM_BITS(48)))
226 {
227 BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch);
228 }
229
230 // Align height to even row to cover for HW over - fetch
231 BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW);
232
233 if((Status = // <-- Note assignment.
234 FillTexPitchAndSize(
235 pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS)
236 {
237 Fill2DTexOffsetAddress(pTexInfo);
238
239 // Init to no-packed mips. It'll be initialized when app calls to get packed
240 // mips. Calculate packed mips here if there's a chance apps won't call to
241 // get packed mips.
242 pTexInfo->Alignment.PackedMipStartLod = GMM_TILED_RESOURCE_NO_PACKED_MIPS;
243 }
244
245 GMM_DPF_EXIT;
246 return (Status);
247 }
248
249
250 /////////////////////////////////////////////////////////////////////////////////////
251 /// Calculates the mip offset of given LOD in 2D mip layout
252 ///
253 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
254 ///
255 /// @return offset value in bytes
256 /////////////////////////////////////////////////////////////////////////////////////
Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO * pTexInfo,uint32_t MipLevel)257 GMM_GFX_SIZE_T GmmLib::GmmGen7TextureCalc::Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo,
258 uint32_t MipLevel)
259 {
260 GMM_GFX_SIZE_T MipOffset;
261 uint32_t AlignedMipHeight, i, MipHeight, OffsetHeight;
262 uint32_t HAlign, VAlign;
263 uint32_t CompressHeight, CompressWidth, CompressDepth;
264 uint8_t Compress;
265
266 __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
267 GMM_DPF_ENTER;
268
269 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
270
271 HAlign = pTexInfo->Alignment.HAlign;
272 VAlign = pTexInfo->Alignment.VAlign;
273
274 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
275
276 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
277
278 MipHeight = pTexInfo->BaseHeight;
279 OffsetHeight = 0;
280
281 // Mips 0 and 1 are on the left edge...
282 if(MipLevel < 2)
283 {
284 MipOffset = 0;
285 }
286 else // Mip2 and beyond are to the right of Mip1...
287 {
288 uint32_t Mip1Width = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> 1;
289
290 Mip1Width = __GMM_EXPAND_WIDTH(this, Mip1Width, HAlign, pTexInfo);
291
292 if(Compress)
293 {
294 Mip1Width /= CompressWidth;
295
296 if((pGmmLibContext->GetWaTable().WaAstcCorruptionForOddCompressedBlockSizeX || pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) && pPlatform->FormatTable[pTexInfo->Format].ASTC && CompressWidth == 5)
297 {
298 uint32_t Width1 = (pTexInfo->BaseWidth == 1) ? 1 : (GFX_ULONG_CAST(pTexInfo->BaseWidth) >> 1);
299 uint32_t Modulo10 = Width1 % 10;
300 if(Modulo10 >= 1 && Modulo10 <= CompressWidth)
301 {
302 Mip1Width += 3;
303 }
304 }
305 }
306 else if(pTexInfo->Flags.Gpu.SeparateStencil)
307 {
308 Mip1Width *= 2;
309 }
310
311 MipOffset = (GMM_GFX_SIZE_T)Mip1Width * pTexInfo->BitsPerPixel >> 3;
312 }
313
314 for(i = 1; i <= MipLevel; i++)
315 {
316 AlignedMipHeight = GFX_ULONG_CAST(__GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo));
317
318 if(Compress)
319 {
320 AlignedMipHeight /= CompressHeight;
321 }
322 else if(pTexInfo->Flags.Gpu.SeparateStencil)
323 {
324 AlignedMipHeight /= 2;
325 }
326
327 OffsetHeight += ((i != 2) ? AlignedMipHeight : 0);
328
329 MipHeight >>= 1;
330 }
331
332 MipOffset += OffsetHeight * GFX_ULONG_CAST(pTexInfo->Pitch);
333
334 GMM_DPF_EXIT;
335 return (MipOffset);
336 }
337
338
339 /////////////////////////////////////////////////////////////////////////////////////
340 /// Calculates height of the 2D mip layout
341 ///
342 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
343 ///
344 /// @return Height of 2D mip layout
345 /////////////////////////////////////////////////////////////////////////////////////
Get2DMipMapHeight(GMM_TEXTURE_INFO * pTexInfo)346 uint32_t GmmLib::GmmGen7TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo)
347 {
348 uint32_t Height, BlockHeight, NumLevels; // Final height for 2D surface
349 uint32_t HeightLines, HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2;
350 uint32_t VAlign, CompressHeight, CompressWidth, CompressDepth;
351 uint32_t i;
352 uint8_t Compress;
353
354 GMM_DPF_ENTER;
355
356 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
357
358 // Mip 0 height is needed later
359 Height = pTexInfo->BaseHeight;
360 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
361 NumLevels = pTexInfo->MaxLod;
362 HeightLines = Height;
363 VAlign = pTexInfo->Alignment.VAlign;
364 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
365
366 HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, HeightLines, VAlign, pTexInfo);
367
368 if(Compress)
369 {
370 HeightLinesLevel0 /= CompressHeight;
371 }
372 else if(pTexInfo->Flags.Gpu.SeparateStencil)
373 {
374 HeightLinesLevel0 /= 2;
375 }
376
377 // Start out with mip0
378 BlockHeight = HeightLinesLevel0;
379
380 // Height of mip1 and height of all others mips(2,3,4,5,,) needed later
381 HeightLinesLevel1 = HeightLinesLevel2 = 0;
382 for(i = 1; i <= NumLevels; i++)
383 {
384 uint32_t AlignedHeightLines;
385
386 HeightLines >>= 1;
387
388 AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, HeightLines, VAlign, pTexInfo);
389
390 if(Compress)
391 {
392 AlignedHeightLines /= CompressHeight;
393 }
394 else if(pTexInfo->Flags.Gpu.SeparateStencil)
395 {
396 AlignedHeightLines /= 2;
397 }
398
399 if(i == 1)
400 {
401 HeightLinesLevel1 = AlignedHeightLines;
402 }
403 else
404 {
405 HeightLinesLevel2 += AlignedHeightLines;
406 }
407 }
408
409 // If mip1 height covers all others then that is all we need
410 if(HeightLinesLevel1 >= HeightLinesLevel2)
411 {
412 BlockHeight += GFX_ALIGN_NP2(HeightLinesLevel1, VAlign);
413 }
414 else
415 {
416 BlockHeight += GFX_ALIGN_NP2(HeightLinesLevel2, VAlign);
417 }
418
419 GMM_DPF_EXIT;
420 return (BlockHeight);
421 }
422
423
424 /////////////////////////////////////////////////////////////////////////////////////
425 /// Calculates the address offset for each mip map of 2D texture and store them
426 /// into the GMM_TEXTURE_INFO for surf state programming.
427 ///
428 /// @param[in] pTexInfo: pointer to ::GMM_TEXTURE_INFO
429 ///
430 /////////////////////////////////////////////////////////////////////////////////////
Fill2DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)431 void GmmLib::GmmGen7TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
432 {
433 uint32_t i;
434
435 __GMM_ASSERTPTR(pTexInfo, VOIDRETURN);
436
437 GMM_DPF_ENTER;
438
439 // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch...
440 // -------------------------------------------------------------------------
441 // Note: Gen7 MSAA RT samples stored as contiguous array planes--
442 // e.g. MSAA-4X'ed array elements A and B stored: A0 A1 A2 A3 B0 B1 B2 B3.
443 // However, for GMM's purposes QPitch is still the distance between
444 // elements--not the distance between samples.
445 // -------------------------------------------------------------------------
446 if((pTexInfo->ArraySize <= 1) &&
447 (pTexInfo->Type != RESOURCE_CUBE) &&
448 !(pTexInfo->Flags.Gpu.ColorSeparation ||
449 pTexInfo->Flags.Gpu.ColorSeparationRGBX))
450 {
451 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = 0;
452 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = 0;
453 }
454 else
455 {
456 uint32_t Height, Height0, Height1, ArrayQPitch, VAlign;
457
458 Height = pTexInfo->BaseHeight;
459
460 VAlign = pTexInfo->Alignment.VAlign;
461
462 Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo);
463 Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo);
464
465 if(!pTexInfo->Alignment.ArraySpacingSingleLod)
466 {
467 // QPitch = (h0 + h1 + 12j) * pitch
468 ArrayQPitch = Height0 + Height1 + 12 * VAlign;
469 }
470 else // SURFACE_STATE: Surface Array Spacing: ARYSPC_LOD0
471 {
472 // QPitch = h0 * pitch
473 ArrayQPitch = Height0;
474 }
475
476 if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format))
477 {
478 uint32_t CompressHeight, CompressWidth, CompressDepth;
479
480 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
481
482 ArrayQPitch /= CompressHeight;
483 }
484 else if(pTexInfo->Flags.Gpu.SeparateStencil)
485 {
486 ArrayQPitch /= 2;
487 }
488
489 if((pTexInfo->MSAA.NumSamples > 1) && !(pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil))
490 {
491 // Gen7 MSAA (non-Depth/Stencil) RT samples stored as array planes;
492 // QPitch still element-to-element, not sample-to-sample.
493 ArrayQPitch *= pTexInfo->MSAA.NumSamples;
494 }
495
496 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = ArrayQPitch * pTexInfo->Pitch;
497 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = ArrayQPitch * pTexInfo->Pitch;
498 }
499
500 for(i = 0; i <= pTexInfo->MaxLod; i++)
501 {
502 pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i);
503 }
504
505 GMM_DPF_EXIT;
506 }
507
508
509 /////////////////////////////////////////////////////////////////////////////////////
510 /// Calculates total height of an arrayed 3D mip layout
511 ///
512 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
513 ///
514 /// @return height of arrayed 3D mip layout
515 /////////////////////////////////////////////////////////////////////////////////////
GetTotal3DHeight(GMM_TEXTURE_INFO * pTexInfo)516 uint32_t GmmLib::GmmGen7TextureCalc::GetTotal3DHeight(GMM_TEXTURE_INFO *pTexInfo)
517 {
518 uint32_t AlignedHeight, BlockHeight, Depth;
519 uint8_t Compressed;
520 uint32_t i, MipsInThisRow, MipLevel, MipRows;
521 uint32_t Total3DHeight = 0, UnitAlignHeight;
522 uint32_t CompressHeight, CompressWidth, CompressDepth;
523 GMM_TEXTURE_CALC *pTextureCalc;
524
525 GMM_DPF_ENTER;
526
527 pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext);
528
529 BlockHeight = pTexInfo->BaseHeight;
530 Depth = pTexInfo->Depth;
531 MipLevel = pTexInfo->MaxLod;
532 UnitAlignHeight = pTexInfo->Alignment.VAlign;
533
534 Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
535 pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
536
537 // All mip0s of all planes are stacked together, then mip1s and so on...
538 for(i = 0; i <= MipLevel; i++)
539 {
540 BlockHeight = GFX_MAX(BlockHeight, UnitAlignHeight);
541 AlignedHeight = GFX_ALIGN(BlockHeight, UnitAlignHeight);
542
543 if(Compressed)
544 {
545 AlignedHeight /= CompressHeight;
546 }
547 else if(pTexInfo->Flags.Gpu.SeparateStencil)
548 {
549 AlignedHeight /= 2;
550 }
551 else if(pTexInfo->Flags.Gpu.CCS)
552 {
553 if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
554 {
555 AlignedHeight /= 32;
556 }
557 else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
558 {
559 AlignedHeight /= 16;
560 }
561 }
562
563 // See how many mip can fit in one row
564 MipsInThisRow = GFX_2_TO_POWER_OF(i);
565
566 // calculate if the mips will spill over to multiple rows
567 MipRows = GFX_CEIL_DIV(GFX_MAX(1, Depth >> i), MipsInThisRow);
568
569 Total3DHeight += MipRows * AlignedHeight;
570
571 // next level height
572 BlockHeight >>= 1;
573 }
574
575 GMM_DPF_EXIT;
576 return Total3DHeight;
577 }
578
579
580 /////////////////////////////////////////////////////////////////////////////////////
581 /// Calculates the address offset for each mip map of 3D texture and store them
582 /// into the GMM_TEXTURE_INFO for surf state programming.
583 ///
584 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
585 ///
586 /////////////////////////////////////////////////////////////////////////////////////
Fill3DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)587 void GmmLib::GmmGen7TextureCalc::Fill3DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
588 {
589 uint32_t AlignedMipHeight, AlignedMipWidth;
590 uint32_t i, Depth;
591 uint32_t MipsInThisRow, MipLevel, MipRows;
592 uint32_t MipHeight, MipWidth;
593 uint32_t UnitAlignHeight, UnitAlignWidth;
594 uint32_t CompressHeight, CompressWidth, CompressDepth;
595 uint32_t OffsetMipRows = 0;
596 GMM_GFX_SIZE_T OffsetValue;
597 uint8_t Compress;
598 GMM_TEXTURE_CALC *pTextureCalc;
599
600 __GMM_ASSERT(pTexInfo);
601
602 pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext);
603
604 // Assign directly to unaligned MipMap dimension variables
605 // There isn't a need to save original dimensions
606 MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth);
607 MipHeight = pTexInfo->BaseHeight;
608
609 // Align before we compress
610 UnitAlignWidth = pTexInfo->Alignment.HAlign;
611 UnitAlignHeight = pTexInfo->Alignment.VAlign;
612 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
613 pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
614
615 // Aligned MipMap Dimensions
616 AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
617 AlignedMipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
618
619 Depth = pTexInfo->Depth;
620 MipLevel = pTexInfo->MaxLod;
621
622 // Start with base offset
623 OffsetValue = 0;
624
625 // calculate the offset for each Mip level
626 for(i = 0; i <= MipLevel; i++)
627 {
628 // store the value in blockdesc
629 if(Compress)
630 {
631 // If there is compression, compress after the alignment at each level
632 AlignedMipWidth /= CompressWidth;
633 AlignedMipHeight /= CompressHeight;
634 }
635 else if(pTexInfo->Flags.Gpu.SeparateStencil)
636 {
637 AlignedMipWidth *= 2;
638 AlignedMipHeight /= 2;
639 }
640 else if(pTexInfo->Flags.Gpu.CCS)
641 {
642 if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
643 {
644 switch(pTexInfo->BitsPerPixel)
645 {
646 case 32:
647 AlignedMipWidth /= 8;
648 break;
649 case 64:
650 AlignedMipWidth /= 4;
651 break;
652 case 128:
653 AlignedMipWidth /= 2;
654 break;
655 default:
656 __GMM_ASSERT(0);
657 }
658
659 AlignedMipHeight /= 32;
660 }
661 else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
662 {
663 switch(pTexInfo->BitsPerPixel)
664 {
665 case 32:
666 AlignedMipWidth /= 16;
667 break;
668 case 64:
669 AlignedMipWidth /= 8;
670 break;
671 case 128:
672 AlignedMipWidth /= 4;
673 break;
674 default:
675 __GMM_ASSERT(0);
676 }
677
678 AlignedMipHeight /= 16;
679 }
680 }
681
682 pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[i] = OffsetValue;
683
684 // See how many mip can fit in one row
685 MipsInThisRow = GFX_2_TO_POWER_OF(i);
686
687 // Slice pitch for LOD0
688 if(MipsInThisRow == 1)
689 {
690 pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch =
691 AlignedMipHeight * pTexInfo->Pitch;
692 }
693
694 // calculate if the mips will spill over to multiple rows
695 MipRows = GFX_CEIL_DIV(GFX_MAX(1, Depth >> i), MipsInThisRow);
696
697 // Offset in terms of height
698 OffsetMipRows += MipRows * AlignedMipHeight;
699
700 // For a particular mip This is offset of a base slice (i.e. Slice 0)
701 OffsetValue = OffsetMipRows * pTexInfo->Pitch;
702
703 // next level height
704 MipHeight >>= 1;
705 // Clamp such that mip height is at least1
706 MipHeight = GFX_MAX(MipHeight, 1);
707 AlignedMipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
708
709 MipWidth >>= 1;
710 // Clamp such that mip width is at least 1
711 MipWidth = GFX_MAX(MipWidth, 1);
712 AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
713 }
714 }
715
716 /////////////////////////////////////////////////////////////////////////////////////
717 /// Calculates the 3D offset and QPitch for surface state programming.
718 ///
719 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
720 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
721 ///
722 /// @return ::GMM_STATUS
723 /////////////////////////////////////////////////////////////////////////////////////
FillTex3D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)724 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex3D(GMM_TEXTURE_INFO * pTexInfo,
725 __GMM_BUFFER_TYPE *pRestrictions)
726 {
727 uint32_t AlignedMipWidth;
728 uint32_t BitsPerPixel;
729 uint32_t Depth, Height, Width;
730 uint32_t i, MipsInThisRow, MipWidth;
731 uint32_t RenderPitch = 0, ThisRowPitch;
732 uint32_t UnitAlignWidth;
733 uint32_t Total3DHeight;
734 uint32_t WidthBytesPhysical;
735 uint8_t Compress;
736 uint32_t CompressHeight, CompressWidth, CompressDepth;
737 bool SeparateStencil;
738 GMM_STATUS Status;
739
740 GMM_DPF_ENTER;
741
742 __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
743 __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
744
745 const __GMM_PLATFORM_RESOURCE *pPlatformResource = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
746
747 BitsPerPixel = pTexInfo->BitsPerPixel;
748 Height = pTexInfo->BaseHeight;
749 Width = GFX_ULONG_CAST(pTexInfo->BaseWidth);
750 Depth = pTexInfo->Depth;
751
752 // Align before we compress
753 UnitAlignWidth = pTexInfo->Alignment.HAlign;
754 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
755 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
756 SeparateStencil = pTexInfo->Flags.Gpu.SeparateStencil ? true : false;
757
758 // Unaligned MipMap dimension variables
759 MipWidth = Width;
760
761 // Aligned MipMap dimension variables
762 AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
763
764 // Calculate the render pitch exactly the same way we do the
765 // offset for each Mip level
766 for(i = 0; i <= pTexInfo->MaxLod; i++)
767 {
768 if(Compress)
769 {
770 // If there is compression, compress after the alignment at each level
771 AlignedMipWidth /= CompressWidth;
772 }
773 else if(SeparateStencil)
774 {
775 AlignedMipWidth *= 2;
776 }
777 else if(pTexInfo->Flags.Gpu.CCS)
778 {
779 if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
780 {
781 switch(BitsPerPixel)
782 {
783 case 32:
784 AlignedMipWidth /= 8;
785 break;
786 case 64:
787 AlignedMipWidth /= 4;
788 break;
789 case 128:
790 AlignedMipWidth /= 2;
791 break;
792 default:
793 __GMM_ASSERT(0);
794 }
795 }
796 else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
797 {
798 switch(BitsPerPixel)
799 {
800 case 32:
801 AlignedMipWidth /= 16;
802 break;
803 case 64:
804 AlignedMipWidth /= 8;
805 break;
806 case 128:
807 AlignedMipWidth /= 4;
808 break;
809 default:
810 __GMM_ASSERT(0);
811 }
812 }
813 }
814
815 // See how many mip can fit in one row
816 MipsInThisRow = GFX_2_TO_POWER_OF(i);
817
818 // LOD planes may be less than MipsInThisRow, take the smaller value for pitch
819 MipsInThisRow = GFX_MIN(GFX_MAX(1, (Depth >> i)), MipsInThisRow);
820 ThisRowPitch = AlignedMipWidth * MipsInThisRow;
821
822 // Default pitch
823 WidthBytesPhysical = ThisRowPitch * BitsPerPixel >> 3;
824
825 if(RenderPitch < WidthBytesPhysical)
826 {
827 RenderPitch = WidthBytesPhysical;
828 }
829
830 MipWidth >>= 1;
831 // Clamp such that mip width is at least 1
832 MipWidth = GFX_MAX(MipWidth, 1);
833 AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
834 }
835
836 WidthBytesPhysical = RenderPitch;
837
838 // Make sure the pitch satisfy linear min pitch requirment
839 WidthBytesPhysical = GFX_MAX(WidthBytesPhysical,
840 pRestrictions->MinPitch);
841
842 // Make sure pitch satisfy alignment restriction
843 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical,
844 pRestrictions->PitchAlignment);
845
846 // Get Total height for the entire 3D texture
847 Total3DHeight = GetTotal3DHeight(pTexInfo);
848
849 if(GMM_IS_TILED(pPlatformResource->TileInfo[pTexInfo->TileMode]))
850 {
851 // Align to tile boundary
852 Total3DHeight = GFX_ALIGN(Total3DHeight,
853 pPlatformResource->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
854 WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical,
855 pPlatformResource->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
856 }
857
858 // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
859 // padding needs to be added. Since this will create a none pitch aligned
860 // surface the padding is aligned to the next row
861 if(GmmIsYUVPacked(pTexInfo->Format) ||
862 (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
863 (pTexInfo->BitsPerPixel == GMM_BITS(48)))
864 {
865 Total3DHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), WidthBytesPhysical);
866 }
867
868 Total3DHeight = GFX_ALIGN(Total3DHeight, __GMM_EVEN_ROW);
869
870 if((Status = // <-- Note assignment.
871 FillTexPitchAndSize(
872 pTexInfo, WidthBytesPhysical, Total3DHeight, pRestrictions)) == GMM_SUCCESS)
873 {
874 Fill3DTexOffsetAddress(pTexInfo);
875 }
876
877 GMM_DPF_EXIT;
878 return (Status);
879 }
880
881 /////////////////////////////////////////////////////////////////////////////////////
882 /// Allocates the 1D mip layout for surface state programming.
883 ///
884 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
885 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
886 ///
887 /// @return ::GMM_STATUS
888 /////////////////////////////////////////////////////////////////////////////////////
FillTex1D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)889 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo,
890 __GMM_BUFFER_TYPE *pRestrictions)
891 {
892 return FillTex2D(pTexInfo, pRestrictions);
893 }
894
895 /////////////////////////////////////////////////////////////////////////////////////
896 /// Calculates the cube layout for surface state programming.
897 ///
898 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
899 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
900 ///
901 /// @return ::GMM_STATUS
902 /////////////////////////////////////////////////////////////////////////////////////
FillTexCube(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)903 GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo,
904 __GMM_BUFFER_TYPE *pRestrictions)
905 {
906 return FillTex2D(pTexInfo, pRestrictions);
907 }
908