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.
This commit is contained in:
Stefan Kalkowski 2013-05-02 14:10:41 +02:00 committed by Norman Feske
parent 0950b2f340
commit cddd69a122
3 changed files with 63 additions and 19 deletions

View File

@ -87,8 +87,6 @@ class Framebuffer::Driver
return true; return true;
} }
Mode mode() { return Mode(_width, _height, Mode::RGB565); } Mode mode() { return Mode(_width, _height, Mode::RGB565); }
size_t size() { return BYTES_PER_PIXEL * _width * _height; } Ipu &ipu() { return _ipu; }
Ipu &ipu() { return _ipu; }
}; };

View File

@ -1,6 +1,7 @@
/* /*
* \brief Frame-buffer driver for the i.MX53 * \brief Frame-buffer driver for the i.MX53
* \author Nikolay Golikov <nik@ksyslabs.org> * \author Nikolay Golikov <nik@ksyslabs.org>
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2012-06-21 * \date 2012-06-21
*/ */
@ -11,6 +12,8 @@
#include <base/printf.h> #include <base/printf.h>
#include <base/sleep.h> #include <base/sleep.h>
#include <os/static_root.h> #include <os/static_root.h>
#include <os/config.h>
#include <blit/blit.h>
/* local includes */ /* local includes */
#include <driver.h> #include <driver.h>
@ -26,23 +29,34 @@ class Framebuffer::Session_component :
{ {
private: private:
size_t _size; bool _buffered;
Dataspace_capability _ds; Mode _mode;
addr_t _phys_base; size_t _size;
Mode _mode;
/* 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; Ipu &_ipu;
public: public:
Session_component(Driver &driver) Session_component(Driver &driver, bool buffered)
: _size(driver.size()), : _buffered(buffered),
_ds(env()->ram_session()->alloc(_size, false)),
_phys_base(Dataspace_client(_ds).phys_addr()),
_mode(driver.mode()), _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()) _ipu(driver.ipu())
{ {
if (!driver.init(_phys_base)) { if (!driver.init(Dataspace_client(_fb_ds).phys_addr())) {
PERR("Could not initialize display"); PERR("Could not initialize display");
struct Could_not_initialize_display : Exception { }; struct Could_not_initialize_display : Exception { };
throw Could_not_initialize_display(); throw Could_not_initialize_display();
@ -54,16 +68,48 @@ class Framebuffer::Session_component :
** Framebuffer::session interface ** ** Framebuffer::session interface **
**************************************/ **************************************/
Dataspace_capability dataspace() { return _ds; } Dataspace_capability dataspace() { return _buffered ? _bb_ds : _fb_ds; }
void release() { } void release() { }
Mode mode() const { return _mode; } Mode mode() const { return _mode; }
void mode_sigh(Genode::Signal_context_capability) { } 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) { void overlay(Genode::addr_t phys_base, int x, int y, int alpha) {
_ipu.overlay(phys_base, x, y, 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 **) int main(int, char **)
{ {
Genode::printf("Starting i.MX53 framebuffer driver\n"); Genode::printf("Starting i.MX53 framebuffer driver\n");
@ -76,7 +122,7 @@ int main(int, char **)
static Cap_connection cap; static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep"); 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<Framebuffer::Session> fb_root(ep.manage(&fb_session)); static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
env()->parent()->announce(ep.manage(&fb_root)); env()->parent()->announce(ep.manage(&fb_root));

View File

@ -1,7 +1,7 @@
TARGET = fb_drv TARGET = fb_drv
REQUIRES = imx53 REQUIRES = imx53
SRC_CC = main.cc SRC_CC = main.cc
LIBS = base LIBS = base blit
INC_DIR += $(PRG_DIR) INC_DIR += $(PRG_DIR)
vpath main.cc $(PRG_DIR) vpath main.cc $(PRG_DIR)