 cda659955c
			
		
	
	
		cda659955c
		
			
		
	
	
	
	
		
			
			* Initial test for texture sync * WIP new texture flushing setup * Improve rules for incompatible overlaps Fixes a lot of issues with Unreal Engine games. Still a few minor issues (some caused by dma fast path?) Needs docs and cleanup. * Cleanup, improvements Improve rules for fast DMA * Small tweak to group together flushes of overlapping handles. * Fixes, flush overlapping texture data for ASTC and BC4/5 compressed textures. Fixes the new Life is Strange game. * Flush overlaps before init data, fix 3d texture size/overlap stuff * Fix 3D Textures, faster single layer flush Note: nosy people can no longer merge this with Vulkan. (unless they are nosy enough to implement the new backend methods) * Remove unused method * Minor cleanup * More cleanup * Use the More Fun and Hopefully No Driver Bugs method for getting compressed tex too This one's for metro * Address feedback, ASTC+ETC to FormatClass * Change offset to use Span slice rather than IntPtr Add * Fix this too
		
			
				
	
	
		
			287 lines
		
	
	
		
			No EOL
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			No EOL
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Ryujinx.Common;
 | |
| using System;
 | |
| 
 | |
| using static Ryujinx.Graphics.Texture.BlockLinearConstants;
 | |
| 
 | |
| namespace Ryujinx.Graphics.Texture
 | |
