|
|
- using System.Collections;
- using System.Collections.Generic;
- using Oculus.Avatar;
- using UnityEngine;
-
- public class OvrAvatarTextureCopyManager : MonoBehaviour
- {
- [System.Serializable]
- public struct FallbackTextureSet
- {
- public bool Initialized;
- public Texture2D DiffuseRoughness;
- public Texture2D Normal;
- }
- // Fallback texture sets are indexed with ovrAvatarAssetLevelOfDetail.
- // We currently only use 1, 3 (mobile default), 5 (PC default).
- public FallbackTextureSet[] FallbackTextureSets = new FallbackTextureSet[(int)ovrAvatarAssetLevelOfDetail.Highest + 1];
-
- struct CopyTextureParams
- {
- public Texture Src;
- public Texture Dst;
- public int Mip;
- public int SrcSize;
- public int DstElement;
-
- public CopyTextureParams(
- Texture src,
- Texture dst,
- int mip,
- int srcSize,
- int dstElement)
- {
- Src = src;
- Dst = dst;
- Mip = mip;
- SrcSize = srcSize;
- DstElement = dstElement;
- }
- }
- private Queue<CopyTextureParams> texturesToCopy;
-
- public struct TextureSet
- {
- // Contains all texture asset IDs that are part of an avatar spec.
- // Used by DeleteTextureSet().
- // Textures that are part of combined mesh avatars can be safely deleted once they have been
- // uploaded to the texture arrays.
- // Textures that are part of single component meshes will remain in memory.
- public Dictionary<ulong, bool> TextureIDSingleMeshPair;
- public bool IsProcessed;
-
- public TextureSet(
- Dictionary<ulong, bool> textureIDSingleMeshPair,
- bool isProcessed)
- {
- TextureIDSingleMeshPair = textureIDSingleMeshPair;
- IsProcessed = isProcessed;
- }
- }
- private Dictionary<int, TextureSet> textureSets;
-
- private const int TEXTURES_TO_COPY_QUEUE_CAPACITY = 256;
- private const int COPIES_PER_FRAME = 8;
-
- // Fallback texture paths are indexed with ovrAvatarAssetLevelOfDetail
- // We currently only use 1, 3 (mobile default), 5 (PC default)
- private readonly string[] FALLBACK_TEXTURE_PATHS_DIFFUSE_ROUGHNESS = new string[]
- {
- "null",
- PATH_LOWEST_DIFFUSE_ROUGHNESS,
- "null",
- PATH_MEDIUM_DIFFUSE_ROUGHNESS,
- "null",
- PATH_HIGHEST_DIFFUSE_ROUGHNESS,
- };
- private readonly string[] FALLBACK_TEXTURE_PATHS_NORMAL = new string[]
- {
- "null",
- PATH_LOWEST_NORMAL,
- "null",
- PATH_MEDIUM_NORMAL,
- "null",
- PATH_HIGHEST_NORMAL,
- };
-
- private const string PATH_HIGHEST_DIFFUSE_ROUGHNESS = "FallbackTextures/fallback_diffuse_roughness_2048";
- private const string PATH_MEDIUM_DIFFUSE_ROUGHNESS = "FallbackTextures/fallback_diffuse_roughness_1024";
- private const string PATH_LOWEST_DIFFUSE_ROUGHNESS = "FallbackTextures/fallback_diffuse_roughness_256";
- private const string PATH_HIGHEST_NORMAL = "FallbackTextures/fallback_normal_2048";
- private const string PATH_MEDIUM_NORMAL = "FallbackTextures/fallback_normal_1024";
- private const string PATH_LOWEST_NORMAL = "FallbackTextures/fallback_normal_256";
-
- private const int GPU_TEXTURE_COPY_WAIT_TIME = 10;
-
- public OvrAvatarTextureCopyManager()
- {
- texturesToCopy = new Queue<CopyTextureParams>(TEXTURES_TO_COPY_QUEUE_CAPACITY);
- textureSets = new Dictionary<int, TextureSet>();
- }
-
- public void Update()
- {
- if (texturesToCopy.Count == 0)
- {
- return;
- }
-
- lock (texturesToCopy)
- {
- for (int i = 0; i < Mathf.Min(COPIES_PER_FRAME, texturesToCopy.Count); ++i)
- {
- CopyTexture(texturesToCopy.Dequeue());
- }
- }
- }
-
- public int GetTextureCount()
- {
- return texturesToCopy.Count;
- }
-
- public void CopyTexture(
- Texture src,
- Texture dst,
- int mipLevel,
- int mipSize,
- int dstElement,
- bool useQueue = true)
- {
- var copyTextureParams = new CopyTextureParams(src, dst, mipLevel, mipSize, dstElement);
-
- if (useQueue)
- {
- lock (texturesToCopy)
- {
- if (texturesToCopy.Count < TEXTURES_TO_COPY_QUEUE_CAPACITY)
- {
- texturesToCopy.Enqueue(copyTextureParams);
- }
- else
- {
- // Queue is full so copy texture immediately
- CopyTexture(copyTextureParams);
- }
- }
- }
- else
- {
- CopyTexture(copyTextureParams);
- }
- }
-
- private void CopyTexture(CopyTextureParams copyTextureParams)
- {
- Graphics.CopyTexture(
- copyTextureParams.Src,
- 0,
- copyTextureParams.Mip,
- copyTextureParams.Dst,
- copyTextureParams.DstElement,
- copyTextureParams.Mip);
- }
-
- public void AddTextureIDToTextureSet(int gameobjectID, ulong textureID, bool isSingleMesh)
- {
- if (!textureSets.ContainsKey(gameobjectID))
- {
- TextureSet newTextureSet = new TextureSet(new Dictionary<ulong, bool>(), false);
- newTextureSet.TextureIDSingleMeshPair.Add(textureID, isSingleMesh);
- textureSets.Add(gameobjectID, newTextureSet);
- }
- else
- {
- bool TexIDSingleMesh;
- if (textureSets[gameobjectID].TextureIDSingleMeshPair.TryGetValue(textureID, out TexIDSingleMesh))
- {
- if (!TexIDSingleMesh && isSingleMesh)
- {
- textureSets[gameobjectID].TextureIDSingleMeshPair[textureID] = true;
- }
- }
- else
- {
- textureSets[gameobjectID].TextureIDSingleMeshPair.Add(textureID, isSingleMesh);
- }
- }
- }
-
- // This is called by a fully loaded avatar using combined mesh to safely delete unused textures.
- public void DeleteTextureSet(int gameobjectID)
- {
- TextureSet textureSetToDelete;
- if (!textureSets.TryGetValue(gameobjectID, out textureSetToDelete))
- {
- return;
- };
-
- if (textureSetToDelete.IsProcessed)
- {
- return;
- }
-
- StartCoroutine(DeleteTextureSetCoroutine(textureSetToDelete, gameobjectID));
- }
-
- private IEnumerator DeleteTextureSetCoroutine(TextureSet textureSetToDelete, int gameobjectID)
- {
- // Wait a conservative amount of time for gpu upload to finish. Unity 2017 doesn't support async GPU calls,
- // so this 10 second time is a very conservative delay for this process to occur, which should be <1 sec.
- yield return new WaitForSeconds(GPU_TEXTURE_COPY_WAIT_TIME);
-
- // Spin if an avatar is loading
- while (OvrAvatarSDKManager.Instance.IsAvatarLoading())
- {
- yield return null;
- }
-
- // The avatar's texture set is compared against all other loaded or loading avatar texture sets.
- foreach (var textureIdAndSingleMeshFlag in textureSetToDelete.TextureIDSingleMeshPair)
- {
- bool triggerDelete = !textureIdAndSingleMeshFlag.Value;
- if (triggerDelete)
- {
- foreach (KeyValuePair<int, TextureSet> textureSet in textureSets)
- {
- if (textureSet.Key == gameobjectID)
- {
- continue;
- }
-
- foreach (var comparisonTextureIDSingleMeshPair in textureSet.Value.TextureIDSingleMeshPair)
- {
- // Mark the texture as not deletable if it's present in another set and that set hasn't been processed
- // or that texture ID is marked as part of a single mesh component.
- if (comparisonTextureIDSingleMeshPair.Key == textureIdAndSingleMeshFlag.Key &&
- (!textureSet.Value.IsProcessed || comparisonTextureIDSingleMeshPair.Value))
- {
- triggerDelete = false;
- break;
- }
- }
-
- if (!triggerDelete)
- {
- break;
- }
- }
- }
-
- if (triggerDelete)
- {
- Texture2D textureToDelete = OvrAvatarComponent.GetLoadedTexture(textureIdAndSingleMeshFlag.Key);
- if (textureToDelete != null)
- {
- AvatarLogger.Log("Deleting texture " + textureIdAndSingleMeshFlag.Key);
- OvrAvatarSDKManager.Instance.DeleteAssetFromCache(textureIdAndSingleMeshFlag.Key);
- Destroy(textureToDelete);
- }
- }
- }
- textureSetToDelete.IsProcessed = true;
- textureSets.Remove(gameobjectID);
- }
-
- public void CheckFallbackTextureSet(ovrAvatarAssetLevelOfDetail lod)
- {
- if (FallbackTextureSets[(int)lod].Initialized)
- {
- return;
- }
-
- InitFallbackTextureSet(lod);
- }
-
- private void InitFallbackTextureSet(ovrAvatarAssetLevelOfDetail lod)
- {
- FallbackTextureSets[(int)lod].DiffuseRoughness = FallbackTextureSets[(int)lod].DiffuseRoughness =
- Resources.Load<Texture2D>(FALLBACK_TEXTURE_PATHS_DIFFUSE_ROUGHNESS[(int)lod]);
- FallbackTextureSets[(int)lod].Normal = FallbackTextureSets[(int)lod].Normal =
- Resources.Load<Texture2D>(FALLBACK_TEXTURE_PATHS_NORMAL[(int)lod]);
- FallbackTextureSets[(int)lod].Initialized = true;
- }
- }
|