How to use the new render pass API for an external renderer? I am developing an addon for an external renderer and want to register custom render passes.
Last time I implemented this feature I had to resort to images because Blender only had hardcoded render passes.

Nowadays the RenderEngine class offers several methods that seem to allow the registration of custom passes:


register_pass(scene=None, srl=None, name="", channels=1, chanid="", type='VALUE')
update_render_passes(scene=None, renderlayer=None)
add_pass(name, channels, chan_id, layer="")


However, I could not find any explanation or examples of how to use these methods. Looking at the Cycles source code also did not help much.


Cycles implements the update_render_passes method: https://github.com/dfelinto/blender/blob/1d33843ea6b128242183bb31804474019c606a9d/intern/cycles/blender/addon/init.py#L105

But I could not find out how or when this method is ever called. 
When I implement this method in my addon, it is never called.
In this implementation, it uses the register_pass method: https://github.com/dfelinto/blender/blob/1d33843ea6b128242183bb31804474019c606a9d/intern/cycles/blender/addon/engine.py#L209


Where I currently am

I have managed to add a custom pass with the following code, which is currently executed in the constructor of my RenderEngine implementation:

self.add_pass("Samplecount", 1, "X")

It shows up in the image editor:



Problems/Questions


The custom pass is always available in the image editor dropdown, even if it is not used in the current rendering
It seems there is no method to remove or unregister a custom pass - how does Cycles do this?
The custom pass does not show up in the compositor:
Thanks to brecht's explanation in IRC I can now answer my own question:

Custom passes in compositor

update_render_passes is called by the compositor to display the custom passes as output sockets. In this method, register_pass should be used.

Example:

def update_render_passes(self, scene=None, renderlayer=None):
    self.register_pass(scene, renderlayer, "Combined", 4, "RGBA", 'COLOR')

    aovs = scene.luxcore.aovs

    if aovs.samplecount:
        self.register_pass(scene, renderlayer, "Samplecount", 1, "X", 'VALUE')
    if aovs.shading_normal:
        self.register_pass(scene, renderlayer, "Shading_Normal", 3, "XYZ", 'VECTOR')


Custom passes in image editor

add_pass on the other hand should be called at the start of the render method to add custom passes (before writing data into a render_result).

Example:

# Note: the Depth pass is already added by Blender
# If you add it again, it won't be displayed correctly 
# in the "Depth" view mode of the "Combined" pass
# in the image editor.

aovs = scene.luxcore.aovs

if aovs.samplecount:
    self.add_pass("Samplecount", 1, "X")
if aovs.shading_normal:
    self.add_pass("Shading_Normal", 3, "XYZ")


I hope this helps other developers of addons for external render engines.