[Performance] Referencing the "draw_callback" as local() would improve performance?

The template python “operator_modal_draw.py”, we can see that the variable “draw_callback_px” is referenced globally.

However if we reference-it locally, the function would look like this:


import bpy
import bgl
import blf


class ModalDrawOperator(bpy.types.Operator):
    """Draw a line with the mouse"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Simple Modal View3D Operator"


    def draw_callback_px(self, context):
        print("mouse points", len(self.mouse_path))


        font_id = 0  # XXX, need to find out how best to get this.


        # draw some text
        blf.position(font_id, 15, 30, 0)
        blf.size(font_id, 20, 72)
        blf.draw(font_id, "Hello Word " + str(len(self.mouse_path)))


        # 50% alpha, 2 pixel width line
        bgl.glEnable(bgl.GL_BLEND)
        bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
        bgl.glLineWidth(2)


        bgl.glBegin(bgl.GL_LINE_STRIP)
        for x, y in self.mouse_path:
            bgl.glVertex2i(x, y)


        bgl.glEnd()


        # restore opengl defaults
        bgl.glLineWidth(1)
        bgl.glDisable(bgl.GL_BLEND)
        bgl.glColor4f(0.0, 0.0, 0.0, 1.0)


    def modal(self, context, event):
        context.area.tag_redraw()


        if event.type == 'MOUSEMOVE':
            self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))


        elif event.type == 'LEFTMOUSE':
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'FINISHED'}


        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}


        return {'RUNNING_MODAL'}


    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
            self._handle = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, (context,), 'WINDOW', 'POST_PIXEL')


            self.mouse_path = []


            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}




def register():
    bpy.utils.register_class(ModalDrawOperator)




def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)


if __name__ == "__main__":
    register()

The amount of local variables is less than the amount of global variables. This is advantageous for loops. But there are other things into consideration.

Then, this solution is better or worse for performance?

Not sure whether this is better or worse for performance… Might the local function be re-defined on every invocation of the operator? Or is it just a global as if it was defined outside the class? I wonder if the mysterious “struct error” you sometimes see in console when scripting draw handlers and reload scripts will be gone if it’s a local function…

If this error is the same error I’m thinking, then the answer is no. :\

I do not know how to test the performance difference, since I do not know how to do Blender redraw this draw_callback several times to calculate the time. :frowning:

Hm maybe add a timer and tag_redraw the area on every timer event?

I have my doubts if it is wise to tag_redraw on every iteration of modal. As far as I understand it, modal is called a lot more often than the window is redrawn.

@Bayesian: how else would you benchmark the difference? Without tagging for redraw, it would depend on user input otherwise…