From cddd69a122224ead0fbb1ef384adcb3a1462a131 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Thu, 2 May 2013 14:10:41 +0200 Subject: [PATCH] Double buffering for i.MX53 fb driver (fix #721) Enable optinal support for double buffering in the i.MX53 framebuffer driver. This prevents flickering in certain scenarios, where applications directly render in the framebuffer dataspace given by the driver. --- os/src/drivers/framebuffer/imx53/driver.h | 6 +- os/src/drivers/framebuffer/imx53/main.cc | 74 ++++++++++++++++++---- os/src/drivers/framebuffer/imx53/target.mk | 2 +- 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/os/src/drivers/framebuffer/imx53/driver.h b/os/src/drivers/framebuffer/imx53/driver.h index 9a724d6bd6..932059f252 100644 --- a/os/src/drivers/framebuffer/imx53/driver.h +++ b/os/src/drivers/framebuffer/imx53/driver.h @@ -87,8 +87,6 @@ class Framebuffer::Driver return true; } - Mode mode() { return Mode(_width, _height, Mode::RGB565); } - size_t size() { return BYTES_PER_PIXEL * _width * _height; } - - Ipu &ipu() { return _ipu; } + Mode mode() { return Mode(_width, _height, Mode::RGB565); } + Ipu &ipu() { return _ipu; } }; diff --git a/os/src/drivers/framebuffer/imx53/main.cc b/os/src/drivers/framebuffer/imx53/main.cc index 418a4488b9..608940ca07 100644 --- a/os/src/drivers/framebuffer/imx53/main.cc +++ b/os/src/drivers/framebuffer/imx53/main.cc @@ -1,6 +1,7 @@ /* * \brief Frame-buffer driver for the i.MX53 * \author Nikolay Golikov + * \author Stefan Kalkowski * \date 2012-06-21 */ @@ -11,6 +12,8 @@ #include #include #include +#include +#include /* local includes */ #include @@ -26,23 +29,34 @@ class Framebuffer::Session_component : { private: - size_t _size; - Dataspace_capability _ds; - addr_t _phys_base; - Mode _mode; + bool _buffered; + Mode _mode; + size_t _size; + + /* dataspace uses a back buffer (if '_buffered' is true) */ + Genode::Dataspace_capability _bb_ds; + void *_bb_addr; + + /* dataspace of physical frame buffer */ + Genode::Dataspace_capability _fb_ds; + void *_fb_addr; Ipu &_ipu; public: - Session_component(Driver &driver) - : _size(driver.size()), - _ds(env()->ram_session()->alloc(_size, false)), - _phys_base(Dataspace_client(_ds).phys_addr()), + Session_component(Driver &driver, bool buffered) + : _buffered(buffered), _mode(driver.mode()), + _size(_mode.bytes_per_pixel() * _mode.width() * _mode.height()), + _bb_ds(buffered ? Genode::env()->ram_session()->alloc(_size) + : Genode::Ram_dataspace_capability()), + _bb_addr(buffered ? (void*)Genode::env()->rm_session()->attach(_bb_ds) : 0), + _fb_ds(Genode::env()->ram_session()->alloc(_size, false)), + _fb_addr((void*)Genode::env()->rm_session()->attach(_fb_ds)), _ipu(driver.ipu()) { - if (!driver.init(_phys_base)) { + if (!driver.init(Dataspace_client(_fb_ds).phys_addr())) { PERR("Could not initialize display"); struct Could_not_initialize_display : Exception { }; throw Could_not_initialize_display(); @@ -54,16 +68,48 @@ class Framebuffer::Session_component : ** Framebuffer::session interface ** **************************************/ - Dataspace_capability dataspace() { return _ds; } - void release() { } - Mode mode() const { return _mode; } + Dataspace_capability dataspace() { return _buffered ? _bb_ds : _fb_ds; } + void release() { } + Mode mode() const { return _mode; } void mode_sigh(Genode::Signal_context_capability) { } - void refresh(int, int, int, int) { } + + void refresh(int x, int y, int w, int h) + { + if (!_buffered) return; + + /* clip specified coordinates against screen boundaries */ + int x2 = min(x + w - 1, (int)_mode.width() - 1), + y2 = min(y + h - 1, (int)_mode.height() - 1); + int x1 = max(x, 0), + y1 = max(y, 0); + if (x1 > x2 || y1 > y2) return; + + int bypp = _mode.bytes_per_pixel(); + + /* copy pixels from back buffer to physical frame buffer */ + char *src = (char *)_bb_addr + bypp*(_mode.width()*y + x), + *dst = (char *)_fb_addr + bypp*(_mode.width()*y + x); + + blit(src, bypp*_mode.width(), dst, bypp*_mode.width(), + bypp*(x2 - x1 + 1), y2 - y1 + 1); + } void overlay(Genode::addr_t phys_base, int x, int y, int alpha) { _ipu.overlay(phys_base, x, y, alpha); } }; + +static bool config_attribute(const char *attr_name) +{ + bool result = false; + try { + result = + Genode::config()->xml_node().attribute(attr_name).has_value("yes"); } + catch (...) {} + return result; +} + + int main(int, char **) { Genode::printf("Starting i.MX53 framebuffer driver\n"); @@ -76,7 +122,7 @@ int main(int, char **) static Cap_connection cap; static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep"); - static Session_component fb_session(driver); + static Session_component fb_session(driver, config_attribute("buffered")); static Static_root fb_root(ep.manage(&fb_session)); env()->parent()->announce(ep.manage(&fb_root)); diff --git a/os/src/drivers/framebuffer/imx53/target.mk b/os/src/drivers/framebuffer/imx53/target.mk index b387f4298f..54597876cf 100644 --- a/os/src/drivers/framebuffer/imx53/target.mk +++ b/os/src/drivers/framebuffer/imx53/target.mk @@ -1,7 +1,7 @@ TARGET = fb_drv REQUIRES = imx53 SRC_CC = main.cc -LIBS = base +LIBS = base blit INC_DIR += $(PRG_DIR) vpath main.cc $(PRG_DIR)