From 359fb894fe4a556ecd13ec577dc1f6056de9eb9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=98yvind=20Kol=C3=A5s?= <pippin@gimp.org>
Date: Thu, 10 Aug 2023 14:17:05 +0200
Subject: [PATCH] st3m/gfx: make empty drawlists skip render and blit

---
 components/st3m/st3m_gfx.c     | 17 +++++++++++++++--
 components/st3m/st3m_gfx.h     |  6 ++++--
 python_payload/st3m/reactor.py |  4 +++-
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c
index a2facf3bf3..a88e58e756 100644
--- a/components/st3m/st3m_gfx.c
+++ b/components/st3m/st3m_gfx.c
@@ -81,7 +81,8 @@ static void st3m_gfx_crtc_task(void *_arg) {
         st3m_counter_timer_sample(&blit_read_time, end - start);
 
         start = esp_timer_get_time();
-        flow3r_bsp_display_send_fb(framebuffer_descs[descno].buffer);
+        if (!framebuffer_descs[descno].empty)
+            flow3r_bsp_display_send_fb(framebuffer_descs[descno].buffer);
         end = esp_timer_get_time();
         st3m_counter_timer_sample(&blit_work_time, end - start);
 
@@ -131,7 +132,19 @@ static void st3m_gfx_rast_task(void *_arg) {
 
         // Render drawctx into fbctx.
         start = esp_timer_get_time();
-        ctx_render_ctx(draw->ctx, fb->ctx);
+        int count = 0;
+        const CtxEntry *drawlist = ctx_get_drawlist(draw->ctx, &count);
+
+        // XXX maybe we should just rely on count < 4 meaning empty,
+        // this is after-all a time critical path
+        if ((count == 4 && (drawlist[0].code == CTX_SAVE) &&
+             (drawlist[1].code == CTX_SAVE)) ||
+            count <= 2) {
+            fb->empty = 1;
+        } else {
+            fb->empty = 0;
+            ctx_render_ctx(draw->ctx, fb->ctx);
+        }
         ctx_drawlist_clear(draw->ctx);
         end = esp_timer_get_time();
         st3m_counter_timer_sample(&rast_work_time, end - start);
diff --git a/components/st3m/st3m_gfx.h b/components/st3m/st3m_gfx.h
index e5a2d94b6a..571779459e 100644
--- a/components/st3m/st3m_gfx.h
+++ b/components/st3m/st3m_gfx.h
@@ -18,6 +18,8 @@
 typedef struct {
     // The numeric ID of this descriptor.
     int num;
+    // set when the drawlist was empty
+    int empty;
     // SPIRAM buffer.
     uint16_t buffer[240 * 240];
     Ctx *ctx;
@@ -50,7 +52,7 @@ uint8_t st3m_gfx_drawctx_pipe_full(void);
 // Flush any in-flight pipelined work, resetting the free ctx/framebuffer queues
 // to their initial state. This should be called if there has been any drawlist
 // ctx dropped (ie. drawctx_free_get was called but then drawctx_pipe_put
-// wasn't, for exaple if Micropython restarted).
+// wasn't, for example if Micropython restarted).
 //
 // This causes a graphical disturbance and shouldn't be called during normal
 // operation.
@@ -74,4 +76,4 @@ void st3m_gfx_splash(const char *text);
 
 // Draw the flow3r multi-coloured logo at coordinates x,y and with given
 // dimension (approx. bounding box size).
-void st3m_gfx_flow3r_logo(Ctx *ctx, float x, float y, float dim);
\ No newline at end of file
+void st3m_gfx_flow3r_logo(Ctx *ctx, float x, float y, float dim);
diff --git a/python_payload/st3m/reactor.py b/python_payload/st3m/reactor.py
index b24384d8dd..42ed2d164e 100644
--- a/python_payload/st3m/reactor.py
+++ b/python_payload/st3m/reactor.py
@@ -40,7 +40,9 @@ class Responder(ABCBase):
         coordinates are +/- 120 in both X and Y (positive numbers towards up and
         right), with 0,0 being the middle of the screen.
 
-        The Reactor will then rasterize and blit the result.
+        The Reactor will then rasterize and blit the result. If no ctx drawing
+        commands are issued, it is interpreted as a wish to keep the display
+        contents as-is, and cpu time is not spent on rasterization and blitting.
 
         The code must not sleep or block during this callback, as that will
         impact the system tickrate and framerate.
-- 
GitLab