Search Unity

[Bug 842097] DiscardContents() doesn't work with 3D RenderTexture

Discussion in 'General Graphics' started by raphael-ernaelsten-heaj, Oct 17, 2016.

  1. raphael-ernaelsten-heaj

    raphael-ernaelsten-heaj

    Joined:
    Mar 9, 2016
    Posts:
    78
    I tried to clear the content of my 3d render texture but DiscardContents() doesn't work on 3D RenderTextures.

    Who has encountered the same issue, or who has found a (non costy) workaround?
     
  2. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    DiscardContents doesn't clear texture contents. It is more like a hint that tells the driver that the texture contents are no longer needed. It can then do some optimizations. All of that applies only to some platforms. Mostly mobile gpus. It does nothing on PC for example.

    What you want to use is GL.Clear(). It clears currently bound render texture. Some platforms let you bind entire 3d render texture at once (use Graphics.SetRenderTarget with depthSlice = -1). On other platforms you have to bind and clear one depth slice at a time with Graphics.SetRenderTarget and GL.Clear. You'll need at least Unity 5.4 for that.

    You can alternatively use compute shader to clear your texture. That would work on older versions of Unity.
     
  3. raphael-ernaelsten-heaj

    raphael-ernaelsten-heaj

    Joined:
    Mar 9, 2016
    Posts:
    78
    Hello Michal!
    Thank you for your answer.

    My understanding is different.

    After reading the documentation, I would say that the behavior you are describing is triggered by the Release() function :
    The documentation is not very precise about the DiscardContents() method but a hint can be found on the page documenting the MarkRestoreExpected() function :
    They are directly linking the clearing action and the discarding method.

    I also tried GL.Clear() but it has no luck with 3D rendertexture either. :(

    Writing in a Texture3D is costly as hell (even with a compute shader) because of the obvious amount of "voxels" to write. Clearing/Discarding is a quick low level action simply replacing the memory from &A -> &B with 0.
     
  4. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    Ok, I don't have a Unity source code around so I could be wrong but I think that RenderTexture.Release releases GPU part of the texture and keeps the CPU part around for possible future use. That's not what I was talking about.

    I'm talking about following situation. Some (mostly mobile) gpus have small and very fast memory pool for render textures. Everything is fine as long as all your textures can fit into this cache. If they don't fit the gpu has to take one that isn't needed at the moment and copy its content into different memory pool. And then back if you want to use it again. This store/restore operation is very costly.
    Calling RenderTexture.DiscardContents tells the driver that you're going to manually clear/rewrite the texture before next use and the gpu doesn't have to store/restore its contents.
    And you use MarkRestoreExpected when you care about the contents and you want this store/restore operation to happen. When you don't want to use clear or discard.
    It is this extension in OpenGL ES world (xbox had similar one). That is my understanding based on Unity docs and my previous experience with mobile renderer.

    Shame if GL.Clear doesn't work. I didn't try it myself but that's how the underlying API does it. You have to bind it and then clear it.
     
  5. raphael-ernaelsten-heaj

    raphael-ernaelsten-heaj

    Joined:
    Mar 9, 2016
    Posts:
    78
    Hello Michal,
    I now understand better what you meant.
    I must have misunderstood the documentation.

    As workaround, when I said I tried to clear with GL.Clear() and it didn't work, I wasn't aware that specifying -1 in the depthSlice would bind the whole 3D rendertexture (they'll probably want to document this @Aras ). That's the part I was missing.
    It works now with GL.Clear() workaround. Thanks :)

    EDIT : I keep the thread alive as the DiscardContents() effectively clears the content on 2D render textures but not on 3D render textures. As confirmed by Q&A (https://issuetracker.unity3d.com/issues/discardcontents-doesnt-discard-3d-rendertexture)