internal void ReleaseContainer(ShadowContainer container)
        {
            if (container == null)
            {
                return;
            }

            if (--container.RefCount > 0)
            {
                return;
            }

            RenderTexture.ReleaseTemporary(container.Texture);
            shadowCache.Remove(container.requestHash);

            // Debug.Log($"Released container for request\t{container.requestHash}\tTotal Released: {++releasedContainerCount}\t Alive: {createdContainerCount - releasedContainerCount}");
        }
        // public int createdContainerCount;
        // public int releasedContainerCount;

        public void Get(ShadowRenderingRequest request, ref ShadowContainer container)
        {
            if (float.IsNaN(request.dimensions.x) || request.dimensions.x < 1 ||
                float.IsNaN(request.dimensions.y) || request.dimensions.y < 1)
            {
                ReleaseContainer(container);
                return;
            }

#if LETAI_TRUESHADOW_DEBUG
            RenderTexture.ReleaseTemporary(debugTexture);
            if (request.shadow.alwaysRender)
            {
                debugTexture = RenderShadow(request);
            }
#endif

            // Each request need a coresponding shadow texture
            // Texture may be shared by multiple elements
            // Texture are released when no longer used by any element
            // ShadowContainer keep track of texture and their usage


            int requestHash = request.GetHashCode();

            // Case: requester can keep the same texture
            if (container?.requestHash == requestHash)
            {
                return;
            }

            ReleaseContainer(container);

            if (shadowCache.TryGetValue(requestHash, out var existingContainer))
            {
                // Case: requester got texture from someone else
                existingContainer.RefCount++;
                container = existingContainer;
            }
            else
            {
                // Case: requester got new unique texture
                container = shadowCache[requestHash] = new ShadowContainer(RenderShadow(request), request);
                // Debug.Log($"Created new container for request\t{requestHash}\tTotal Created: {++createdContainerCount}\t Alive: {createdContainerCount - releasedContainerCount}");
            }
        }
        void BakeShadows()
        {
#if UNITY_EDITOR
            ShadowContainer container = null;
            ShadowFactory.Instance.Get(new ShadowRenderingRequest(this), ref container);
            var renderTexture = container.Texture;
            Debug.Assert(renderTexture);
            var texture = new Texture2D(renderTexture.width, renderTexture.height,
                                        TextureFormat.ARGB32, false);

            var activeTexture = RenderTexture.active;
            RenderTexture.active = renderTexture;
            texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
            RenderTexture.active = activeTexture;

            var textureName = $"{SceneManager.GetActiveScene().name} - {gameObject.name} @{size}.png";
            var texturePath = BAKED_SHADOWS_PATH + textureName;
            Directory.CreateDirectory(BAKED_SHADOWS_PATH);
            File.WriteAllBytes(texturePath, texture.EncodeToPNG());
            AssetDatabase.Refresh(ImportAssetOptions.DontDownloadFromCacheServer);

            var importer = (TextureImporter)AssetImporter.GetAtPath(texturePath);

            TextureImporterSettings importSettings = new TextureImporterSettings();
            importer.ReadTextureSettings(importSettings);
            importSettings.textureType    = TextureImporterType.Sprite;
            importSettings.spriteMeshType = SpriteMeshType.Tight;
            importSettings.spriteGenerateFallbackPhysicsShape = false;
            importSettings.alphaSource         = TextureImporterAlphaSource.FromInput;
            importSettings.alphaIsTransparency = true;
            importSettings.mipmapEnabled       = false;
            importer.SetTextureSettings(importSettings);
            importer.SaveAndReimport();

            var bakedSprite = AssetDatabase.LoadAssetAtPath <Sprite>(texturePath);
            bakedShadows.Add(bakedSprite);

            if (Graphic is Image image)
            {
                SpriteAtlasCache.AddToSameAtlas(bakedSprite, image.sprite);
            }

            shadowRenderer.SetSprite(bakedSprite);
#endif
        }