wgpu-py icon indicating copy to clipboard operation
wgpu-py copied to clipboard

Refactor wgpu.gui for scheduling

Open almarklein opened this issue 1 year ago • 6 comments

Refs

  • This finally addresses the main points in wgpu for https://github.com/pygfx/pygfx/issues/495.
  • Closes #355
  • closes #471

Summary

Canvas

  • Remove WgpuAutoGui, since its no simply a part of WgpuCanvasBase
  • Implementation of WgpuCanvasBase is cleaner because it moves events and scheduling out.

Events

  • Event handling logic is moved into a separate class.
  • The event handling logic can merge events by itself (Canvas implementations don't have to do this).
  • Events are queued until they are explicitly flushed (by the scheduling mechanics).
  • EventType enum!

Scheduling

  • The WgpuCanvasBase implements a scheduling mechanic (Canvas implementations no longer have to do this).
  • Multiple update modes are implemented: fastest, continuous, ondemand, manual.
  • The max_fps applies (only) to continuous and ondemand mode.
  • New force_draw() method for a blocking render call. Note that this still passes through the paint event on Qt, to avoid flicker.

Gui modules

  • run() and call_later() functions are replaced with a loop object that has both as a method.

Design decisions

  • We assume that users use the event-loop corresponding to the canvas, and don't use two GUI systems at the same time (e.g. Qt with glfw). We can accommodate for this, but it will complicate the code and feels like a bad idea in general.
  • Do we keep canvas.add_event_handler() or do we switch to canvas.events.add_handler() or canvas.events.connect()?
    • I like canvas.add_event_handler() as it feels flat. That way canvas._events stays an implementation detail.
  • Not sure yet about the canvas.loop prop.
  • How to allow users to control scheduling, like setting mode or max_fps?
    • Proposal: use canvas.scheduler.max_fps, canvas.scheduler.mode, etc.

API changes

  • canvas.add_event_handler()?
  • New canvas.force_draw().
  • New canvas.loop property?
  • Replaced from wgpu.gui.xx import WgpuCanvas, run with from wgpu.gui.xx import WgpuCanvas, loop
  • The glfw canvas is more friendly on your laptop battery (thanks to a proper event loop).
  • The WgpuAutoGui mixin class is removed.

Tasks

  • [x] Update base canvas.
  • [x] Take threading into account.
  • [x] Update glfw gui
  • [x] Update qt gui
  • [ ] Update wx gui
  • [ ] Update jupyter gui
  • [x] Update offscreen gui
  • [x] Don't draw when minimized.
  • [x] Update docs
  • [x] Show/test force_draw in an example.
  • [x] Can we make 'ondemand' with calling request_draw() in the draw function equal 'continuous'.

After this PR

  • Handle sigint.
  • Animate events.
  • Allow draw_func to be an asyn function.
  • Can we move present() out of CanvasContext()?
  • Register the draw function as a draw event handler instead of with request_draw()?
  • Allow requesting a draw by setting a field in the event object?
  • Tracking statistics (track time spent on different things). Plus visualizing them.

almarklein avatar Oct 14 '24 10:10 almarklein

I've been working on this for more than a week. This is hard, but it's beginning to take shape now.

almarklein avatar Oct 14 '24 10:10 almarklein

This implements (amongst other things) the ideas presented in http://gameprogrammingpatterns.com/game-loop.html

As robert says:

image

In addition to that, we also gave multiple different GUI systems and event loops.

Do you own the game loop, or does the platform?

In our case that actually depends 😅 The scheduling code assumes it runs on an externally provided eventloop. For glfw we do provide the loop, but the scheduling logic does not know this.

almarklein avatar Oct 14 '24 10:10 almarklein

How to allow users to control scheduling, like setting mode or max_fps?

  • Proposal: use canvas.scheduler.max_fps, canvas.scheduler.mode, etc.

Does scheduler need to be a prop on canvas? Can it live on its own?

Korijn avatar Oct 21 '24 20:10 Korijn

Does scheduler need to be a prop on canvas? Can it live on its own?

Yeah, I'd rather hide it. So you mean the prop can be something like canvas.update_mode?

almarklein avatar Oct 22 '24 08:10 almarklein

Does scheduler need to be a prop on canvas? Can it live on its own?

Yeah, I'd rather hide it. So you mean the prop can be something like canvas.update_mode?

I meant, it could be just scheduler, instead of canvas.scheduler :)

Korijn avatar Oct 22 '24 08:10 Korijn

Does scheduler need to be a prop on canvas? Can it live on its own?

Yeah, I'd rather hide it. So you mean the prop can be something like canvas.update_mode?

I meant, it could be just scheduler, instead of canvas.scheduler :)

There's no point for a scheduler without a canvas. It's really a little helper that I preferably hide from the user.

almarklein avatar Oct 22 '24 08:10 almarklein

Proposal: use canvas.scheduler.max_fps, canvas.scheduler.mode, etc.

These args can be passed when the canvas is instantiated. For now, we can leave it at that (no changing these at runtime).

almarklein avatar Oct 24 '24 13:10 almarklein

Ok, this is almost done. All backends are working and tested on different platforms. I'm going to do a round of self-review and cleanup.

I think we will never merge this here, but in the new repo: #627

almarklein avatar Oct 24 '24 13:10 almarklein

This is ready for review. It does not actually break compatibility so much. You can run pygfx examples with it.

When this pr is approved, I'll re-recreate the pr at rendercanvas so we can apply it there.

almarklein avatar Oct 28 '24 10:10 almarklein

Merged in rendercanvas.

almarklein avatar Nov 22 '24 14:11 almarklein