- Home /
Is operating using GetRawTextureData faster that doing SetPixel/Pixels?
I'm writing a Texture2D manipulation script and I wonder if switching the way of doing thins would make it faster - does using the NativeArray that you get from GetRawTextureData give a performance advantage vs just Getting and Setting pixels?
Answer by Kaart · Jul 31, 2020 at 10:50 PM
I was curious myself and wrote a small program to test this. While I'm not really familiar with RawTextureData it doesn't seem to be much slower or faster than Texture2D.GetPixels() and Texture2D.SetPixels(). However Texture2D.GetPixel(x,y) and Texture2D.SetPixel(x, y) is much slower when you need to manipulate multiple pixels.
I used a 1000x1000 .png image to test with the following import settings:
I did a few runs and this would be a typical result:
I've included the script I used if you want to do further testing, I'm really interested in your results. using System.Diagnostics; using UnityEngine;
public class Example : MonoBehaviour
{
[SerializeField]
private Texture2D _image;
private Stopwatch _stopwatch = new Stopwatch();
// Start is called before the first frame update
void Start()
{
if (_image != null)
{
TestGetSetPixel();
TestGetSetPixels();
TestRawTextureData();
}
}
private void TestGetSetPixel()
{
_stopwatch.Start();
for (int y = 0; y < _image.height; y++)
{
for (int x = 0; x < _image.width; x++)
{
Color color = _image.GetPixel(x, y);
// Do something fancy with the color value.
color = new Color(0f, 0f, 0f);
_image.SetPixel(x, y, color);
}
}
_stopwatch.Stop();
UnityEngine.Debug.Log("TestGetSetPixel took: " + _stopwatch.ElapsedMilliseconds + " milliseconds to complete.");
_stopwatch.Reset();
}
private void TestGetSetPixels()
{
_stopwatch.Start();
Color[] colors = _image.GetPixels();
for (int i = 0; i < colors.Length; i++)
{
// Do something fancy with the color value.
colors[i] = new Color(0f, 0f, 0f);
}
_image.SetPixels(colors);
_stopwatch.Stop();
UnityEngine.Debug.Log("TestGetSetPixels took: " + _stopwatch.ElapsedMilliseconds + " milliseconds to complete.");
_stopwatch.Reset();
}
private void TestRawTextureData()
{
_stopwatch.Start();
Unity.Collections.NativeArray<Color32> colors = _image.GetRawTextureData<Color32>();
for (int i = 0; i < colors.Length; i++)
{
colors[i] = new Color32(0, 0, 0, 255);
}
_image.Apply();
_stopwatch.Stop();
UnityEngine.Debug.Log("TestRawTextureData took: " + _stopwatch.ElapsedMilliseconds + " to complete.");
_stopwatch.Reset();
}
}
So in my implementation I'm blurring an image, so I do need to make changes per individual pixel and it turns out that yes, when there are hundreds/thousands of those then setting individual bytes in the NativeArray is faster than doing GetPixel, SetPixel. In my case I had a texture with TextureFormat.RGB24, which means there are 3 array elements per color, but I think it would still be faster even with RGB32.
The exact values probably have a lot to do with other stuff in the implementation, but the SetPixel GetPixel one took around 3050ms on a 1600x800 texture and around 2000ms with GetRawTextureData(), with the same resolution and other settings of the blur.
Please note there is a difference between Texture2D.GetPixel()/SetPixel() and Texture2D.GetPixels()/SetPixels(). The later uses a Color array which is much faster than getting and setting each individual pixel colors using GetPixel()/SetPixel().
Answer by joshrs926 · Feb 07 at 07:43 PM
Yes it can be a lot faster depending on a few things. First you need to know exactly what format Unity has stored the pixels. For example they might be stored as RGBA32 which means each pixel is 4 bytes, 1 byte per channel or it might be stored as RGB24 which is similar but without the alpha so it is 3 bytes per pixel. Also you'd be getting/setting bytes not floats so a float value of .5f would probably be rougly a byte value of 128. You'd have to do that conversion. Using GetRawTextureData I think will also avoid some copying of data back and forth. The big speedup up you can get is using the Job system with burst and multithreading to manipulate that data. You have to provide a job with a NativeArray (or some other Native Collection). If you aren't sure about the data format you could actually use GetPixels to get a Color[] and then create a NativeArray from it and give that to the job too. This would involve multiply copies but might be faster than manipulating the data outside a bursted job. Coverting code to Bursted Jobs can give orders of magnitude speed ups.
Your answer
![](https://koobas.hobune.stream/wayback/20220613004558im_/https://answers.unity.com/themes/thub/images/avi.jpg)