ASTCDecoder.cs 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. namespace Ryujinx.Graphics.Texture
  7. {
  8. public class ASTCDecoderException : Exception
  9. {
  10. public ASTCDecoderException(string ExMsg) : base(ExMsg) { }
  11. }
  12. //https://github.com/GammaUNC/FasTC/blob/master/ASTCEncoder/src/Decompressor.cpp
  13. public static class ASTCDecoder
  14. {
  15. struct TexelWeightParams
  16. {
  17. public int Width;
  18. public int Height;
  19. public bool DualPlane;
  20. public int MaxWeight;
  21. public bool Error;
  22. public bool VoidExtentLDR;
  23. public bool VoidExtentHDR;
  24. public int GetPackedBitSize()
  25. {
  26. // How many indices do we have?
  27. int Indices = Height * Width;
  28. if (DualPlane)
  29. {
  30. Indices *= 2;
  31. }
  32. IntegerEncoded IntEncoded = IntegerEncoded.CreateEncoding(MaxWeight);
  33. return IntEncoded.GetBitLength(Indices);
  34. }
  35. public int GetNumWeightValues()
  36. {
  37. int Ret = Width * Height;
  38. if (DualPlane)
  39. {
  40. Ret *= 2;
  41. }
  42. return Ret;
  43. }
  44. }
  45. public static byte[] DecodeToRGBA8888(
  46. byte[] InputBuffer,
  47. int BlockX,
  48. int BlockY,
  49. int BlockZ,
  50. int X,
  51. int Y,
  52. int Z)
  53. {
  54. using (MemoryStream InputStream = new MemoryStream(InputBuffer))
  55. {
  56. BinaryReader BinReader = new BinaryReader(InputStream);
  57. if (BlockX > 12 || BlockY > 12)
  58. {
  59. throw new ASTCDecoderException("Block size unsupported!");
  60. }
  61. if (BlockZ != 1 || Z != 1)
  62. {
  63. throw new ASTCDecoderException("3D compressed textures unsupported!");
  64. }
  65. using (MemoryStream OutputStream = new MemoryStream())
  66. {
  67. int BlockIndex = 0;
  68. for (int j = 0; j < Y; j += BlockY)
  69. {
  70. for (int i = 0; i < X; i += BlockX)
  71. {
  72. int[] DecompressedData = new int[144];
  73. DecompressBlock(BinReader.ReadBytes(0x10), DecompressedData, BlockX, BlockY);
  74. int DecompressedWidth = Math.Min(BlockX, X - i);
  75. int DecompressedHeight = Math.Min(BlockY, Y - j);
  76. int BaseOffsets = (j * X + i) * 4;
  77. for (int jj = 0; jj < DecompressedHeight; jj++)
  78. {
  79. OutputStream.Seek(BaseOffsets + jj * X * 4, SeekOrigin.Begin);
  80. byte[] OutputBuffer = new byte[DecompressedData.Length * sizeof(int)];
  81. Buffer.BlockCopy(DecompressedData, 0, OutputBuffer, 0, OutputBuffer.Length);
  82. OutputStream.Write(OutputBuffer, jj * BlockX * 4, DecompressedWidth * 4);
  83. }
  84. BlockIndex++;
  85. }
  86. }
  87. return OutputStream.ToArray();
  88. }
  89. }
  90. }
  91. public static bool DecompressBlock(
  92. byte[] InputBuffer,
  93. int[] OutputBuffer,
  94. int BlockWidth,
  95. int BlockHeight)
  96. {
  97. BitArrayStream BitStream = new BitArrayStream(new BitArray(InputBuffer));
  98. TexelWeightParams TexelParams = DecodeBlockInfo(BitStream);
  99. if (TexelParams.Error)
  100. {
  101. throw new ASTCDecoderException("Invalid block mode");
  102. }
  103. if (TexelParams.VoidExtentLDR)
  104. {
  105. FillVoidExtentLDR(BitStream, OutputBuffer, BlockWidth, BlockHeight);
  106. return true;
  107. }
  108. if (TexelParams.VoidExtentHDR)
  109. {
  110. throw new ASTCDecoderException("HDR void extent blocks are unsupported!");
  111. }
  112. if (TexelParams.Width > BlockWidth)
  113. {
  114. throw new ASTCDecoderException("Texel weight grid width should be smaller than block width");
  115. }
  116. if (TexelParams.Height > BlockHeight)
  117. {
  118. throw new ASTCDecoderException("Texel weight grid height should be smaller than block height");
  119. }
  120. // Read num partitions
  121. int NumberPartitions = BitStream.ReadBits(2) + 1;
  122. Debug.Assert(NumberPartitions <= 4);
  123. if (NumberPartitions == 4 && TexelParams.DualPlane)
  124. {
  125. throw new ASTCDecoderException("Dual plane mode is incompatible with four partition blocks");
  126. }
  127. // Based on the number of partitions, read the color endpoint mode for
  128. // each partition.
  129. // Determine partitions, partition index, and color endpoint modes
  130. int PlaneIndices = -1;
  131. int PartitionIndex;
  132. uint[] ColorEndpointMode = { 0, 0, 0, 0 };
  133. BitArrayStream ColorEndpointStream = new BitArrayStream(new BitArray(16 * 8));
  134. // Read extra config data...
  135. uint BaseColorEndpointMode = 0;
  136. if (NumberPartitions == 1)
  137. {
  138. ColorEndpointMode[0] = (uint)BitStream.ReadBits(4);
  139. PartitionIndex = 0;
  140. }
  141. else
  142. {
  143. PartitionIndex = BitStream.ReadBits(10);
  144. BaseColorEndpointMode = (uint)BitStream.ReadBits(6);
  145. }
  146. uint BaseMode = (BaseColorEndpointMode & 3);
  147. // Remaining bits are color endpoint data...
  148. int NumberWeightBits = TexelParams.GetPackedBitSize();
  149. int RemainingBits = 128 - NumberWeightBits - BitStream.Position;
  150. // Consider extra bits prior to texel data...
  151. uint ExtraColorEndpointModeBits = 0;
  152. if (BaseMode != 0)
  153. {
  154. switch (NumberPartitions)
  155. {
  156. case 2: ExtraColorEndpointModeBits += 2; break;
  157. case 3: ExtraColorEndpointModeBits += 5; break;
  158. case 4: ExtraColorEndpointModeBits += 8; break;
  159. default: Debug.Assert(false); break;
  160. }
  161. }
  162. RemainingBits -= (int)ExtraColorEndpointModeBits;
  163. // Do we have a dual plane situation?
  164. int PlaneSelectorBits = 0;
  165. if (TexelParams.DualPlane)
  166. {
  167. PlaneSelectorBits = 2;
  168. }
  169. RemainingBits -= PlaneSelectorBits;
  170. // Read color data...
  171. int ColorDataBits = RemainingBits;
  172. while (RemainingBits > 0)
  173. {
  174. int NumberBits = Math.Min(RemainingBits, 8);
  175. int Bits = BitStream.ReadBits(NumberBits);
  176. ColorEndpointStream.WriteBits(Bits, NumberBits);
  177. RemainingBits -= 8;
  178. }
  179. // Read the plane selection bits
  180. PlaneIndices = BitStream.ReadBits(PlaneSelectorBits);
  181. // Read the rest of the CEM
  182. if (BaseMode != 0)
  183. {
  184. uint ExtraColorEndpointMode = (uint)BitStream.ReadBits((int)ExtraColorEndpointModeBits);
  185. uint TempColorEndpointMode = (ExtraColorEndpointMode << 6) | BaseColorEndpointMode;
  186. TempColorEndpointMode >>= 2;
  187. bool[] C = new bool[4];
  188. for (int i = 0; i < NumberPartitions; i++)
  189. {
  190. C[i] = (TempColorEndpointMode & 1) != 0;
  191. TempColorEndpointMode >>= 1;
  192. }
  193. byte[] M = new byte[4];
  194. for (int i = 0; i < NumberPartitions; i++)
  195. {
  196. M[i] = (byte)(TempColorEndpointMode & 3);
  197. TempColorEndpointMode >>= 2;
  198. Debug.Assert(M[i] <= 3);
  199. }
  200. for (int i = 0; i < NumberPartitions; i++)
  201. {
  202. ColorEndpointMode[i] = BaseMode;
  203. if (!(C[i])) ColorEndpointMode[i] -= 1;
  204. ColorEndpointMode[i] <<= 2;
  205. ColorEndpointMode[i] |= M[i];
  206. }
  207. }
  208. else if (NumberPartitions > 1)
  209. {
  210. uint TempColorEndpointMode = BaseColorEndpointMode >> 2;
  211. for (uint i = 0; i < NumberPartitions; i++)
  212. {
  213. ColorEndpointMode[i] = TempColorEndpointMode;
  214. }
  215. }
  216. // Make sure everything up till here is sane.
  217. for (int i = 0; i < NumberPartitions; i++)
  218. {
  219. Debug.Assert(ColorEndpointMode[i] < 16);
  220. }
  221. Debug.Assert(BitStream.Position + TexelParams.GetPackedBitSize() == 128);
  222. // Decode both color data and texel weight data
  223. int[] ColorValues = new int[32]; // Four values * two endpoints * four maximum partitions
  224. DecodeColorValues(ColorValues, ColorEndpointStream.ToByteArray(), ColorEndpointMode, NumberPartitions, ColorDataBits);
  225. ASTCPixel[][] EndPoints = new ASTCPixel[4][];
  226. EndPoints[0] = new ASTCPixel[2];
  227. EndPoints[1] = new ASTCPixel[2];
  228. EndPoints[2] = new ASTCPixel[2];
  229. EndPoints[3] = new ASTCPixel[2];
  230. int ColorValuesPosition = 0;
  231. for (int i = 0; i < NumberPartitions; i++)
  232. {
  233. ComputeEndpoints(EndPoints[i], ColorValues, ColorEndpointMode[i], ref ColorValuesPosition);
  234. }
  235. // Read the texel weight data.
  236. byte[] TexelWeightData = (byte[])InputBuffer.Clone();
  237. // Reverse everything
  238. for (int i = 0; i < 8; i++)
  239. {
  240. byte a = ReverseByte(TexelWeightData[i]);
  241. byte b = ReverseByte(TexelWeightData[15 - i]);
  242. TexelWeightData[i] = b;
  243. TexelWeightData[15 - i] = a;
  244. }
  245. // Make sure that higher non-texel bits are set to zero
  246. int ClearByteStart = (TexelParams.GetPackedBitSize() >> 3) + 1;
  247. TexelWeightData[ClearByteStart - 1] &= (byte)((1 << (TexelParams.GetPackedBitSize() % 8)) - 1);
  248. int cLen = 16 - ClearByteStart;
  249. for (int i = ClearByteStart; i < ClearByteStart + cLen; i++) TexelWeightData[i] = 0;
  250. List<IntegerEncoded> TexelWeightValues = new List<IntegerEncoded>();
  251. BitArrayStream WeightBitStream = new BitArrayStream(new BitArray(TexelWeightData));
  252. IntegerEncoded.DecodeIntegerSequence(TexelWeightValues, WeightBitStream, TexelParams.MaxWeight, TexelParams.GetNumWeightValues());
  253. // Blocks can be at most 12x12, so we can have as many as 144 weights
  254. int[][] Weights = new int[2][];
  255. Weights[0] = new int[144];
  256. Weights[1] = new int[144];
  257. UnquantizeTexelWeights(Weights, TexelWeightValues, TexelParams, BlockWidth, BlockHeight);
  258. // Now that we have endpoints and weights, we can interpolate and generate
  259. // the proper decoding...
  260. for (int j = 0; j < BlockHeight; j++)
  261. {
  262. for (int i = 0; i < BlockWidth; i++)
  263. {
  264. int Partition = Select2DPartition(PartitionIndex, i, j, NumberPartitions, ((BlockHeight * BlockWidth) < 32));
  265. Debug.Assert(Partition < NumberPartitions);
  266. ASTCPixel Pixel = new ASTCPixel(0, 0, 0, 0);
  267. for (int Component = 0; Component < 4; Component++)
  268. {
  269. int Component0 = EndPoints[Partition][0].GetComponent(Component);
  270. Component0 = BitArrayStream.Replicate(Component0, 8, 16);
  271. int Component1 = EndPoints[Partition][1].GetComponent(Component);
  272. Component1 = BitArrayStream.Replicate(Component1, 8, 16);
  273. int Plane = 0;
  274. if (TexelParams.DualPlane && (((PlaneIndices + 1) & 3) == Component))
  275. {
  276. Plane = 1;
  277. }
  278. int Weight = Weights[Plane][j * BlockWidth + i];
  279. int FinalComponent = (Component0 * (64 - Weight) + Component1 * Weight + 32) / 64;
  280. if (FinalComponent == 65535)
  281. {
  282. Pixel.SetComponent(Component, 255);
  283. }
  284. else
  285. {
  286. double FinalComponentFloat = FinalComponent;
  287. Pixel.SetComponent(Component, (int)(255.0 * (FinalComponentFloat / 65536.0) + 0.5));
  288. }
  289. }
  290. OutputBuffer[j * BlockWidth + i] = Pixel.Pack();
  291. }
  292. }
  293. return true;
  294. }
  295. private static int Select2DPartition(int Seed, int X, int Y, int PartitionCount, bool IsSmallBlock)
  296. {
  297. return SelectPartition(Seed, X, Y, 0, PartitionCount, IsSmallBlock);
  298. }
  299. private static int SelectPartition(int Seed, int X, int Y, int Z, int PartitionCount, bool IsSmallBlock)
  300. {
  301. if (PartitionCount == 1)
  302. {
  303. return 0;
  304. }
  305. if (IsSmallBlock)
  306. {
  307. X <<= 1;
  308. Y <<= 1;
  309. Z <<= 1;
  310. }
  311. Seed += (PartitionCount - 1) * 1024;
  312. int RightNum = Hash52((uint)Seed);
  313. byte Seed01 = (byte)(RightNum & 0xF);
  314. byte Seed02 = (byte)((RightNum >> 4) & 0xF);
  315. byte Seed03 = (byte)((RightNum >> 8) & 0xF);
  316. byte Seed04 = (byte)((RightNum >> 12) & 0xF);
  317. byte Seed05 = (byte)((RightNum >> 16) & 0xF);
  318. byte Seed06 = (byte)((RightNum >> 20) & 0xF);
  319. byte Seed07 = (byte)((RightNum >> 24) & 0xF);
  320. byte Seed08 = (byte)((RightNum >> 28) & 0xF);
  321. byte Seed09 = (byte)((RightNum >> 18) & 0xF);
  322. byte Seed10 = (byte)((RightNum >> 22) & 0xF);
  323. byte Seed11 = (byte)((RightNum >> 26) & 0xF);
  324. byte Seed12 = (byte)(((RightNum >> 30) | (RightNum << 2)) & 0xF);
  325. Seed01 *= Seed01; Seed02 *= Seed02;
  326. Seed03 *= Seed03; Seed04 *= Seed04;
  327. Seed05 *= Seed05; Seed06 *= Seed06;
  328. Seed07 *= Seed07; Seed08 *= Seed08;
  329. Seed09 *= Seed09; Seed10 *= Seed10;
  330. Seed11 *= Seed11; Seed12 *= Seed12;
  331. int SeedHash1, SeedHash2, SeedHash3;
  332. if ((Seed & 1) != 0)
  333. {
  334. SeedHash1 = (Seed & 2) != 0 ? 4 : 5;
  335. SeedHash2 = (PartitionCount == 3) ? 6 : 5;
  336. }
  337. else
  338. {
  339. SeedHash1 = (PartitionCount == 3) ? 6 : 5;
  340. SeedHash2 = (Seed & 2) != 0 ? 4 : 5;
  341. }
  342. SeedHash3 = (Seed & 0x10) != 0 ? SeedHash1 : SeedHash2;
  343. Seed01 >>= SeedHash1; Seed02 >>= SeedHash2; Seed03 >>= SeedHash1; Seed04 >>= SeedHash2;
  344. Seed05 >>= SeedHash1; Seed06 >>= SeedHash2; Seed07 >>= SeedHash1; Seed08 >>= SeedHash2;
  345. Seed09 >>= SeedHash3; Seed10 >>= SeedHash3; Seed11 >>= SeedHash3; Seed12 >>= SeedHash3;
  346. int a = Seed01 * X + Seed02 * Y + Seed11 * Z + (RightNum >> 14);
  347. int b = Seed03 * X + Seed04 * Y + Seed12 * Z + (RightNum >> 10);
  348. int c = Seed05 * X + Seed06 * Y + Seed09 * Z + (RightNum >> 6);
  349. int d = Seed07 * X + Seed08 * Y + Seed10 * Z + (RightNum >> 2);
  350. a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F;
  351. if (PartitionCount < 4) d = 0;
  352. if (PartitionCount < 3) c = 0;
  353. if (a >= b && a >= c && a >= d) return 0;
  354. else if (b >= c && b >= d) return 1;
  355. else if (c >= d) return 2;
  356. return 3;
  357. }
  358. static int Hash52(uint Val)
  359. {
  360. Val ^= Val >> 15; Val -= Val << 17; Val += Val << 7; Val += Val << 4;
  361. Val ^= Val >> 5; Val += Val << 16; Val ^= Val >> 7; Val ^= Val >> 3;
  362. Val ^= Val << 6; Val ^= Val >> 17;
  363. return (int)Val;
  364. }
  365. static void UnquantizeTexelWeights(
  366. int[][] OutputBuffer,
  367. List<IntegerEncoded> Weights,
  368. TexelWeightParams TexelParams,
  369. int BlockWidth,
  370. int BlockHeight)
  371. {
  372. int WeightIndices = 0;
  373. int[][] Unquantized = new int[2][];
  374. Unquantized[0] = new int[144];
  375. Unquantized[1] = new int[144];
  376. for (int i = 0; i < Weights.Count; i++)
  377. {
  378. Unquantized[0][WeightIndices] = UnquantizeTexelWeight(Weights[i]);
  379. if (TexelParams.DualPlane)
  380. {
  381. i++;
  382. Unquantized[1][WeightIndices] = UnquantizeTexelWeight(Weights[i]);
  383. if (i == Weights.Count)
  384. {
  385. break;
  386. }
  387. }
  388. if (++WeightIndices >= (TexelParams.Width * TexelParams.Height)) break;
  389. }
  390. // Do infill if necessary (Section C.2.18) ...
  391. int Ds = (1024 + (BlockWidth / 2)) / (BlockWidth - 1);
  392. int Dt = (1024 + (BlockHeight / 2)) / (BlockHeight - 1);
  393. int PlaneScale = TexelParams.DualPlane ? 2 : 1;
  394. for (int Plane = 0; Plane < PlaneScale; Plane++)
  395. {
  396. for (int t = 0; t < BlockHeight; t++)
  397. {
  398. for (int s = 0; s < BlockWidth; s++)
  399. {
  400. int cs = Ds * s;
  401. int ct = Dt * t;
  402. int gs = (cs * (TexelParams.Width - 1) + 32) >> 6;
  403. int gt = (ct * (TexelParams.Height - 1) + 32) >> 6;
  404. int js = gs >> 4;
  405. int fs = gs & 0xF;
  406. int jt = gt >> 4;
  407. int ft = gt & 0x0F;
  408. int w11 = (fs * ft + 8) >> 4;
  409. int w10 = ft - w11;
  410. int w01 = fs - w11;
  411. int w00 = 16 - fs - ft + w11;
  412. int v0 = js + jt * TexelParams.Width;
  413. int p00 = 0;
  414. int p01 = 0;
  415. int p10 = 0;
  416. int p11 = 0;
  417. if (v0 < (TexelParams.Width * TexelParams.Height))
  418. {
  419. p00 = Unquantized[Plane][v0];
  420. }
  421. if (v0 + 1 < (TexelParams.Width * TexelParams.Height))
  422. {
  423. p01 = Unquantized[Plane][v0 + 1];
  424. }
  425. if (v0 + TexelParams.Width < (TexelParams.Width * TexelParams.Height))
  426. {
  427. p10 = Unquantized[Plane][v0 + TexelParams.Width];
  428. }
  429. if (v0 + TexelParams.Width + 1 < (TexelParams.Width * TexelParams.Height))
  430. {
  431. p11 = Unquantized[Plane][v0 + TexelParams.Width + 1];
  432. }
  433. OutputBuffer[Plane][t * BlockWidth + s] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
  434. }
  435. }
  436. }
  437. }
  438. static int UnquantizeTexelWeight(IntegerEncoded IntEncoded)
  439. {
  440. int BitValue = IntEncoded.BitValue;
  441. int BitLength = IntEncoded.NumberBits;
  442. int A = BitArrayStream.Replicate(BitValue & 1, 1, 7);
  443. int B = 0, C = 0, D = 0;
  444. int Result = 0;
  445. switch (IntEncoded.GetEncoding())
  446. {
  447. case IntegerEncoded.EIntegerEncoding.JustBits:
  448. Result = BitArrayStream.Replicate(BitValue, BitLength, 6);
  449. break;
  450. case IntegerEncoded.EIntegerEncoding.Trit:
  451. {
  452. D = IntEncoded.TritValue;
  453. Debug.Assert(D < 3);
  454. switch (BitLength)
  455. {
  456. case 0:
  457. {
  458. int[] Results = { 0, 32, 63 };
  459. Result = Results[D];
  460. break;
  461. }
  462. case 1:
  463. {
  464. C = 50;
  465. break;
  466. }
  467. case 2:
  468. {
  469. C = 23;
  470. int b = (BitValue >> 1) & 1;
  471. B = (b << 6) | (b << 2) | b;
  472. break;
  473. }
  474. case 3:
  475. {
  476. C = 11;
  477. int cb = (BitValue >> 1) & 3;
  478. B = (cb << 5) | cb;
  479. break;
  480. }
  481. default:
  482. throw new ASTCDecoderException("Invalid trit encoding for texel weight");
  483. }
  484. break;
  485. }
  486. case IntegerEncoded.EIntegerEncoding.Quint:
  487. {
  488. D = IntEncoded.QuintValue;
  489. Debug.Assert(D < 5);
  490. switch (BitLength)
  491. {
  492. case 0:
  493. {
  494. int[] Results = { 0, 16, 32, 47, 63 };
  495. Result = Results[D];
  496. break;
  497. }
  498. case 1:
  499. {
  500. C = 28;
  501. break;
  502. }
  503. case 2:
  504. {
  505. C = 13;
  506. int b = (BitValue >> 1) & 1;
  507. B = (b << 6) | (b << 1);
  508. break;
  509. }
  510. default:
  511. throw new ASTCDecoderException("Invalid quint encoding for texel weight");
  512. }
  513. break;
  514. }
  515. }
  516. if (IntEncoded.GetEncoding() != IntegerEncoded.EIntegerEncoding.JustBits && BitLength > 0)
  517. {
  518. // Decode the value...
  519. Result = D * C + B;
  520. Result ^= A;
  521. Result = (A & 0x20) | (Result >> 2);
  522. }
  523. Debug.Assert(Result < 64);
  524. // Change from [0,63] to [0,64]
  525. if (Result > 32)
  526. {
  527. Result += 1;
  528. }
  529. return Result;
  530. }
  531. static byte ReverseByte(byte b)
  532. {
  533. // Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
  534. return (byte)((((b) * 0x80200802L) & 0x0884422110L) * 0x0101010101L >> 32);
  535. }
  536. static uint[] ReadUintColorValues(int Number, int[] ColorValues, ref int ColorValuesPosition)
  537. {
  538. uint[] Ret = new uint[Number];
  539. for (int i = 0; i < Number; i++)
  540. {
  541. Ret[i] = (uint)ColorValues[ColorValuesPosition++];
  542. }
  543. return Ret;
  544. }
  545. static int[] ReadIntColorValues(int Number, int[] ColorValues, ref int ColorValuesPosition)
  546. {
  547. int[] Ret = new int[Number];
  548. for (int i = 0; i < Number; i++)
  549. {
  550. Ret[i] = ColorValues[ColorValuesPosition++];
  551. }
  552. return Ret;
  553. }
  554. static void ComputeEndpoints(
  555. ASTCPixel[] EndPoints,
  556. int[] ColorValues,
  557. uint ColorEndpointMode,
  558. ref int ColorValuesPosition)
  559. {
  560. switch (ColorEndpointMode)
  561. {
  562. case 0:
  563. {
  564. uint[] Val = ReadUintColorValues(2, ColorValues, ref ColorValuesPosition);
  565. EndPoints[0] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[0], (short)Val[0]);
  566. EndPoints[1] = new ASTCPixel(0xFF, (short)Val[1], (short)Val[1], (short)Val[1]);
  567. break;
  568. }
  569. case 1:
  570. {
  571. uint[] Val = ReadUintColorValues(2, ColorValues, ref ColorValuesPosition);
  572. int L0 = (int)((Val[0] >> 2) | (Val[1] & 0xC0));
  573. int L1 = (int)Math.Max(L0 + (Val[1] & 0x3F), 0xFFU);
  574. EndPoints[0] = new ASTCPixel(0xFF, (short)L0, (short)L0, (short)L0);
  575. EndPoints[1] = new ASTCPixel(0xFF, (short)L1, (short)L1, (short)L1);
  576. break;
  577. }
  578. case 4:
  579. {
  580. uint[] Val = ReadUintColorValues(4, ColorValues, ref ColorValuesPosition);
  581. EndPoints[0] = new ASTCPixel((short)Val[2], (short)Val[0], (short)Val[0], (short)Val[0]);
  582. EndPoints[1] = new ASTCPixel((short)Val[3], (short)Val[1], (short)Val[1], (short)Val[1]);
  583. break;
  584. }
  585. case 5:
  586. {
  587. int[] Val = ReadIntColorValues(4, ColorValues, ref ColorValuesPosition);
  588. BitArrayStream.BitTransferSigned(ref Val[1], ref Val[0]);
  589. BitArrayStream.BitTransferSigned(ref Val[3], ref Val[2]);
  590. EndPoints[0] = new ASTCPixel((short)Val[2], (short)Val[0], (short)Val[0], (short)Val[0]);
  591. EndPoints[1] = new ASTCPixel((short)(Val[2] + Val[3]), (short)(Val[0] + Val[1]), (short)(Val[0] + Val[1]), (short)(Val[0] + Val[1]));
  592. EndPoints[0].ClampByte();
  593. EndPoints[1].ClampByte();
  594. break;
  595. }
  596. case 6:
  597. {
  598. uint[] Val = ReadUintColorValues(4, ColorValues, ref ColorValuesPosition);
  599. EndPoints[0] = new ASTCPixel(0xFF, (short)(Val[0] * Val[3] >> 8), (short)(Val[1] * Val[3] >> 8), (short)(Val[2] * Val[3] >> 8));
  600. EndPoints[1] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[1], (short)Val[2]);
  601. break;
  602. }
  603. case 8:
  604. {
  605. uint[] Val = ReadUintColorValues(6, ColorValues, ref ColorValuesPosition);
  606. if (Val[1] + Val[3] + Val[5] >= Val[0] + Val[2] + Val[4])
  607. {
  608. EndPoints[0] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[2], (short)Val[4]);
  609. EndPoints[1] = new ASTCPixel(0xFF, (short)Val[1], (short)Val[3], (short)Val[5]);
  610. }
  611. else
  612. {
  613. EndPoints[0] = ASTCPixel.BlueContract(0xFF, (short)Val[1], (short)Val[3], (short)Val[5]);
  614. EndPoints[1] = ASTCPixel.BlueContract(0xFF, (short)Val[0], (short)Val[2], (short)Val[4]);
  615. }
  616. break;
  617. }
  618. case 9:
  619. {
  620. int[] Val = ReadIntColorValues(6, ColorValues, ref ColorValuesPosition);
  621. BitArrayStream.BitTransferSigned(ref Val[1], ref Val[0]);
  622. BitArrayStream.BitTransferSigned(ref Val[3], ref Val[2]);
  623. BitArrayStream.BitTransferSigned(ref Val[5], ref Val[4]);
  624. if (Val[1] + Val[3] + Val[5] >= 0)
  625. {
  626. EndPoints[0] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[2], (short)Val[4]);
  627. EndPoints[1] = new ASTCPixel(0xFF, (short)(Val[0] + Val[1]), (short)(Val[2] + Val[3]), (short)(Val[4] + Val[5]));
  628. }
  629. else
  630. {
  631. EndPoints[0] = ASTCPixel.BlueContract(0xFF, Val[0] + Val[1], Val[2] + Val[3], Val[4] + Val[5]);
  632. EndPoints[1] = ASTCPixel.BlueContract(0xFF, Val[0], Val[2], Val[4]);
  633. }
  634. EndPoints[0].ClampByte();
  635. EndPoints[1].ClampByte();
  636. break;
  637. }
  638. case 10:
  639. {
  640. uint[] Val = ReadUintColorValues(6, ColorValues, ref ColorValuesPosition);
  641. EndPoints[0] = new ASTCPixel((short)Val[4], (short)(Val[0] * Val[3] >> 8), (short)(Val[1] * Val[3] >> 8), (short)(Val[2] * Val[3] >> 8));
  642. EndPoints[1] = new ASTCPixel((short)Val[5], (short)Val[0], (short)Val[1], (short)Val[2]);
  643. break;
  644. }
  645. case 12:
  646. {
  647. uint[] Val = ReadUintColorValues(8, ColorValues, ref ColorValuesPosition);
  648. if (Val[1] + Val[3] + Val[5] >= Val[0] + Val[2] + Val[4])
  649. {
  650. EndPoints[0] = new ASTCPixel((short)Val[6], (short)Val[0], (short)Val[2], (short)Val[4]);
  651. EndPoints[1] = new ASTCPixel((short)Val[7], (short)Val[1], (short)Val[3], (short)Val[5]);
  652. }
  653. else
  654. {
  655. EndPoints[0] = ASTCPixel.BlueContract((short)Val[7], (short)Val[1], (short)Val[3], (short)Val[5]);
  656. EndPoints[1] = ASTCPixel.BlueContract((short)Val[6], (short)Val[0], (short)Val[2], (short)Val[4]);
  657. }
  658. break;
  659. }
  660. case 13:
  661. {
  662. int[] Val = ReadIntColorValues(8, ColorValues, ref ColorValuesPosition);
  663. BitArrayStream.BitTransferSigned(ref Val[1], ref Val[0]);
  664. BitArrayStream.BitTransferSigned(ref Val[3], ref Val[2]);
  665. BitArrayStream.BitTransferSigned(ref Val[5], ref Val[4]);
  666. BitArrayStream.BitTransferSigned(ref Val[7], ref Val[6]);
  667. if (Val[1] + Val[3] + Val[5] >= 0)
  668. {
  669. EndPoints[0] = new ASTCPixel((short)Val[6], (short)Val[0], (short)Val[2], (short)Val[4]);
  670. EndPoints[1] = new ASTCPixel((short)(Val[7] + Val[6]), (short)(Val[0] + Val[1]), (short)(Val[2] + Val[3]), (short)(Val[4] + Val[5]));
  671. }
  672. else
  673. {
  674. EndPoints[0] = ASTCPixel.BlueContract(Val[6] + Val[7], Val[0] + Val[1], Val[2] + Val[3], Val[4] + Val[5]);
  675. EndPoints[1] = ASTCPixel.BlueContract(Val[6], Val[0], Val[2], Val[4]);
  676. }
  677. EndPoints[0].ClampByte();
  678. EndPoints[1].ClampByte();
  679. break;
  680. }
  681. default:
  682. throw new ASTCDecoderException("Unsupported color endpoint mode (is it HDR?)");
  683. }
  684. }
  685. static void DecodeColorValues(
  686. int[] OutputValues,
  687. byte[] InputData,
  688. uint[] Modes,
  689. int NumberPartitions,
  690. int NumberBitsForColorData)
  691. {
  692. // First figure out how many color values we have
  693. int NumberValues = 0;
  694. for (int i = 0; i < NumberPartitions; i++)
  695. {
  696. NumberValues += (int)((Modes[i] >> 2) + 1) << 1;
  697. }
  698. // Then based on the number of values and the remaining number of bits,
  699. // figure out the max value for each of them...
  700. int Range = 256;
  701. while (--Range > 0)
  702. {
  703. IntegerEncoded IntEncoded = IntegerEncoded.CreateEncoding(Range);
  704. int BitLength = IntEncoded.GetBitLength(NumberValues);
  705. if (BitLength <= NumberBitsForColorData)
  706. {
  707. // Find the smallest possible range that matches the given encoding
  708. while (--Range > 0)
  709. {
  710. IntegerEncoded NewIntEncoded = IntegerEncoded.CreateEncoding(Range);
  711. if (!NewIntEncoded.MatchesEncoding(IntEncoded))
  712. {
  713. break;
  714. }
  715. }
  716. // Return to last matching range.
  717. Range++;
  718. break;
  719. }
  720. }
  721. // We now have enough to decode our integer sequence.
  722. List<IntegerEncoded> IntegerEncodedSequence = new List<IntegerEncoded>();
  723. BitArrayStream ColorBitStream = new BitArrayStream(new BitArray(InputData));
  724. IntegerEncoded.DecodeIntegerSequence(IntegerEncodedSequence, ColorBitStream, Range, NumberValues);
  725. // Once we have the decoded values, we need to dequantize them to the 0-255 range
  726. // This procedure is outlined in ASTC spec C.2.13
  727. int OutputIndices = 0;
  728. foreach (IntegerEncoded IntEncoded in IntegerEncodedSequence)
  729. {
  730. int BitLength = IntEncoded.NumberBits;
  731. int BitValue = IntEncoded.BitValue;
  732. Debug.Assert(BitLength >= 1);
  733. int A = 0, B = 0, C = 0, D = 0;
  734. // A is just the lsb replicated 9 times.
  735. A = BitArrayStream.Replicate(BitValue & 1, 1, 9);
  736. switch (IntEncoded.GetEncoding())
  737. {
  738. case IntegerEncoded.EIntegerEncoding.JustBits:
  739. {
  740. OutputValues[OutputIndices++] = BitArrayStream.Replicate(BitValue, BitLength, 8);
  741. break;
  742. }
  743. case IntegerEncoded.EIntegerEncoding.Trit:
  744. {
  745. D = IntEncoded.TritValue;
  746. switch (BitLength)
  747. {
  748. case 1:
  749. {
  750. C = 204;
  751. break;
  752. }
  753. case 2:
  754. {
  755. C = 93;
  756. // B = b000b0bb0
  757. int b = (BitValue >> 1) & 1;
  758. B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
  759. break;
  760. }
  761. case 3:
  762. {
  763. C = 44;
  764. // B = cb000cbcb
  765. int cb = (BitValue >> 1) & 3;
  766. B = (cb << 7) | (cb << 2) | cb;
  767. break;
  768. }
  769. case 4:
  770. {
  771. C = 22;
  772. // B = dcb000dcb
  773. int dcb = (BitValue >> 1) & 7;
  774. B = (dcb << 6) | dcb;
  775. break;
  776. }
  777. case 5:
  778. {
  779. C = 11;
  780. // B = edcb000ed
  781. int edcb = (BitValue >> 1) & 0xF;
  782. B = (edcb << 5) | (edcb >> 2);
  783. break;
  784. }
  785. case 6:
  786. {
  787. C = 5;
  788. // B = fedcb000f
  789. int fedcb = (BitValue >> 1) & 0x1F;
  790. B = (fedcb << 4) | (fedcb >> 4);
  791. break;
  792. }
  793. default:
  794. throw new ASTCDecoderException("Unsupported trit encoding for color values!");
  795. }
  796. break;
  797. }
  798. case IntegerEncoded.EIntegerEncoding.Quint:
  799. {
  800. D = IntEncoded.QuintValue;
  801. switch (BitLength)
  802. {
  803. case 1:
  804. {
  805. C = 113;
  806. break;
  807. }
  808. case 2:
  809. {
  810. C = 54;
  811. // B = b0000bb00
  812. int b = (BitValue >> 1) & 1;
  813. B = (b << 8) | (b << 3) | (b << 2);
  814. break;
  815. }
  816. case 3:
  817. {
  818. C = 26;
  819. // B = cb0000cbc
  820. int cb = (BitValue >> 1) & 3;
  821. B = (cb << 7) | (cb << 1) | (cb >> 1);
  822. break;
  823. }
  824. case 4:
  825. {
  826. C = 13;
  827. // B = dcb0000dc
  828. int dcb = (BitValue >> 1) & 7;
  829. B = (dcb << 6) | (dcb >> 1);
  830. break;
  831. }
  832. case 5:
  833. {
  834. C = 6;
  835. // B = edcb0000e
  836. int edcb = (BitValue >> 1) & 0xF;
  837. B = (edcb << 5) | (edcb >> 3);
  838. break;
  839. }
  840. default:
  841. throw new ASTCDecoderException("Unsupported quint encoding for color values!");
  842. }
  843. break;
  844. }
  845. }
  846. if (IntEncoded.GetEncoding() != IntegerEncoded.EIntegerEncoding.JustBits)
  847. {
  848. int T = D * C + B;
  849. T ^= A;
  850. T = (A & 0x80) | (T >> 2);
  851. OutputValues[OutputIndices++] = T;
  852. }
  853. }
  854. // Make sure that each of our values is in the proper range...
  855. for (int i = 0; i < NumberValues; i++)
  856. {
  857. Debug.Assert(OutputValues[i] <= 255);
  858. }
  859. }
  860. static void FillVoidExtentLDR(BitArrayStream BitStream, int[] OutputBuffer, int BlockWidth, int BlockHeight)
  861. {
  862. // Don't actually care about the void extent, just read the bits...
  863. for (int i = 0; i < 4; ++i)
  864. {
  865. BitStream.ReadBits(13);
  866. }
  867. // Decode the RGBA components and renormalize them to the range [0, 255]
  868. ushort R = (ushort)BitStream.ReadBits(16);
  869. ushort G = (ushort)BitStream.ReadBits(16);
  870. ushort B = (ushort)BitStream.ReadBits(16);
  871. ushort A = (ushort)BitStream.ReadBits(16);
  872. int RGBA = (R >> 8) | (G & 0xFF00) | ((B) & 0xFF00) << 8 | ((A) & 0xFF00) << 16;
  873. for (int j = 0; j < BlockHeight; j++)
  874. {
  875. for (int i = 0; i < BlockWidth; i++)
  876. {
  877. OutputBuffer[j * BlockWidth + i] = RGBA;
  878. }
  879. }
  880. }
  881. static TexelWeightParams DecodeBlockInfo(BitArrayStream BitStream)
  882. {
  883. TexelWeightParams TexelParams = new TexelWeightParams();
  884. // Read the entire block mode all at once
  885. ushort ModeBits = (ushort)BitStream.ReadBits(11);
  886. // Does this match the void extent block mode?
  887. if ((ModeBits & 0x01FF) == 0x1FC)
  888. {
  889. if ((ModeBits & 0x200) != 0)
  890. {
  891. TexelParams.VoidExtentHDR = true;
  892. }
  893. else
  894. {
  895. TexelParams.VoidExtentLDR = true;
  896. }
  897. // Next two bits must be one.
  898. if ((ModeBits & 0x400) == 0 || BitStream.ReadBits(1) == 0)
  899. {
  900. TexelParams.Error = true;
  901. }
  902. return TexelParams;
  903. }
  904. // First check if the last four bits are zero
  905. if ((ModeBits & 0xF) == 0)
  906. {
  907. TexelParams.Error = true;
  908. return TexelParams;
  909. }
  910. // If the last two bits are zero, then if bits
  911. // [6-8] are all ones, this is also reserved.
  912. if ((ModeBits & 0x3) == 0 && (ModeBits & 0x1C0) == 0x1C0)
  913. {
  914. TexelParams.Error = true;
  915. return TexelParams;
  916. }
  917. // Otherwise, there is no error... Figure out the layout
  918. // of the block mode. Layout is determined by a number
  919. // between 0 and 9 corresponding to table C.2.8 of the
  920. // ASTC spec.
  921. int Layout = 0;
  922. if ((ModeBits & 0x1) != 0 || (ModeBits & 0x2) != 0)
  923. {
  924. // layout is in [0-4]
  925. if ((ModeBits & 0x8) != 0)
  926. {
  927. // layout is in [2-4]
  928. if ((ModeBits & 0x4) != 0)
  929. {
  930. // layout is in [3-4]
  931. if ((ModeBits & 0x100) != 0)
  932. {
  933. Layout = 4;
  934. }
  935. else
  936. {
  937. Layout = 3;
  938. }
  939. }
  940. else
  941. {
  942. Layout = 2;
  943. }
  944. }
  945. else
  946. {
  947. // layout is in [0-1]
  948. if ((ModeBits & 0x4) != 0)
  949. {
  950. Layout = 1;
  951. }
  952. else
  953. {
  954. Layout = 0;
  955. }
  956. }
  957. }
  958. else
  959. {
  960. // layout is in [5-9]
  961. if ((ModeBits & 0x100) != 0)
  962. {
  963. // layout is in [7-9]
  964. if ((ModeBits & 0x80) != 0)
  965. {
  966. // layout is in [7-8]
  967. Debug.Assert((ModeBits & 0x40) == 0);
  968. if ((ModeBits & 0x20) != 0)
  969. {
  970. Layout = 8;
  971. }
  972. else
  973. {
  974. Layout = 7;
  975. }
  976. }
  977. else
  978. {
  979. Layout = 9;
  980. }
  981. }
  982. else
  983. {
  984. // layout is in [5-6]
  985. if ((ModeBits & 0x80) != 0)
  986. {
  987. Layout = 6;
  988. }
  989. else
  990. {
  991. Layout = 5;
  992. }
  993. }
  994. }
  995. Debug.Assert(Layout < 10);
  996. // Determine R
  997. int R = (ModeBits >> 4) & 1;
  998. if (Layout < 5)
  999. {
  1000. R |= (ModeBits & 0x3) << 1;
  1001. }
  1002. else
  1003. {
  1004. R |= (ModeBits & 0xC) >> 1;
  1005. }
  1006. Debug.Assert(2 <= R && R <= 7);
  1007. // Determine width & height
  1008. switch (Layout)
  1009. {
  1010. case 0:
  1011. {
  1012. int A = (ModeBits >> 5) & 0x3;
  1013. int B = (ModeBits >> 7) & 0x3;
  1014. TexelParams.Width = B + 4;
  1015. TexelParams.Height = A + 2;
  1016. break;
  1017. }
  1018. case 1:
  1019. {
  1020. int A = (ModeBits >> 5) & 0x3;
  1021. int B = (ModeBits >> 7) & 0x3;
  1022. TexelParams.Width = B + 8;
  1023. TexelParams.Height = A + 2;
  1024. break;
  1025. }
  1026. case 2:
  1027. {
  1028. int A = (ModeBits >> 5) & 0x3;
  1029. int B = (ModeBits >> 7) & 0x3;
  1030. TexelParams.Width = A + 2;
  1031. TexelParams.Height = B + 8;
  1032. break;
  1033. }
  1034. case 3:
  1035. {
  1036. int A = (ModeBits >> 5) & 0x3;
  1037. int B = (ModeBits >> 7) & 0x1;
  1038. TexelParams.Width = A + 2;
  1039. TexelParams.Height = B + 6;
  1040. break;
  1041. }
  1042. case 4:
  1043. {
  1044. int A = (ModeBits >> 5) & 0x3;
  1045. int B = (ModeBits >> 7) & 0x1;
  1046. TexelParams.Width = B + 2;
  1047. TexelParams.Height = A + 2;
  1048. break;
  1049. }
  1050. case 5:
  1051. {
  1052. int A = (ModeBits >> 5) & 0x3;
  1053. TexelParams.Width = 12;
  1054. TexelParams.Height = A + 2;
  1055. break;
  1056. }
  1057. case 6:
  1058. {
  1059. int A = (ModeBits >> 5) & 0x3;
  1060. TexelParams.Width = A + 2;
  1061. TexelParams.Height = 12;
  1062. break;
  1063. }
  1064. case 7:
  1065. {
  1066. TexelParams.Width = 6;
  1067. TexelParams.Height = 10;
  1068. break;
  1069. }
  1070. case 8:
  1071. {
  1072. TexelParams.Width = 10;
  1073. TexelParams.Height = 6;
  1074. break;
  1075. }
  1076. case 9:
  1077. {
  1078. int A = (ModeBits >> 5) & 0x3;
  1079. int B = (ModeBits >> 9) & 0x3;
  1080. TexelParams.Width = A + 6;
  1081. TexelParams.Height = B + 6;
  1082. break;
  1083. }
  1084. default:
  1085. //Don't know this layout...
  1086. TexelParams.Error = true;
  1087. break;
  1088. }
  1089. // Determine whether or not we're using dual planes
  1090. // and/or high precision layouts.
  1091. bool D = ((Layout != 9) && ((ModeBits & 0x400) != 0));
  1092. bool H = (Layout != 9) && ((ModeBits & 0x200) != 0);
  1093. if (H)
  1094. {
  1095. int[] MaxWeights = { 9, 11, 15, 19, 23, 31 };
  1096. TexelParams.MaxWeight = MaxWeights[R - 2];
  1097. }
  1098. else
  1099. {
  1100. int[] MaxWeights = { 1, 2, 3, 4, 5, 7 };
  1101. TexelParams.MaxWeight = MaxWeights[R - 2];
  1102. }
  1103. TexelParams.DualPlane = D;
  1104. return TexelParams;
  1105. }
  1106. }
  1107. }