|
|
|
|
|
|
using UnityEditor; |
|
|
|
#endif
|
|
|
|
|
|
|
|
public class TextureCache2D : TextureCache |
|
|
|
namespace UnityEngine.Experimental.Rendering |
|
|
|
private Texture2DArray m_Cache; |
|
|
|
|
|
|
|
public override void TransferToSlice(int sliceIndex, Texture texture) |
|
|
|
public class TextureCache2D : TextureCache |
|
|
|
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height); |
|
|
|
private Texture2DArray m_Cache; |
|
|
|
if (texture is Texture2D) |
|
|
|
public override void TransferToSlice(int sliceIndex, Texture texture) |
|
|
|
mismatch |= (m_Cache.format != (texture as Texture2D).format); |
|
|
|
} |
|
|
|
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height); |
|
|
|
if (mismatch) |
|
|
|
{ |
|
|
|
if (!Graphics.ConvertTexture(texture, 0, m_Cache, sliceIndex)) |
|
|
|
if (texture is Texture2D) |
|
|
|
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})", |
|
|
|
texture.name, m_Cache.width, m_Cache.height, m_Cache.format); |
|
|
|
mismatch |= (m_Cache.format != (texture as Texture2D).format); |
|
|
|
} |
|
|
|
|
|
|
|
if (mismatch) |
|
|
|
{ |
|
|
|
if (!Graphics.ConvertTexture(texture, 0, m_Cache, sliceIndex)) |
|
|
|
{ |
|
|
|
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})", |
|
|
|
texture.name, m_Cache.width, m_Cache.height, m_Cache.format); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Graphics.CopyTexture(texture, 0, m_Cache, sliceIndex); |
|
|
|
else |
|
|
|
|
|
|
|
public override Texture GetTexCache() |
|
|
|
Graphics.CopyTexture(texture, 0, m_Cache, sliceIndex); |
|
|
|
return m_Cache; |
|
|
|
} |
|
|
|
|
|
|
|
public bool AllocTextureArray(int numTextures, int width, int height, TextureFormat format, bool isMipMapped) |
|
|
|
{ |
|
|
|
var res = AllocTextureArray(numTextures); |
|
|
|
m_NumMipLevels = GetNumMips(width, height); |
|
|
|
public override Texture GetTexCache() |
|
|
|
{ |
|
|
|
return m_Cache; |
|
|
|
} |
|
|
|
m_Cache = new Texture2DArray(width, height, numTextures, format, isMipMapped) |
|
|
|
{ |
|
|
|
hideFlags = HideFlags.HideAndDontSave, |
|
|
|
wrapMode = TextureWrapMode.Clamp |
|
|
|
}; |
|
|
|
public bool AllocTextureArray(int numTextures, int width, int height, TextureFormat format, bool isMipMapped) |
|
|
|
{ |
|
|
|
var res = AllocTextureArray(numTextures); |
|
|
|
m_NumMipLevels = GetNumMips(width, height); |
|
|
|
return res; |
|
|
|
} |
|
|
|
m_Cache = new Texture2DArray(width, height, numTextures, format, isMipMapped) |
|
|
|
public void Release() |
|
|
|
hideFlags = HideFlags.HideAndDontSave, |
|
|
|
wrapMode = TextureWrapMode.Clamp |
|
|
|
}; |
|
|
|
|
|
|
|
return res; |
|
|
|
Texture.DestroyImmediate(m_Cache); // do I need this?
|
|
|
|
} |
|
|
|
public void Release() |
|
|
|
public class TextureCacheCubemap : TextureCache |
|
|
|
Texture.DestroyImmediate(m_Cache); // do I need this?
|
|
|
|
} |
|
|
|
} |
|
|
|
private CubemapArray m_Cache; |
|
|
|
public class TextureCacheCubemap : TextureCache |
|
|
|
{ |
|
|
|
private CubemapArray m_Cache; |
|
|
|
// the member variables below are only in use when TextureCache.supportsCubemapArrayTextures is false
|
|
|
|
private Texture2DArray m_CacheNoCubeArray; |
|
|
|
private RenderTexture[] m_StagingRTs; |
|
|
|
private int m_NumPanoMipLevels; |
|
|
|
private Material m_CubeBlitMaterial; |
|
|
|
private int m_CubeMipLevelPropName; |
|
|
|
private int m_cubeSrcTexPropName; |
|
|
|
// the member variables below are only in use when TextureCache.supportsCubemapArrayTextures is false
|
|
|
|
private Texture2DArray m_CacheNoCubeArray; |
|
|
|
private RenderTexture[] m_StagingRTs; |
|
|
|
private int m_NumPanoMipLevels; |
|
|
|
private Material m_CubeBlitMaterial; |
|
|
|
private int m_CubeMipLevelPropName; |
|
|
|
private int m_cubeSrcTexPropName; |
|
|
|
|
|
|
|
public override void TransferToSlice(int sliceIndex, Texture texture) |
|
|
|
{ |
|
|
|
if(!TextureCache.supportsCubemapArrayTextures) |
|
|
|
TransferToPanoCache(sliceIndex, texture); |
|
|
|
else |
|
|
|
public override void TransferToSlice(int sliceIndex, Texture texture) |
|
|
|
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height); |
|
|
|
|
|
|
|
if (texture is Cubemap) |
|
|
|
if(!TextureCache.supportsCubemapArrayTextures) |
|
|
|
TransferToPanoCache(sliceIndex, texture); |
|
|
|
else |
|
|
|
mismatch |= (m_Cache.format != (texture as Cubemap).format); |
|
|
|
} |
|
|
|
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height); |
|
|
|
if (mismatch) |
|
|
|
{ |
|
|
|
bool failed = false; |
|
|
|
if (texture is Cubemap) |
|
|
|
{ |
|
|
|
mismatch |= (m_Cache.format != (texture as Cubemap).format); |
|
|
|
} |
|
|
|
for (int f = 0; f < 6; f++) |
|
|
|
if (mismatch) |
|
|
|
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f)) |
|
|
|
bool failed = false; |
|
|
|
|
|
|
|
for (int f = 0; f < 6; f++) |
|
|
|
failed = true; |
|
|
|
break; |
|
|
|
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f)) |
|
|
|
{ |
|
|
|
failed = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (failed) |
|
|
|
if (failed) |
|
|
|
{ |
|
|
|
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})", |
|
|
|
texture.name, m_Cache.width, m_Cache.height, m_Cache.format); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})", |
|
|
|
texture.name, m_Cache.width, m_Cache.height, m_Cache.format); |
|
|
|
for (int f = 0; f < 6; f++) |
|
|
|
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f); |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int f = 0; f < 6; f++) |
|
|
|
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f); |
|
|
|
} |
|
|
|
} |
|
|
|
public override Texture GetTexCache() |
|
|
|
{ |
|
|
|
return !TextureCache.supportsCubemapArrayTextures ? (Texture) m_CacheNoCubeArray : m_Cache; |
|
|
|
} |
|
|
|
public override Texture GetTexCache() |
|
|
|
{ |
|
|
|
return !TextureCache.supportsCubemapArrayTextures ? (Texture) m_CacheNoCubeArray : m_Cache; |
|
|
|
} |
|
|
|
public bool AllocTextureArray(int numCubeMaps, int width, TextureFormat format, bool isMipMapped) |
|
|
|
{ |
|
|
|
var res = AllocTextureArray(numCubeMaps); |
|
|
|
m_NumMipLevels = GetNumMips(width, width); // will calculate same way whether we have cube array or not
|
|
|
|
public bool AllocTextureArray(int numCubeMaps, int width, TextureFormat format, bool isMipMapped) |
|
|
|
{ |
|
|
|
var res = AllocTextureArray(numCubeMaps); |
|
|
|
m_NumMipLevels = GetNumMips(width, width); // will calculate same way whether we have cube array or not
|
|
|
|
if(!TextureCache.supportsCubemapArrayTextures) |
|
|
|
{ |
|
|
|
if(!m_CubeBlitMaterial) m_CubeBlitMaterial = new Material(Shader.Find("Hidden/CubeToPano")); |
|
|
|
if(!TextureCache.supportsCubemapArrayTextures) |
|
|
|
{ |
|
|
|
if(!m_CubeBlitMaterial) m_CubeBlitMaterial = new Material(Shader.Find("Hidden/CubeToPano")); |
|
|
|
int panoWidthTop = 4*width; |
|
|
|
int panoHeightTop = 2*width; |
|
|
|
int panoWidthTop = 4*width; |
|
|
|
int panoHeightTop = 2*width; |
|
|
|
|
|
|
|
// create panorama 2D array. Hardcoding the render target for now. No convenient way atm to
|
|
|
|
// map from TextureFormat to RenderTextureFormat and don't want to deal with sRGB issues for now.
|
|
|
|
m_CacheNoCubeArray = new Texture2DArray(panoWidthTop, panoHeightTop, numCubeMaps, TextureFormat.RGBAHalf, isMipMapped) |
|
|
|
{ |
|
|
|
hideFlags = HideFlags.HideAndDontSave, |
|
|
|
wrapMode = TextureWrapMode.Repeat, |
|
|
|
wrapModeV = TextureWrapMode.Clamp, |
|
|
|
filterMode = FilterMode.Trilinear, |
|
|
|
anisoLevel = 0 |
|
|
|
}; |
|
|
|
// create panorama 2D array. Hardcoding the render target for now. No convenient way atm to
|
|
|
|
// map from TextureFormat to RenderTextureFormat and don't want to deal with sRGB issues for now.
|
|
|
|
m_CacheNoCubeArray = new Texture2DArray(panoWidthTop, panoHeightTop, numCubeMaps, TextureFormat.RGBAHalf, isMipMapped) |
|
|
|
{ |
|
|
|
hideFlags = HideFlags.HideAndDontSave, |
|
|
|
wrapMode = TextureWrapMode.Repeat, |
|
|
|
wrapModeV = TextureWrapMode.Clamp, |
|
|
|
filterMode = FilterMode.Trilinear, |
|
|
|
anisoLevel = 0 |
|
|
|
}; |
|
|
|
m_NumPanoMipLevels = isMipMapped ? GetNumMips(panoWidthTop, panoHeightTop) : 1; |
|
|
|
m_StagingRTs = new RenderTexture[m_NumPanoMipLevels]; |
|
|
|
for(int m=0; m<m_NumPanoMipLevels; m++) |
|
|
|
{ |
|
|
|
m_StagingRTs[m] = new RenderTexture(Mathf.Max(1,panoWidthTop>>m), Mathf.Max(1,panoHeightTop>>m), 0, RenderTextureFormat.ARGBHalf); |
|
|
|
} |
|
|
|
m_NumPanoMipLevels = isMipMapped ? GetNumMips(panoWidthTop, panoHeightTop) : 1; |
|
|
|
m_StagingRTs = new RenderTexture[m_NumPanoMipLevels]; |
|
|
|
for(int m=0; m<m_NumPanoMipLevels; m++) |
|
|
|
{ |
|
|
|
m_StagingRTs[m] = new RenderTexture(Mathf.Max(1,panoWidthTop>>m), Mathf.Max(1,panoHeightTop>>m), 0, RenderTextureFormat.ARGBHalf); |
|
|
|
if(m_CubeBlitMaterial) |
|
|
|
{ |
|
|
|
m_CubeMipLevelPropName = Shader.PropertyToID("_cubeMipLvl"); |
|
|
|
m_cubeSrcTexPropName = Shader.PropertyToID("_srcCubeTexture"); |
|
|
|
} |
|
|
|
|
|
|
|
if(m_CubeBlitMaterial) |
|
|
|
else |
|
|
|
m_CubeMipLevelPropName = Shader.PropertyToID("_cubeMipLvl"); |
|
|
|
m_cubeSrcTexPropName = Shader.PropertyToID("_srcCubeTexture"); |
|
|
|
m_Cache = new CubemapArray(width, numCubeMaps, format, isMipMapped) |
|
|
|
{ |
|
|
|
hideFlags = HideFlags.HideAndDontSave, |
|
|
|
wrapMode = TextureWrapMode.Clamp, |
|
|
|
filterMode = FilterMode.Trilinear, |
|
|
|
anisoLevel = 0 // It is important to set 0 here, else unity force anisotropy filtering
|
|
|
|
}; |
|
|
|
|
|
|
|
return res; |
|
|
|
else |
|
|
|
|
|
|
|
public void Release() |
|
|
|
m_Cache = new CubemapArray(width, numCubeMaps, format, isMipMapped) |
|
|
|
if (m_CacheNoCubeArray) |
|
|
|
hideFlags = HideFlags.HideAndDontSave, |
|
|
|
wrapMode = TextureWrapMode.Clamp, |
|
|
|
filterMode = FilterMode.Trilinear, |
|
|
|
anisoLevel = 0 // It is important to set 0 here, else unity force anisotropy filtering
|
|
|
|
}; |
|
|
|
Texture.DestroyImmediate(m_CacheNoCubeArray); |
|
|
|
for(int m=0; m<m_NumPanoMipLevels; m++) |
|
|
|
{ |
|
|
|
m_StagingRTs[m].Release(); |
|
|
|
} |
|
|
|
m_StagingRTs=null; |
|
|
|
if(m_CubeBlitMaterial) Material.DestroyImmediate(m_CubeBlitMaterial); |
|
|
|
} |
|
|
|
if (m_Cache) |
|
|
|
Texture.DestroyImmediate(m_Cache); |
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
public void Release() |
|
|
|
{ |
|
|
|
if (m_CacheNoCubeArray) |
|
|
|
private void TransferToPanoCache(int sliceIndex, Texture texture) |
|
|
|
Texture.DestroyImmediate(m_CacheNoCubeArray); |
|
|
|
m_CubeBlitMaterial.SetTexture(m_cubeSrcTexPropName, texture); |
|
|
|
m_StagingRTs[m].Release(); |
|
|
|
m_CubeBlitMaterial.SetInt(m_CubeMipLevelPropName, Mathf.Min(m_NumMipLevels-1,m) ); |
|
|
|
Graphics.SetRenderTarget(m_StagingRTs[m]); |
|
|
|
Graphics.Blit(null, m_CubeBlitMaterial, 0); |
|
|
|
m_StagingRTs=null; |
|
|
|
if(m_CubeBlitMaterial) Material.DestroyImmediate(m_CubeBlitMaterial); |
|
|
|
} |
|
|
|
if (m_Cache) |
|
|
|
Texture.DestroyImmediate(m_Cache); |
|
|
|
} |
|
|
|
private void TransferToPanoCache(int sliceIndex, Texture texture) |
|
|
|
{ |
|
|
|
m_CubeBlitMaterial.SetTexture(m_cubeSrcTexPropName, texture); |
|
|
|
for(int m=0; m<m_NumPanoMipLevels; m++) |
|
|
|
{ |
|
|
|
m_CubeBlitMaterial.SetInt(m_CubeMipLevelPropName, Mathf.Min(m_NumMipLevels-1,m) ); |
|
|
|
Graphics.SetRenderTarget(m_StagingRTs[m]); |
|
|
|
Graphics.Blit(null, m_CubeBlitMaterial, 0); |
|
|
|
for(int m=0; m<m_NumPanoMipLevels; m++) |
|
|
|
Graphics.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m); |
|
|
|
|
|
|
|
for(int m=0; m<m_NumPanoMipLevels; m++) |
|
|
|
Graphics.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m); |
|
|
|
} |
|
|
|
public abstract class TextureCache |
|
|
|
{ |
|
|
|
protected int m_NumMipLevels; |
|
|
|
public abstract class TextureCache |
|
|
|
{ |
|
|
|
protected int m_NumMipLevels; |
|
|
|
static int s_GlobalTextureCacheVersion = 0; |
|
|
|
int m_TextureCacheVersion = 0; |
|
|
|
static int s_GlobalTextureCacheVersion = 0; |
|
|
|
int m_TextureCacheVersion = 0; |
|
|
|
#if UNITY_EDITOR
|
|
|
|
internal class AssetReloader : UnityEditor.AssetPostprocessor |
|
|
|
{ |
|
|
|
void OnPostprocessTexture(Texture texture) |
|
|
|
#if UNITY_EDITOR
|
|
|
|
internal class AssetReloader : UnityEditor.AssetPostprocessor |
|
|
|
s_GlobalTextureCacheVersion++; |
|
|
|
void OnPostprocessTexture(Texture texture) |
|
|
|
{ |
|
|
|
s_GlobalTextureCacheVersion++; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
public static bool isMobileBuildTarget |
|
|
|
{ |
|
|
|
get |
|
|
|
public static bool isMobileBuildTarget |
|
|
|
#if UNITY_EDITOR
|
|
|
|
switch (EditorUserBuildSettings.activeBuildTarget) |
|
|
|
get |
|
|
|
case BuildTarget.iOS: |
|
|
|
case BuildTarget.Android: |
|
|
|
case BuildTarget.Tizen: |
|
|
|
case BuildTarget.WSAPlayer: |
|
|
|
// Note: We return true on purpose even if Windows Store Apps are running on Desktop.
|
|
|
|
return true; |
|
|
|
default: |
|
|
|
return false; |
|
|
|
#if UNITY_EDITOR
|
|
|
|
switch (EditorUserBuildSettings.activeBuildTarget) |
|
|
|
{ |
|
|
|
case BuildTarget.iOS: |
|
|
|
case BuildTarget.Android: |
|
|
|
case BuildTarget.Tizen: |
|
|
|
case BuildTarget.WSAPlayer: |
|
|
|
// Note: We return true on purpose even if Windows Store Apps are running on Desktop.
|
|
|
|
return true; |
|
|
|
default: |
|
|
|
return false; |
|
|
|
} |
|
|
|
#else
|
|
|
|
return Application.isMobilePlatform; |
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
return Application.isMobilePlatform; |
|
|
|
#endif
|
|
|
|
} |
|
|
|
public static TextureFormat GetPreferredCompressedTextureFormat |
|
|
|
{ |
|
|
|
get |
|
|
|
public static TextureFormat GetPreferredCompressedTextureFormat |
|
|
|
var format = TextureFormat.RGBAHalf; |
|
|
|
get |
|
|
|
{ |
|
|
|
var format = TextureFormat.RGBAHalf; |
|
|
|
var probeFormat = TextureFormat.BC6H; |
|
|
|
var probeFormat = TextureFormat.BC6H; |
|
|
|
// On editor the texture is uncompressed when operating against mobile build targets
|
|
|
|
if (SystemInfo.SupportsTextureFormat(probeFormat) && !TextureCache.isMobileBuildTarget) |
|
|
|
format = probeFormat; |
|
|
|
// On editor the texture is uncompressed when operating against mobile build targets
|
|
|
|
if (SystemInfo.SupportsTextureFormat(probeFormat) && !TextureCache.isMobileBuildTarget) |
|
|
|
format = probeFormat; |
|
|
|
return format; |
|
|
|
return format; |
|
|
|
} |
|
|
|
} |
|
|
|
public static bool supportsCubemapArrayTextures |
|
|
|
{ |
|
|
|
get |
|
|
|
public static bool supportsCubemapArrayTextures |
|
|
|
return (SystemInfo.supportsCubemapArrayTextures && !TextureCache.isMobileBuildTarget); |
|
|
|
get |
|
|
|
{ |
|
|
|
return (SystemInfo.supportsCubemapArrayTextures && !TextureCache.isMobileBuildTarget); |
|
|
|
} |
|
|
|
} |
|
|
|
private struct SSliceEntry |
|
|
|
{ |
|
|
|
public uint texId; |
|
|
|
public uint countLRU; |
|
|
|
}; |
|
|
|
private struct SSliceEntry |
|
|
|
{ |
|
|
|
public uint texId; |
|
|
|
public uint countLRU; |
|
|
|
}; |
|
|
|
private int m_NumTextures; |
|
|
|
private int[] m_SortedIdxArray; |
|
|
|
private SSliceEntry[] m_SliceArray; |
|
|
|
private int m_NumTextures; |
|
|
|
private int[] m_SortedIdxArray; |
|
|
|
private SSliceEntry[] m_SliceArray; |
|
|
|
Dictionary<uint, int> m_LocatorInSliceArray; |
|
|
|
Dictionary<uint, int> m_LocatorInSliceArray; |
|
|
|
private static uint g_MaxFrameCount = unchecked((uint)(-1)); |
|
|
|
private static uint g_InvalidTexID = (uint)0; |
|
|
|
private static uint g_MaxFrameCount = unchecked((uint)(-1)); |
|
|
|
private static uint g_InvalidTexID = (uint)0; |
|
|
|
public int FetchSlice(Texture texture) |
|
|
|
{ |
|
|
|
var texId = (uint)texture.GetInstanceID(); |
|
|
|
public int FetchSlice(Texture texture) |
|
|
|
{ |
|
|
|
var texId = (uint)texture.GetInstanceID(); |
|
|
|
//assert(TexID!=g_InvalidTexID);
|
|
|
|
if (texId == g_InvalidTexID) return 0; |
|
|
|
//assert(TexID!=g_InvalidTexID);
|
|
|
|
if (texId == g_InvalidTexID) return 0; |
|
|
|
var bSwapSlice = false; |
|
|
|
var bFoundAvailOrExistingSlice = false; |
|
|
|
var sliceIndex = -1; |
|
|
|
var bSwapSlice = false; |
|
|
|
var bFoundAvailOrExistingSlice = false; |
|
|
|
var sliceIndex = -1; |
|
|
|
// search for existing copy
|
|
|
|
if (m_LocatorInSliceArray.ContainsKey(texId)) |
|
|
|
{ |
|
|
|
if (m_TextureCacheVersion != s_GlobalTextureCacheVersion) |
|
|
|
// search for existing copy
|
|
|
|
if (m_LocatorInSliceArray.ContainsKey(texId)) |
|
|
|
m_LocatorInSliceArray.Remove(texId); |
|
|
|
m_TextureCacheVersion++; |
|
|
|
Debug.Assert(m_TextureCacheVersion <= s_GlobalTextureCacheVersion); |
|
|
|
if (m_TextureCacheVersion != s_GlobalTextureCacheVersion) |
|
|
|
{ |
|
|
|
m_LocatorInSliceArray.Remove(texId); |
|
|
|
m_TextureCacheVersion++; |
|
|
|
Debug.Assert(m_TextureCacheVersion <= s_GlobalTextureCacheVersion); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
sliceIndex = m_LocatorInSliceArray[texId]; |
|
|
|
bFoundAvailOrExistingSlice = true; |
|
|
|
} |
|
|
|
//assert(m_SliceArray[sliceIndex].TexID==TexID);
|
|
|
|
else |
|
|
|
|
|
|
|
// If no existing copy found in the array
|
|
|
|
if (!bFoundAvailOrExistingSlice) |
|
|
|
sliceIndex = m_LocatorInSliceArray[texId]; |
|
|
|
bFoundAvailOrExistingSlice = true; |
|
|
|
// look for first non zero entry. Will by the least recently used entry
|
|
|
|
// since the array was pre-sorted (in linear time) in NewFrame()
|
|
|
|
var bFound = false; |
|
|
|
int j = 0, idx = 0; |
|
|
|
while ((!bFound) && j < m_NumTextures) |
|
|
|
{ |
|
|
|
idx = m_SortedIdxArray[j]; |
|
|
|
if (m_SliceArray[idx].countLRU == 0) ++j; // if entry already snagged by a new texture in this frame then ++j
|
|
|
|
else bFound = true; |
|
|
|
} |
|
|
|
|
|
|
|
if (bFound) |
|
|
|
{ |
|
|
|
// if we are replacing an existing entry delete it from m_locatorInSliceArray.
|
|
|
|
if (m_SliceArray[idx].texId != g_InvalidTexID) |
|
|
|
{ |
|
|
|
m_LocatorInSliceArray.Remove(m_SliceArray[idx].texId); |
|
|
|
} |
|
|
|
|
|
|
|
m_LocatorInSliceArray.Add(texId, idx); |
|
|
|
m_SliceArray[idx].texId = texId; |
|
|
|
|
|
|
|
sliceIndex = idx; |
|
|
|
bFoundAvailOrExistingSlice = true; |
|
|
|
bSwapSlice = true; |
|
|
|
} |
|
|
|
//assert(m_SliceArray[sliceIndex].TexID==TexID);
|
|
|
|
|
|
|
|
|
|
|
|
// wrap up
|
|
|
|
//assert(bFoundAvailOrExistingSlice);
|
|
|
|
if (bFoundAvailOrExistingSlice) |
|
|
|
{ |
|
|
|
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame
|
|
|
|
|
|
|
|
if (bSwapSlice) // if this was a miss
|
|
|
|
{ |
|
|
|
// transfer new slice to sliceIndex from source texture
|
|
|
|
TransferToSlice(sliceIndex, texture); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return sliceIndex; |
|
|
|
// If no existing copy found in the array
|
|
|
|
if (!bFoundAvailOrExistingSlice) |
|
|
|
public void NewFrame() |
|
|
|
// look for first non zero entry. Will by the least recently used entry
|
|
|
|
// since the array was pre-sorted (in linear time) in NewFrame()
|
|
|
|
var bFound = false; |
|
|
|
int j = 0, idx = 0; |
|
|
|
while ((!bFound) && j < m_NumTextures) |
|
|
|
var numNonZeros = 0; |
|
|
|
var tmpBuffer = new int[m_NumTextures]; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
idx = m_SortedIdxArray[j]; |
|
|
|
if (m_SliceArray[idx].countLRU == 0) ++j; // if entry already snagged by a new texture in this frame then ++j
|
|
|
|
else bFound = true; |
|
|
|
tmpBuffer[i] = m_SortedIdxArray[i]; // copy buffer
|
|
|
|
if (m_SliceArray[m_SortedIdxArray[i]].countLRU != 0) ++numNonZeros; |
|
|
|
|
|
|
|
if (bFound) |
|
|
|
int nonZerosBase = 0, zerosBase = 0; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
// if we are replacing an existing entry delete it from m_locatorInSliceArray.
|
|
|
|
if (m_SliceArray[idx].texId != g_InvalidTexID) |
|
|
|
if (m_SliceArray[tmpBuffer[i]].countLRU == 0) |
|
|
|
{ |
|
|
|
m_SortedIdxArray[zerosBase + numNonZeros] = tmpBuffer[i]; |
|
|
|
++zerosBase; |
|
|
|
} |
|
|
|
else |
|
|
|
m_LocatorInSliceArray.Remove(m_SliceArray[idx].texId); |
|
|
|
m_SortedIdxArray[nonZerosBase] = tmpBuffer[i]; |
|
|
|
++nonZerosBase; |
|
|
|
} |
|
|
|
m_LocatorInSliceArray.Add(texId, idx); |
|
|
|
m_SliceArray[idx].texId = texId; |
|
|
|
|
|
|
|
sliceIndex = idx; |
|
|
|
bFoundAvailOrExistingSlice = true; |
|
|
|
bSwapSlice = true; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
{ |
|
|
|
if (m_SliceArray[i].countLRU < g_MaxFrameCount) ++m_SliceArray[i].countLRU; // next frame
|
|
|
|
|
|
|
|
//for(int q=1; q<m_numTextures; q++)
|
|
|
|
// assert(m_SliceArray[m_SortedIdxArray[q-1]].CountLRU>=m_SliceArray[m_SortedIdxArray[q]].CountLRU);
|
|
|
|
|
|
|
|
// wrap up
|
|
|
|
//assert(bFoundAvailOrExistingSlice);
|
|
|
|
if (bFoundAvailOrExistingSlice) |
|
|
|
protected TextureCache() |
|
|
|
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame
|
|
|
|
|
|
|
|
if (bSwapSlice) // if this was a miss
|
|
|
|
{ |
|
|
|
// transfer new slice to sliceIndex from source texture
|
|
|
|
TransferToSlice(sliceIndex, texture); |
|
|
|
} |
|
|
|
m_NumTextures = 0; |
|
|
|
m_NumMipLevels = 0; |
|
|
|
return sliceIndex; |
|
|
|
} |
|
|
|
public virtual void TransferToSlice(int sliceIndex, Texture texture) |
|
|
|
{ |
|
|
|
} |
|
|
|
public void NewFrame() |
|
|
|
{ |
|
|
|
var numNonZeros = 0; |
|
|
|
var tmpBuffer = new int[m_NumTextures]; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
public virtual Texture GetTexCache() |
|
|
|
tmpBuffer[i] = m_SortedIdxArray[i]; // copy buffer
|
|
|
|
if (m_SliceArray[m_SortedIdxArray[i]].countLRU != 0) ++numNonZeros; |
|
|
|
return null; |
|
|
|
int nonZerosBase = 0, zerosBase = 0; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
|
|
|
|
protected bool AllocTextureArray(int numTextures) |
|
|
|
if (m_SliceArray[tmpBuffer[i]].countLRU == 0) |
|
|
|
if (numTextures > 0) |
|
|
|
m_SortedIdxArray[zerosBase + numNonZeros] = tmpBuffer[i]; |
|
|
|
++zerosBase; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
m_SortedIdxArray[nonZerosBase] = tmpBuffer[i]; |
|
|
|
++nonZerosBase; |
|
|
|
m_SliceArray = new SSliceEntry[numTextures]; |
|
|
|
m_SortedIdxArray = new int[numTextures]; |
|
|
|
m_LocatorInSliceArray = new Dictionary<uint, int>(); |
|
|
|
|
|
|
|
m_NumTextures = numTextures; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
{ |
|
|
|
m_SliceArray[i].countLRU = g_MaxFrameCount; // never used before
|
|
|
|
m_SliceArray[i].texId = g_InvalidTexID; |
|
|
|
m_SortedIdxArray[i] = i; |
|
|
|
} |
|
|
|
|
|
|
|
//return m_SliceArray != NULL && m_SortedIdxArray != NULL && numTextures > 0;
|
|
|
|
return numTextures > 0; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
// should not really be used in general. Assuming lights are culled properly entries will automatically be replaced efficiently.
|
|
|
|
public void RemoveEntryFromSlice(Texture texture) |
|
|
|
if (m_SliceArray[i].countLRU < g_MaxFrameCount) ++m_SliceArray[i].countLRU; // next frame
|
|
|
|
} |
|
|
|
var texId = (uint)texture.GetInstanceID(); |
|
|
|
//for(int q=1; q<m_numTextures; q++)
|
|
|
|
// assert(m_SliceArray[m_SortedIdxArray[q-1]].CountLRU>=m_SliceArray[m_SortedIdxArray[q]].CountLRU);
|
|
|
|
} |
|
|
|
//assert(TexID!=g_InvalidTexID);
|
|
|
|
if (texId == g_InvalidTexID) return; |
|
|
|
protected TextureCache() |
|
|
|
{ |
|
|
|
m_NumTextures = 0; |
|
|
|
m_NumMipLevels = 0; |
|
|
|
} |
|
|
|
// search for existing copy
|
|
|
|
if (!m_LocatorInSliceArray.ContainsKey(texId)) |
|
|
|
return; |
|
|
|
public virtual void TransferToSlice(int sliceIndex, Texture texture) |
|
|
|
{ |
|
|
|
} |
|
|
|
var sliceIndex = m_LocatorInSliceArray[texId]; |
|
|
|
public virtual Texture GetTexCache() |
|
|
|
{ |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
protected bool AllocTextureArray(int numTextures) |
|
|
|
{ |
|
|
|
if (numTextures > 0) |
|
|
|
{ |
|
|
|
m_SliceArray = new SSliceEntry[numTextures]; |
|
|
|
m_SortedIdxArray = new int[numTextures]; |
|
|
|
m_LocatorInSliceArray = new Dictionary<uint, int>(); |
|
|
|
//assert(m_SliceArray[sliceIndex].TexID==TexID);
|
|
|
|
m_NumTextures = numTextures; |
|
|
|
for (int i = 0; i < m_NumTextures; i++) |
|
|
|
// locate entry sorted by uCountLRU in m_pSortedIdxArray
|
|
|
|
var foundIdxSortLRU = false; |
|
|
|
var i = 0; |
|
|
|
while ((!foundIdxSortLRU) && i < m_NumTextures) |
|
|
|
m_SliceArray[i].countLRU = g_MaxFrameCount; // never used before
|
|
|
|
m_SliceArray[i].texId = g_InvalidTexID; |
|
|
|
m_SortedIdxArray[i] = i; |
|
|
|
if (m_SortedIdxArray[i] == sliceIndex) foundIdxSortLRU = true; |
|
|
|
else ++i; |
|
|
|
} |
|
|
|
//return m_SliceArray != NULL && m_SortedIdxArray != NULL && numTextures > 0;
|
|
|
|
return numTextures > 0; |
|
|
|
} |
|
|
|
if (!foundIdxSortLRU) |
|
|
|
return; |
|
|
|
// should not really be used in general. Assuming lights are culled properly entries will automatically be replaced efficiently.
|
|
|
|
public void RemoveEntryFromSlice(Texture texture) |
|
|
|
{ |
|
|
|
var texId = (uint)texture.GetInstanceID(); |
|
|
|
// relocate sliceIndex to front of m_pSortedIdxArray since uCountLRU will be set to maximum.
|
|
|
|
for (int j = 0; j < i; j++) |
|
|
|
{ |
|
|
|
m_SortedIdxArray[j + 1] = m_SortedIdxArray[j]; |
|
|
|
} |
|
|
|
m_SortedIdxArray[0] = sliceIndex; |
|
|
|
//assert(TexID!=g_InvalidTexID);
|
|
|
|
if (texId == g_InvalidTexID) return; |
|
|
|
|
|
|
|
// search for existing copy
|
|
|
|
if (!m_LocatorInSliceArray.ContainsKey(texId)) |
|
|
|
return; |
|
|
|
|
|
|
|
var sliceIndex = m_LocatorInSliceArray[texId]; |
|
|
|
|
|
|
|
//assert(m_SliceArray[sliceIndex].TexID==TexID);
|
|
|
|
// delete from m_locatorInSliceArray and m_pSliceArray.
|
|
|
|
m_LocatorInSliceArray.Remove(texId); |
|
|
|
m_SliceArray[sliceIndex].countLRU = g_MaxFrameCount; // never used before
|
|
|
|
m_SliceArray[sliceIndex].texId = g_InvalidTexID; |
|
|
|
} |
|
|
|
// locate entry sorted by uCountLRU in m_pSortedIdxArray
|
|
|
|
var foundIdxSortLRU = false; |
|
|
|
var i = 0; |
|
|
|
while ((!foundIdxSortLRU) && i < m_NumTextures) |
|
|
|
protected int GetNumMips(int width, int height) |
|
|
|
if (m_SortedIdxArray[i] == sliceIndex) foundIdxSortLRU = true; |
|
|
|
else ++i; |
|
|
|
return GetNumMips(width > height ? width : height); |
|
|
|
if (!foundIdxSortLRU) |
|
|
|
return; |
|
|
|
|
|
|
|
// relocate sliceIndex to front of m_pSortedIdxArray since uCountLRU will be set to maximum.
|
|
|
|
for (int j = 0; j < i; j++) |
|
|
|
protected int GetNumMips(int dim) |
|
|
|
m_SortedIdxArray[j + 1] = m_SortedIdxArray[j]; |
|
|
|
var uDim = (uint)dim; |
|
|
|
var iNumMips = 0; |
|
|
|
while (uDim > 0) |
|
|
|
{ ++iNumMips; uDim >>= 1; } |
|
|
|
return iNumMips; |
|
|
|
m_SortedIdxArray[0] = sliceIndex; |
|
|
|
|
|
|
|
// delete from m_locatorInSliceArray and m_pSliceArray.
|
|
|
|
m_LocatorInSliceArray.Remove(texId); |
|
|
|
m_SliceArray[sliceIndex].countLRU = g_MaxFrameCount; // never used before
|
|
|
|
m_SliceArray[sliceIndex].texId = g_InvalidTexID; |
|
|
|
} |
|
|
|
|
|
|
|
protected int GetNumMips(int width, int height) |
|
|
|
{ |
|
|
|
return GetNumMips(width > height ? width : height); |
|
|
|
} |
|
|
|
|
|
|
|
protected int GetNumMips(int dim) |
|
|
|
{ |
|
|
|
var uDim = (uint)dim; |
|
|
|
var iNumMips = 0; |
|
|
|
while (uDim > 0) |
|
|
|
{ ++iNumMips; uDim >>= 1; } |
|
|
|
return iNumMips; |
|
|
|
} |
|
|
|
} |