genode/repos/gems/include/gems/nitpicker_buffer.h

190 lines
5.1 KiB
C++

/*
* \brief Utility for the buffered pixel output via nitpicker
* \author Norman Feske
* \date 2014-08-22
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__GEMS__NITPICKER_BUFFER_H_
#define _INCLUDE__GEMS__NITPICKER_BUFFER_H_
/* Genode includes */
#include <base/ram_allocator.h>
#include <nitpicker_session/connection.h>
#include <base/attached_dataspace.h>
#include <base/attached_ram_dataspace.h>
#include <os/surface.h>
#include <os/pixel_rgb565.h>
#include <os/pixel_alpha8.h>
#include <os/pixel_rgb888.h>
/* gems includes */
#include <gems/dither_painter.h>
struct Nitpicker_buffer
{
typedef Genode::Pixel_rgb888 Pixel_rgb888;
typedef Genode::Pixel_rgb565 Pixel_rgb565;
typedef Genode::Pixel_alpha8 Pixel_alpha8;
typedef Genode::Surface<Pixel_rgb888> Pixel_surface;
typedef Genode::Surface<Pixel_alpha8> Alpha_surface;
typedef Genode::Surface_base::Area Area;
typedef Genode::Surface_base::Rect Rect;
typedef Genode::Surface_base::Point Point;
typedef Genode::Attached_ram_dataspace Ram_ds;
Genode::Ram_allocator &ram;
Genode::Region_map &rm;
Nitpicker::Connection &nitpicker;
Framebuffer::Mode const mode;
/**
* Return dataspace capability for virtual framebuffer
*/
Genode::Dataspace_capability _ds_cap(Nitpicker::Connection &nitpicker)
{
/* setup virtual framebuffer mode */
nitpicker.buffer(mode, true);
if (mode.format() != Framebuffer::Mode::RGB565) {
Genode::warning("color mode ", mode, " not supported");
return Genode::Dataspace_capability();
}
return nitpicker.framebuffer()->dataspace();
}
Genode::Attached_dataspace fb_ds { rm, _ds_cap(nitpicker) };
Genode::size_t pixel_surface_num_bytes() const
{
return size().count()*sizeof(Pixel_rgb888);
}
Genode::size_t alpha_surface_num_bytes() const
{
return size().count();
}
Ram_ds pixel_surface_ds { ram, rm, pixel_surface_num_bytes() };
Ram_ds alpha_surface_ds { ram, rm, alpha_surface_num_bytes() };
/**
* Constructor
*/
Nitpicker_buffer(Nitpicker::Connection &nitpicker, Area size,
Genode::Ram_allocator &ram, Genode::Region_map &rm)
:
ram(ram), rm(rm), nitpicker(nitpicker),
mode(Genode::max(1UL, size.w()), Genode::max(1UL, size.h()),
nitpicker.mode().format())
{
reset_surface();
}
/**
* Return size of virtual framebuffer
*/
Area size() const { return Area(mode.width(), mode.height()); }
template <typename FN>
void apply_to_surface(FN const &fn)
{
Pixel_surface pixel(pixel_surface_ds.local_addr<Pixel_rgb888>(), size());
Alpha_surface alpha(alpha_surface_ds.local_addr<Pixel_alpha8>(), size());
fn(pixel, alpha);
}
void reset_surface()
{
Pixel_surface pixel(pixel_surface_ds.local_addr<Pixel_rgb888>(), size());
Alpha_surface alpha(alpha_surface_ds.local_addr<Pixel_alpha8>(), size());
Genode::size_t const num_pixels = size().count();
Genode::memset(alpha.addr(), 0, num_pixels);
/*
* Initialize color buffer with 50% gray
*
* We do not use black to limit the bleeding of black into antialiased
* drawing operations applied onto an initially transparent background.
*/
Pixel_rgb888 *dst = pixel.addr();
Pixel_rgb888 const gray(127, 127, 127, 255);
for (unsigned n = num_pixels; n; n--)
*dst++ = gray;
}
template <typename DST_PT, typename SRC_PT>
void _convert_back_to_front(DST_PT *front_base,
Genode::Texture<SRC_PT> const &texture,
Rect const clip_rect)
{
Genode::Surface<DST_PT> surface(front_base, size());
surface.clip(clip_rect);
Dither_painter::paint(surface, texture, Point());
}
void _update_input_mask()
{
unsigned const num_pixels = size().count();
unsigned char * const alpha_base = fb_ds.local_addr<unsigned char>()
+ mode.bytes_per_pixel()*num_pixels;
unsigned char * const input_base = alpha_base + num_pixels;
unsigned char const *src = alpha_base;
unsigned char *dst = input_base;
/*
* Set input mask for all pixels where the alpha value is above a
* given threshold. The threshold is defines such that typical
* drop shadows are below the value.
*/
unsigned char const threshold = 100;
for (unsigned i = 0; i < num_pixels; i++)
*dst++ = (*src++) > threshold;
}
void flush_surface()
{
/* represent back buffer as texture */
Genode::Texture<Pixel_rgb888>
texture(pixel_surface_ds.local_addr<Pixel_rgb888>(),
alpha_surface_ds.local_addr<unsigned char>(),
size());
// XXX track dirty rectangles
Rect const clip_rect(Genode::Surface_base::Point(0, 0), size());
Pixel_rgb565 *pixel_base = fb_ds.local_addr<Pixel_rgb565>();
Pixel_alpha8 *alpha_base = fb_ds.local_addr<Pixel_alpha8>()
+ mode.bytes_per_pixel()*size().count();
_convert_back_to_front(pixel_base, texture, clip_rect);
_convert_back_to_front(alpha_base, texture, clip_rect);
_update_input_mask();
}
};
#endif /* _INCLUDE__GEMS__NITPICKER_BUFFER_H_ */