libremarkable icon indicating copy to clipboard operation
libremarkable copied to clipboard

expose flags on framebuffer

Open darvin opened this issue 6 years ago • 4 comments

I'm using libremarkable to port Plato reader on remarkable, i need to pass EPDC_FLAG_ENABLE_INVERSION to update flags

darvin avatar May 19 '18 20:05 darvin

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.

canselcik avatar May 19 '18 23:05 canselcik

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.

canselcik avatar May 19 '18 23:05 canselcik

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

LinusCDE avatar Sep 10 '20 13:09 LinusCDE

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?

LinusCDE avatar Jan 17 '22 14:01 LinusCDE