Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Texture2D.SetPixels that takes a srcRect and destRect would be nice

Discussion in 'Scripting' started by Twitwi, Aug 22, 2018.

  1. Twitwi

    Twitwi

    Joined:
    Apr 11, 2012
    Posts:
    22
    I am trying to optimize a method in our code. From profiling we found the offending line to be a call to SetPixels.

    We have a spirte with a texture (1024x1024 pixels) and a color buffer of the same size. We make a lot of edits to our color buffer and the we apply the entire thing the a single:
    SetPixels(Color[] colors, int miplevel = 0)


    Since we can know ahead of time which part of the color buffer has changed, I was hoping we could use:
    SetPixels(int x, int y, int blockWidth, int blockHeight, Color[] colors, int miplevel = 0);


    However; that stretches the color buffer in unfortunate ways.

    To demonstrate I have made an example project:
    Original Texture:


    Color Buffer (the same image but slightly darker):


    The Result I was hoping for when calling OriginalTexture.SetPixels(256, 256, 512, 512, ColorBuffer);


    The result I got:



    As you can see, I did not get the same region of the ColorBuffer, instead I got the x=0,y=0 and with the picture stretched height (and width but of course you cannot see that in a gradient).

    In our use case we, we get 5-10 smallish (like max 64x64 pixels) areas around the same general area, that needs to be updated. So I would like to avoid having to allocate 5-10 color buffers, as I am trying to optimize.

    If I had a SetPixels that took a source and a dist rect (like: Texture2D.SetPixels(RectInt source, RectInt destination, Color[] colors, miplevel = 0); ) then that would solve my problem.

    Has anyone tried to do similar? What solutions did you come up with?
     
  2. Twitwi

    Twitwi

    Joined:
    Apr 11, 2012
    Posts:
    22
    Like for this project we have the following metrics:
    Code (CSharp):
    1. m_Texture.SetPixels(m_TexturePixelBuffer); // 20.89 ms
    Code (CSharp):
    1.  
    2. for (int y = changedPixels.yMin; y < changedPixels.yMax; y++)
    3. {
    4.     int yIdx = y * changedPixels.height;
    5.     for (int x = changedPixels.xMin; x < changedPixels.xMax; x++) // <- Could probably squeeze 1.5 ms more out by caching xMax outside the loop
    6.     {
    7.         m_Texture.SetPixel(x, y, m_TexturePixelBuffer[x + yIdx]);
    8.     }
    9. } // 12.34 ms
    10.  
    Code (CSharp):
    1.  
    2. // [...  
    3. // Recreating the buffer m_TexturePixelBuffer but just in that area
    4. // ...]
    5.  
    6. m_Texture.SetPixels(
    7.     changedPixels.x, changedPixels.y,
    8.     changedPixels.width, changedPixels.height,
    9.     tempBuffer); // 0.99ms but also 504KB
    10.  
    I have some nasty artifacting currently with the 2nd and 3rd solution, but I believe that is my own fault.

    Still from the numbers it seems like reducing the amount of pixels that need to be set significantly reduces the time spent, and I'm guessing that SetPixels internally is 2 nested for loops (for x and y) and maybe some SIMD magic for performance. So I don't see why Texture2D.SetPixels(RectInt, RectInt, Color[] colors) could/should-n't be a thing.