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 /// Allocates the 2D mip layout for surface state programming.
28 ///
29 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
30 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
31 ///
32 /// @return ::GMM_STATUS
33 /////////////////////////////////////////////////////////////////////////////////////
FillTex2D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)34 GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo,
35 __GMM_BUFFER_TYPE *pRestrictions)
36 {
37 uint32_t Width, Height, BitsPerPixel;
38 uint32_t HAlign, VAlign;
39 uint32_t CompressHeight, CompressWidth, CompressDepth;
40 uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch;
41 uint8_t Compress = 0;
42 GMM_STATUS Status;
43
44 GMM_DPF_ENTER;
45
46 __GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
47 __GMM_ASSERTPTR(pRestrictions, GMM_ERROR);
48
49 const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext);
50
51 BitsPerPixel = pTexInfo->BitsPerPixel;
52 Height = pTexInfo->BaseHeight;
53 Width = GFX_ULONG_CAST(pTexInfo->BaseWidth);
54
55 pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1);
56
57 ExpandedArraySize =
58 GFX_MAX(pTexInfo->ArraySize, 1) *
59 ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays.
60 ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ?
61 1 :
62 pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes.
63
64 //
65 // Check for color separation
66 //
67 if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)
68 {
69 bool csRestrictionsMet = (((ExpandedArraySize <= 2) &&
70 (ExpandedArraySize == pTexInfo->ArraySize) &&
71 ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) ||
72 (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) ||
73 (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) ||
74 (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) ||
75 (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) ||
76 (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) &&
77 ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) ||
78 (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0))));
79
80 if(csRestrictionsMet)
81 {
82 ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE;
83 }
84 else
85 {
86 pTexInfo->Flags.Gpu.ColorSeparation = 0;
87 pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0;
88 }
89 }
90
91 HAlign = pTexInfo->Alignment.HAlign;
92 VAlign = pTexInfo->Alignment.VAlign;
93 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
94
95 Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format);
96
97 // Calculate Block Surface Height
98 /////////////////////////////////
99
100 if(ExpandedArraySize > 1)
101 {
102 uint32_t Height0, Height1, Mip0BlockHeight, Slice0Delta = 0;
103
104 Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo);
105 Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo);
106
107 Mip0BlockHeight = BlockHeight = (pTexInfo->MaxLod > 0) ?
108 Height0 + Height1 + 12 * VAlign :
109 Height0;
110 BlockHeight -= (pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) ? Height0 : 0;
111
112 if(pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d)
113 {
114 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
115 }
116
117 // QPitch for compressed surface must be multiple of BlockHeight and 4...
118 if(Compress && (CompressHeight % 4))
119 {
120 uint32_t LCM = CompressHeight * ((CompressHeight % 2) ? 4 : 2);
121 BlockHeight = GFX_ALIGN_NP2(BlockHeight, LCM);
122 Mip0BlockHeight = GFX_ALIGN_NP2(Mip0BlockHeight, LCM);
123 }
124
125 // Gen8 QPitch programming refers to the logical view, not physical.
126 pTexInfo->Alignment.QPitch = BlockHeight;
127
128 if(Compress)
129 {
130 BlockHeight /= CompressHeight;
131 Mip0BlockHeight /= CompressHeight;
132 }
133 else if(pTexInfo->Flags.Gpu.SeparateStencil)
134 {
135 BlockHeight /= 2;
136 }
137 else if(pTexInfo->Flags.Gpu.CCS)
138 {
139 if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
140 {
141 BlockHeight /= 32;
142 }
143 else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
144 {
145 BlockHeight /= 16;
146 }
147 }
148
149 Slice0Delta = (pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) ? (Mip0BlockHeight - BlockHeight) : 0;
150 BlockHeight *= ExpandedArraySize;
151 BlockHeight += Slice0Delta;
152 }
153 else
154 {
155 pTexInfo->Alignment.QPitch = 0;
156
157 BlockHeight = Get2DMipMapHeight(pTexInfo);
158 }
159
160 ///////////////////////////////////
161 // Calculate Pitch
162 ///////////////////////////////////
163
164 AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo);
165
166 // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths
167 // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1
168 if(pTexInfo->MaxLod >= 2)
169 {
170 uint32_t AlignedWidthLod1, AlignedWidthLod2;
171
172 AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo);
173 AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo);
174
175 if((pGmmLibContext->GetWaTable().WaAstcCorruptionForOddCompressedBlockSizeX || pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) && pPlatform->FormatTable[pTexInfo->Format].ASTC && CompressWidth == 5)
176 {
177 uint32_t Width1 = (Width == 1) ? 1 : (Width >> 1);
178 uint32_t Modulo10 = Width1 % 10;
179 if(Modulo10 >= 1 && Modulo10 <= CompressWidth)
180 {
181 AlignedWidthLod2 += 3 * CompressWidth;
182 }
183 }
184 AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2);
185 }
186
187 if(Compress)
188 {
189 AlignedWidth /= CompressWidth;
190 }
191 else if(pTexInfo->Flags.Gpu.SeparateStencil)
192 {
193 AlignedWidth *= 2;
194 }
195 else if(pTexInfo->Flags.Gpu.CCS)
196 {
197 if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
198 {
199 switch(pTexInfo->BitsPerPixel)
200 {
201 case 32:
202 AlignedWidth /= 8;
203 break;
204 case 64:
205 AlignedWidth /= 4;
206 break;
207 case 128:
208 AlignedWidth /= 2;
209 break;
210 default:
211 __GMM_ASSERT(0);
212 }
213 }
214 else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
215 {
216 switch(pTexInfo->BitsPerPixel)
217 {
218 case 32:
219 AlignedWidth /= 16;
220 break;
221 case 64:
222 AlignedWidth /= 8;
223 break;
224 case 128:
225 AlignedWidth /= 4;
226 break;
227 default:
228 __GMM_ASSERT(0);
229 }
230 }
231 }
232 else if(pTexInfo->Flags.Gpu.ColorSeparation)
233 {
234 AlignedWidth *= pTexInfo->ArraySize;
235 __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION));
236 AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION;
237 }
238 else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX)
239 {
240 AlignedWidth *= pTexInfo->ArraySize;
241 __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION));
242 AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION;
243 }
244
245 // Default pitch
246 Pitch = AlignedWidth * BitsPerPixel >> 3;
247
248 // Make sure the pitch satisfy linear min pitch requirment
249 Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch);
250
251 // Make sure pitch satisfy alignment restriction
252 Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment);
253
254 ////////////////////
255 // Adjust for Tiling
256 ////////////////////
257 if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]))
258 {
259 Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth);
260 BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
261
262 // If Tiled Resource or Undefined64KBSwizzle resource, align to 64KB tile size
263 if((pTexInfo->Flags.Gpu.TiledResource || pTexInfo->Flags.Info.Undefined64KBSwizzle) &&
264 (pTexInfo->Flags.Info.TiledY))
265 {
266 uint32_t ColFactor = 0, RowFactor = 0;
267 uint32_t TRTileWidth = 0, TRTileHeight = 0;
268
269 GmmGetD3DToHwTileConversion(pTexInfo, &ColFactor, &RowFactor);
270 TRTileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * ColFactor;
271 TRTileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight * RowFactor;
272
273 Pitch = GFX_ALIGN(Pitch, TRTileWidth);
274 BlockHeight = GFX_ALIGN(BlockHeight, TRTileHeight);
275 }
276 }
277
278 GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!");
279 pTexInfo->Flags.Info.LayoutBelow = 1;
280 pTexInfo->Flags.Info.LayoutRight = 0;
281
282 // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of
283 // padding needs to be added. Since this will create a none pitch aligned
284 // surface the padding is aligned to the next row
285 if(GmmIsYUVPacked(pTexInfo->Format) ||
286 (pTexInfo->BitsPerPixel == GMM_BITS(96)) ||
287 (pTexInfo->BitsPerPixel == GMM_BITS(48)))
288 {
289 BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch);
290 }
291
292 // Align height to even row to cover for HW over-fetch
293 BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW);
294
295 if((Status = // <-- Note assignment.
296 FillTexPitchAndSize(
297 pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS)
298 {
299 Fill2DTexOffsetAddress(pTexInfo);
300
301 // Init to no-packed mips. It'll be initialized when app calls to get packed
302 // mips. Calculate packed mips here if there's a chance apps won't call to
303 // get packed mips.
304 pTexInfo->Alignment.PackedMipStartLod = GMM_TILED_RESOURCE_NO_PACKED_MIPS;
305 }
306
307 if(pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips)
308 {
309 uint32_t i = 0;
310 uint64_t SkipMip0Tiles = 0;
311 SkipMip0Tiles = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[1] /
312 (pTexInfo->Pitch * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight);
313 SkipMip0Tiles *= pTexInfo->Pitch * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight;
314 pTexInfo->Size -= SkipMip0Tiles;
315 for(i = 0; i <= pTexInfo->MaxLod; i++)
316 {
317 pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] -= SkipMip0Tiles;
318 }
319 }
320 GMM_DPF_EXIT;
321
322 return (Status);
323 }
324
325
326 /////////////////////////////////////////////////////////////////////////////////////
327 /// Calculates the address offset for each mip map of 2D texture and store them into
328 /// the GMM_TEXTURE_INFO for surf state programming.
329 ///
330 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
331 ///
332 /////////////////////////////////////////////////////////////////////////////////////
Fill2DTexOffsetAddress(GMM_TEXTURE_INFO * pTexInfo)333 void GmmLib::GmmGen8TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo)
334 {
335 uint32_t i;
336
337 GMM_DPF_ENTER;
338
339 // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch...
340 if((pTexInfo->ArraySize <= 1) &&
341 (pTexInfo->Type != RESOURCE_CUBE) &&
342 !(pTexInfo->Flags.Gpu.ColorSeparation ||
343 pTexInfo->Flags.Gpu.ColorSeparationRGBX))
344 {
345 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = 0;
346 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = 0;
347 }
348 else
349 {
350 uint32_t ArrayQPitch;
351 uint32_t CompressHeight, CompressWidth, CompressDepth;
352
353 GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
354
355 ArrayQPitch = pTexInfo->Alignment.QPitch;
356
357 if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format))
358 {
359 ArrayQPitch /= CompressHeight;
360 }
361 else if(pTexInfo->Flags.Gpu.SeparateStencil)
362 {
363 ArrayQPitch /= 2;
364 }
365 else if(pTexInfo->Flags.Gpu.CCS)
366 {
367 if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)
368 {
369 ArrayQPitch /= 32;
370 }
371 else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)
372 {
373 ArrayQPitch /= 16;
374 }
375 }
376
377 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = ArrayQPitch * pTexInfo->Pitch;
378 pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = ArrayQPitch * pTexInfo->Pitch;
379 }
380
381 for(i = 0; i <= pTexInfo->MaxLod; i++)
382 {
383 pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i);
384 }
385
386 GMM_DPF_EXIT;
387 }
388
389 /////////////////////////////////////////////////////////////////////////////////////
390 /// Allocates the 1D mip layout for surface state programming.
391 ///
392 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
393 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
394 ///
395 /// @return ::GMM_STATUS
396 /////////////////////////////////////////////////////////////////////////////////////
FillTex1D(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)397 GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo,
398 __GMM_BUFFER_TYPE *pRestrictions)
399 {
400 return FillTex2D(pTexInfo, pRestrictions);
401 }
402
403 /////////////////////////////////////////////////////////////////////////////////////
404 /// Calculates the cube layout for surface state programming.
405 ///
406 /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO,
407 /// @param[in] pRestrictions: ptr to surface alignment and size restrictions
408 ///
409 /// @return ::GMM_STATUS
410 /////////////////////////////////////////////////////////////////////////////////////
FillTexCube(GMM_TEXTURE_INFO * pTexInfo,__GMM_BUFFER_TYPE * pRestrictions)411 GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo,
412 __GMM_BUFFER_TYPE *pRestrictions)
413 {
414 return FillTex2D(pTexInfo, pRestrictions);
415 }
416
417 /////////////////////////////////////////////////////////////////////////////////////
418 /// This function does any special-case conversion from client-provided pseudo creation
419 /// parameters to actual parameters for CCS.
420 ///
421 /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO
422 ///
423 /// @return ::GMM_STATUS
424 /////////////////////////////////////////////////////////////////////////////////////
MSAACCSUsage(GMM_TEXTURE_INFO * pTexInfo)425 GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo)
426 {
427 GMM_STATUS Status = GMM_SUCCESS;
428
429 if(pTexInfo->MSAA.NumSamples > 1) // CCS for MSAA Compression
430 {
431 Status = MSAACompression(pTexInfo);
432 }
433 else // Non-MSAA CCS Use (i.e. Render Target Fast Clear)
434 {
435 if(!pTexInfo->Flags.Info.TiledW &&
436 ((!pTexInfo->Flags.Info.Linear) ||
437 (GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) ||
438 (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear))) && //!Yf - deprecate Yf
439 ((pTexInfo->BitsPerPixel == 32) ||
440 (pTexInfo->BitsPerPixel == 64) ||
441 (pTexInfo->BitsPerPixel == 128)))
442 {
443 // For non-MSAA CCS usage, the four tables of
444 // requirements:
445 // (1) RT Alignment (GMM Don't Care: Occurs Naturally)
446 // (2) ClearRect Alignment
447 // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter)
448 // (4) Non-MSAA CCS Sizing
449
450 // Gen8+:
451 // Since mip-mapped and arrayed surfaces are supported, we
452 // deal with alignment later at per mip level. Here, we set
453 // tiling type only. TileX is not supported on Gen9+.
454 // Pre-Gen8:
455 // (!) For all the above, there are separate entries for
456 // 32/64/128bpp--and then deals with PIXEL widths--Here,
457 // though, we will unify by considering 8bpp table entries
458 // (unlisted--i.e. do the math)--and deal with BYTE widths.
459
460 // (1) RT Alignment -- The surface width and height don't
461 // need to be padded to RT CL granularity. On HSW, all tiled
462 // RT's will have appropriate alignment (given 4KB surface
463 // base and no mip-map support) and appropriate padding
464 // (due to tile padding). On BDW+, GMM uses H/VALIGN that
465 // will guarantee the MCS RT alignment for all subresources.
466
467 // (2) ClearRect Alignment -- I.e. FastClears must be done
468 // with certain granularity:
469 // TileY: 512 Bytes x 128 Lines
470 // TileX: 1024 Bytes x 64 Lines
471 // So a CCS must be sized to match that granularity (though
472 // the RT itself need not be fully padded to that
473 // granularity to use FastClear).
474
475 // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the
476 // size of the FastClear (with granularity padding) for the
477 // paired RT. CCS's (byte widths and heights) are scaled
478 // down from their RT's by:
479 // TileY: 32 x 32
480 // TileX: 64 x 16
481
482 // ### Example #############################################
483 // RT: 800x600, 32bpp, TileY
484 // 8bpp: 3200x600
485 // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128)
486 // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32)
487
488 pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs;
489 pTexInfo->Flags.Gpu.__NonMsaaTileXCcs = pTexInfo->Flags.Info.TiledX;
490 }
491 else
492 {
493 GMM_ASSERTDPF(0, "Illegal CCS creation parameters!");
494 Status = GMM_ERROR;
495 }
496 }
497 return Status;
498 }
499