CommandBuffer.DrawProcedural crashes editor when converted to DrawProceduralIndirect

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

using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
using System.Runtime.InteropServices;

// Apply Script to Camera GameObject
public class MyCommandBuffer : MonoBehaviour {

    public Shader shader;

    ComputeBuffer cbPoints;

    void Start () {
        Material mat = new Material(this.shader);
        Camera cam = this.GetComponent<Camera>();
        CommandBuffer cb = new CommandBuffer();

        var verts = new Vector4[6] { new Vector4(-1, -1, 0, 1),
                                     new Vector4(1, 1, 0, 1),
                                     new Vector4(1, -1, 0, 1),
                                     new Vector4(1, 1, 0, 1),
                                     new Vector4(-1, -1, 0, 1),
                                     new Vector4(-1, 1, 0, 1) };

        this.cbPoints = new ComputeBuffer(6, Marshal.SizeOf(typeof(Vector4)), ComputeBufferType.Default);
        this.cbPoints.SetData(verts);
        mat.SetBuffer("quadVerts", this.cbPoints);

        cb.name = "stencil mask";
        cb.DrawProcedural(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, 6, 1);
        cam.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, cb);
    }

    void OnDestroy () {
        if (this.cbPoints != null) this.cbPoints.Release();
        this.cbPoints = null;
    }
}

And here is the same code using CommandBuffer.DrawProceduralIndirect that is causing the Unity Editor to hang.

using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
using System.Runtime.InteropServices;

// Apply Script to Camera GameObject
public class MyCommandBuffer : MonoBehaviour {

    public Shader shader;

    ComputeBuffer cbPoints;

    void Start () {
        Material mat = new Material(this.shader);
        Camera cam = this.GetComponent<Camera>();
        CommandBuffer cb = new CommandBuffer();

        var verts = new Vector4[6] { new Vector4(-1, -1, 0, 1),
                                     new Vector4(1, 1, 0, 1),
                                     new Vector4(1, -1, 0, 1),
                                     new Vector4(1, 1, 0, 1),
                                     new Vector4(-1, -1, 0, 1),
                                     new Vector4(-1, 1, 0, 1) };

        this.cbPoints = new ComputeBuffer(6, Marshal.SizeOf(typeof(Vector4)), ComputeBufferType.IndirectArguments);
        this.cbPoints.SetData(verts);
        mat.SetBuffer("quadVerts", this.cbPoints);

        cb.name = "stencil mask";
        cb.DrawProceduralIndirect(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, this.cbPoints);
        cam.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, cb);
    }

    void OnDestroy () {
        if (this.cbPoints != null) this.cbPoints.Release();
        this.cbPoints = null;
    }
}

Here is a simply shader to supply it:

Shader "testShader" {
    SubShader {
        Pass {
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                struct input {
                    uint id : SV_VertexID;
                    uint inst : SV_InstanceID;
                };

                struct v2f {
                    float4 pos : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };

                StructuredBuffer<float4> quadVerts;

                v2f vert(input i) {
                    v2f o;
                    o.pos = quadVerts[i.id];
                    o.uv = quadVerts[i.id].xy * 0.5 + 0.5;
                    return o;
                }

                half4 frag(v2f i) : COLOR {
                    return half4(i.uv.x, i.uv.y, 0, 1);
                }
            ENDCG
        }
    }
}

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.

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:

uint[] args = new uint[4] { 0, 0, 0, 0 };
args[0] = 6; // or if copying submesh 0 of a mesh: mesh.GetIndexCount(0);
args[1] = 1; // your instance count
args[2] = 0; // or if copying submesh 0 of a mesh: mesh.GetIndexStart(0);
// args[3] must remain 0, it's not there by accident
ComputeBuffer argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
argsBuffer.SetData(args);
cb.DrawProceduralIndirect(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, argsBuffer, 0);
// notice that the above is the equivalent of:
// cb.DrawProcedural(cam.cameraToWorldMatrix, mat, 0, MeshTopology.Triangles, args[0], args[1]);
1 Like