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