From 458458b65f2648d68668a622c20237ace128eb8c Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 23 Sep 2024 16:53:21 +0200 Subject: [PATCH] intel/display: support stop/wakeup protocol Issue #5344 --- .../src/driver/framebuffer/intel/pc/lx_i915.h | 4 +- .../src/driver/framebuffer/intel/pc/lx_user.c | 57 +++++++++++++++++-- .../src/driver/framebuffer/intel/pc/main.cc | 33 ++++++++--- 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h b/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h index 168af23096..1fc5490bb6 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h @@ -33,10 +33,12 @@ struct genode_mode { char name[32]; }; -int lx_emul_i915_blit(unsigned); +int lx_emul_i915_blit(unsigned const connector_id, char const may_sleep); +void lx_emul_i915_wakeup(unsigned connector_id); void lx_emul_i915_report_discrete(void * genode_xml); void lx_emul_i915_report_non_discrete(void * genode_xml); void lx_emul_i915_hotplug_connector(void); + void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, char const *name, char connected, unsigned brightness, diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c index 4e930c6d04..3c257db068 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c @@ -837,25 +837,67 @@ static void mark_framebuffer_dirty(struct drm_framebuffer * const fb) } +/* track per connector (16 max) the empty capture attempts before stopping */ +enum { CAPTURE_RATE_MS = 10, ATTEMPTS_BEFORE_STOP = 7 }; +static unsigned unchanged[16] = { }; + +void lx_emul_i915_wakeup(unsigned const connector_id) +{ + bool const valid_id = connector_id < sizeof(unchanged) / sizeof(*unchanged); + + if (!valid_id) { + printk("%s: connector id invalid %d\n", __func__, connector_id); + return; + } + + unchanged[connector_id] = 0; + + /* wake potential sleeping update task */ + lx_emul_task_unblock(lx_update_task); +} + + static int update_content(void *) { while (true) { struct drm_connector_list_iter conn_iter; - struct drm_connector *connector = NULL; - struct drm_device const *dev = dev_client->dev; + struct drm_connector *connector = NULL; + struct drm_device const *dev = dev_client->dev; + bool block_task = true; drm_connector_list_iter_begin(dev, &conn_iter); drm_client_for_each_connector_iter(connector, &conn_iter) { + struct drm_modeset_acquire_ctx ctx; struct drm_framebuffer *fb = NULL; - int err = -1; + + int err = -1; + bool may_sleep = false; + bool const valid_id = connector->index < sizeof(unchanged) / sizeof(*unchanged); if (connector->status != connector_status_connected) continue; - if (!lx_emul_i915_blit(connector->index)) + if (valid_id) { + unchanged[connector->index] ++; + + if (unchanged[connector->index] > ATTEMPTS_BEFORE_STOP) + continue; + } + else + printk("%s: connector id invalid %d\n", __func__, connector->index); + + block_task = false; + + if (valid_id) + may_sleep = unchanged[connector->index] >= ATTEMPTS_BEFORE_STOP; + + if (!lx_emul_i915_blit(connector->index, may_sleep)) continue; + if (valid_id) + unchanged[connector->index] = 0; + if (!connector->state || !connector->state->crtc) continue; @@ -872,8 +914,11 @@ static int update_content(void *) } drm_connector_list_iter_end(&conn_iter); - /* schedule_timeout(jiffes) or hrtimer or msleep */ - msleep(20); + if (block_task) + lx_emul_task_schedule(true /* block task */); + else + /* schedule_timeout(jiffes) or hrtimer or msleep */ + msleep(CAPTURE_RATE_MS); } return 0; diff --git a/repos/pc/src/driver/framebuffer/intel/pc/main.cc b/repos/pc/src/driver/framebuffer/intel/pc/main.cc index 49cbce956e..70299d3158 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/main.cc +++ b/repos/pc/src/driver/framebuffer/intel/pc/main.cc @@ -67,9 +67,8 @@ struct Framebuffer::Driver using Space = Id_space; using Id = Space::Id; - Space::Element id_element; - - Connector(Space &space, Id id) : id_element(*this, space, id) { } + Space::Element id_element; + Signal_handler capture_wakeup; addr_t base { }; Capture::Area size { }; @@ -78,11 +77,23 @@ struct Framebuffer::Driver Constructible capture { }; Constructible screen { }; + + Connector(Env &env, Space &space, Id id) + : + id_element(*this, space, id), + capture_wakeup(env.ep(), *this, &Connector::wakeup_handler) + { } + + void wakeup_handler() + { + lx_emul_i915_wakeup(unsigned(id_element.id().value)); + Lx_kit::env().scheduler.execute(); + } }; Connector::Space ids { }; - bool capture(Connector::Space &ids, Connector::Id const &id) + bool capture(Connector::Space &ids, Connector::Id const &id, bool const may_stop) { using Pixel = Capture::Pixel; @@ -109,6 +120,10 @@ struct Framebuffer::Driver dirty = true; }); }); + + if (!dirty && may_stop) + connector.capture->capture_stopped(); + }, [&](){ /* unknown connector id */ }); return dirty; @@ -136,6 +151,8 @@ struct Framebuffer::Driver Capture::Connection::Screen::Attr attr = { .px = conn.size, .mm = conn.size_mm }; conn.capture.construct(env, label); conn.screen .construct(*conn.capture, env.rm(), attr); + + conn.capture->wakeup_sigh(conn.capture_wakeup); } else { conn.screen .destruct(); conn.capture.destruct(); @@ -450,7 +467,9 @@ void lx_emul_i915_framebuffer_ready(unsigned const connector_id, if (!base) return; - new (drv.heap) Connector (drv.ids, id); + new (drv.heap) Connector (env, drv.ids, id); + + lx_emul_i915_wakeup(unsigned(id.value)); }); drv.ids.apply(id, [&](Connector &conn) { @@ -549,13 +568,13 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode) } -int lx_emul_i915_blit(unsigned connector_id) +int lx_emul_i915_blit(unsigned const connector_id, char const may_stop) { auto &drv = driver(Lx_kit::env().env); auto const id = Framebuffer::Driver::Connector::Id { connector_id }; - return drv.capture(drv.ids, id); + return drv.capture(drv.ids, id, may_stop); }