Search Unity

SetPixel / Apply alternative

Discussion in 'Scripting' started by McKrackeN, Nov 9, 2010.

  1. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    Hi there, ppl! :D

    I need to refresh a bitmap every frame, so the Texture2D.SetPixel / Apply doesn't work for me 'cause it's REALLY slow. So I need a faster alternative. In my case, I need to send less than a byte for pixel (just the indexes of a 16 color palette), is there a faster way to send this information to the video card? I don't know much about shaders, so any code or pseudocode will be appreciated! :D

    Thanks in advance! :)
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Sure its slow, you have to reupload the texture every frame.

    There is no way to accelerate it, as the upload must happen or there is nothing to render.

    Optimally you just don't come up with rather unsmart ideas like having larger textures you want to update or doing so every frame but instead 30 times per second for example.


    Also there is no such thing as 16color palette. Its 16bit at least and 128bit at max
     
  3. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    I've tried updating 30 times per second and I know that there's no 16 color palette, but I want to know if there is a way to send an array of bytes to a shader so I can generate the texture with that information or some workaround to achieve that.
     
  4. Jordii

    Jordii

    Joined:
    Sep 14, 2010
    Posts:
    135
    I believe (!!!!!) I've done some succesfull Apply()'s on every single frame. Just be sure to call Apply once all your SetPixel changes have been made on the Texture2D. For example:

    Code (csharp):
    1.  
    2. for(var i:int = 0 ... blahblahblah)
    3. {
    4.  setPixel on i;
    5. }
    6. Apply();
    7.  
    and not:

    Code (csharp):
    1. for(var i:int = 0 ... blahblahblah)
    2. {
    3.  setPixel on i;
    4.  Apply();
    5. }
    In other words: be sure Apply() doesn't get called when you don't need to (multiple times in 1 frame)
     
  5. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    I've tried that, but it didn't work. I've got 10 FPS max. :(
     
  6. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    don't use setpixel, always use SetPixels if you want to apply whole lines / rects etc

    the single pixel operations (read as write) is fine if you want to update a handful of pixels at max.


    as for sending it to a shader: Sure, you can feed registers on a custom shader you write, thats no problem. if its 16, you can technically even feed a 4x4 matrix if you want for example or 4 vector4
     
  7. windexglow

    windexglow

    Joined:
    Jun 18, 2010
    Posts:
    378
  8. Jordii

    Jordii

    Joined:
    Sep 14, 2010
    Posts:
    135
    Hmmm that's still odd, I do it too and I've got perfectly good framerates. You should run through your code, see if anything else is causing the framelag, because I believe (!!! BIG EFFING EXCLAMATION MARKS !!!) it should be possible.
     
  9. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    I need to update a 400x300 texture per frame. I do use SetPixels and I apply once all the texture has been updated. But it doesn't work very well. That's why I want an faster alternative like sending one byte per pixel to a shader instead of 32bits (or 24) per pixel.
     
  10. Jordii

    Jordii

    Joined:
    Sep 14, 2010
    Posts:
    135
    My application uses a 1024x1024 texture, plots a bunch of pixels every frame and after that Apply's, every single frame. No problems in framerates, even on slower computers. I don't want to sound like a stubborn asshole, I really want to help you :) (either that or I'm terribly wrong :D)
     
  11. reissgrant

    reissgrant

    Joined:
    Aug 20, 2009
    Posts:
    726
    If you don't mind forcing OpenGL you can use native OpenGL calls to update the texture and it will be much faster. Or you can just update the portion of the texture that changes rather than updating the whole thing. If only a small portion changes then it will update quicker.
     
  12. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Split your texture into lots of smaller ones and only upload the ones that change?
     
    amanpu likes this.
  13. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    I've changed the texture from 400x300 to 512x512 (power of 2) and now it works MUCH faster. It's seems to be a problem that it tries to convert the texture to a power of two every time one call the Apply.

    Thanks to all for your time and help! :D
     
  14. Jordii

    Jordii

    Joined:
    Sep 14, 2010
    Posts:
    135
    Ah there ya go :)
    Glad I could be of any help McKrackeN :)
     
  15. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Mind if we ask what grpahic card you have? such an enforcement indicates that it is either a few years old or no NVIDIA / ATI card?
     
  16. tonyd

    tonyd

    Joined:
    Jun 2, 2009
    Posts:
    1,224
    I've tested SetPixel on an older machine, and even with a small 128 x 128 texture, I'm only getting around 14 fps.

    I'll compare that to SetPixels, as soon as I figure out how to make it work! :)
     
  17. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    I have a MacBook Pro 13" with a NVidia 320M. It's not a graphics card problem (I guess). :p
     
  18. tonyd

    tonyd

    Joined:
    Jun 2, 2009
    Posts:
    1,224
    That's intel, right? The machine that I see slowdowns on (even with power of two) is a single processor G5.
     
  19. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Apply() causes a big performance hit; a Mac Pro with a 5870 is reduced to 55fps or so when doing nothing but setting one pixel and calling Apply() on a 1024x1024 texture every frame, and a Mac mini with a GMA 950 can only manage 26-27fps when doing the same thing. It uses hardly any CPU though, so it must be limited by bandwidth. Depending on what you're doing, that speed may be acceptable, but it's still a big hit. Going down to 256x256 for the texture makes the fps go up to 500 (Mac Pro) and 90 (Mac mini) though.

    --Eric
     
  20. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,279
    Apply() = "Call Apply to actually upload the changed pixels to the graphics card." as the manual says.
    So this copies the system memory copy of the texture (which you modify) to the graphics card - so is not a CPU hit so much as bandwidth indeed.

    SetPixel must modify the system copy of the texture - it will not be fast if you want to modify say every pixel because just the fact that you are calling a function width*height times is a big CPU cost - thus to modify loads of pixels you could grab a copy of all pixels at program start - then each frame modify that array of Colors and call SetPixels.

    However - Unity must convert every Color value into the correct format for the texture which must be not cheap in itself.
     
  21. McKrackeN

    McKrackeN

    Joined:
    Oct 28, 2009
    Posts:
    51
    That's what I'm doing. But it doesn't matters how many pixels I change, the FPS are the same.