netpyoung / unity.webp

:art: WebP made easy for Unity3d
https://netpyoung.github.io/unity.webp/
MIT License
237 stars 28 forks source link

Reduce Garbage #26

Open umresh opened 3 years ago

umresh commented 3 years ago

Hi, Awesome plugin. We are trying to develop an app where we decode multiple webp images(2k) and it creates too much garbage since we are using mid-end device it impacts performance. Is there any solution or can we decode in c# threads?

netpyoung commented 3 years ago

There is optimizable point.

instead of that using new byte or new Texture2D, make a function which passing texture2d as argument to prevent new allocation.

https://github.com/netpyoung/unity.webp/blob/76a58b03aadc57a3d9d22e21a04dd4bd83566136/unity_project/Assets/unity.webp/Texture2DExt.cs#L115

https://github.com/netpyoung/unity.webp/blob/76a58b03aadc57a3d9d22e21a04dd4bd83566136/unity_project/Assets/unity.webp/Texture2DExt.cs#L185

netpyoung commented 3 years ago

I updated code to using byte array as buffer. Could you check that?

https://github.com/netpyoung/unity.webp/blob/bf2212ff2c87cb23874ef8ff6b58762171582873/unity_project/Assets/example/Example.cs#L19

umresh commented 3 years ago

Sure I'll check and update. Thanks.

umresh commented 3 years ago

Hi, I've used your sample project to load a single image which is a 4096 x 2048 image and I have attached the profiler snap and the image file. We are creating an app for an Android TV device which has low memory and high garbage sometimes crashes the app. Reducing texture res in such images is not possible because we are targeting for TV and reducing size pixelates images. We decided to use WebP to reduce download time. Another profiler snap

netpyoung commented 3 years ago

It needs to reuse bytearraypool. and you can reuse texture2d instance if image size is fixed. and turn off mipmap. and use Task to background load.

Capture

  void LoadWebpUsingPool(RawImage image)
    {
        byte[] bytePool = new byte[1024 * 1024 * 50];
        for (int i = 0; i < 100; ++i)
        {

            var textasset = Resources.Load<TextAsset>("webp_1");
            var webpBytes = textasset.bytes;

            Texture2DExt.GetWebPDimensions(webpBytes, out int width, out int height);

            Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, mipChain: false, linear: true);
            image.texture = texture;

            int numBytesRequired = Texture2DExt.GetRequireByteSize(width, height, isUseMipmap: false);

            Debug.Assert(bytePool.Length >= numBytesRequired);

            Texture2DExt.LoadTexture2DFromWebP(webpBytes, texture, lMipmaps: false, lLinear: true, bytePool, numBytesRequired);
        }
    }

    void LoadWebp(RawImage image)
    {
        for (int i = 0; i < 100; ++i)
        {
            var textasset = Resources.Load<TextAsset>("webp_1");
            var bytes = textasset.bytes;

            Texture2D texture = Texture2DExt.CreateTexture2DFromWebP(bytes, lMipmaps: false, lLinear: true, lError: out Error lError);

            if (lError == Error.Success)
            {
                image.texture = texture;
            }
            else
            {
                Debug.LogError("Webp Load Error : " + lError.ToString());
            }
        }
    }
umresh commented 3 years ago

Hi, garbage is reduced on multiple image loading. Thanks. Is there any other optimization we can do to reduce load time(CPU usage/time) or move to BackgroundWorker were we can have callback after decoding for keeping track of the decoded image and assigning it to the correct object?

netpyoung commented 3 years ago

@umresh Could you try using task for background work? and If you have any good idea to handle it please pull request!