From 01b436b4f926b71f171811347f20b997ccfd6fed Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Mon, 17 May 2021 19:53:14 +0200 Subject: [PATCH] [unity] Minor: Updated documentation and example scene scripts regarding `GetRepackedSkin`, `GetRepackedAttachments` and `GetRemappedClone` to describe texture cache and cleanup. --- .../EquipSystemExample.cs | 10 ++++++ .../EquipsVisualsComponentExample.cs | 7 +++- .../MixAndMatchSkinsExample.cs | 7 +++- .../Spine Examples/Scripts/MixAndMatch.cs | 8 +++++ .../Scripts/MixAndMatchGraphic.cs | 8 +++++ .../spine-unity/Utility/AtlasUtilities.cs | 36 +++++++++++++++---- .../Utility/AttachmentCloneExtensions.cs | 7 +++- .../Utility/AttachmentRegionExtensions.cs | 5 ++- 8 files changed, 77 insertions(+), 11 deletions(-) diff --git a/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipSystemExample.cs b/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipSystemExample.cs index fc0521e45..381ed541b 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipSystemExample.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipSystemExample.cs @@ -82,6 +82,8 @@ namespace Spine.Unity.Examples { var templateSkin = skeletonData.FindSkin(templateSkinName); Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName); attachment = templateAttachment.GetRemappedClone(asset.sprite, sourceMaterial, premultiplyAlpha: this.applyPMA); + // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates + // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as shown in the method below. cachedAttachments.Add(asset, attachment); // Cache this value for next time this asset is used. } @@ -91,6 +93,14 @@ namespace Spine.Unity.Examples { public void Done () { target.OptimizeSkin(); + // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` + // creates cached Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). + // You can optionally clear the textures cache after multiple repack operations. + // Just be aware that while this cleanup frees up memory, it is also a costly operation + // and will likely cause a spike in the framerate. + + //AtlasUtilities.ClearCache(); + //Resources.UnloadUnusedAssets(); } } diff --git a/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs b/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs index a548a3408..8caf2ca9b 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs @@ -78,9 +78,14 @@ namespace Spine.Unity.Examples { Destroy(runtimeMaterial); if (runtimeAtlas) Destroy(runtimeAtlas); - var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas); + var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, + out runtimeMaterial, out runtimeAtlas, maxAtlasSize : 1024, clearCache: false); collectedSkin.Clear(); + // You can optionally clear the textures cache after each ore multiple repack operations are done. + //AtlasUtilities.ClearCache(); + //Resources.UnloadUnusedAssets(); + // 3. Use the repacked skin. skeletonAnimation.Skeleton.Skin = repackedSkin; RefreshSkeletonAttachments(); diff --git a/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs b/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs index 13951f94d..a0c4a6c70 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs @@ -149,8 +149,13 @@ namespace Spine.Unity.Examples { skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); - // You can optionally clear the cache after multiple repack operations. + // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` + // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). + // You can optionally clear the textures cache after multiple repack operations. + // Just be aware that while this cleanup frees up memory, it is also a costly operation + // and will likely cause a spike in the framerate. AtlasUtilities.ClearCache(); + Resources.UnloadUnusedAssets(); } void UpdateCharacterSkin () { diff --git a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs index b5dba28e6..64200eb91 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs @@ -95,6 +95,8 @@ namespace Spine.Unity.Examples { int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster. Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1 Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords : false); // STEP 1.2 - 1.3 + // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates + // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done in the method below. customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4 // And now for the gun. @@ -136,6 +138,12 @@ namespace Spine.Unity.Examples { skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose. skeletonAnimation.Update(0); // Use the pose in the currently active animation. + // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` + // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). + // You can optionally clear the textures cache after multiple repack operations. + // Just be aware that while this cleanup frees up memory, it is also a costly operation + // and will likely cause a spike in the framerate. + AtlasUtilities.ClearCache(); Resources.UnloadUnusedAssets(); } } diff --git a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatchGraphic.cs b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatchGraphic.cs index 570abd4d0..eabe0a084 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatchGraphic.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatchGraphic.cs @@ -96,6 +96,8 @@ namespace Spine.Unity.Examples { int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster. Attachment baseAttachment = baseSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1 Attachment newAttachment = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3 + // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates + // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done below. customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4 // And now for the gun. @@ -135,6 +137,12 @@ namespace Spine.Unity.Examples { skeletonGraphic.Update(0); skeletonGraphic.OverrideTexture = runtimeAtlas; + // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` + // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). + // You can optionally clear the textures cache after multiple repack operations. + // Just be aware that while this cleanup frees up memory, it is also a costly operation + // and will likely cause a spike in the framerate. + AtlasUtilities.ClearCache(); Resources.UnloadUnusedAssets(); } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs index a8d156d2c..be9317076 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs @@ -242,11 +242,17 @@ namespace Spine.Unity.AttachmentTools { /// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments, /// but mapped to a new single texture using the same material. /// Returned Material and Texture behave like new Texture2D(), thus you need to call Destroy() - /// to free resources. + /// to free resources. + /// This method caches necessary Texture copies for later re-use, which might steadily increase the texture memory + /// footprint when used excessively. Set to true + /// or call to clear this texture cache. + /// You may want to call Resources.UnloadUnusedAssets() after that. + /// /// The list of attachments to be repacked. /// The List(Attachment) to populate with the newly created Attachment objects. - /// /// May be null. If no Material property source is provided, no special + /// When set to true, is called after + /// repacking to clear the texture cache. See remarks for additional info. public static void GetRepackedAttachments (List sourceAttachments, List outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) { if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments"); if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments"); @@ -337,7 +343,14 @@ namespace Spine.Unity.AttachmentTools { /// GetRepackedSkin is an expensive operation, preferably call it at level load time. /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. /// Returned Material and Texture behave like new Texture2D(), thus you need to call Destroy() - /// to free resources. + /// to free resources. + /// This method caches necessary Texture copies for later re-use, which might steadily increase the texture memory + /// footprint when used excessively. Set to true + /// or call to clear this texture cache. + /// You may want to call Resources.UnloadUnusedAssets() after that. + /// + /// When set to true, is called after + /// repacking to clear the texture cache. See remarks for additional info. /// Optional additional textures (such as normal maps) to copy while repacking. /// To copy e.g. the main texture and normal maps, pass 'new int[] { Shader.PropertyToID("_BumpMap") }' at this parameter. /// When additionalTexturePropertyIDsToCopy is non-null, @@ -368,10 +381,7 @@ namespace Spine.Unity.AttachmentTools { /// /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas /// comprised of all the regions from the original skin. - /// GetRepackedSkin is an expensive operation, preferably call it at level load time. - /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. - /// Returned Material and Texture behave like new Texture2D(), thus you need to call Destroy() - /// to free resources. + /// See documentation of for details. public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true, @@ -525,6 +535,18 @@ namespace Spine.Unity.AttachmentTools { static Dictionary CachedRegionTextures = new Dictionary(); static List CachedRegionTexturesList = new List(); + /// + /// Frees up textures cached by repacking and remapping operations. + /// + /// Calling with parameter premultiplyAlpha=true, + /// or will cache textures for later re-use, + /// which might steadily increase the texture memory footprint when used excessively. + /// You can clear this Texture cache by calling . + /// You may also want to call Resources.UnloadUnusedAssets() after that. Be aware that while this cleanup + /// frees up memory, it is also a costly operation and will likely cause a spike in the framerate. + /// Thus it is recommended to perform costly repacking and cleanup operations after e.g. a character customization + /// screen has been exited, and if required additionally after a certain number of GetRemappedClone() calls. + /// public static void ClearCache () { foreach (var t in CachedRegionTexturesList) { UnityEngine.Object.Destroy(t); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs index 2629c41f9..218156213 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs @@ -80,7 +80,8 @@ namespace Spine.Unity.AttachmentTools { /// The original attachment. /// The sprite whose texture to use. /// The source material used to copy the shader and material properties from. - /// If true, a premultiply alpha clone of the original texture will be created. + /// If true, a premultiply alpha clone of the original texture will be created. + /// See remarks below for additional info. /// If true MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment. /// If true the size of the original attachment will be followed, instead of using the Sprite size. /// If true and the original Attachment is a MeshAttachment, then @@ -89,6 +90,10 @@ namespace Spine.Unity.AttachmentTools { /// If true and the original Attachment is a RegionAttachment, then /// the original region's scale value is used instead of the Sprite's pixels per unit property. Since uniform scale is used, /// x scale of the original attachment (width scale) is used, scale in y direction (height scale) is ignored. + /// When parameter premultiplyAlpha is set to true, a premultiply alpha clone of the + /// original texture will be created. Additionally, this PMA Texture clone is cached for later re-use, + /// which might steadily increase the Texture memory footprint when used excessively. + /// See on how to clear these cached textures. public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial, bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false, bool pivotShiftsMeshUVCoords = true, bool useOriginalRegionScale = false) { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs index 6e786019a..600538748 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs @@ -125,7 +125,10 @@ namespace Spine.Unity.AttachmentTools { } /// - /// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data. Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton" + /// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data. + /// Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton". + /// The duplicate texture is cached for later re-use. See documentation of + /// for additional details. public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, Material materialPropertySource = null, float rotation = 0f) { if (sprite == null) throw new System.ArgumentNullException("sprite"); if (shader == null) throw new System.ArgumentNullException("shader");