Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Fastest way to copy a Texture2D ?

Discussion in 'General Graphics' started by AnselmeUnity, May 11, 2023.

  1. AnselmeUnity

    AnselmeUnity

    Joined:
    Feb 26, 2014
    Posts:
    16
    Hi,

    I'm creating a game working with Kinect 2.0 and from time to time during the game, I'm saving some pictures with the camera, which involves getting the camera's Texture2D. However I'm forced to create a copy of this Texture2D in real-time to store the picture in memory, otherwise it's only grabbing a reference to the Texture2D on which the camera is rendering.

    The problem is that each capture is making a big spike lag (~40ms freeze) on the game due to the texture copying. I mean, lot of games are doing this, it should be possible to take the player in picture without affecting so much the FPS. Are there faster ways of copying a Texture2D ? Is there a way to do this operation in another thread so that it does not affect the main game loop ? There's surely a way to make this efficiently but I can't figure how.

    Thanks for the help

    Anselme.
     

    Attached Files:

  2. aras-p

    aras-p

    Joined:
    Feb 17, 2022
    Posts:
    74
    One thing to make sure would be to not create & destroy a texture all over again. Rather create one (or several, if needed) textures and reuse them.

    Absolutely the fastest way to copy a texture would be to not copy anything at all. Why do you need to copy it in the first place? I did not quite understand from your description.

    The second fastest way to copy a texture would be to use Graphics.CopyTexture.
     
    AnselmeUnity likes this.
  3. AnselmeUnity

    AnselmeUnity

    Joined:
    Feb 26, 2014
    Posts:
    16
    Hi, thanks for your answer.

    Each frame, the Unity-Kinect API is writing onto a specific Texture2D which contains the pixels of the camera.
    The thing is : if I want to take a snapshot of this Texture2D at any given time I need to save and copy the current content of the Texture2D somewhere, otherwise this data will be overriden on the next frame. In other words the Kinect camera's Texture2D is only containing the latest image of the camera. I don't know if that's clear. So I am forced to make copies of this Texture2D on real time in order to make captures, this is forced to happen.

    After lots of research I found that this might be one of the few solutions : https://github.com/keijiro/AsyncCaptureTest

    I was just wondering if it's normal to create a 50ms drop to copy a single texture of 1920x1080, and how games usually handle this as it does not seem to be something "impossible". I'm only asking for one or two pictures every 10s, but these spike of lag is making the game not really playable.
     
  4. c0d3_m0nk3y

    c0d3_m0nk3y

    Joined:
    Oct 21, 2021
    Posts:
    651
    Sounds like you are reading the data back from the GPU to the CPU which is slow indeed. Do you really need the data on the CPU? Why not just make a copy on the GPU with Graphics.CopyTexture, as aras-p said?

    If you really need it on the CPU, AsyncGPUReadback is the fastest way to do that but you have to be aware that it can take up to 3 frames before you get the data because the CPU can be to 3 frames ahead of the GPU (this is why you get a spike with the synchronous version - the CPU has to wait for the GPU to catch up).
     
    AnselmeUnity likes this.
  5. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,350
    if you can access the texture2d that kinect sets,
    could just grab raw byte array from it ? (and later save that as image, in another thread too)
    https://docs.unity3d.com/2023.2/Documentation/ScriptReference/Texture2D.GetRawTextureData.html

    alternatives:
    Nuitrack has this method that you can subscribe (it works with kinects too)
    https://github.com/3DiVi/nuitrack-sdk/blob/master/doc/Unity_RGB_Skeletons.md

    i guess kinect has some also,
    https://ratemt.com/k2gpapi/class_kinect_manager.html
    GetUsersClrTex2D
     
    AnselmeUnity likes this.
  6. AnselmeUnity

    AnselmeUnity

    Joined:
    Feb 26, 2014
    Posts:
    16
    Hi Both,

    Thanks for your answers !

    mgear : Indeed I tried by just grabbing the raw byte array and it's now a lot faster, and I'm decoding it as PNG when FPS is not important anymore. But I don't understand how is that copy faster than copying the texture2D itself, aren't both data the same size ? Could you brievly explain to me the difference this makes ?

    c0d3_m0nk3y : For this solution if I understand I would need to create a Texture2D and copy the image data onto it using Graphics.CopyTexture() ? For now I've been using SetPixels(). Is Graphics.CopyTexture() just a faster way to do this using the GPU ?
     
  7. aras-p

    aras-p

    Joined:
    Feb 17, 2022
    Posts:
    74
    CopyTexture is the fastest way to copy a texture, if you don't need to access it on the CPU. The docs are pretty elaborate: https://docs.unity3d.com/ScriptReference/Graphics.CopyTexture.html

    If you do need to access the texture pixels on the CPU (e.g. save it as a PNG file, etc.), then doing async readback like suggested above would be the most efficient way -- especially if you can wait on the async readback to naturally finish (usually that finishes in a couple of frames), without stalling the rest of the game.
     
    AnselmeUnity and c0d3_m0nk3y like this.
  8. SpookyCat

    SpookyCat

    Joined:
    Jan 25, 2010
    Posts:
    3,748
    So is Graphics.CopyTexture faster than Graphics.Blit?
     
    AnselmeUnity likes this.
  9. c0d3_m0nk3y

    c0d3_m0nk3y

    Joined:
    Oct 21, 2021
    Posts:
    651
    Yes, CopyTexture just copies the memory. Blit runs a shader for each pixel.

    CopyTexture works only if the source and destination have compatible (usually identical) formats.
     
    AnselmeUnity likes this.
  10. AnselmeUnity

    AnselmeUnity

    Joined:
    Feb 26, 2014
    Posts:
    16
    Ok, thanks for the help everyone !