Search Unity

CommandBuffer.DrawProcedural crashes editor when converted to DrawProceduralIndirect

Discussion in 'General Graphics' started by ramy_d, Sep 30, 2016.

  1. ramy_d

    ramy_d

    Joined:
    Oct 12, 2014
    Posts:
    19
    I am using a commandbuffer to draw a quad in front of the camera. The code works using CommandBuffer.DrawProcedural but when I use CommandBuffer.DrawProceduralIndirect the Unity Editor interface becomes unresponsive and I have to kill the application.

    Here is the CommandBuffer.DrawProcedural version
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. using System.Collections;
    4. using System.Runtime.InteropServices;
    5.  
    6. // Apply Script to Camera GameObject
    7. public class MyCommandBuffer : MonoBehaviour {
    8.  
    9.     public Shader shader;
    10.  
    11.     ComputeBuffer cbPoints;
    12.  
    13.     void Start () {
    14.         Material mat = new Material(this.shader);
    15.         Camera cam = this.GetComponent<Camera>();
    16.         CommandBuffer cb = new CommandBuffer();
    17.  
    18.         var verts = new Vector4[6] { new Vector4(-1, -1, 0, 1),
    19.                                      new Vector4(1, 1, 0, 1),
    20.                                      new Vector4(1, -1, 0, 1),
    21.                                      new Vector4(1, 1, 0, 1),
    22.                                      new Vector4(-1, -1, 0, 1),
    23.                                      new Vector4(-1, 1, 0, 1) };
    24.  
    25.         this.cbPoints = new ComputeBuffer(6, Marshal.SizeOf(typeof(Vector4)), ComputeBufferType.Default);
    26.         this.cbPoints.SetData(verts);
    27.         mat.SetBuffer("quadVerts", this.cbPoints);
    28.  
    29.         cb.name = "stencil mask";
    30.         cb.DrawProcedural(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, 6, 1);
    31.         cam.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, cb);
    32.     }
    33.  
    34.     void OnDestroy () {
    35.         if (this.cbPoints != null) this.cbPoints.Release();
    36.         this.cbPoints = null;
    37.     }
    38. }
    39.  
    And here is the same code using CommandBuffer.DrawProceduralIndirect that is causing the Unity Editor to hang.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. using System.Collections;
    4. using System.Runtime.InteropServices;
    5.  
    6. // Apply Script to Camera GameObject
    7. public class MyCommandBuffer : MonoBehaviour {
    8.  
    9.     public Shader shader;
    10.  
    11.     ComputeBuffer cbPoints;
    12.  
    13.     void Start () {
    14.         Material mat = new Material(this.shader);
    15.         Camera cam = this.GetComponent<Camera>();
    16.         CommandBuffer cb = new CommandBuffer();
    17.  
    18.         var verts = new Vector4[6] { new Vector4(-1, -1, 0, 1),
    19.                                      new Vector4(1, 1, 0, 1),
    20.                                      new Vector4(1, -1, 0, 1),
    21.                                      new Vector4(1, 1, 0, 1),
    22.                                      new Vector4(-1, -1, 0, 1),
    23.                                      new Vector4(-1, 1, 0, 1) };
    24.  
    25.         this.cbPoints = new ComputeBuffer(6, Marshal.SizeOf(typeof(Vector4)), ComputeBufferType.IndirectArguments);
    26.         this.cbPoints.SetData(verts);
    27.         mat.SetBuffer("quadVerts", this.cbPoints);
    28.  
    29.         cb.name = "stencil mask";
    30.         cb.DrawProceduralIndirect(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, this.cbPoints);
    31.         cam.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, cb);
    32.     }
    33.  
    34.     void OnDestroy () {
    35.         if (this.cbPoints != null) this.cbPoints.Release();
    36.         this.cbPoints = null;
    37.     }
    38. }
    39.  

    Here is a simply shader to supply it:
    Code (Shader):
    1. Shader "testShader" {
    2.     SubShader {
    3.         Pass {
    4.             CGPROGRAM
    5.                 #pragma vertex vert
    6.                 #pragma fragment frag
    7.  
    8.                 struct input {
    9.                     uint id : SV_VertexID;
    10.                     uint inst : SV_InstanceID;
    11.                 };
    12.  
    13.                 struct v2f {
    14.                     float4 pos : SV_POSITION;
    15.                     float2 uv : TEXCOORD0;
    16.                 };
    17.  
    18.                 StructuredBuffer<float4> quadVerts;
    19.  
    20.                 v2f vert(input i) {
    21.                     v2f o;
    22.                     o.pos = quadVerts[i.id];
    23.                     o.uv = quadVerts[i.id].xy * 0.5 + 0.5;
    24.                     return o;
    25.                 }
    26.  
    27.                 half4 frag(v2f i) : COLOR {
    28.                     return half4(i.uv.x, i.uv.y, 0, 1);
    29.                 }
    30.             ENDCG
    31.         }
    32.     }
    33. }
    34.  
    I'd appreciate any help in trying to get this working. Maybe I am misunderstanding how to use DrawProceduralIndirect with respect to the setup of my ComputeBuffer.
     
  2. c6burnz

    c6burnz

    Joined:
    Jun 22, 2014
    Posts:
    5
    Hey I get that you probably solved or didn't solve this problem at some point in the last 2 years, and therefore are not in need of my help in any way, but I keep ending up on this page looking for cool usage examples of CommandBuffer.DrawProceduralIndirect so I might as well answer what went wrong

    Your code is passing a structured buffer of float4 as the bufferWithArgs parameter. Your vertex / instance count is definitely not inside that buffer, which you can imagine could only end poorly.

    What you wanted to do in order to match your call to CommandBuffer.DrawProcedural is something like:
    Code (CSharp):
    1.  
    2. uint[] args = new uint[4] { 0, 0, 0, 0 };
    3. args[0] = 6; // or if copying submesh 0 of a mesh: mesh.GetIndexCount(0);
    4. args[1] = 1; // your instance count
    5. args[2] = 0; // or if copying submesh 0 of a mesh: mesh.GetIndexStart(0);
    6. // args[3] must remain 0, it's not there by accident
    7. ComputeBuffer argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
    8. argsBuffer.SetData(args);
    9. cb.DrawProceduralIndirect(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, argsBuffer, 0);
    10. // notice that the above is the equivalent of:
    11. // cb.DrawProcedural(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, args[0], args[1]);
    12.  
     
    richardkettlewell likes this.