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;
}
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; }
};

View File

@ -1,6 +1,7 @@
/*
* \brief Frame-buffer driver for the i.MX53
* \author Nikolay Golikov <nik@ksyslabs.org>
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2012-06-21
*/
@ -11,6 +12,8 @@
#include <base/printf.h>
#include <base/sleep.h>
#include <os/static_root.h>
#include <os/config.h>
#include <blit/blit.h>
/* local includes */
#include <driver.h>
@ -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<Framebuffer::Session> fb_root(ep.manage(&fb_session));
env()->parent()->announce(ep.manage(&fb_root));

View File

@ -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)