public static List <uint[]> GenerateMipSizes(TEX_FORMAT Format, uint Width, uint Height, uint Depth, uint SurfaceCount, uint MipCount, uint ImageSize) { List <uint[]> MipMapSizes = new List <uint[]>(); uint bpp = STGenericTexture.GetBytesPerPixel(Format); uint blkWidth = STGenericTexture.GetBlockWidth(Format); uint blkHeight = STGenericTexture.GetBlockHeight(Format); uint blkDepth = STGenericTexture.GetBlockDepth(Format); uint blockHeight = GetBlockHeight(DIV_ROUND_UP(Height, blkHeight)); uint BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; uint Pitch = 0; uint DataAlignment = 512; int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; uint ArrayCount = SurfaceCount; uint ArrayOffset = 0; for (int arrayLevel = 0; arrayLevel < ArrayCount; arrayLevel++) { uint SurfaceSize = 0; int blockHeightShift = 0; uint[] MipOffsets = new uint[MipCount]; for (int mipLevel = 0; mipLevel < MipCount; mipLevel++) { uint width = (uint)Math.Max(1, Width >> mipLevel); uint height = (uint)Math.Max(1, Height >> mipLevel); uint depth = (uint)Math.Max(1, Depth >> mipLevel); uint size = DIV_ROUND_UP(width, blkWidth) * DIV_ROUND_UP(height, blkHeight) * bpp; MipOffsets[mipLevel] = size; } ArrayOffset += (uint)(ImageSize / ArrayCount); MipMapSizes.Add(MipOffsets); } return(MipMapSizes); }
public static byte[] GetImageData(STGenericTexture texture, byte[] ImageData, int ArrayLevel, int MipLevel, int DepthLevel, uint BlockHeightLog2, int target = 1, bool LinearTileMode = false) { uint bpp = STGenericTexture.GetBytesPerPixel(texture.Format); uint blkWidth = STGenericTexture.GetBlockWidth(texture.Format); uint blkHeight = STGenericTexture.GetBlockHeight(texture.Format); uint blkDepth = STGenericTexture.GetBlockDepth(texture.Format); uint TileMode = 0; if (LinearTileMode) { TileMode = 1; } uint numDepth = 1; if (texture.Depth > 1) { numDepth = texture.Depth; } var blockHeightMip0 = GetBlockHeight(DIV_ROUND_UP(texture.Height, blkHeight)); uint arrayOffset = 0; // TODO: Why is depth done like this? for (int depthLevel = 0; depthLevel < numDepth; depthLevel++) { for (int arrayLevel = 0; arrayLevel < texture.ArrayCount; arrayLevel++) { var mipOffset = 0u; for (int mipLevel = 0; mipLevel < texture.MipCount; mipLevel++) { uint width = Math.Max(1, texture.Width >> mipLevel); uint height = Math.Max(1, texture.Height >> mipLevel); uint depth = Math.Max(1, texture.Depth >> mipLevel); uint widthInBlocks = DIV_ROUND_UP(width, blkWidth); uint heightInBlocks = DIV_ROUND_UP(height, blkHeight); uint depthInBlocks = DIV_ROUND_UP(depth, blkDepth); // tegra_swizzle only allows block heights supported by the TRM (1,2,4,8,16,32). var mipBlockHeightLog2 = (int)Math.Log(GetMipBlockHeight(heightInBlocks, blockHeightMip0), 2); var mipBlockHeight = 1 << Math.Max(Math.Min(mipBlockHeightLog2, 5), 0); uint mipSize; if (Environment.Is64BitProcess) { mipSize = (uint)GetSurfaceSizeX64(widthInBlocks, heightInBlocks, depthInBlocks, (ulong)mipBlockHeight, bpp); } else { mipSize = (uint)GetSurfaceSizeX86(widthInBlocks, heightInBlocks, depthInBlocks, (uint)mipBlockHeight, bpp); } // TODO: Avoid this copy. byte[] mipData = Utils.SubArray(ImageData, arrayOffset + mipOffset, mipSize); try { if (ArrayLevel == arrayLevel && MipLevel == mipLevel && DepthLevel == depthLevel) { // The set of swizzled addresses is at least as big as the set of linear addresses. // When defined appropriately, we only require a single memory allocation for the output. byte[] result = deswizzle(width, height, depth, blkWidth, blkHeight, blkDepth, target, bpp, TileMode, mipBlockHeightLog2, mipData); return(result); } } catch (Exception e) { System.Windows.Forms.MessageBox.Show($"Failed to swizzle texture {texture.Text}!"); Console.WriteLine(e); return(new byte[0]); } mipOffset += mipSize; } arrayOffset += (uint)(ImageData.Length / texture.ArrayCount); } } return(new byte[0]); }
public static byte[] GetImageData(STGenericTexture texture, byte[] ImageData, int ArrayLevel, int MipLevel, int DepthLevel, uint BlockHeightLog2, int target = 1, bool LinearTileMode = false) { uint bpp = STGenericTexture.GetBytesPerPixel(texture.Format); uint blkWidth = STGenericTexture.GetBlockWidth(texture.Format); uint blkHeight = STGenericTexture.GetBlockHeight(texture.Format); uint blkDepth = STGenericTexture.GetBlockDepth(texture.Format); uint blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(texture.Height, blkHeight)); uint Pitch = 0; uint DataAlignment = 512; uint TileMode = 0; if (LinearTileMode) { TileMode = 1; } uint numDepth = 1; if (texture.Depth > 1) { numDepth = texture.Depth; } int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; uint ArrayOffset = 0; for (int depthLevel = 0; depthLevel < numDepth; depthLevel++) { for (int arrayLevel = 0; arrayLevel < texture.ArrayCount; arrayLevel++) { uint SurfaceSize = 0; int blockHeightShift = 0; List <uint> MipOffsets = new List <uint>(); for (int mipLevel = 0; mipLevel < texture.MipCount; mipLevel++) { uint width = (uint)Math.Max(1, texture.Width >> mipLevel); uint height = (uint)Math.Max(1, texture.Height >> mipLevel); uint depth = (uint)Math.Max(1, texture.Depth >> mipLevel); uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; Console.WriteLine($"size " + size); if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) { blockHeightShift += 1; } uint width__ = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth); uint height__ = TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight); //Calculate the mip size instead byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, DataAlignment) - SurfaceSize)]; SurfaceSize += (uint)AlignedData.Length; MipOffsets.Add(SurfaceSize); //Get the first mip offset and current one and the total image size int msize = (int)((MipOffsets[0] + ImageData.Length - MipOffsets[mipLevel]) / texture.ArrayCount); byte[] data_ = Utils.SubArray(ImageData, ArrayOffset + MipOffsets[mipLevel], (uint)msize); try { Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64); SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8); byte[] result = TegraX1Swizzle.deswizzle(width, height, depth, blkWidth, blkHeight, blkDepth, target, bpp, TileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), data_); //Create a copy and use that to remove uneeded data byte[] result_ = new byte[size]; Array.Copy(result, 0, result_, 0, size); result = null; if (ArrayLevel == arrayLevel && MipLevel == mipLevel && DepthLevel == depthLevel) { return(result_); } } catch (Exception e) { System.Windows.Forms.MessageBox.Show($"Failed to swizzle texture {texture.Text}!"); Console.WriteLine(e); return(new byte[0]); } } ArrayOffset += (uint)(ImageData.Length / texture.ArrayCount); } } return(new byte[0]); }
public static List <uint[]> GenerateMipSizes(TEX_FORMAT Format, uint Width, uint Height, uint Depth, uint SurfaceCount, uint MipCount, uint ImageSize) { List <uint[]> MipMapSizes = new List <uint[]>(); uint bpp = STGenericTexture.GetBytesPerPixel(Format); uint blkWidth = STGenericTexture.GetBlockWidth(Format); uint blkHeight = STGenericTexture.GetBlockHeight(Format); uint blkDepth = STGenericTexture.GetBlockDepth(Format); uint blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(Height, blkHeight)); uint BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; uint Pitch = 0; uint DataAlignment = 512; int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; uint ArrayCount = SurfaceCount; uint ArrayOffset = 0; for (int arrayLevel = 0; arrayLevel < ArrayCount; arrayLevel++) { uint SurfaceSize = 0; int blockHeightShift = 0; uint[] MipOffsets = new uint[MipCount]; for (int mipLevel = 0; mipLevel < MipCount; mipLevel++) { uint width = (uint)Math.Max(1, Width >> mipLevel); uint height = (uint)Math.Max(1, Height >> mipLevel); uint depth = (uint)Math.Max(1, Depth >> mipLevel); uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) { blockHeightShift += 1; } uint width__ = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth); uint height__ = TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight); //Calculate the mip size instead byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, DataAlignment) - SurfaceSize)]; SurfaceSize += (uint)AlignedData.Length; MipOffsets[mipLevel] = (SurfaceSize); //Get the first mip offset and current one and the total image size int msize = (int)((MipOffsets[0] + ImageSize - MipOffsets[mipLevel]) / ArrayCount); Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64); SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8); } ArrayOffset += (uint)(ImageSize / ArrayCount); MipMapSizes.Add(MipOffsets); } return(MipMapSizes); }
public static List <byte[]> SwizzleSurfaceMipMaps(Texture tex, byte[] data, uint MipCount) { var TexFormat = TextureData.ConvertFormat(tex.Format); int blockHeightShift = 0; int target = 1; uint Pitch = 0; uint SurfaceSize = 0; uint blockHeight = 0; uint blkWidth = STGenericTexture.GetBlockWidth(TexFormat); uint blkHeight = STGenericTexture.GetBlockHeight(TexFormat); uint blkDepth = STGenericTexture.GetBlockDepth(TexFormat); uint bpp = STGenericTexture.GetBytesPerPixel(TexFormat); uint linesPerBlockHeight = 0; if (tex.TileMode == TileMode.LinearAligned) { blockHeight = 1; tex.BlockHeightLog2 = 0; tex.Alignment = 1; linesPerBlockHeight = 1; tex.ReadTextureLayout = 0; } else { blockHeight = TegraX1Swizzle.GetBlockHeight(DIV_ROUND_UP(tex.Height, blkHeight)); tex.BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; tex.Alignment = 512; tex.ReadTextureLayout = 1; linesPerBlockHeight = blockHeight * 8; } List <byte[]> mipmaps = new List <byte[]>(); for (int mipLevel = 0; mipLevel < MipCount; mipLevel++) { var result = TextureHelper.GetCurrentMipSize(tex.Width, tex.Height, blkWidth, blkHeight, bpp, mipLevel); uint offset = result.Item1; uint size = result.Item2; byte[] data_ = Utils.SubArray(data, offset, size); uint width_ = Math.Max(1, tex.Width >> mipLevel); uint height_ = Math.Max(1, tex.Height >> mipLevel); uint depth_ = Math.Max(1, tex.Depth >> mipLevel); uint width__ = DIV_ROUND_UP(width_, blkWidth); uint height__ = DIV_ROUND_UP(height_, blkHeight); uint depth__ = DIV_ROUND_UP(depth_, blkDepth); byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, (uint)tex.Alignment) - SurfaceSize)]; SurfaceSize += (uint)AlignedData.Length; // Console.WriteLine("SurfaceSize Aligned " + AlignedData); Console.WriteLine("MipOffsets " + SurfaceSize); Console.WriteLine("size " + size); tex.MipOffsets[mipLevel] = SurfaceSize; if (tex.TileMode == TileMode.LinearAligned) { Pitch = width__ * bpp; if (target == 1) { Pitch = TegraX1Swizzle.round_up(width__ * bpp, 32); } SurfaceSize += Pitch * height__; } else { if (TegraX1Swizzle.pow2_round_up(height__) < linesPerBlockHeight) { blockHeightShift += 1; } Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64); SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8); } byte[] SwizzledData = TegraX1Swizzle.swizzle(width_, height_, depth_, blkWidth, blkHeight, blkDepth, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), data_); mipmaps.Add(AlignedData.Concat(SwizzledData).ToArray()); } tex.ImageSize = SurfaceSize; return(mipmaps); }
List <byte[]> SwizzleSurfaceMipMaps(STGenericTexture tex, byte[] data, uint MipCount) { int blockHeightShift = 0; int target = 1; uint Pitch = 0; uint SurfaceSize = 0; uint blockHeight = 0; uint blkWidth = tex.GetBlockWidth(); uint blkHeight = tex.GetBlockHeight(); uint blkDepth = tex.GetBlockDepth(); uint bpp = tex.GetBytesPerPixel(); MipOffsets = new uint[MipCount]; uint linesPerBlockHeight = 0; if (LinearMode) { blockHeight = 1; BlockHeightLog2 = 0; Alignment = 1; linesPerBlockHeight = 1; ReadTextureLayout = 0; } else { blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(tex.Height, blkHeight)); BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; Alignment = 512; ReadTextureLayout = 1; linesPerBlockHeight = blockHeight * 8; } List <byte[]> mipmaps = new List <byte[]>(); for (int mipLevel = 0; mipLevel < MipCount; mipLevel++) { var result = WiiU.TextureHelper.GetCurrentMipSize(tex.Width, tex.Height, blkWidth, blkHeight, bpp, mipLevel); uint offset = result.Item1; uint size = result.Item2; byte[] data_ = ByteUtils.SubArray(data, offset, size); uint width_ = Math.Max(1, tex.Width >> mipLevel); uint height_ = Math.Max(1, tex.Height >> mipLevel); uint depth_ = Math.Max(1, tex.Depth >> mipLevel); uint width__ = TegraX1Swizzle.DIV_ROUND_UP(width_, blkWidth); uint height__ = TegraX1Swizzle.DIV_ROUND_UP(height_, blkHeight); uint depth__ = TegraX1Swizzle.DIV_ROUND_UP(depth_, blkDepth); byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, Alignment) - SurfaceSize)]; SurfaceSize += (uint)AlignedData.Length; ImageSize = 0; MipOffsets[mipLevel] = SurfaceSize; if (LinearMode) { Pitch = width__ * bpp; if (target == 1) { Pitch = TegraX1Swizzle.round_up(width__ * bpp, 32); } SurfaceSize += Pitch * height__; } else { if (TegraX1Swizzle.pow2_round_up(height__) < linesPerBlockHeight) { blockHeightShift += 1; } Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64); SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8); } byte[] SwizzledData = TegraX1Swizzle.swizzle(width_, height_, depth_, blkWidth, blkHeight, blkDepth, target, bpp, (uint)TileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), data_); mipmaps.Add(AlignedData.Concat(SwizzledData).ToArray()); } ImageSize = SurfaceSize; return(mipmaps); }