1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

Compute Shaders

Discussion in 'Developer Preview Archive' started by FPires, Aug 26, 2012.

  1. FPires

    FPires

    Joined:
    Jan 5, 2012
    Posts:
    127
    Greetings!

    First of all, I'd like to thank the Unity crew for their amazing work.

    I would like to know if anyone's managed to get compute shaders working, as they don't appear to be functional here. I opened a Bug Report Ticket (486962) including a sample scene.

    I'm currently using a GeForce GTX 460 which, as far as I'm aware (from NVidia website and NVIDIA Control Panel) supports DX11 as it states my current DX version is 11.1; Driver version 304.79; Windows 8 64-bits. Unity 4.0 is set to support DX11 in the Preferences and in the Windows Build settings.

    Which leads me to one (or more) of these hypothesis:

    1) Windows 8 has some crazy compatibility issues. Unfortunately I do not have a DX11-ready W7 machine here at the moment (as I'm using the other computer to test compatibility with Intel integrated video cards), hence why I'd like to hear from your experiences.

    2) A human-made error. Either the documented shader code doesn't work or I'm not initializing the .compute files correctly (probably).

    3) Compute Shaders are simply not active right now.

    4) There's some odd compatibility issue with my video card.


    What's befuddling me is that DX11 by all means seems to be enabled (I was getting errors before setting DX11 in the Preferences). There's a definite bug happening regardless of human error - if I initialize a Texture2D with the following code:

    Code (csharp):
    1.     public Texture2D sampleTex;
    2.     public ComputeShader compute;
    3.    
    4.     void Start () {
    5.         sampleTex = new Texture2D(128,128);
    6.            
    7.         compute.SetTexture(0,"res",sampleTex);
    8.         compute.Dispatch(0,4,4,1);
    9.         //Using compute.FindKernel returns 0 as the correct Kernel.
    10.  
    11.         renderer.material.SetTexture("_MainTex",sampleTex);    
    12.  
    13.     }
    And I use a RWRT in the Compute Shader as in the documentation:

    Code (csharp):
    1. #pragma kernel FillWithRed
    2.  
    3. RWTexture2D<float4> res;
    4.  
    5. [numthreads(32,32,1)]
    6.  
    7. void FillWithRed (uint3 dtid : SV_DispatchThreadID)
    8. {
    9.     res[dtid.xy] = float4(1,0,0,1);
    10.    
    11. }

    The Editor creates a standard Texture2D (a blank image with light grey color) when you hit "Play", but once you stop the scene it displays a standard RenderTexture (dark grey with darker edges) in the material. This doesn't happen if you build (it will display a generic RT during Play), which means at some point a ComputeShader is being dispatched, but using a native RWRT instead of a T2D doesn't fix the issue either. If you've got Compute Shaders working, could you tell me where is the error here?

    Thanks!
     
  2. MattCarr

    MattCarr

    Joined:
    Jul 5, 2009
    Posts:
    224
    I spent 30 mins messing around with them a couple of days ago and wasn't able to get anything working. I too tried the FillWithRed with render texture similar to you and didn't see any expected result. I also wrote a couple of compute shaders to test simple setting array values with RWStructuredBuffer instead of RWTexture2D, but couldn't see any way to retrieve returned values in script. ComputeBuffer class had no methods to return data from what I could see.

    I think the compute shaders were compiling and working fine since it would report compile errors when I'd intentionally add errors. Hopefully we're either missing something or full support will be added in an upcoming Beta version? Either way some more info would be good so we can start testing things out.
     
  3. FPires

    FPires

    Joined:
    Jan 5, 2012
    Posts:
    127
    Glad to see I'm not crazy! I tried playing with the buffer too, to no avail. I feel like I'm missing something here.
     
  4. pvloon

    pvloon

    Joined:
    Oct 5, 2011
    Posts:
    503
    Hmm, I've been playing with this as well. I'm new to compute shaders anyway, but I can't get it to work either.

    However, making a extremely heavy compute shader lags the game, so it must be dispatched somewhere. This leads me to think that there's just not a way yet to get the data from the GPU to the CPU.

    However, with Graphics.DrawProceduralIndirect we might be able to do something? No clue how that works though. Also Graphics.SetRandomWriteTarget seems intresting.

    Also, any clue on how to bind buffers to data in a pixel shader?

    Hmm, let's hope there's some docs soon.
     
  5. Aras

    Aras

    Graphics Plumber Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,521
    The docs are lacking, aren't they? :)

    Here's a very small example project to get you started. Does not look fancy, but shows how to use (most of) new APIs: https://dl.dropbox.com/u/1119248/DX11Examples-4.0.0b7.zip. There's a scene per "scenario of DX11 stuff".

    To answer the above questions: writing into a texture (RWTexture2D) from a compute shader requires a render texture with "random write" enabled (which makes it into an Unordered Access View in DX11 lingo).
     
  6. MattCarr

    MattCarr

    Joined:
    Jul 5, 2009
    Posts:
    224
    Thanks Aras. Checked them out and they all work fine. Now to see what I was doing wrong :).

    Is it possible now or will it be possible to retrieve non-renderTexture results from compute shaders? For example passing some array of ints to the compute shader to operate on and then have the result returned to system ram to be accessed via script?
     
  7. Aras

    Aras

    Graphics Plumber Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,521
    Not right now. So I guess you'd be looking at adding something like ComputeBuffer.GetData?
     
  8. MattCarr

    MattCarr

    Joined:
    Jul 5, 2009
    Posts:
    224
    Yeah that's what I was scouring intellisense for :). Probably not going to be overly useful typically, but one of the projects I'm working on at the moment has a large number of systems/objects that update in parallel in threads and it'd be cool to have compute shader variations of the update functions and see what gains can be made.

    I've taken a functional programming approach to these systems so it should port into compute shaders easily enough and I'm looking forward to having a thread job manager that can arbitrarily fire off compute shaders and cpu threads interchangeably. Whether it ends up being viable or fast enough to be worth doing or not remains to be seen, but if "GetData()" functionality is added then that'd be awesome because it's something I'd like to check out.
     
  9. FPires

    FPires

    Joined:
    Jan 5, 2012
    Posts:
    127
    I tried creating a RWRT but since it's new I've probably initialized it wrong then. This should help me pinpoint the problem.

    Thank you very much, Aras.
     
  10. productofself

    productofself

    Joined:
    Sep 2, 2011
    Posts:
    138
    I too am not seeing anything except unshaded objects. (pics below) I am using a similar card to FPires, a NVIDIA GeForce GT 440. I basically went out and bought what I figured a gamer on a budget would buy - something in the $120-$160 range that supports DX11.

    I just re-downloaded latest drivers from nvidia, who auto detected my card correctly. Restarted. Checking dxdiag also reveals DX11 is installed. (Pics below.)

    One curious thing I found though, when poking around in the editor log...I found the below happening (note it says Version: Direct3D 9.0c [nvd3dum.dll 9.18.13.282]) hmm...not sure how that is coming up when I believe I've done everything correctly with my DX11 setup. Thoughts?

    C:/Users/USER/Desktop/DX11Examples-b7/DX11Examples
    Initialize engine version: 4.0.0b7
    GfxDevice: creating device client; threaded=1
    Direct3D:
    Version: Direct3D 9.0c [nvd3dum.dll 9.18.13.282]
    Renderer: NVIDIA GeForce GT 440
    Vendor: NVIDIA
    VRAM: 1999 MB (via DXGI)
    Caps: Shader=30 DepthRT=1 NativeDepth=1 NativeShadow=1 DF16=0 DF24=0 INTZ=1 RAWZ=0 NULL=1 RESZ=0 SlowINTZ=0
    Loading GUID <-> Path mappings ... 0.017318 seconds.

    Promised pics:
    No shading
    $dis-tes_noWrk.JPG

    DX11 Showing
    $dx11_proof.JPG

    NOTE: I'm using Windows 8...as is releasing in oct.
     
    Last edited: Aug 29, 2012
  11. Aras

    Aras

    Graphics Plumber Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,521
    Did you set DirectX 11 as the graphics device in editor preferences (Edit -> Preferences), and restart the editor? This is confusing and we want to fix this, but for now you have to do this.

    When you're in DX11 mode, editor's window title has "<DX11>" appended.
     
  12. Aras

    Aras

    Graphics Plumber Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,521
    I'll add ComputeBuffer.GetData that lets you read back the contents of it into system memory.

    However, if you want to use compute shaders for job-like small tasks outside of actual rendering and with a CPU readback, then I think that won't be very efficient. Unless your tasks take a really long time on the CPU and going to GPU would make them much faster. Why? Because GPUs are very good at throughput, but quite bad at having small latency. Typically when you tell GPU to do something, you have around 100 milliseconds or so latency until you get fetch back the results to the CPU.

    If, for example, you'd do compute shader dispatch, immediately followed by compute buffer data readback to the CPU, you'd be stalling until GPU actually gets to execute the shader transfer the results back. Just worth having to keep this in mind.
     
  13. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    548
    Ah, I thought Unity deferred all render-to-texture activity until the end of the frame - is that not the case then? I can't remember where I read this - perhaps in the Unity 4 release notes, but I can't find a link to those online any more.

    If we perform compute on one frame, can we read the results back on the next? Do you perform any internal buffering of staging buffers etc in order to avoid stalls?
     
  14. pvloon

    pvloon

    Joined:
    Oct 5, 2011
    Posts:
    503
    Thanks so much for the examples Aras :) I'm experimenting with compute shaders. Damn, amazing!


    (O, and unfortunately only a few examples work on basic. No Render Textures, to bad)
     
  15. productofself

    productofself

    Joined:
    Sep 2, 2011
    Posts:
    138
    Aras, working now...thanks for the info. Sounds like you guys have on your radar. I do actually like being able to switch in preferences, just didn't know. Perhaps if it started out in DX11 mode rather than DX9. But I'll leave that decision to those with bigger brains :)
     
  16. kenshin

    kenshin

    Joined:
    Apr 21, 2010
    Posts:
    895
    Hello Aras,

    on my PC I have the same probem (black cubes) but I have the <DX11> on the editor's window title :(

    Any idea?
    Is a bug report required?

    Kenshin
     
    Last edited: Aug 30, 2012
  17. kenshin

    kenshin

    Joined:
    Apr 21, 2010
    Posts:
    895
    Bug report sended!
    (Case 487955)
     
    Last edited: Aug 31, 2012
  18. kenshin

    kenshin

    Joined:
    Apr 21, 2010
    Posts:
    895
    Thanks Aras for yoyr answer.
    Sorry, I was really sure and I haven't checked my videocard :oops:
     
    Last edited: Aug 31, 2012
  19. productofself

    productofself

    Joined:
    Sep 2, 2011
    Posts:
    138
    I love how the tessellation works in the above sample...I am now working towards making it "water tight" (preventing cracks from appearing in the square example) I have found the below blog which mentions how to do it...just need a few pointers on where to implement the following:

    blog: http://recreationstudios.blogspot.com/2010/03/watertight-adaptive-tessellation.html
    The next question is, can we do efficient watertight adaptive tessellation without adjacency information or the midpoint calculation? The answer is yes! If we calculate the tessellation factors from the vertices themselves, then we can guarantee that the surrounding quads will use the same factors (because they are using the same vertices).

    The basic algorithm is this:
    - Calculate the tessellation factor based on camera distance for each of the 4 vertices

    Code (csharp):
    1. float distanceRange = maxDistance - minDistance;
    2. float vertex0 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[0].position) - minDistance) / distanceRange))));
    3. float vertex1 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[1].position) - minDistance) / distanceRange))));
    4. float vertex2 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[2].position) - minDistance) / distanceRange))));
    5. float vertex3 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[3].position) - minDistance) / distanceRange))));
    - Use the minimum value for each edge factor (pair of vertices)

    Code (csharp):
    1. output.edges[0] = min(vertex0, vertex3);
    2. output.edges[1] = min(vertex0, vertex1);
    3. output.edges[2] = min(vertex1, vertex2);
    4. output.edges[3] = min(vertex2, vertex3);
    - Use the overall minimum value for the inside tessellation factor

    Code (csharp):
    1. float minTess = min(output.edges[1], output.edges[3]);
    2. output.inside[0] = minTess;
    3. output.inside[1] = minTess;
    obligatory video demonstrating water tight tess:
     
    Last edited: Sep 4, 2012
  20. pvloon

    pvloon

    Joined:
    Oct 5, 2011
    Posts:
    503
    I have a quite specific problem. I need multiple compute shaders doing the same thing, just to other buffers. However, the buffers between all compute shaders are shared. I tried to use Instansiate to create a clone, but that doesn't seem to work.

    Any way to duplicate a compute shader?
     
  21. Aras

    Aras

    Graphics Plumber Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,521
    How about just setting different buffers on the same shader before you want to do something?

    something like:
    Code (csharp):
    1.  
    2. cs.SetBuffer (blah);
    3. cs.Dispatch (...);
    4.  
    5. cs.SetBuffer (foo);
    6. cs.Dispatch (...);
    7.  
     
  22. pvloon

    pvloon

    Joined:
    Oct 5, 2011
    Posts:
    503
    Ah, that makes sense! Thank you for the answer :)

    Had some trouble getting it to work, but turned out to be my own fault, woops!

    However, ScriptableObjects gave me some weird behaviour. As long as I stored the buffer there, I kept getting errors 'cannot call DestroyBuffer from mainthread', as soon as the buffer was created.... All well
     
  23. brn

    brn

    Joined:
    Feb 8, 2011
    Posts:
    297
    Thanks for the examples Aras, very much appreciated.