PixelConverter.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using Ryujinx.Common;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. using System.Runtime.Intrinsics;
  5. using System.Runtime.Intrinsics.X86;
  6. namespace Ryujinx.Graphics.Texture
  7. {
  8. public static class PixelConverter
  9. {
  10. private static (int remainder, int outRemainder, int height) GetLineRemainders(int length, int width, int bpp, int outBpp)
  11. {
  12. int stride = BitUtils.AlignUp(width * bpp, LayoutConverter.HostStrideAlignment);
  13. int remainder = stride / bpp - width;
  14. int outStride = BitUtils.AlignUp(width * outBpp, LayoutConverter.HostStrideAlignment);
  15. int outRemainder = outStride / outBpp - width;
  16. return (remainder, outRemainder, length / stride);
  17. }
  18. public unsafe static byte[] ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data, int width)
  19. {
  20. byte[] output = new byte[data.Length * 2];
  21. (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2);
  22. Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(output);
  23. if (remainder == 0)
  24. {
  25. int start = 0;
  26. if (Sse41.IsSupported)
  27. {
  28. int sizeTrunc = data.Length & ~7;
  29. start = sizeTrunc;
  30. fixed (byte* inputPtr = data, outputPtr = output)
  31. {
  32. for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8)
  33. {
  34. Sse2.Store(outputPtr + offset * 2, Sse41.ConvertToVector128Int16(inputPtr + offset).AsByte());
  35. }
  36. }
  37. }
  38. for (int i = start; i < data.Length; i++)
  39. {
  40. outputSpan[i] = (ushort)data[i];
  41. }
  42. }
  43. else
  44. {
  45. int offset = 0;
  46. int outOffset = 0;
  47. for (int y = 0; y < height; y++)
  48. {
  49. for (int x = 0; x < width; x++)
  50. {
  51. outputSpan[outOffset++] = data[offset++];
  52. }
  53. offset += remainder;
  54. outOffset += outRemainder;
  55. }
  56. }
  57. return output;
  58. }
  59. public unsafe static byte[] ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
  60. {
  61. byte[] output = new byte[data.Length * 2];
  62. int offset = 0;
  63. int outOffset = 0;
  64. (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
  65. ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
  66. Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
  67. for (int y = 0; y < height; y++)
  68. {
  69. for (int x = 0; x < width; x++)
  70. {
  71. uint packed = inputSpan[offset++];
  72. uint outputPacked = 0xff000000;
  73. outputPacked |= (packed << 3) & 0x000000f8;
  74. outputPacked |= (packed << 8) & 0x00f80000;
  75. // Replicate 5 bit components.
  76. outputPacked |= (outputPacked >> 5) & 0x00070007;
  77. // Include and replicate 6 bit component.
  78. outputPacked |= ((packed << 5) & 0x0000fc00) | ((packed >> 1) & 0x00000300);
  79. outputSpan[outOffset++] = outputPacked;
  80. }
  81. offset += remainder;
  82. outOffset += outRemainder;
  83. }
  84. return output;
  85. }
  86. public unsafe static byte[] ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha)
  87. {
  88. byte[] output = new byte[data.Length * 2];
  89. int offset = 0;
  90. int outOffset = 0;
  91. (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
  92. ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
  93. Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
  94. for (int y = 0; y < height; y++)
  95. {
  96. for (int x = 0; x < width; x++)
  97. {
  98. uint packed = inputSpan[offset++];
  99. uint a = forceAlpha ? 1 : (packed >> 15);
  100. uint outputPacked = a * 0xff000000;
  101. outputPacked |= (packed << 3) & 0x000000f8;
  102. outputPacked |= (packed << 6) & 0x0000f800;
  103. outputPacked |= (packed << 9) & 0x00f80000;
  104. // Replicate 5 bit components.
  105. outputPacked |= (outputPacked >> 5) & 0x00070707;
  106. outputSpan[outOffset++] = outputPacked;
  107. }
  108. offset += remainder;
  109. outOffset += outRemainder;
  110. }
  111. return output;
  112. }
  113. public unsafe static byte[] ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
  114. {
  115. byte[] output = new byte[data.Length * 2];
  116. int offset = 0;
  117. int outOffset = 0;
  118. (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
  119. ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
  120. Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
  121. for (int y = 0; y < height; y++)
  122. {
  123. for (int x = 0; x < width; x++)
  124. {
  125. uint packed = inputSpan[offset++];
  126. uint a = packed >> 15;
  127. uint outputPacked = a * 0xff000000;
  128. outputPacked |= (packed >> 8) & 0x000000f8;
  129. outputPacked |= (packed << 5) & 0x0000f800;
  130. outputPacked |= (packed << 18) & 0x00f80000;
  131. // Replicate 5 bit components.
  132. outputPacked |= (outputPacked >> 5) & 0x00070707;
  133. outputSpan[outOffset++] = outputPacked;
  134. }
  135. offset += remainder;
  136. outOffset += outRemainder;
  137. }
  138. return output;
  139. }
  140. public unsafe static byte[] ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
  141. {
  142. byte[] output = new byte[data.Length * 2];
  143. int offset = 0;
  144. int outOffset = 0;
  145. (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
  146. ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
  147. Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
  148. for (int y = 0; y < height; y++)
  149. {
  150. for (int x = 0; x < width; x++)
  151. {
  152. uint packed = inputSpan[offset++];
  153. uint outputPacked = packed & 0x0000000f;
  154. outputPacked |= (packed << 4) & 0x00000f00;
  155. outputPacked |= (packed << 8) & 0x000f0000;
  156. outputPacked |= (packed << 12) & 0x0f000000;
  157. outputSpan[outOffset++] = outputPacked * 0x11;
  158. }
  159. offset += remainder;
  160. outOffset += outRemainder;
  161. }
  162. return output;
  163. }
  164. }
  165. }