using System; namespace Ryujinx.Graphics.Gpu { class SwizzleAddr { private int Width; private int XB; private int YB; public SwizzleAddr(int Width, int Height, int Pad) { int W = Pow2RoundUp(Width); int H = Pow2RoundUp(Height); XB = CountZeros(W); YB = CountZeros(H); int HH = H >> 1; if (!IsPow2(Height) && Height <= HH + HH / 3 && YB > 3) { YB--; } this.Width = RoundSize(Width, Pad); } private static int Pow2RoundUp(int Value) { Value--; Value |= (Value >> 1); Value |= (Value >> 2); Value |= (Value >> 4); Value |= (Value >> 8); Value |= (Value >> 16); return ++Value; } private static bool IsPow2(int Value) { return Value != 0 && (Value & (Value - 1)) == 0; } private static int CountZeros(int Value) { int Count = 0; for (int i = 0; i < 32; i++) { if ((Value & (1 << i)) != 0) { break; } Count++; } return Count; } private static int RoundSize(int Size, int Pad) { int Mask = Pad - 1; if ((Size & Mask) != 0) { Size &= ~Mask; Size += Pad; } return Size; } public int GetSwizzledAddress8(int X, int Y) { return GetSwizzledAddress(X, Y, 4); } public int GetSwizzledAddress16(int X, int Y) { return GetSwizzledAddress(X, Y, 3); } public int GetSwizzledAddress32(int X, int Y) { return GetSwizzledAddress(X, Y, 2); } public int GetSwizzledAddress64(int X, int Y) { return GetSwizzledAddress(X, Y, 1); } public int GetSwizzledAddress128(int X, int Y) { return GetSwizzledAddress(X, Y, 0); } private int GetSwizzledAddress(int X, int Y, int XBase) { /* * Examples of patterns: * x x y x y y x y 0 0 0 0 64 x 64 dxt5 * x x x x x y y y y x y y x y 0 0 0 0 512 x 512 dxt5 * y x x x x x x y y y y x y y x y 0 0 0 0 1024 x 1024 dxt5 * y y x x x x x x y y y y x y y x y x 0 0 0 2048 x 2048 dxt1 * y y y x x x x x x y y y y x y y x y x x 0 0 1024 x 1024 rgba8888 * * Read from right to left, LSB first. */ int XCnt = XBase; int YCnt = 1; int XUsed = 0; int YUsed = 0; int Address = 0; while (XUsed < XBase + 2 && XUsed + XCnt < XB) { int XMask = (1 << XCnt) - 1; int YMask = (1 << YCnt) - 1; Address |= (X & XMask) << XUsed + YUsed; Address |= (Y & YMask) << XUsed + YUsed + XCnt; X >>= XCnt; Y >>= YCnt; XUsed += XCnt; YUsed += YCnt; XCnt = Math.Min(XB - XUsed, 1); YCnt = Math.Min(YB - YUsed, YCnt << 1); } Address |= (X + Y * (Width >> XUsed)) << (XUsed + YUsed); return Address; } } }