gfx-rs/wgpu-native

RenderBundleEncoder extremely fragile and frequently crashes.

fyellin opened this issue · 0 comments

I was using the attached code to compare using set_xxx and draw_xxx commands on a RenderBundleEncoder vs performing the same operations on an ordinary RenderPass. In many cases, the RenderBundleEncoder would either fail to give a validation error or would crash.

My basic operation was:

    def do_draw(encoder):
        encoder.set_pipeline(pipeline)
        encoder.set_bind_group(0, bind_group)
        encoder.set_vertex_buffer(0, vertex_buffer)
        encoder.set_index_buffer(index_buffer, "uint32")
        encoder.draw(4, 1, 0, 0)
        encoder.draw_indexed(4, 1, 0, 0)
        encoder.draw_indirect(indirect_buffer, 0)

where I would either pass in a RenderPass or a RenderBundleEncoder. In the latter case, I would then .finish() it and pass it to a RenderPass.

First bug: I would try commenting out each of the encoder.set_XXX lines in the code above.

  • RenderPass correctly gives me a ValidationError in all four cases.
  • RenderBundleEncoder
    • Crashes if set_pipeline is commented out.
    • Gives an error message and then crashes if set_index_buffer is commented out.
    • Gives no indication of a program if set_bind_group or set_vertex_buffer is commented out. I have not yet
      figured out what data it uses instead.

Second bug: Immediately after calling do_draw, I would try to see what would happen if I set one or more of pipeline, bind_group, vertex_buffer, index_buffer, or indirect_buffer to. None. Since this is the only reference to those objects, that causes Python to release those objects using the appropriate WGPU...Release(x) call.

  • RenderPass had no problem with my setting all the variables to None. It clearly protects those objects from being destroyed.
    With a longer program I verified that the code is actually using the intended buffers.

  • RenderBundleEncoder crashed if I set any of the variables to None before the call to .finish()

  • RenderBundleEncoder had no problems if I set all the variables to None after the call to .finish()

Third bug: If RenderBundleEncoder is given the wrong color format argument at creation, it prints a correct error message and then crashes.

Attached is RenderBundleEncoderBug.zip, which contains RenderBundleEncoderBug.py. It is run by calling python RenderBundleEncoderBug.py <flag> where flag is one of the following arguments.

  • normal.
    Show the program running normally.
  • no-pipeline, no-bind-group, no-vertex-buffer, no-index-buffer.
    As in the first bug above, "forget" the call to set_XXXX in the do_draw call.
  • null-pipeline, null-bind-group, null-vertex-buffer, null-index-buffer, null-indirect-buffer.
    As in the second bug above, set the corresponding GPU Object to None immediately after the call to do_draw,
    so that the object is released.
  • wrong-color-format, missing-color-format.
    As in the third bug above, either use the wrong texture format in color-attachments, or make color-attachments
    be an empty list.

The only requirement for the code is:
pip install wgpu

RenderBundleEncoderBug.zip