Search Unity

RWTexture2D shader in OnPostRender problems...

Discussion in 'Shaders' started by bd, Mar 10, 2013.

  1. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    I'm trying to play a bit with RenderTexture/RWTexture2D. In my c# code, within my OnPostRender block, I have code like this:

    Code (csharp):
    1. private RenderTexture g_texTest = null;
    2. void OnPostRender()
    3. {
    4.     if(g_texTest == null)
    5.     {
    6.         g_texTest = new RenderTexture(1, 1, 0, RenderTextureFormat.RInt);
    7.         g_texTest.enableRandomWrite = true;
    8.         g_texTest.hideFlags = HideFlags.HideAndDontSave;
    9.         g_texTest.filterMode = FilterMode.Point;
    10.         g_texTest.Create();
    11.        
    12.         //clear initially (I assume this is valid even though the texture is RInt??)...
    13.         Graphics.SetRenderTarget(g_texTest);
    14.         GL.Clear(false, true, new Color(0,0,0,0));
    15.     }
    16.     ...
    17.     Graphics.ClearRandomWriteTargets();
    18.     Graphics.SetRandomWriteTarget(1, g_texTest);
    19.     camRef.RenderWithShader(shader, "RenderType");
    20.     Graphics.ClearRandomWriteTargets();
    21. }
    And within the shader (which works aside from the RWTexture2D), I have something like this:

    Code (csharp):
    1. RWTexture2D<int> textureTest : register(u1);
    2. half4 frag(v2f input) : COLOR
    3. {
    4.     int iTextureTest;
    5.     iTextureTest = textureTest[uint2(0, 0)];
    6.     textureTest[uint2(0, 0)] = 0x000000FF;
    7.     vfRGBA = float4(iTextureTest  0x000000FF,
    8.         (iTextureTest >> 8)  0x000000FF,
    9.         (iTextureTest >> 16)  0x000000FF,
    10.         (iTextureTest >> 24)  0x000000FF);
    11.    
    12.     vOutput.rgb = vfRGBA.rgb / 255.0f;
    13.     vOutput.a = 1;
    14.     return vOutput;
    15. }
    So, what do I expect to see? Well, I expect the first frame's first few hundred pixels to be black (since they won't yet have "red" set and I'm not using atomics), but then as things make their way through the various caches, the remaining pixels should all should red.

    And indeed that's exactly what I see, but only on the first frame. On every subsequent frame, everything I read is black, almost as if the texture has been invalidated. I assume that the texture should still be valid from frame to frame though, but perhaps I'm just fundamentally misunderstanding how things are supposed to work here?
     
  2. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    On first look it sounds like this should work. Do you have full repro project somewhere?
     
  3. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    Sure - I've included a .7z file that should have everything. I basically started from the ShowUVMapping sample. The single frame of red is easy to miss unless stopped in the debugger. Thanks!! :)

    FWIW, I'm running this test on a GTX-670 (driver version 301.42) with Windows7-Pro(64) SP1.
     

    Attached Files:

  4. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    Were you able to repro? Can I provide anything else if not?
     
  5. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Sorry, was travelling for a few days...
    ...I'm not able to download the file though (all I get is a 1x1 pixel gif). I'm poking IT/forum folks, but in the meantime you're welcome to file a bug with the file, or post the file somewhere else where I can access it (dropbox?).
     
  6. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
  7. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Hmm, I actually can't see what is going wrong. Everything seems to be working as normal, PIX displays the right order of calls and stuff, but the UAV texture apparently doesn't get the right values written. PIX does not display UAVs or RInt texture contents, so not much help in debugging with it. No idea what's going wrong!

    In a small examples project that I did a while ago (http://files.unity3d.com/aras/dx11/DX11Examples-4.0.0b7.zip), building a histogram with UAV writes from PS does seem to be working (see _RandomWriteInPixelShader scene). There I do it as a postprocessing effect, reading the input image (instead of re-rendering the scene like you do).
     
  8. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    Yes, and I saw that example (and played with it). And that one works for me, too. Frustrating! So there is fundamentally something "different" about what I'm trying to do, but hell if I know what. What stinks is that this really is the use case I'm trying to test - there no obviously simple other way to do what I'm trying to (render geo, use and/or update data in buffer based on geo, do the same in the next frame, etc).

    If you modify what I did to use a structured buffer, not even the first frame will work. :|

    The differences between the histogram and what I do that come to mind are: 1) I'm doing a geometry render instead of full screen pass, 2) I'm not initializing the data each frame (and maybe Unity is trying to infer something from that?).

    As for 1), did you manage to see the single frame of red in my example? That shows, I think, that the UAV *is* working, because only the PS writes red there. That it works one frame but not the next makes me think this is a Unity thing (barring a DX bug, I guess). I mean, the example is dead simple, right?

    2) Does Unity somehow think after the first frame that the data might no longer be referenced? Is it possible that some code is making a bad assumption about usage and "doing" something, like invalidating the texture, or setting the wrong values/state in subsequent frames?

    Even though PIX is not showing you contents, can you tell if Unity is actually setting up state with the same texture (as opposed to a dummy one) in the second and subsequent frames? Also, is it possible Unity has released/GC'd the texture (or something critical to its use) somewhere along the line between the first and second frame? Sadly, I'm kind of blind without source.

    I'll try some more poking around on my side - I think I might also try to set up a quick C++ DLL and render myself (with a Unity created texture and with one of my own) to try and isolate whether this is Unity or not...

    Ben
     
  9. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    So, are you sure PIX is displaying the calls in the expected order?? My PIX-fu is not strong (ok, I just opened it for the first time a couple of hours ago), but I did a capture and tried to make sense of it. Here is the PIX file: http://we.tl/XZ7IbJ7a75

    First, I found the Texture itself, with resource address 0x1EDAE5C0. Then I looked at who references that texture, and I get these:

    8038 <0x0C7A6B28> ID3D11Device::CreateRenderTargetView(0x1EDAE5C0, 0x1C19F34C, 0x105873E4 --> 0x1EDADE88)
    8040 <0x0C7A6B28> ID3D11Device::CreateRenderTargetView(0x1EDAE5C0, 0x1C19F304, 0x105873FC --> 0x1EDADEE0)
    8042 <0x0C7A6B28> ID3D11Device::CreateShaderResourceView(0x1EDAE5C0, 0x1C19F300, 0x105873BC --> 0x1EDADF38)
    8045 <0x0C7A6B28> ID3D11Device::CreateUnorderedAccessView(0x1EDAE5C0, 0x1C19F2E8, 0x105873C4 --> 0x1EDADF90)

    Resource 0x1EDADEE0 and 0x1EDADF38 are never used it seems (??), but 0x1EDADE88 and 0x1EDADF90 are. 0x1EDADE88 corresponds to the initialization I do, clearing the texture to black. 0x1EDADF90 corresponds to the UAV usage. Frame 20 is the one working frame. Frame 21 seems to be Unity drawing its own UI (I closed as many Unity windows as I could to make PIX spew a little less). And frame 22 is the second frame, where everything is black.

    The thing is, I'm not convinced Unity is setting things up properly after the first frame. Here is a (very abridged) set of DX calls, tracking usage of that texture, the first draw call for each frame, and when render targets (and UAVs) are set up. And it's curious:

    8038 <0x0C7A6B28> ID3D11Device::CreateRenderTargetView(0x1EDAE5C0, 0x1C19F34C, 0x105873E4 --> 0x1EDADE88)
    8045 <0x0C7A6B28> ID3D11Device::CreateUnorderedAccessView(0x1EDAE5C0, 0x1C19F2E8, 0x105873C4 --> 0x1EDADF90)
    8053 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargets(1, 0x1C19F330 --> { 0x1EDADE88 }, 0x1EDADFE8)
    8055 <0x0C802FD8> ID3D11DeviceContext::ClearRenderTargetView(0x1EDADE88, 0x1A74E680)
    8065 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(1, 0x1C19F330 --> { 0x1EDCB3C8 }, 0x1EDCB4D0, 1, 2, 0x1C19F320 --> { 0x1EDADF90, NULL }, 0x1C19F370 --> { 0, 0 })
    8096 <0x0C802FD8> ID3D11DeviceContext::DrawIndexed(36, 0, 0)
    8170 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(1, 0x1C19F330 --> { 0x1EDADE88 }, 0x1EDADFE8, 1, 2, 0x1C19F320 --> { 0x1EDADF90, NULL }, 0x1C19F370 --> { 0, 0 })
    8173 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargets(1, 0x1C19F35C --> { 0x1EDADE88 }, 0x1EDADFE8)
    8252 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargets(1, 0x1C19F330 --> { 0x0C846198 }, 0x0C8462A0)
    8718 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargets(1, 0x1C19F338 --> { 0x1EDCB3C8 }, 0x1EDCB4D0)
    8720 <0x0C802FD8> ID3D11DeviceContext::OMSetRenderTargets(1, 0x1C19F330 --> { 0x1EDCB3C8 }, 0x1EDCB4D0)
    9183 <0x0C802FD8> ID3D11DeviceContext::DrawIndexed(36, 0, 0)


    There are two things here I don't understand and find curious:

    1) OMSetRenderTargets is set many times after the first frame, but OMSetRenderTargetsAndUnorderedAccessViews is not. When I read the docs on OMSetRenderTargetsAndUnorderedAccessViews and OMSetRenderTargets, they appear to be setting the same resources (there are 8 possible slots, shared between render targets and UAV). That is, OMSetRenderTargets would appear to possibly kill any UAV. Or, at least I saw nothing indicating what the exact interaction was between OMSetRenderTargets andOMSetRenderTargetsAndUnorderedAccessViews, which makes me suspicious that if you call one, the settings of the other may not be defined?

    2) Event 8173 is a curious one. It sets both a color target and a depth target. But isn't the color target the same one as the 1x1 texture target view? And this is right before rendering the GUI stuff?? Maybe the render state is such that this doesn't matter (maybe color writes are disabled?), but according to the MSDN docs, whenever a render target is set using a view that overlaps a UAV, the UAV gets set to NULL and reads as black. And this sounds mighty familiar.

    Does this make any sense to you? I'm no DX expert, so I could totally be missing something - but still, at first glance it looks like Unity might be doing something wonky here...

    Ben
     
  10. Kuba

    Kuba

    Moderator

    Joined:
    Jan 13, 2009
    Posts:
    416
    Hey Ben,

    Short story: update your drivers to 314.22. :)

    Long story:
    It's not an issue specific to Unity. Tim and I were extending Aras' example to make a proper histogram. We wanted to use a RWTexture2D<int> texture to be able to call InterlockedAdd(). Even without InterlockedAdd() it didn't seem to work, whereas RWTexture2D<float> worked nicely.

    I noticed that Stephen Hill had an example with RWTexture2D<uint> and it didn't work on any of the machines I tried -- Windows 7 machines with NVIDIA cards: GTX 580, 560 Ti, 480. The 580 used 314.07 drivers (the newest 2.5 weeks ago) and the rest something quite recent too. The example worked for Stephen before, but then it stopped working.

    Check it out -- http://blog.selfshadow.com/2012/11/12/counting-quads/ -- if you get a pie chart with 4 slices of equal sizes, then the drivers are b0rked.

    We ended up using RWStructureBuffer<int> for our talk: http://is.gd/UnityRenderingPipeline_GDC13.

    Stephen just told me that the newest drivers 314.22 fixed the issue for him.
     
  11. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    Hey Kuba! Thanks for the reply. I'm not convinced that the issue I'm reporting here is the same issue Stephen had. I honestly think there may be a state bug in Unity. Still, when I get a moment this weekend, I will see about trying again with floats and the latest NV driver.

    I've got an open support request with the actual files needed to make the PIX capture above. It would be interesting if you too were able to replicate the behavior I found with the most recent NV drivers to verify whether this is a Unity issue or not.

    As for Stephen's issues, I think they were partially driver related, and partially related to inconsistency with how DX/GL orders the execution of threads (ill-defined w.r.t various IHVs).

    You can follow our twitter conversation about it. :) https://twitter.com/marcosalvi/status/322225748452732928
     
  12. Kuba

    Kuba

    Moderator

    Joined:
    Jan 13, 2009
    Posts:
    416
    I should check the Twitters more often :) I'll dig deeper once I'm back at the office in 1.5 weeks, travelling in Asia now.
     
  13. bd

    bd

    Joined:
    Feb 16, 2013
    Posts:
    13
    Lucky!
     
  14. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    was this ever resolved? I think I am running into the same problem, and I've updated my drivers to the latest nvidia betas.
     
  15. JakubNei

    JakubNei

    Joined:
    Jul 20, 2013
    Posts:
    26
    same here, having issues with RWTexture2D<int>

    for some reason this works, the out shows nice gradient same as in.
    Texture2D<int> in;
    RWTexture2D<int> out;
    out[id.xy] = in[id.xy];

    but if I try to set the value my self, I can't get it working, no gradient at all, behaves like 1bit per pixel texture.
    int red = 2147483647 - 8388607;
    int black = a + 1;
    out[id.xy] = red; // shows full red
    out[id.xy] = black; // shows full black

    the magic numbers seem to be consitent across different RInt textures and shaders

    1059547520 seems to be roughly 0.5

    appears the int texture has it's range in the few middle bytes of int ?
    anyone have any idea how the RWTexture2D<int> actually works ?
     
    Last edited: Aug 22, 2017