libremarkable
libremarkable copied to clipboard
expose flags on framebuffer
I'm using libremarkable to port Plato reader on remarkable, i need to pass EPDC_FLAG_ENABLE_INVERSION to update flags
Hi,
If you look at the mxc_epdc_fb.c
, which is the EPDC driver that our ioctl
is handled by:
/*
* Set PxP LUT transform type based on update flags.
*/
fb_data->pxp_conf.proc_data.lut_transform = 0;
if (upd_desc_list->upd_data.flags & EPDC_FLAG_ENABLE_INVERSION)
fb_data->pxp_conf.proc_data.lut_transform |= PXP_LUT_INVERT;
if (upd_desc_list->upd_data.flags & EPDC_FLAG_FORCE_MONOCHROME)
fb_data->pxp_conf.proc_data.lut_transform |=
PXP_LUT_BLACK_WHITE;
if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_CMAP)
fb_data->pxp_conf.proc_data.lut_transform |=
PXP_LUT_USE_CMAP;
/*
* If no processing required, skip update processing
* No processing means:
* - FB unrotated
* - FB pixel format = 8-bit grayscale
* - No look-up transformations (inversion, posterization, etc.)
*
* Note: A bug with EPDC stride prevents us from skipping
* PxP in versions 2.0 and earlier of EPDC.
*/
is_transform = upd_data_list->update_desc->upd_data.flags &
(EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 |
EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME |
EPDC_FLAG_USE_CMAP) ? true : false;
It looks like EPDC_FLAG_ENABLE_INVERSION
is actually an EPDC_FLAG
that's passed to the refresh ioctl
inside the mxcfb_update_data
that we provide to it. Therefore it is already exposed as a part of the Framebuffer::partial_refresh(..)
and Framebuffer::full_refresh(..)
under the flags
parameter.
On the other hand, if you wanted to enable inversion for the entire framebuffer, regardless of the flags passed inside the mxcfb_update_data
struct, this might be of interest to you:
/*
* Toggle inversion processing if 8-bit
* inverted is the current pixel format.
*/
if (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT_INVERTED)
fb_data->pxp_conf.proc_data.lut_transform ^= PXP_LUT_INVERT;
As you can see, here the driver looks at the fb_var_screeninfo
struct's grayscale
field and checks if it is GRAYSCALE_8BIT_INVERTED
. This is also exposed by libremarkable
via the Framebuffer::get_var_screeninfo()
and Framebuffer:put_var_screeninfo()
methods.
For the latter, you'll want to update the contents of var_screen_info
inside your Framebuffer
.
You could also create a new "constructor" for Framebuffer
. The current implementation follows what xochitl
would have done on the device:
fn new(path_to_device: &str) -> Framebuffer {
let device = OpenOptions::new()
.read(true)
.write(true)
.open(path_to_device)
.unwrap();
let mut var_screen_info = Framebuffer::get_var_screeninfo(&device);
let fix_screen_info = Framebuffer::get_fix_screeninfo(&device);
let frame_length = (fix_screen_info.line_length * var_screen_info.yres) as usize;
let mem_map = MemoryMap::new(
frame_length,
&[
mmap::MapOption::MapReadable,
mmap::MapOption::MapWritable,
mmap::MapOption::MapFd(device.as_raw_fd()),
mmap::MapOption::MapOffset(0),
mmap::MapOption::MapNonStandardFlags(libc::MAP_SHARED),
],
).unwrap();
// Load the font
let font_data = include_bytes!("../../assets/DejaVuSans.ttf");
let collection = FontCollection::from_bytes(font_data as &[u8]);
var_screen_info.xres = 1872;
var_screen_info.yres = 1404;
var_screen_info.rotate = 1;
var_screen_info.width = var_screen_info.xres;
var_screen_info.height = var_screen_info.yres;
var_screen_info.pixclock = 160000000;
var_screen_info.left_margin = 32;
var_screen_info.right_margin = 326;
var_screen_info.upper_margin = 4;
var_screen_info.lower_margin = 12;
var_screen_info.hsync_len = 44;
var_screen_info.vsync_len = 1;
var_screen_info.sync = 0;
var_screen_info.vmode = 0; // FB_VMODE_NONINTERLACED
var_screen_info.accel_flags = 0;
let mut fb = Framebuffer {
marker: AtomicU32::new(1),
device,
frame: mem_map,
default_font: collection.into_font().unwrap(),
var_screen_info,
fix_screen_info,
};
if !fb.put_var_screeninfo() {
panic!("FBIOPUT_VSCREENINFO failed");
}
return fb;
}
I would be more than happy to merge a PR that creates an additional constructor that accepts more configurables.
I also stumbled upon this when re-porting plato. Though I didn't deem the feature important enough and ignored using the flags.
I also had to do paste some of the constructor-code to get a proper rotation (RemarkableFrambuffer::set_rotation()
).
This may also be a candidate to add to the this lib, since it tooks me a lot of hours to figure out why the framebuffer either didn't rotate or got all messed up, or clipped (addressed here which got merged with PR #37).
This might be a nice feature to have. But since the rm2 prevents us to go that lowlevel anymore anyway (at least rn, maybe waved can change this), I doubt it would be useful to add custom flags anyway. The implementation should be easy enough though. Do we want to do this?