• 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
Question by Mizuho · Jun 12, 2012 at 11:54 PM · texturetexture2dsetpixelssetpixel

For different texture sizes, which is faster? SetPixel or SetPixels?

I happen to generate quite a few textures (of fairly small size; less than < 300 most of the time) and was just wondering if there was some significant difference in space or cost between using SetPixel and SetPixels?

 int size = 300;
 // No mip-maps because this is a 1-to-1 for the GUI usually
 Texture2D texture = new Texture2D(size, size, TextureFormat.ARGB32, false);
 for(int a = 0; a < size; a++) {
     for(int b = 0; b < size; b++) {
         texture.SetPixel(a, b, Color.white);
     }
 }
 // Down here I would actually change the texture (above makes a "blank" canvas)

And for SetPixels, it looks like:

 int size = 300;
 Texture2D texture = new Texture2D(size, size, TextureFormat.ARGB32, false);
 Color[] colors = new Color[size * size];
 for(int a = 0; a < Mathf.Pow(size, 2); a++) {
     texture.SetPixels(colors);
 }
 // Do stuff to change texture

So which is faster? Is there any significant difference between them, and when does it happen (in 1000x1000 texture sizes)?

EDIT: Tried benchmarking this and I found that SetPixel is actually slower than SetPixels even at 1x1 texture sizes. SetPixels32 is faster than SetPixels for any texture larger than 2x2.

 SetPixel, size: 1, time: 0.003963776
 SetPixels, size: 1, time: 0.0005910769
 SetPixels32, size: 1, time: 0.0005298704

 SetPixel, size: 100, time: 0.003605723
 SetPixels, size: 100, time: 0.002427459
 SetPixels32, size: 100, time: 0.001961112
 
 SetPixel, size: 1000, time: 0.05630431
 SetPixels, size: 1000, time: 0.2315033
 SetPixels32, size: 1000, time: 0.1754332

EDIT 2: Wolfram actually benchmarked the functions and s/he is obviously better at benchmarking than me (benchmark noobs, unite!), so I'll post those benchmarks in here...

                          4096x4096 512x512  64x64     8x8     1x1
 SetPixel                     21.1s   20.0s  20.6s    19.9s   20.4s
 SetPixels+fillArray           7.7s    7.5s   7.4s     7.9s   32.9s
 SetPixels                     5.9s    5.3s   5.3s     5.7s   29.2s
 SetPixels32                   1.8s    0.59s  0.62s    1.2s   34.1s
 SetPixel:SetPixels           x3.6    x3.8   x3.9     x3.5    x0.7
 SetPixel:SetPixels32        x11.5   x33    x33      x16.3    x0.6
 SetPixels:SetPixels32        x3.22   x9.0   x8.5     x4.7    x0.9
Comment
Cenroh

People who like this

1 Show 7
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 · Jun 13, 2012 at 03:42 AM 0
Share

I think your benchmarks are flawed. You have to loop a significant number of times to get results that mean anything (like, at least a million times, so that the time is greater than .1 second), plus you should run the tests multiple times and average the results. When setting a single pixel, SetPixel is faster than SetPixels, which makes sense because SetPixels has some overhead for dealing with arrays.

avatar image Wolfram · Jun 13, 2012 at 11:29 AM 1
Share

Also, note that your current example for SetPixels() is incorrect and does way too much work. You'd need to change your code to this:

 for(int a = 0; a < size*size; a++) {
     colors[a]=Color.white;
 }
 texture.SetPixels(colors);

In addition, try to avoid Mathf.Pow(), it is unbelievably expensive.

avatar image Mizuho · Jun 13, 2012 at 11:31 PM 0
Share

@Eric5h5: I realize the benchmarks are flawed since I didn't really want to blow time attempting to let my graphics card do a million Texture2D.Apply()'s (it's in pretty bad shape already). It gives a consistently faster time for SetPixels, especially on higher sizes though, so I think it's good enough for a general feel.

@Wolfram: That's actually how it looks now. I removed the Mathf.Pow() to have it not affect the times. I put texture.Apply() into each benchmark though, so I think that's eating most of the time.

Overall, I'm not a benchmarking person, and this is my first time actually trying. I now know that I suck at it.

avatar image Eric5h5 · Jun 13, 2012 at 11:45 PM 0
Share

Well, you don't want to put Apply() in there, that's not the issue here...we already know Apply() is slow. ;)

avatar image Wolfram · Jun 14, 2012 at 01:10 AM 0
Share

See the last comment in my answer you accepted, I added a table with some benchmarking results.

Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by Wolfram · Jun 13, 2012 at 12:23 AM

Your second code example is wrong, you are assigning 90000 times the same pixel array to your texture, which doesn't make sense.

