From 18f17883bd787e088e60edc93075d551d1d2b9fd Mon Sep 17 00:00:00 2001
From: Sebastian Krzyszkowiak <dos@dosowisko.net>
Date: Sat, 21 Oct 2023 04:20:52 +0200
Subject: [PATCH] py,st3m: Reactor: Don't make draw calls unless the drawlist
 is submittable

In the current graphics pipeline, only a single drawlist can be submitted
to the rasterizer's queue at a time. This means that at a given time,
there are two "pending" frames: the one currently rasterized, and the one
placed in the queue. Once the queued frame's rasterization starts, a new
frame can be queued. This means that to achieve full pipeline utilization,
a new frame can be submitted anytime between the moment when the queue
becomes empty and when the rasterization of the new frame finishes.

Previously, Reactor would eagerly make the draw calls as soon as a drawlist
became free, setting the drawlist content in stone. Then, at the end of each
think cycle, it would check whether the queue became free and submit the frame
if that's the case. Since draw calls are lightweight, it usually wasn't the
case right away, meaning that the already prepared drawlist would have to
wait for (at least) the next think cycle until being submitted - for no actual
benefit, as another frame would still be rasterized at that point of time.

Reduce latency and only make the draw calls once a drawlist becomes submittable.
The worst case latency regression is a fraction of draw call duration (which
usually is very short anyway), while best case improvement is frame rendering
time plus think cycle time (which can be very long for heavy frames).
---
 python_payload/st3m/reactor.py | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/python_payload/st3m/reactor.py b/python_payload/st3m/reactor.py
index 3b4190fe3e..46bb5a744f 100644
--- a/python_payload/st3m/reactor.py
+++ b/python_payload/st3m/reactor.py
@@ -147,20 +147,19 @@ class Reactor:
         self._top.think(hr, delta)
 
         # Draw!
-        if self._ctx is None and sys_display.pipe_available():
-            self._ctx = sys_display.ctx(0)
-            if self._ctx is not None:
+        if sys_display.pipe_available() and not sys_display.pipe_full():
+            ctx = sys_display.ctx(0)
+            if ctx is not None:
                 if self._last_ctx_get is not None:
                     diff = start - self._last_ctx_get
                     self.stats.record_render_time(diff)
                 self._last_ctx_get = start
 
-                self._ctx.save()
-                self._top.draw(self._ctx)
-                self._ctx.restore()
-        if self._ctx is not None and not sys_display.pipe_full():
-            sys_display.update(self._ctx)
-            self._ctx = None
+                ctx.save()
+                self._top.draw(ctx)
+                ctx.restore()
+
+                sys_display.update(ctx)
 
         # Share!
         if ftop.run(delta):
-- 
GitLab