Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by BillyK · Dec 15, 2010 at 05:10 AM · texturetexture2dwwwdelay

WWW Texture access takes a long time

Hi,

I'm having issues with the "WWW.texture" property and wondering if anyone has a suggestion. The WWW class asynchronously loads it's data from a remote source, which is a good thing. The problem I'm having, however, is that accessing the "WWW.texture" property after that load takes an extremely long time to process. I'm trying to unwrap that texture from within the Update() method, so the extensive delay is causing a significant decrease in frame rate. Further, I have to load a large set of image textures in parallel, so the compounded delays is dragging my frame rate to a crawl temporarily.

That's the problem... Now I'm trying to determine a good solution. I've tried managing the unwrapping of the texture from a secondary thread, but the "WWW.isDone", "WWW.error" and "WWW.texture" method all throw errors indicating that they MUST be called on the main thread. That takes a multi-threaded solution around WWW out of the mix. Anyone have any other thoughts about how to resolve this issue?

Thanks in advance...

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Eric5h5 · Dec 15, 2010 at 06:21 AM

I'm not sure what you mean by "unwrapping the texture", nor am I sure why you'd want to do that in Update, which runs once every frame. Uploading textures to the GPU takes time no matter what, but it's not something I'd call an "extremely long time", and is generally a small fraction of a second (enough to cause a visible framerate hiccup unless the texture is tiny, but that's not something you can avoid). You should probably post code.

The example from the docs for WWW.texture works with no issues, but an alternate technique is to use WWW.LoadImageIntoTexture, which is recommended if you're downloading textures more than once, since WWW.texture stays in memory unless destroyed. Not sure if that has any effect on speed though.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0
Best Answer

Answer by BillyK · Dec 16, 2010 at 01:06 AM

I finally came up with a way to handle this situation. The heart of the problem is that processing "WWW.texture" several times within the same "Update()" call adds up and chokes the frames per second. One or two would be fine, but 96 (which is the number of images I'm queuing) is not. The trick I used in order to resolve this issue was to create a GameObject which acts as a queue for the textures being unwrapped. That GameObject works through a queue during each "Update()" call, processing a single texture each call. This effectively spreads out the texture calls, rather than allowing them to stack up and choke the frame rate.

The code for the class used to act as the queue is as follows:

using UnityEngine; using System.Collections;

public class TextureLoadManager : MonoBehaviour { private static TextureLoadManager _instance = null;

 public static TextureLoadManager FindTextureLoadManager()
 {
     return _instance;
 }

 private Queue _waitingTextureQueue = null;

 void Awake()
 {
     _instance = this;

     Queue queue = new Queue();
     _waitingTextureQueue = Queue.Synchronized(queue);
 }

 public TextureUnwrapper CreateTextureUnwrapper(WWW loadingTexture)
 {
     TextureUnwrapper textureUnwrapper = new TextureUnwrapper(loadingTexture);
     _waitingTextureQueue.Enqueue(textureUnwrapper);
     return textureUnwrapper;
 }

 void Update()
 {
     if (_waitingTextureQueue.Count > 0)
     {
         ((TextureUnwrapper)_waitingTextureQueue.Dequeue()).Unwrap();
     }
 }

 public class TextureUnwrapper
 {
     private WWW _loadingTexture;
     private Texture2D _texture;

     private bool _isUnwrapped = false;

     public TextureUnwrapper(WWW loadingTexture)
     {
         _loadingTexture = loadingTexture;
     }

     public Texture2D Texture
     {
         get { return _texture; }
     }

     public IEnumerator WaitForUnwrapCompletion()
     {
         while (!_isUnwrapped)
         {
             yield return 0;
         }
     }

     public void Unwrap()
     {
         _texture = _loadingTexture.texture;
         _loadingTexture = null;
         _isUnwrapped = true;
     }
 }

}

An example of the code I'm using in order to process textures through that queue would be the following:

void Update() { if (!_initCoverMaterial) { _initCoverMaterial = true;

         StartCoroutine(UpdateCoverMaterial());
     }
 }

 private IEnumerator UpdateCoverMaterial()
 {
     if (_coverMaterial != null && _iconImageSource != null && _iconImageSource.Trim().Length > 0)
     {
         WWW loadingImage = null;

         try
         {
             loadingImage = new WWW(_iconImageSource);
         }
         catch (Exception genErr)
         {                
         }

         if (loadingImage != null)
         {
             yield return loadingImage;

             if (loadingImage.error == null)
             {
                 TextureLoadManager.TextureUnwrapper textureUnwrapper = _textureLoadManager.CreateTextureUnwrapper(loadingImage);
                 yield return StartCoroutine(textureUnwrapper.WaitForUnwrapCompletion());
                 _coverImage = textureUnwrapper.Texture;

                 _coverMaterial.mainTexture = _coverImage;
             }

             loadingImage.Dispose();
             loadingImage = null;
         }
     }

     yield return 0;
 }

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by BillyK · Dec 15, 2010 at 07:44 AM

"Unwrapping the texture" was referring to the operation that occurs when "WWW.texture" is called, considering the fact that it does not return immediately, I can only assume that the data is turned into a Texture2D object at that point, which makes sense, and that process takes some time. Looking at a deep profile of the operation, a small sampling of the cases when that property is called for chew up times from 77 - 83ms a piece. I'm loading several images in parallel (i.e. a wall of images, essentially), and if several of the WWW instances complete the download within the same approximate time, the calls for textures adds up, dropping the frame rate dramatically (i.e. < 6fps).

With regards to the reason for why the "Update()" method is used, rather than the "Start()" or "Awake()" method is that the list of images to load is dynamically obtained from a back-end service and the GameObject is present and visible prior to the point at which that call returns. That being said, the access of the "WWW.texture" property occurs only once, since I use a lock in order to ensure that fact. The following is an example of the code I'm currently using:

void Update() { if (!_initCoverMaterial) { // This lock disallows multiple processing attempts _initCoverMaterial = true;

     StartCoroutine(UpdateCoverMaterial());
 }

}

private IEnumerator UpdateCoverMaterial() { if (_coverMaterial != null && _iconImageSource != null && _iconImageSource.Trim().Length > 0) { WWW loadingImage = null;

     try
     {
         loadingImage = new WWW(_iconImageSource);
     }
     catch (Exception genErr)
     {
     }

     if (loadingImage != null)
     {
         yield return loadingImage;

         if (loadingImage.error == null)
         {
             yield return (_coverImage = loadingImage.texture);
             _coverMaterial.mainTexture = _coverImage;
         }

         loadingImage.Dispose();
         loadingImage = null;
     }
 }

 yield return 0;

}

The code works just fine, but the problem is that I have several of these running in parallel to ensure that all images appear as quickly as possible.

Any thoughts about an alternate approach? As I mentioned, all Texture2D and WWW methods appear to require that they occur on the main thread, so a multi-threaded solution doesn't appear to work (unless someone knows a work-around). Is there some way to cause the WWW instance to pre-generate the Texture during it's asynchronous operation (probably not, due to the "run on the main thread" restriction in the related classes, but maybe someone knows a trick)?

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Eric5h5 · Dec 15, 2010 at 08:23 AM 0
Share

I edited my answer with a mention of LoadImageIntoTexture. The Update function here still seems entirely superfluous; ins$$anonymous$$d of constantly polling _initCover$$anonymous$$aterial I'd just call UpdateCover$$anonymous$$aterial directly when needed.

avatar image BillyK · Dec 16, 2010 at 12:54 AM 0
Share

I can't, actually. The callback used to obtain the list of images is in a separate thread. As a result, I'm not able to process the WWW methods and properties, since they have to be on the main thread. I'm polling from the "Update()" method to make sure that the processing occurs on the main thread whereas the callback does not.

avatar image BillyK · Dec 16, 2010 at 12:55 AM 0
Share

That being said... I actually figured out a way to resolve the issue (see below).

avatar image stijn · May 10, 2012 at 09:52 AM 0
Share

I managed to move part of the image decoding and resizing to a separate thread by using a third-party jpeg library:

http://answers.unity3d.com/questions/249993/typeloadexception-trying-to-use-fjcore-fluxjpeg.html

Unfortunately the resulting code is very slow, so I posted a suggestion here:

http://feedback.unity3d.com/forums/15792-unity/suggestions/2840580-async-image-decoding-and-resizing-for-www-texture

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

No one has followed this question yet.

Related Questions

Image is not loading into Texture 0 Answers

www.texture memory leak 1 Answer

Unity won't let me load an image into a texture 0 Answers

Can't assign a texture from WWW to Image.material.maintexture 1 Answer

NGUI 3.4.9 error NullReferenceException UnityEngine.Material..ctor (UnityEngine.Shader shader) UIDrawCall.CreateMaterial () 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges