Questions about space draw handlers, with possible bugs found

I’m starting to experiment with draw handlers of Spaces, and some behaviors seem strange to me, so I have a few questions.

Here is a simple operator where I add a draw handler to each 3D space:
The handler just prints the window and space pointer.

Now in Blender, I open two 3D areas and run the operator. When I select or unselect the default cube in one of the area, I see a bunch of calls of my handler, with two different space pointers, so everything seems ok.
But if I remove one of the two areas, my handler is still called for each space. Is this a bug ? should I detect that the area (and its space) does not exist anymore and remove the handler manually ? Do I have a callback on this or should it be detected in a timer (or in the draw handler function directly) ?

Another strange behavior: If I open another main window displaying a different scene, run again the operator to attach handlers, and select/unselect the cube, then the draw handler of the space that display the other scene is also called. It seems unecessary to me to redraw all 3d areas when only one scene is affected by my action.

Finally, each handler is called 8 times, but @JeroenBakker explains here that it is normal and due to AA enabled.
Do I have any control over this as a developper ? I don’t want to force the antialiasing of the user to be disabled, but if I want my handler to be called once it seems complicated. Do I need to manually count each run and compare to the “viewport_aa” property ?

Thanks for your answers

PS: I’m on Blender 2.83.1

Another strange behavior I just noticed: I open blender (with AA disabled on viewport), run my operator then click on the cube -> my draw handler is called once as expected.
Then I open a new 3D area, but I don’t run my operator again. Then I unselect the cube, but my draw handler gets called two times (with a single space pointer). Why would the second 3D area triggers another run of the first 3D area drawing function ?

Now if I run again my operator to attach a draw handler to the second 3D area, I get 4 calls, 2 for each 3D area.
And if I create more 3D areas, I get for each 3D area as many calls as the number of visible 3D areas, so it can quickly become expensive, especially if I enable back viewport anti aliasing.


Adding to the list: When I try to draw something different in each 3d area, all of my 3d drawings are drawn in all areas. Even for 3d areas that display different scenes. There must be something I’m missing here, or a bug: what is the point of attaching a draw handler to a space if all other spaces are also drawn into by the same handler ?

To illustrate this I’ve added the drawing of a single vertical line in my draw handler:
I was expectiing each 3d area to draw a single line at the offset position defined when the handler is added. But as described above, all 3d areas draw all lines. So I can’t get a drawing that only depends on the specific 3d area, or the scene displayed in the area.


The draw handler are stored in a global handler list on the space 3d view type (eg any 3d view). Specific editor draw handlers (on 3d view instances) aren’t provided. I haven’t tested it but is it possible to check the as_pointer of the space with the space that was provided when attaching the draw handler. eg add an early exit when the space as_pointer isn’t the same.

When any 3d view is drawn the (global registered) draw handler is invoked for the instance. This matches what you describe in your posts.

Related developments
A month ago @julianeisel and I discussed the way how to render input controls for the OpenXR branch. We proposed to register a GPUBatch and it would be rendered in a scene based on the input control matrix. It would be an idea to extend this mechanism to support view frustums of others. To my knowledge @sebastian_k had a prototype working but I am not up2date with the implementation details.

1 Like

Ok my bad, I understand now: I need to register only one draw handler and use bpy.context.* to know which area, or scene, or whatever else is currently the target of the draw handler. Thanks for the answer !