Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Writing to RenderTexture in a compute shader doesn't work on Metal

Discussion in '2018.2 Beta' started by camel82106, Jun 21, 2018.

  1. camel82106

    camel82106

    Joined:
    Jul 2, 2013
    Posts:
    304
    Hi,
    I'm writing to RWTexture2D<float4> texture in a compute shader. It's working nicely on desktop with directx. But it doesn't work on metal with iphone or ipad.

    I have tried it on 2017.4.4 and newest beta 2018.2b9 too.

    Compute Shader
    Code (CSharp):
    1. RWTexture2D<float4> textureOut;
    2. StructuredBuffer<float4> colors;
    3.  
    4. #pragma kernel pixelCalc  
    5.  
    6. [numthreads(16,16,1)]        
    7. void pixelCalc (uint2 id : SV_DispatchThreadID){
    8.      textureOut[id.xy] = colors[id.x + id.y * 250];
    9. }
    CPU side:
    Code (CSharp):
    1. this.outputTexture = new RenderTexture(250, 250, 32);
    2.             this.outputTexture.enableRandomWrite = true;
    3.             this.outputTexture.useMipMap = false;
    4.             this.outputTexture.Create();
    5.  
    6. this.colorArray = new Color[250 * 250];
    7.  
    8. // Color size is four values of four bytes, so 4 * 4
    9.             this.colorsBuffer = new ComputeBuffer(this.colorArray.Length, 4 * 4);
    10.  
    11.             // again, we're setting color array to the buffer
    12.             colorsBuffer.SetData(colorArray);
    13.  
    14.  
    15.             var overlayGameObject = GameObject.Find("Overlay");
    16.             var renderer = overlayGameObject.GetComponent<Renderer>();
    17.             renderer.material.mainTexture = this.outputTexture;
    18.  
    19. ar kernelIndex = this.shader.FindKernel("pixelCalc");
    20.  
    21.             this.shader.SetBuffer(kernelIndex, "colors", colorsBuffer);
    22.             this.shader.SetTexture(kernelIndex, "textureOut", this.outputTexture);
    23.  
    24.             this.shader.Dispatch(kernelIndex, 16, 16, 1);
    Am I doing something wrong or render texture simply doesn't work in metal and compute shaders?

    P.S.: I have tried an approach used here. But without success:
    https://forum.unity.com/threads/con...ass-shader-to-unity-hlsl.418238/#post-3478159

    Basically passing StructuredBuffer in normal shader. And bypassing usage of render texture.
    Thanks
    Peter
     
  2. elbows

    elbows

    Joined:
    Nov 28, 2009
    Posts:
    2,502
    I'd guess its something you are doing wrong, because I've had this sort of thing working consistently on metal for macOS for a very long time with a very large number of different Unity versions, including all the 2018.2 betas. I've had the same stuff working on iOS too, but I dont test that so often.

    I'm not in a position to work out exactly what is wrong with your code, but there is some very low hanging fruit that I would probably explore first if it were me:

    The third parameter you are setting when doing new rendertexture is the number of bits in depth buffer, you are using a value of 32 but the manual only mentions 0,16,24 as valid settings.

    Try setting a RenderTextureFormat explicitly (4th parameter when creating new rendertexture.)

    Try power of 2 texture resolutions (eg 256x256 rather than 250x250)

    Rule out the StructuredBuffer side of your code/Unity as potentially being the problem, by trying some code that reads from another texture rather than a buffer.

    Try different numthreads values (and associated dispatch parameters).
     
  3. Andrius-Keidonas

    Andrius-Keidonas

    Grand Inquisitor Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    8
    Hey, the problem is that you're trying to write outside the RT's bounds - you're dispatching (16*16) * (16*16) threads in total, but your texture is only 250*250.
    Solution is to either change RT size to 256*256 (to match dispatch thread size) or
    add a check in the shader "if ((id.x + id.y * 250) < (250*250)) textureOut[id.xy] = ...".

    Most likely desktops are robust enough to ignore out of bound writes and iOS not so much.

    A
     
    PrimalCoder and LeonhardP like this.
  4. camel82106

    camel82106

    Joined:
    Jul 2, 2013
    Posts:
    304
    Thanks you guys for your recommendations. So far I have tried to set rendercamera depth to 16 (will try 24 as next)
    Changed code to use 256x256 to mach threads total.

    I have removed StructuredBuffer part of compute shader and CPu code.
    So it looks like this now:
    Code (CSharp):
    1. RWTexture2D<float4> textureOut;
    2. //StructuredBuffer<float4> colors;
    3.  
    4. #pragma kernel pixelCalc
    5.  
    6. [numthreads(16,16,1)]                            
    7. void pixelCalc (uint2 id : SV_DispatchThreadID){
    8.     textureOut[id.xy] = float4(1, 0, 0, 1);//colors[id.x + id.y * 256];
    9. }
    Code (CSharp):
    1. this.outputTexture = new RenderTexture(256, 256, 16);
    2.             this.outputTexture.enableRandomWrite = true;
    3.             this.outputTexture.Create();
    4.  
    5. var kernelIndex = this.shader.FindKernel("pixelCalc");
    6.  
    7.             //this.shader.SetBuffer(kernelIndex, "colors", colorsBuffer);
    8.             this.shader.SetTexture(kernelIndex, "textureOut", this.outputTexture);
    9.  
    10.             this.shader.Dispatch(kernelIndex, 16, 16, 1);
    But still without sucess. On Desktop I get red screen as background on ipad nothing. Just my objects so it doesn't crashed or whatever.

    So what is left:
    Try setting a RenderTextureFormat explicitly
    And 24 depth for render texture. I will try that next.

    Maybe it would be great to have an ios sample project that is working for sure.
    Thanks
    Peter
     
    Last edited: Jun 21, 2018
  5. camel82106

    camel82106

    Joined:
    Jul 2, 2013
    Posts:
    304
    Wow, now it finally works at least with some settings.

    I have used this:
    Code (CSharp):
    1. RWTexture2D<float4> textureOut;
    2. StructuredBuffer<float4> colors;
    3.  
    4. #pragma kernel pixelCalc
    5.  
    6. [numthreads(8,8,1)]                            
    7. void pixelCalc (uint2 id : SV_DispatchThreadID){  
    8.     textureOut[id.xy] = colors[id.x + id.y * 256];
    9. }
    Code (CSharp):
    1. this.outputTexture = new RenderTexture(256, 256, 24);
    2.             this.outputTexture.enableRandomWrite = true;
    3.             this.outputTexture.Create();
    4.          
    5.  
    6. var kernelIndex = this.shader.FindKernel("pixelCalc");
    7.  
    8.             this.shader.SetBuffer(kernelIndex, "colors", colorsBuffer);
    9.             this.shader.SetTexture(kernelIndex, "textureOut", this.outputTexture);
    10.  
    11.             this.shader.Dispatch(kernelIndex, 256 / 8, 256 / 8, 1);
    Decision point was lowering threads to 8 8 1. I will experiment with it further but it looks like it's not working with 16 16 1.

    But at least it's working with structured buffer and render rexture

    Thanks!
     
    elbows likes this.
  6. Andrius-Keidonas

    Andrius-Keidonas

    Grand Inquisitor Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    8
    Good to hear it works.
    A question - what kind of iPad do you use for testing and what iOS version?
    Maybe there's some limit on thread group size for that device/os although I don't see how 16*16 could be too big (lowest limit in the specs is 512 threads per group).
    Also have you tried running with metal validation on? It might tell more about the issue.

    A
     
  7. camel82106

    camel82106

    Joined:
    Jul 2, 2013
    Posts:
    304
    I'm testing it on iPhone SE and iPad 2018. iOS version 11.4

    Of course I will try to set back again bigger number of threads as I was tweaking many values and I could make an mistake. Although I doubt. (I was checking threads limit too in specifications and 256 seemed to be safe for all devices)

    Sadly I'm not using metal validation. I'm experimenting now with windows only development machine. So I'm developing it on windows 10 and for building I'm using Unity Cloud. (As far I see this option is available only in metal editor)

    Developing on windows is very comfortable for me. Although it has its drawbacks as you see...

    Peter