PixelConverter.cs 7.6 KB

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