/// <summary> /// Untile surface. The input dimensions must be in terms of blocks. /// </summary> /// <param name="width">Width of the surface in blocks</param> /// <param name="height">Height of the surface in blocks</param> /// <param name="rowPitch">Size in bytes of a row of pixels in the destination image</param> /// <param name="point">Offset in the surface</param> /// <param name="source">Source data</param> /// <param name="texelPitch">Size in bytes of a block</param> /// <param name="rect">Image rectangle to untile</param> /// <returns></returns> private static byte[] UntileSurface(uint width, uint height, uint rowPitch, XGPOINT point, byte[] source, uint texelPitch, D3DBOX rect) { uint nBlocksWidth = rect.Right - rect.Left; uint nBlocksHeight = rect.Bottom - rect.Top; uint alignedWidth = (width + 31) & ~31u; uint alignedHeight = (height + 31) & ~31u; uint totalSize = AlignToPage(alignedWidth * alignedHeight); // may not be necessary on PC byte[] result = new byte[totalSize]; uint v12 = 16 / texelPitch; uint logBpp = XGLog2LE16(texelPitch); // log bytes per pixel uint v14 = (~(v12 - 1u) & (rect.Left + v12)) - rect.Left; // v12 - (rect.Left) % v12 uint v42 = (~(v12 - 1u) & (rect.Left + nBlocksWidth)) - rect.Left; // nBlocksWidth - (rect.Left + nBlocksWidth) % v12 //int x = XGAddress2DTiledX(offset, xChunks, texPitch); //int y = XGAddress2DTiledY(offset, xChunks, texPitch); //int sourceIndex = ((i * xChunks) * texPitch) + (j * texPitch); //int destinationIndex = ((y * xChunks) * texPitch) + (x * texPitch); for (uint yBlockIndex = 0; yBlockIndex < nBlocksHeight; yBlockIndex++) { uint v38 = alignedWidth >> 5; uint _y = yBlockIndex + rect.Top; uint v47 = v38 * (_y >> 5); uint v44 = (_y >> 4) & 1; uint yBlockOffset = (uint)point.Y; uint v17 = (_y >> 3) & 1; uint v46 = 16 * (_y & 1); uint v45 = 2 * v17; uint v19 = rect.Left; uint v18 = 4 * (_y & 6); uint v52 = v17 << (int)(logBpp + 6); uint heightOffset = rowPitch * (yBlockIndex + yBlockOffset); { uint v30 = rect.Left; uint v31 = (v44 + 2 * ((v45 + (byte)(v19 >> 3)) & 3)); uint micro = (v18 + (v30 & 7)) << (int)(logBpp + 6); uint v32 = v46 + v52 + ((micro >> 6) & 0xF) + 2 * (((micro >> 6) & ~0xFu) + (((v47 + (v19 >> 5)) << (int)(logBpp + 6)) & 0x1FFFFFFF)); uint v28 = ((v32 >> 6) & 7) + 8 * (v31 & 1); var v37a = v14; if (v37a > nBlocksWidth) { v37a = nBlocksWidth; } uint sourceOffset = 8 * ((v32 & ~0x1FFu) + 4 * ((v31 & ~1u) + 8 * v28)) + (v32 & 0x3F); uint destinationOffset = heightOffset + ((uint)point.X << (int)logBpp); uint blockSize = v37a; Array.Copy(source, sourceOffset, result, destinationOffset, blockSize); } uint x = v14; uint v48 = v14; while (x < v42) { uint v30 = x + rect.Left; uint v31 = v44 + 2 * ((v45 + (byte)(v30 >> 3)) & 3); uint v25 = (v18 + (v30 & 7)) << (int)(logBpp + 6); uint v32 = v46 + v52 + ((v25 >> 6) & 0xF) + 2 * (((v25 >> 6) & ~0xFu) + (((v47 + (v30 >> 5)) << (int)(logBpp + 6)) & 0x1FFFFFFF)); uint v28 = ((v32 >> 6) & 7) + 8 * (v31 & 1); uint sourceOffset = 8 * ((v32 & ~0x1FFu) + 4 * ((v31 & ~1u) + 8 * v28)) + (v32 & 0x3F); uint destinationOffset = heightOffset + ((v48 + (uint)point.X) << (int)logBpp); uint blockSize = v12 << (int)logBpp; Array.Copy(source, sourceOffset, result, destinationOffset, blockSize); x += v12; } if (x < nBlocksWidth) { uint v30 = x + rect.Left; uint v31 = v44 + 2 * ((v45 + (byte)(v30 >> 3)) & 3); uint v25 = (v18 + (v30 & 7)) << (int)(logBpp + 6); uint v32 = v46 + v52 + ((v25 >> 6) & 0xF) + 2 * (((v25 >> 6) & ~0xFu) + (((v47 + (v30 >> 5)) << (int)(logBpp + 6)) & 0x1FFFFFFF)); uint v28 = ((v32 >> 6) & 7) + 8 * (v31 & 1); uint sourceOffset = 8 * ((v32 & ~0x1FFu) + 4 * ((v31 & ~1u) + 8 * v28)) + (v32 & 0x3F); uint destinationOffset = heightOffset + ((v48 + (uint)point.X) << (int)logBpp); uint blockSize = (nBlocksWidth - v48) << (int)logBpp; Array.Copy(source, sourceOffset, result, destinationOffset, blockSize); } } return(result); }
public static byte[] XGUntileTextureLevel(uint width, uint height, uint level, TextureFormat format, XGTILE flags, uint rowPitch, XGPOINT point, byte[] source, D3DBOX box) { uint width_as_blocks; uint height_as_blocks; uint texelPitch; uint blockWidth = 0; uint blockHeight = 0; XGGetBlockDimensions(format, out blockWidth, out blockHeight); int blockLogWidth = (int)Log2Floor((int)blockWidth); int blockLogHeight = (int)Log2Floor((int)blockHeight); var bitsPerPixel = XGBitsPerPixelFromGpuFormat(format); texelPitch = (bitsPerPixel << (blockLogWidth + blockLogHeight)) >> 3; // also bytes per block int borderSize = flags.HasFlag(XGTILE.XGTILE_BORDER) ? 2 : 0; int hasBorder = flags.HasFlag(XGTILE.XGTILE_BORDER) ? 1 : 0; if (level > 0) { int nextPowerOfTwoWidth = 1 << (hasBorder - (int)Log2Ceiling((int)(width - borderSize - 1))) >> (int)level; int nextPowerOfTwoHeight = 1 << (hasBorder - (int)Log2Ceiling((int)(height - borderSize - 1))) >> (int)level; if (nextPowerOfTwoWidth <= 1) { nextPowerOfTwoWidth = 1; } if (nextPowerOfTwoHeight <= 1) { nextPowerOfTwoHeight = 1; } width_as_blocks = (uint)(nextPowerOfTwoWidth + blockWidth - 1) >> blockLogWidth; height_as_blocks = (uint)(nextPowerOfTwoHeight + blockHeight - 1) >> blockLogHeight; } else { width_as_blocks = (width + blockWidth - 1) >> blockLogWidth; height_as_blocks = (height + blockHeight - 1) >> blockLogHeight; } // update point to be in terms of the block width and height if (point != null) { point.X >>= blockLogWidth; point.Y >>= blockLogWidth; } else { point = new XGPOINT(); point.X = 0; point.Y = 0; } // update box bounds to be in terms of the block width and height if (box != null) { box.Left >>= blockLogWidth; box.Right = (box.Right + blockWidth - 1) >> blockLogWidth; box.Top >>= blockLogHeight; box.Bottom = (box.Bottom + blockHeight - 1) >> blockLogHeight; } else { box = new D3DBOX(); box.Left = 0; box.Top = 0; var tempWidth = (width - borderSize) >> (int)level; if (tempWidth <= 1) { tempWidth = 1; } box.Right = (uint)(tempWidth + blockWidth - 1) >> blockLogWidth; var tempHeight = (height - borderSize) >> (int)level; if (tempHeight <= 1) { tempHeight = 1; } box.Bottom = (uint)(tempHeight + blockHeight - 1) >> blockLogHeight; } if (!flags.HasFlag(XGTILE.XGTILE_NONPACKED)) { XGPOINT offset = new XGPOINT(); // need to understand the return value and modify the byte[] var offsetInByteArray = GetMipTailLevelOffsetCoords(width, height, 1, level, format, true, flags.HasFlag(XGTILE.XGTILE_BORDER), offset); box.Top += (uint)offset.Y; box.Bottom += (uint)offset.Y; box.Left += (uint)offset.X; box.Right += (uint)offset.X; } return(UntileSurface(width_as_blocks, height_as_blocks, rowPitch, point, source, texelPitch, box)); }