| {
 | |
|     public static class SizeCalculator
 | |
|     {
 | |
|         private const int StrideAlignment = 32;
 | |
| 
 | |
|         private static int Calculate3DOffsetCount(int levels, int depth)
 | |
|         {
 | |
|             int offsetCount = depth;
 | |
| 
 | |
|             while (--levels > 0)
 | |
|             {
 | |
|                 depth = Math.Max(1, depth >> 1);
 | |
|                 offsetCount += depth;
 | |
|             }
 | |
| 
 | |
|             return offsetCount;
 | |
|         }
 | |
| 
 | |
|         public static SizeInfo GetBlockLinearTextureSize(
 | |
|             int width,
 | |
|             int height,
 | |
|             int depth,
 | |
|             int levels,
 | |
|             int layers,
 | |
|             int blockWidth,
 | |
|             int blockHeight,
 | |
|             int bytesPerPixel,
 | |
|             int gobBlocksInY,
 | |
|             int gobBlocksInZ,
 | |
|             int gobBlocksInTileX,
 | |
|             int gpuLayerSize = 0)
 | |
|         {
 | |
|             bool is3D = depth > 1;
 | |
| 
 | |
|             int layerSize = 0;
 | |
| 
 | |
|             int[] allOffsets = new int[is3D ? Calculate3DOffsetCount(levels, depth) : levels * layers * depth];
 | |
|             int[] mipOffsets = new int[levels];
 | |
|             int[] sliceSizes = new int[levels];
 | |
|             int[] levelSizes = new int[levels];
 | |
| 
 | |
|             int mipGobBlocksInY = gobBlocksInY;
 | |
|             int mipGobBlocksInZ = gobBlocksInZ;
 | |
| 
 | |
|             int gobWidth  = (GobStride / bytesPerPixel) * gobBlocksInTileX;
 | |
|             int gobHeight = gobBlocksInY * GobHeight;
 | |
| 
 | |
|             int depthLevelOffset = 0;
 | |
| 
 | |
|             for (int level = 0; level < levels; level++)
 | |
|             {
 | |
|                 int w = Math.Max(1, width  >> level);
 | |
|                 int h = Math.Max(1, height >> level);
 | |
|                 int d = Math.Max(1, depth  >> level);
 | |
| 
 | |
|                 w = BitUtils.DivRoundUp(w, blockWidth);
 | |
|                 h = BitUtils.DivRoundUp(h, blockHeight);
 | |
| 
 | |
|                 while (h <= (mipGobBlocksInY >> 1) * GobHeight && mipGobBlocksInY != 1)
 | |
|                 {
 | |
|                     mipGobBlocksInY >>= 1;
 | |
|                 }
 | |
| 
 | |
|                 while (d <= (mipGobBlocksInZ >> 1) && mipGobBlocksInZ != 1)
 | |
|                 {
 | |
|                     mipGobBlocksInZ >>= 1;
 | |
|                 }
 | |
| 
 | |
|                 int widthInGobs = BitUtils.DivRoundUp(w * bytesPerPixel, GobStride);
 | |
| 
 | |
|                 int alignment = gobBlocksInTileX;
 | |
| 
 | |
|                 if (d < gobBlocksInZ || w <= gobWidth || h <= gobHeight)
 | |
|                 {
 | |
|                     alignment = 1;
 | |
|                 }
 | |
| 
 | |
|                 widthInGobs = BitUtils.AlignUp(widthInGobs, alignment);
 | |
| 
 | |
|                 int totalBlocksOfGobsInZ = BitUtils.DivRoundUp(d, mipGobBlocksInZ);
 | |
|                 int totalBlocksOfGobsInY = BitUtils.DivRoundUp(BitUtils.DivRoundUp(h, GobHeight), mipGobBlocksInY);
 | |
| 
 | |
|                 int robSize = widthInGobs * mipGobBlocksInY * mipGobBlocksInZ * GobSize;
 | |
| 
 | |
|                 if (is3D)
 | |
|                 {
 | |
|                     int gobSize = mipGobBlocksInY * GobSize;
 | |
| 
 | |
|                     int sliceSize = totalBlocksOfGobsInY * widthInGobs * gobSize;
 | |
| 
 | |
|                     int baseOffset = layerSize;
 | |
| 
 | |
|                     int mask = gobBlocksInZ - 1;
 | |
| 
 | |
|                     for (int z = 0; z < d; z++)
 | |
|                     {
 | |
|                         int zLow  = z &  mask;
 | |
|                         int zHigh = z & ~mask;
 | |
| 
 | |
|                         allOffsets[z + depthLevelOffset] = baseOffset + zLow * gobSize + zHigh * sliceSize;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 mipOffsets[level] = layerSize;
 | |
|                 sliceSizes[level] = totalBlocksOfGobsInY * robSize;
 | |
|                 levelSizes[level] = totalBlocksOfGobsInZ * sliceSizes[level];
 | |
| 
 | |
|                 layerSize += levelSizes[level];
 | |
| 
 | |
|                 depthLevelOffset += d;
 | |
|             }
 | |
| 
 | |
|             if (layers > 1)
 | |
|             {
 | |
|                 layerSize = AlignLayerSize(
 | |
|                     layerSize,
 | |
|                     height,
 | |
|                     depth,
 | |
|                     blockHeight,
 | |
|                     gobBlocksInY,
 | |
|                     gobBlocksInZ,
 | |
|                     gobBlocksInTileX);
 | |
|             }
 | |
| 
 | |
|             int totalSize;
 | |
| 
 | |
|             if (layerSize < gpuLayerSize)
 | |
|             {
 | |
|                 totalSize = (layers - 1) * gpuLayerSize + layerSize;
 | |
|                 layerSize = gpuLayerSize;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 totalSize = layerSize * layers;
 | |
|             }
 | |
| 
 | |
|             if (!is3D)
 | |
|             {
 | |
|                 for (int layer = 0; layer < layers; layer++)
 | |
|                 {
 | |
|                     int baseIndex  = layer * levels;
 | |
|                     int baseOffset = layer * layerSize;
 | |
| 
 | |
|                     for (int level = 0; level < levels; level++)
 | |
|                     {
 | |
|                         allOffsets[baseIndex + level] = baseOffset + mipOffsets[level];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return new SizeInfo(mipOffsets, allOffsets, sliceSizes, levelSizes, depth, levels, layerSize, totalSize, is3D);
 | |
|         }
 | |
| 
 | |
|         public static SizeInfo GetLinearTextureSize(int stride, int height, int blockHeight)
 | |
|         {
 | |
|             // Non-2D or mipmapped linear textures are not supported by the Switch GPU,
 | |
|             // so we only need to handle a single case (2D textures without mipmaps).
 | |
|             int totalSize = stride * BitUtils.DivRoundUp(height, blockHeight);
 | |
| 
 | |
|             return new SizeInfo(totalSize);
 | |
|         }
 | |
| 
 | |
|         private static int AlignLayerSize(
 | |
|             int size,
 | |
|             int height,
 | |
|             int depth,
 | |
|             int blockHeight,
 | |
|             int gobBlocksInY,
 | |
|             int gobBlocksInZ,
 | |
|             int gobBlocksInTileX)
 | |
|         {
 | |
|             if (gobBlocksInTileX < 2)
 | |
|             {
 | |
|                 height = BitUtils.DivRoundUp(height, blockHeight);
 | |
| 
 | |
|                 while (height <= (gobBlocksInY >> 1) * GobHeight && gobBlocksInY != 1)
 | |
|                 {
 | |
|                     gobBlocksInY >>= 1;
 | |
|                 }
 | |
| 
 | |
|                 while (depth <= (gobBlocksInZ >> 1) && gobBlocksInZ != 1)
 | |
|                 {
 | |
|                     gobBlocksInZ >>= 1;
 | |
|                 }
 | |
| 
 | |
|                 int blockOfGobsSize = gobBlocksInY * gobBlocksInZ * GobSize;
 | |
| 
 | |
|                 int sizeInBlockOfGobs = size / blockOfGobsSize;
 | |
| 
 | |
|                 if (size != sizeInBlockOfGobs * blockOfGobsSize)
 | |
|                 {
 | |
|                     size = (sizeInBlockOfGobs + 1) * blockOfGobsSize;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 int alignment = (gobBlocksInTileX * GobSize) * gobBlocksInY * gobBlocksInZ;
 | |
| 
 | |
|                 size = BitUtils.AlignUp(size, alignment);
 | |
|             }
 | |
| 
 | |
|             return size;
 | |
|         }
 | |
| 
 | |
|         public static Size GetBlockLinearAlignedSize(
 | |
|             int width,
 | |
|             int height,
 | |
|             int depth,
 | |
|             int blockWidth,
 | |
|             int blockHeight,
 | |
|             int bytesPerPixel,
 | |
|             int gobBlocksInY,
 | |
|             int gobBlocksInZ,
 | |
|             int gobBlocksInTileX)
 | |
|         {
 | |
|             width  = BitUtils.DivRoundUp(width,  blockWidth);
 | |
|             height = BitUtils.DivRoundUp(height, blockHeight);
 | |
| 
 | |
|             int gobWidth  = (GobStride / bytesPerPixel) * gobBlocksInTileX;
 | |
|             int gobHeight = gobBlocksInY * GobHeight;
 | |
| 
 | |
|             int alignment = gobWidth;
 | |
| 
 | |
|             if (depth < gobBlocksInZ || width <= gobWidth || height <= gobHeight)
 | |
|             {
 | |
|                 alignment = GobStride / bytesPerPixel;
 | |
|             }
 | |
| 
 | |
|             // Height has already been divided by block height, so pass it as 1.
 | |
|             (gobBlocksInY, gobBlocksInZ) = GetMipGobBlockSizes(height, depth, 1, gobBlocksInY, gobBlocksInZ);
 | |
| 
 | |
|             int blockOfGobsHeight = gobBlocksInY * GobHeight;
 | |
|             int blockOfGobsDepth  = gobBlocksInZ;
 | |
| 
 | |
|             width  = BitUtils.AlignUp(width,  alignment);
 | |
|             height = BitUtils.AlignUp(height, blockOfGobsHeight);
 | |
|             depth  = BitUtils.AlignUp(depth,  blockOfGobsDepth);
 | |
| 
 | |
|             return new Size(width, height, depth);
 | |
|         }
 | |
| 
 | |
|         public static Size GetLinearAlignedSize(
 | |
|             int width,
 | |
|             int height,
 | |
|             int blockWidth,
 | |
|             int blockHeight,
 | |
|             int bytesPerPixel)
 | |
|         {
 | |
|             width  = BitUtils.DivRoundUp(width,  blockWidth);
 | |
|             height = BitUtils.DivRoundUp(height, blockHeight);
 | |
| 
 | |
|             int widthAlignment = StrideAlignment / bytesPerPixel;
 | |
| 
 | |
|             width = BitUtils.AlignUp(width, widthAlignment);
 | |
| 
 | |
|             return new Size(width, height, 1);
 | |
|         }
 | |
| 
 | |
|         public static (int, int) GetMipGobBlockSizes(
 | |
|             int height,
 | |
|             int depth,
 | |
|             int blockHeight,
 | |
|             int gobBlocksInY,
 | |
|             int gobBlocksInZ)
 | |
|         {
 | |
|             height = BitUtils.DivRoundUp(height, blockHeight);
 | |
| 
 | |
|             while (height <= (gobBlocksInY >> 1) * GobHeight && gobBlocksInY != 1)
 | |
|             {
 | |
|                 gobBlocksInY >>= 1;
 | |
|             }
 | |
| 
 | |
|             while (depth <= (gobBlocksInZ >> 1) && gobBlocksInZ != 1)
 | |
|             {
 | |
|                 gobBlocksInZ >>= 1;
 | |
|             }
 | |
| 
 | |
|             return (gobBlocksInY, gobBlocksInZ);
 | |
|         }
 | |
|     }
 | |
| } |