To answer your question, SetPixel() will be significantly slower, possibly by an order of magnitude or more. You are setting each of the single pixels individually, 90000 times in total, calling a function that needs to access the texture data, compute the exact location of that pixel, and replace it, plus there is the loop overhead of 300x executing the inner loop.

On the other hand, SetPixels() is just one call, assinging the whole array, which can just memcopied into the texture data.

EDIT:

If your question is about how to best initialize the array, a compromize might be feasible: With your first approach you'll need to execute a statement 90000x in two nested loops. With your second approach you'll need to execute a statement 90000x (=filling the color array with its initial value (note, in your current code, the color will be black, since it is not initialized)).

Instead, the fastest method (*) will be to create a Color array of size 300, initialize that, and then call SetPixels 300 times, setting one row at a time:

 for(int a = 0; a < size; a++)
     texture.SetPixels(0,a,size,1,colors);

(*) EDIT: After doing some benchmarks, you don't gain anything by splitting the initialization into a "one row at a time" loop. So simply create a Color32[size*size] array, initialize it, and use a single call to texture.SetPixels32(). This will be fastest for most texture resolutions, as @Eric5h5 explained.

Comment
Eric5h5

People who like this

1 Show 6 · 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 · Jun 13, 2012 at 12:43 AM 1
Share

SetPixel actually isn't that much slower than SetPixels, maybe 3X for the same number of pixels. A lot of the overhead is converting Color, and the texture isn't actually changed until you use Apply(). It's better to use SetPixels32 than SetPixels, not only because SetPixels32 is around 5X faster then SetPixels, but because it uses 4X less RAM for the array. That makes SetPixels32 about 15X faster than SetPixel for the same number of pixels; there isn't a SetPixel32.

avatar image Wolfram · Jun 13, 2012 at 01:04 AM 0
Share

However, in his question he is filling the texture with an initial color, which would mean 90000 calls to SetPixel() vs. 1 call to SetPixels() (plus filling the Color array, of course).

Also, the difference in speed will highly depend on the number of pixels in the block accessed simultaneously by SetPixels(). Unless by "3X slower" you mean the actual execution time of the same number of calls to SetPixel() vs. SetPixels()?

avatar image Mizuho · Jun 13, 2012 at 02:19 AM 0
Share

So in general, SetPixels is faster, but is that still true for small numbers (300 was an example)? I assume that SetPixels doesn't internally call SetPixel. Also, sorry about the code quality, it was just a quick example and I was tired (/excuse). ...Also never used SetPixels because I assumed it wouldn't have any significant difference for the texture sizes I was making.

avatar image Wolfram · Jun 13, 2012 at 02:29 AM 0
Share

Well, it should be simple enough to setup a little benchmark for that. Use the two variants of the code, and maybe my per-row example as another variant, and maybe also a SetPixels32() variant, and wrap each into something like this:

 float startTime=Time.realtimeSinceStartup;
 for(int benchmarkLoop=0;benchmarkLoop<maxLoopAmount;benchmarkLoop){
     // place the code you want to benchmark here
 }
 Debug.Log("Execution took "+(Time.realtimeSinceStartup-startTime)+" seconds.");

Then you can experiment with "size" and so on.

avatar image Eric5h5 · Jun 13, 2012 at 02:30 AM 0
Share

@Wolfram: yes, if you're filling, say, a 512X512 texture with SetPixel, using SetPixels would be 3X faster. Regardless of 90000 calls vs 1 call, all of those pixels still have to be converted from Color to the "real" byte values. But SetPixels32 would be 15X faster, primarily because that conversion no longer has to be done.

@Mizuho: see my answer for when you'd use SetPixel. If you are filling an entire texture (or a significant rectangular portion of one), use SetPixels. If you're drawing some arbitrary pixels, use SetPixel. It's not really anything to do with the size of the texture.

Show more comments
avatar image

Answer by Eric5h5 · Jun 13, 2012 at 12:28 AM

The times when it makes sense to use SetPixel instead of SetPixels is if you're only changing a relatively few individual pixels in different places, and you don't want the overhead of getting an array, making a few changes in the array, then copying the array back.

Comment
Wolfram
Shkarface-Noori

People who like this

2 Show 2 · 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 Mizuho · Jun 13, 2012 at 02:32 AM 0
Share

I was kinda like "What?" when I first read this answer because of the GetPixel instead of SetPixel. It makes sense though, but the other answer has all the numbers for speed differences.

avatar image Eric5h5 · Jun 13, 2012 at 02:36 AM 0
Share

Oops, yeah. ;) SetPixel. Not GetPixel.

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Drawing a solid circle onto texture 2 Answers

How to make a custom GUITexture at runtime? 2 Answers

What is the best way to reset textures in the editor after SetPixels? 1 Answer

Fastest rendering of 2D world with lots of changes to screen every frame? 3 Answers

change part of texture with color or other texture 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