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 /// This function does any special-case conversion from client-provided pseudo creation
27 /// parameters to actual parameters for Hiz, CCS, SeparateStencil and Depth buffers.
28 ///
29 /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO
30 ///
31 /////////////////////////////////////////////////////////////////////////////////////
PreProcessTexSpecialCases(GMM_TEXTURE_INFO * pTexInfo)32 GMM_STATUS GmmLib::GmmTextureCalc::PreProcessTexSpecialCases(GMM_TEXTURE_INFO *pTexInfo)
33 {
34 GMM_STATUS Status = GMM_SUCCESS;
35 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
36
37 if(!pTexInfo->Flags.Gpu.CCS &&
38 !pTexInfo->Flags.Gpu.MCS &&
39 !pTexInfo->Flags.Gpu.HiZ &&
40 !pTexInfo->Flags.Gpu.SeparateStencil &&
41 !pTexInfo->Flags.Gpu.MMC)
42 {
43 // Fast-out for non-special-cases.
44 }
45 else if(pTexInfo->Flags.Gpu.HiZ) // ######################################
46 {
47 // With HiZ surface creation, clients send the size/etc. parameters of
48 // the associated Depth Buffer--and here we convert to the appropriate
49 // HiZ creation parameters...
50
51 if((pTexInfo->BaseWidth > 0) &&
52 (pTexInfo->BaseWidth <= pPlatform->HiZ.MaxWidth) &&
53 (pTexInfo->BaseHeight > 0) &&
54 (pTexInfo->BaseHeight <= pPlatform->HiZ.MaxHeight) &&
55 (pTexInfo->Depth <= ((pTexInfo->Type == RESOURCE_3D) ?
56 pPlatform->HiZ.MaxDepth :
57 1)) &&
58 (pTexInfo->ArraySize <= ((pTexInfo->Type == RESOURCE_3D) ?
59 1 :
60 (pTexInfo->Type == RESOURCE_CUBE) ?
61 pPlatform->HiZ.MaxArraySize / 6 :
62 pPlatform->HiZ.MaxArraySize)) &&
63 // SKL+ does not support HiZ surfaces for 1D and 3D surfaces
64 ((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN9_CORE) ||
65 (pTexInfo->Type != RESOURCE_1D && pTexInfo->Type != RESOURCE_3D)))
66 {
67 uint32_t Z_Width, Z_Height, Z_Depth;
68
69 // Latch Z_[Width/Height/Depth]...
70 Z_Width = GFX_ULONG_CAST(pTexInfo->BaseWidth);
71 Z_Height = pTexInfo->BaseHeight;
72 if((pTexInfo->Type == RESOURCE_1D) ||
73 (pTexInfo->Type == RESOURCE_2D))
74 {
75 Z_Depth = GFX_MAX(pTexInfo->ArraySize, 1);
76 }
77 else if(pTexInfo->Type == RESOURCE_3D)
78 {
79 Z_Depth = pTexInfo->Depth;
80 }
81 else if(pTexInfo->Type == RESOURCE_CUBE)
82 {
83 // HW doesn't allow HiZ cube arrays, but GMM is allowing because
84 // clients will redescribe depth/HiZ cube arrays as 2D arrays.
85 Z_Depth = 6 * GFX_MAX(pTexInfo->ArraySize, 1);
86 }
87 else
88 {
89 __GMM_ASSERT(0); // Illegal--Should have caught at upper IF check.
90 Z_Depth = 0;
91 }
92
93 // HZ_[Width/Height/QPitch] Calculation...
94 {
95 uint32_t h0, h1, hL, i, NumSamples, QPitch, Z_HeightL;
96 uint32_t HZ_HAlign = 16, HZ_VAlign = 8;
97 uint8_t HZ_DepthRows = pPlatform->HiZPixelsPerByte;
98
99 // HZ operates in pixel space starting from SKL. So, it does not care
100 // whether the depth buffer is in MSAA mode or not.
101 NumSamples =
102 (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) ?
103 1 :
104 pTexInfo->MSAA.NumSamples;
105
106 pTexInfo->BaseWidth = ExpandWidth(Z_Width, HZ_HAlign, NumSamples);
107
108 h0 = ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
109
110 Z_Height = GmmTexGetMipHeight(pTexInfo, 1);
111 h1 = ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
112
113 if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE)
114 {
115 if(pTexInfo->Type == RESOURCE_3D)
116 {
117 for(i = 0, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++)
118 {
119 Z_Height = GmmTexGetMipHeight(pTexInfo, i);
120 hL = ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
121 Z_HeightL += (hL * GFX_MAX(1, (Z_Depth / GFX_2_TO_POWER_OF(i))));
122 }
123
124 pTexInfo->ArraySize = 0;
125 pTexInfo->BaseHeight = Z_HeightL / 2;
126 }
127 else
128 {
129 for(i = 2, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++)
130 {
131 Z_Height = GmmTexGetMipHeight(pTexInfo, i);
132 Z_HeightL += ExpandHeight(Z_Height, HZ_VAlign, NumSamples);
133 }
134
135 QPitch =
136 (pTexInfo->MaxLod > 0) ?
137 (h0 + GFX_MAX(h1, Z_HeightL)) :
138 h0;
139 QPitch /= HZ_DepthRows;
140 pTexInfo->ArraySize = Z_Depth;
141 pTexInfo->BaseHeight = QPitch;
142 }
143
144 pTexInfo->Alignment.HAlign = HZ_HAlign;
145 pTexInfo->Alignment.VAlign = HZ_VAlign / HZ_DepthRows;
146 }
147 else //if (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN7_CORE)
148 {
149 if(pTexInfo->Type == RESOURCE_3D)
150 {
151 for(i = 0, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++)
152 {
153 hL = ExpandHeight(Z_Height >> i, HZ_VAlign, NumSamples);
154 Z_HeightL += (hL * GFX_MAX(1, (Z_Depth / GFX_2_TO_POWER_OF(i))));
155 }
156
157 pTexInfo->BaseHeight = Z_HeightL / 2;
158 }
159 else
160 {
161 QPitch = h0 + h1 + 12 * HZ_VAlign;
162
163 pTexInfo->BaseHeight = GFX_CEIL_DIV((QPitch * Z_Depth / 2), 8) * 8;
164 }
165
166 pTexInfo->ArraySize = 1;
167 }
168 }
169
170 /// Native HZ Params //////////////////////////////////////////////////
171 pTexInfo->BitsPerPixel = 8;
172 pTexInfo->Depth = 1;
173 pTexInfo->Format = GMM_FORMAT_GENERIC_8BIT;
174 pTexInfo->MaxLod = 0;
175 pTexInfo->MSAA.NumSamples = 1;
176 pTexInfo->MSAA.SamplePattern = GMM_MSAA_DISABLED;
177 pTexInfo->Type = RESOURCE_2D;
178
179 // HiZ Always Tile-Y
180 pTexInfo->Flags.Info.Linear = 0;
181 pTexInfo->Flags.Info.TiledW = 0;
182 pTexInfo->Flags.Info.TiledX = 0;
183 pTexInfo->Flags.Info.TiledYf = 0;
184 GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
185 GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext);
186
187 }
188 else
189 {
190 GMM_ASSERTDPF(0, "Illegal HiZ creation parameters!");
191 Status = GMM_ERROR;
192 }
193 } // HiZ
194 else if(pTexInfo->Flags.Gpu.CCS ||
195 pTexInfo->Flags.Gpu.MCS) // ######################################
196 {
197 // With CCS surface creation, clients send height, width, depth, etc. of
198 // the associated RenderTarget--and here we convert to the appropriate CCS
199 // creation parameters...
200 __GMM_ASSERT((!pGmmLibContext->GetSkuTable().FtrTileY ||
201 (pTexInfo->Flags.Info.Linear + pTexInfo->Flags.Info.TiledW + pTexInfo->Flags.Info.TiledX + pTexInfo->Flags.Info.TiledY)) == 1);
202
203 __GMM_ASSERT((pGmmLibContext->GetSkuTable().FtrTileY || (pTexInfo->Flags.Info.Linear + pTexInfo->Flags.Info.Tile4 + pTexInfo->Flags.Info.Tile64)) == 1);
204
205 __GMM_ASSERT((pTexInfo->MSAA.NumSamples == 1) || (pTexInfo->MSAA.NumSamples == 2) || (pTexInfo->MSAA.NumSamples == 4) ||
206 (pTexInfo->MSAA.NumSamples == 8) || (pTexInfo->MSAA.NumSamples == 16));
207
208 Status = pGmmLibContext->GetTextureCalc()->MSAACCSUsage(pTexInfo);
209
210 if(!pTexInfo->Flags.Gpu.__NonMsaaLinearCCS)
211 {
212 // CCS Always Tile-Y (Even for Non-MSAA FastClear.)
213 pTexInfo->Flags.Info.Linear = 0;
214 pTexInfo->Flags.Info.TiledW = 0;
215 pTexInfo->Flags.Info.TiledX = 0;
216 pTexInfo->Flags.Info.TiledYf = 0;
217
218 GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
219 GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext);
220
221 //Clear compression request in CCS
222 pTexInfo->Flags.Info.RenderCompressed = 0;
223 pTexInfo->Flags.Info.MediaCompressed = 0;
224 }
225
226 } // CCS
227 else if(pTexInfo->Flags.Gpu.SeparateStencil) // ##########################
228 {
229 // Seperate stencil sizing is based on the associated depth buffer
230 // size, however UMD manages this sizing, and GMM will allocate any
231 // arbitrarily sized stencil. Stencils do have specific tiling
232 // requirements however, which is handled below.
233
234 if((pTexInfo->BaseWidth > 0) &&
235 (pTexInfo->BaseHeight > 0))
236 {
237 __GMM_ASSERT(pTexInfo->BitsPerPixel == 8);
238
239 if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN7_CORE)
240 {
241 GMM_ASSERTDPF((pTexInfo->MaxLod == 0), "Stencil Buffer LOD's not supported!");
242 }
243
244 if(pGmmLibContext->GetSkuTable().FtrTileY)
245 {
246 // Separate Stencil Tile-W Gen8-Gen11, otherwise Tile-Y
247 pTexInfo->Flags.Info.Linear = 0;
248 pTexInfo->Flags.Info.TiledX = 0;
249 pTexInfo->Flags.Info.TiledYf = 0;
250 pTexInfo->Flags.Info.TiledW = 0;
251 GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
252 GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext);
253
254 if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE &&
255 GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN11_CORE)
256 {
257 pTexInfo->Flags.Info.TiledW = 1;
258 }
259 else
260 {
261 GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext);
262 }
263 }
264 else
265 {
266 __GMM_ASSERT(pTexInfo->Flags.Info.Tile4 + pTexInfo->Flags.Info.Tile64 == 1);
267 }
268 }
269 else
270 {
271 GMM_ASSERTDPF(0, "Illegal Separate Stencil creation parameters!");
272 Status = GMM_ERROR;
273 }
274 } // Separate Stencil
275 else if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface)
276 {
277 pTexInfo->Flags.Gpu.__NonMsaaLinearCCS = 1;
278 pTexInfo->Flags.Info.Linear = 1;
279 }
280
281 return Status;
282 }
283
284 /////////////////////////////////////////////////////////////////////////////////////
285 /// This function performs rough estimate of memory requirement between 4KB Tile vs
286 /// 64KB Tile surfaces and if the memory wastage due to padding/alignment exceeds
287 /// configured threshold, then optimize to demote the surface to 4KB Tile.
288 ///
289 /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO
290 /// returns 1 if optimization to demote to 4KB tile is required otherwise 0
291 ///
292 /////////////////////////////////////////////////////////////////////////////////////
SurfaceRequires64KBTileOptimization(GMM_TEXTURE_INFO * pTexInfo)293 uint8_t GmmLib::GmmTextureCalc::SurfaceRequires64KBTileOptimization(GMM_TEXTURE_INFO *pTexInfo)
294 {
295 GMM_STATUS Status = GMM_SUCCESS;
296 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
297 uint32_t Size4KbTile, Size64KbTile;
298
299 // Discard the surface if not eligible for 4KB Tile.
300 // All YUV formats restricted with default Tile64 across clients
301 if((pTexInfo->MSAA.NumSamples > 1) ||
302 pTexInfo->Flags.Gpu.TiledResource ||
303 pTexInfo->Flags.Gpu.HiZ ||
304 (!pTexInfo->Flags.Info.Tile64))
305 {
306 return 0;
307 }
308
309 // Calc Surf size for 64KB Tile.
310 // Ignoring the CCS/AuxSurf dimensions since its proportional to main surface size
311 {
312 GMM_TEXTURE_INFO Surf = {};
313 uint32_t ExpandedArraySize, BitsPerPixel;
314 uint32_t SliceHeight, SliceWidth, Pitch;
315 uint32_t BlockHeight = 0;
316 uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
317
318 Surf = *pTexInfo;
319
320 //Get HAlign/VAlign
321 if((Status = __GmmTexFillHAlignVAlign(&Surf, pGmmLibContext)) != GMM_SUCCESS)
322 {
323 __GMM_ASSERT(0);
324 return 0;
325 }
326
327 HAlign = Surf.Alignment.HAlign;
328 VAlign = Surf.Alignment.VAlign;
329 DAlign = Surf.Alignment.DAlign;
330
331 // Set Tile Mode
332 SetTileMode(&Surf);
333 BitsPerPixel = Surf.BitsPerPixel;
334
335 ExpandedArraySize =
336 GFX_MAX(Surf.ArraySize, 1) *
337 ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
338 ((Surf.Type == RESOURCE_3D) ? GFX_MAX(Surf.Depth, 1) : 1); // 3D's simply 2D arrays for sizing.
339
340 if(GMM_IS_64KB_TILE(Surf.Flags))
341 {
342 ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth);
343 }
344
345 // For Mipped Surface, Approx SliceHeight = VAlign(Lod0Height) * Mipped ? 1.5 : 1;
346 SliceHeight = GFX_ALIGN(Surf.BaseHeight, VAlign);
347
348 if(Surf.MaxLod > 1)
349 {
350 SliceHeight = (GFX_ALIGN(Surf.BaseHeight, VAlign) * 3) / 2;
351 }
352
353 uint8_t Compress = GmmIsCompressed(pGmmLibContext, Surf.Format);
354 GetCompressionBlockDimensions(Surf.Format, &CompressWidth, &CompressHeight, &CompressDepth);
355
356
357 SliceWidth = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(Surf.BaseWidth), HAlign, &Surf);
358 BlockHeight = SliceHeight * ExpandedArraySize;
359
360 if(Compress)
361 {
362 SliceWidth = GFX_CEIL_DIV(SliceWidth, CompressWidth);
363 BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
364 }
365
366 // Default pitch
367 Pitch = SliceWidth * BitsPerPixel >> 3;
368
369 if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode]))
370 {
371 Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[Surf.TileMode].LogicalTileWidth);
372 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight);
373 }
374
375 // Calculate Tile aligned size.
376 Size64KbTile = BlockHeight * Pitch;
377
378 if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear)
379 {
380 Size64KbTile *= pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth;
381 }
382 }
383
384 // Calc Surf size for 4KB Tile
385 // Ignoring the CCS/AuxSurf dimensions since its proportional to main surface size
386 {
387 GMM_TEXTURE_INFO Surf = {};
388 uint32_t ExpandedArraySize, BitsPerPixel;
389 uint32_t SliceHeight, SliceWidth, Pitch;
390 uint32_t BlockHeight = 0;
391 uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth;
392
393 Surf = *pTexInfo;
394 Surf.Flags.Info.Tile4 = 1;
395 Surf.Flags.Info.Tile64 = 0;
396
397 //Get HAlign/VAlign
398 if((Status = __GmmTexFillHAlignVAlign(&Surf, pGmmLibContext)) != GMM_SUCCESS)
399 {
400 Status = GMM_ERROR;
401 return Status;
402 }
403
404 HAlign = Surf.Alignment.HAlign;
405 VAlign = Surf.Alignment.VAlign;
406 DAlign = Surf.Alignment.DAlign;
407
408 // Set Tile Mode
409 SetTileMode(&Surf);
410 BitsPerPixel = Surf.BitsPerPixel;
411
412 ExpandedArraySize =
413 GFX_MAX(Surf.ArraySize, 1) *
414 ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
415 ((Surf.Type == RESOURCE_3D) ? GFX_MAX(Surf.Depth, 1) : 1); // 3D's simply 2D arrays for sizing.
416
417 if(GMM_IS_64KB_TILE(Surf.Flags))
418 {
419 ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth);
420 }
421
422 // For Mipped Surface, Approx SliceHeight = VAlign(Lod0Height) * Mipped ? 1.5 : 1;
423 SliceHeight = GFX_ALIGN(Surf.BaseHeight, VAlign);
424
425 if(Surf.MaxLod > 1)
426 {
427 SliceHeight = (GFX_ALIGN(Surf.BaseHeight, VAlign) * 3) / 2;
428 }
429
430 uint8_t Compress = GmmIsCompressed(pGmmLibContext, Surf.Format);
431 GetCompressionBlockDimensions(Surf.Format, &CompressWidth, &CompressHeight, &CompressDepth);
432
433 SliceWidth = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(Surf.BaseWidth), HAlign, &Surf);
434 BlockHeight = SliceHeight * ExpandedArraySize;
435
436 if(Compress)
437 {
438 SliceWidth = GFX_CEIL_DIV(SliceWidth, CompressWidth);
439 BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight);
440 }
441
442 // Default pitch
443 Pitch = SliceWidth * BitsPerPixel >> 3;
444
445 if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode]))
446 {
447 Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[Surf.TileMode].LogicalTileWidth);
448 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight);
449 }
450
451 // Calculate Tile aligned size.
452 Size4KbTile = BlockHeight * Pitch;
453 }
454
455 // check if 64KB tiled resource size exceeds memory wastage threshold.
456 if(((Size4KbTile * (100 + (GMM_GFX_SIZE_T)pGmmLibContext->GetAllowedPaddingFor64KBTileSurf())) / 100) < Size64KbTile)
457 {
458 return 1;
459 }
460
461 return 0;
462 }
463