Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Remarkable support #41

Merged
merged 19 commits into from
Jan 27, 2020
Merged

[RFC] Remarkable support #41

merged 19 commits into from
Jan 27, 2020

Conversation

tcrs
Copy link
Contributor

@tcrs tcrs commented Jan 23, 2020

I'm afraid there is much I don't understand about eink screens. I added a rather arbitrary mapping of the waveform modes in get_wfm_mode. I'm not sure what the dither bit should be set to in the update ioctl. Among other things...

Could you take a look and give me some advice on this? What I've got at the moment is happily displaying some text which is the most important hurdle for me at the moment (I'm porting this to use in my koreader port really).


This change is Reviewable

tcrs added 2 commits January 23, 2020 19:47
Fairly arbitrary mapping of waveform, dither etc :s
@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

Looks fairly okay for a first stab ;).

(And I'm hoping the ifdeffery mess wasn't too awful, especially since the recent cleanup ;)).

  • I haven't double-checked the mxcfb header, but we don't actually need much of it to be "right" ;).
    You're possibly missing a few waveform mode constants (c.f., https://github.com/canselcik/libremarkable/blob/master/src/framebuffer/common.rs#L338).
    Switching to the "better" TEMP flag might be nice, too.

  • Speaking of waveform mode constants, you should be able to use a 1:1 mapping in get_wfm_mode (the enum should have all the required names already, between the Kindle & Kobo support ;)).
    Anything that's in the header/driver should be made available here (even the dubiously useful ones, like INIT ^^), you don't have to specifically care whether they currently do something useful on the device.

  • Related note: I'm slightly confused by the libremarkable notes around GLR16/GLD16. In all the devices I'm familiar with, GLR16 == REAGL and GLD16 == REAGLD. A2 is something else entirely (very specifically a 2-bit mode: black or white, and nothing else. That downside allows it to be the fastest refresh mode, even when you can throw dithering in the mix).

  • Assuming it behaves properly (which isn't a given, it apparently doesn't on some Kindles), look at the mk7 refresh call for the intricacies related to dithering/quant_bit ;).
    You only care about the "v2" dithering modes (in libremarkable, PASSTHROUGH & DRAWING). I don't actually know what to make of "DRAWING" though. On my usual devices, 0x01 would be Floyd-Steinberg, but I've never seen anything else than ORDERED being supported (there's a dmesg warning when you try to use an unimplemented dithering mode).

    See following posts (that variant of, i.e., epdc v2) hardware dithering appears to be unsupported in practice, so you can drop the dithering mode arg, and always set the quant_bit & dithering_mode fields of the struct to 0.

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

At a very quick glance at the driver, the actual dithering value doesn't matter much?

https://github.com/reMarkable/linux/blob/zero-gravitas/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c#L2605

https://github.com/reMarkable/linux/blob/zero-gravitas/include/uapi/linux/mxcfb.h

(I'm not on my main dev box, and Kindle/Kobo kernels are only available as tarballs, so I can't have a quick comparative look at them, so take this with a grain of salt ^^).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

It's also highly unclear to me which version of the driver it's actually supposed to use, especially when looking at the commits in the more up-to-date zero-gravitas_4.9 branch, which mostly appear to target the older driver (https://github.com/reMarkable/linux/blob/lars/zero-gravitas_4.9/drivers/video/fbdev/mxc/mxc_epdc_fb.c && https://github.com/reMarkable/linux/blob/lars/zero-gravitas_4.9/include/uapi/linux/mxcfb.h).

In which case, that dithering flag is actually meaningless (because it's only supported by the v2 driver), and I have no idea why the kernel actually supports the ioctl with that updated, larger struct ^^.

(Although I have seen some weird hoop-jumping being done before in the name of backward compatibility, so, who knows ^^).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

The config appears to confirm that the v2 driver is unused, so you can pretty much forget about all that, and always set dithering & quant_bit to 0 ;).

Still puzzled as to why they kept the updated struct, though.

But I can roll with that, it's certainly less messy than what I've seen before, which is either a different ioctl/struct combo for each device, or a device with support for 2 or 3 different ioctls with a slightly different struct each time ;).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

I wouldn't mind a link to the upstream Kernel repo in the bundled mxcfb header copy, by the way ;).

I probably ought to do that myself for the Kindle & Kobo ones, actually ^^.

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

Extremely minor nitpick: I'm guessing they care about the peculiar casing of the reMarkable name, so I'd double-check that, too ;).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 23, 2020

And, obviously, because I kind of forgot to say it in my excitement: thanks for working on this ;).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 24, 2020

I'd also add a small identify_remarkable to fbink_id.c, just to set the name/codename (which appears to be zero-gravitas), and to set the DPI (226?).

It'll also come in handy if you want to implement fbdepth (as being able to switch to 8bpp would improve performance in KOReader, because RGB565 is the worst).
To that end, I wouldn't mind having a peek at the console output from a random print, mainly to check what the "standard" rotation is ;).

tcrs added 4 commits January 24, 2020 18:46
Looks like this is not used as the kernel is using v1 EPDC driver. So
the field is in the struct which is passed to the ioctl but ignored.
Based this mapping mainly on comments from the libremarkable enum, plus
a little wild guesswork.

ALso added a comment pointing to the source for the mxcfb header.
When used as a user-visible string
Currently there is only a single model of reMarkable so it's easy.
@tcrs
Copy link
Contributor Author

tcrs commented Jan 24, 2020

Thanks for the feedback, I've had a go at the improvements you suggested. The waveform mode mapping is still not 1:1.

Here's the output from a simple fbink invocation, this is just after starting xochitl so should be set up in the default way.

remarkable: ~/ ./fbink 'HELLLO'
[FBInk] Detected a reMarkable
[FBInk] Clock tick frequency appears to be 100 Hz
[FBInk] Screen density set to 226 dpi
[FBInk] Variable fb info: 1404x1872, 16bpp @ rotation: 1 (Clockwise, 90°)
[FBInk] Fontsize set to 24x24 (IBM base glyph size: 8x8)
[FBInk] Line length: 58 cols, Page size: 78 rows
[FBInk] Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes
[FBInk] Pen colors set to #000000 for the foreground and #FFFFFF for the background
Printing string 'HELLLO' @ column 0 + 0px, row 0 + 0px (overlay: N, no BG: N, no FG: N, inverted: N, flashing: N, centered: N, halfway: N, left padded: N, right padded: N, clear screen: N, waveform: AUTO, dithered: N, nightmode: N, skip refresh: N, font: 0, font scaling: x0)
Next line should start @ row 1

@tcrs
Copy link
Contributor Author

tcrs commented Jan 24, 2020

Also, I'm using fbdepth when launching koreader now to set the panel to 8bpp and it seems to be working, does appear a bit snappier (but I could be imagining it...)

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 24, 2020

Great, thanks :).

Don't worry too much about the waveform mapping, I'll take a pass at it tomorrow if I can (I should be able to push to your branch), that'll probably be easier than a few more back & forth, especially since you don't have any other device to compare to ;).
I'll just ask you to double-check that I didn't do anything obviously stupid when I'm done ;).


Good to know about fbdepth (and it being snappier is definitely the end goal. A quick, obvious test is panning a full-screen cover, for instance. You also get free software dithering as a bonus ;).).
Quick question, though: how are you calling it, exactly?
I assume you're omitting the -r, --rota switch?

I'll probably also set a few flags to make that not entirely broken, to that end, you can try running the "rota" tool from the utils folder (it should be built alongside fbdepth w/ the utils target) and posting the output, that should confirm whether there's any weird crap happening on rotation like on some Kobo devices ;).

@tcrs
Copy link
Contributor Author

tcrs commented Jan 24, 2020

I'm currently just using fbdepth to set the depth yea, I've so far left the rotation at the default.

Here's the output of rota, I assume it means more to you that it does to me :)

remarkable: ~/ ./rota 
Variable fb info: 1404x1872, 16bpp @ rotation: 1 (Clockwise, 90°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes

FB_ROTATE_UR to FB_ROTATE_CCW, +1 increments
Setting rotate to 0 (Upright, 0°)
Rotate is now 0 (Upright, 0°)
Variable fb info: 1872x1404, 16bpp @ rotation: 0 (Upright, 0°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 3776 bytes
Setting rotate to 1 (Clockwise, 90°)
Rotate is now 1 (Clockwise, 90°)
Variable fb info: 1404x1872, 16bpp @ rotation: 1 (Clockwise, 90°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes
Setting rotate to 2 (Upside Down, 180°)
Rotate is now 2 (Upside Down, 180°)
Variable fb info: 1872x1404, 16bpp @ rotation: 2 (Upside Down, 180°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 3776 bytes
Setting rotate to 3 (Counter Clockwise, 270°)
Rotate is now 3 (Counter Clockwise, 270°)
Variable fb info: 1404x1872, 16bpp @ rotation: 3 (Counter Clockwise, 270°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes

FB_ROTATE_UR to FB_ROTATE_CCW, +2 increments
Setting rotate to 0 (Upright, 0°)
Rotate is now 0 (Upright, 0°)
Variable fb info: 1872x1404, 16bpp @ rotation: 0 (Upright, 0°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 3776 bytes
Setting rotate to 2 (Upside Down, 180°)
Rotate is now 2 (Upside Down, 180°)
Variable fb info: 1872x1404, 16bpp @ rotation: 2 (Upside Down, 180°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 3776 bytes

FB_ROTATE_CW to FB_ROTATE_CCW, +2 increments
Setting rotate to 1 (Clockwise, 90°)
Rotate is now 1 (Clockwise, 90°)
Variable fb info: 1404x1872, 16bpp @ rotation: 1 (Clockwise, 90°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes
Setting rotate to 3 (Counter Clockwise, 270°)
Rotate is now 3 (Counter Clockwise, 270°)
Variable fb info: 1404x1872, 16bpp @ rotation: 3 (Counter Clockwise, 270°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes

FB_ROTATE_UR to FB_ROTATE_CCW, +2 increments, intermerdiary rota if ==
Setting rotate to 0 (Upright, 0°)
Rotate is now 0 (Upright, 0°)
Variable fb info: 1872x1404, 16bpp @ rotation: 0 (Upright, 0°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 3776 bytes
Setting rotate to 2 (Upside Down, 180°)
Rotate is now 2 (Upside Down, 180°)
Variable fb info: 1872x1404, 16bpp @ rotation: 2 (Upside Down, 180°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 3776 bytes

FB_ROTATE_CW to FB_ROTATE_CCW, +2 increments, intermerdiary rota if ==
Setting rotate to 1 (Clockwise, 90°)
Rotate is now 1 (Clockwise, 90°)
Variable fb info: 1404x1872, 16bpp @ rotation: 1 (Clockwise, 90°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes
Setting rotate to 3 (Counter Clockwise, 270°)
Rotate is now 3 (Counter Clockwise, 270°)
Variable fb info: 1404x1872, 16bpp @ rotation: 3 (Counter Clockwise, 270°)
Fixed fb info: ID is "mxc_epdc_fb", length of fb mem: 10813440 bytes & line length: 2816 bytes

Let me know if there is any other things it would be useful to see the output of.

@tcrs
Copy link
Contributor Author

tcrs commented Jan 25, 2020

I just added some default rotation settings to the deviceQuirks which seem to work OK. I'm not sure if I should be setting ntxRotaQuirk = NTX_ROTA_SANE as the comment says that expects boot rotation to be 0 I think. These settings make fbdepth -r -1 set the rotation to the proper portrait rotation for the remarkable at least.

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 25, 2020

That was precisely what I was planning to do ;).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 25, 2020

Although, yeah, the comment in the enum is a bit misleading, as it's specific to the Kobo Libra.

In practice, it means no rotation shenanigans, and honor bootRota as the "native" Portrait, which is exactly what's needed here, too.


I'll add a bunch of comments to make that clearer ;).

(And clang-format pass)
As per libremarkable recommendations.
Now that it's used somewhere else than only on the Libra ;).
Hopefully. The few constants inherited from the kernel are confusing.
According to the libremarkable comments, I'm fairly confident on the A2
mapping here, but the GL16 one only makes sense by virtue of it usually
always being A2 + 1 on all the platforms I'm familiar with...

TL;DR: Here be dragons!
@NiLuJe
Copy link
Owner

NiLuJe commented Jan 26, 2020

Okay, I've hopefully untangled the get_wfm_mode mapping...

As a quick test, because it might come in handy for KOReader to have a definitive answer on that front, can you check if displaying an image w/ A2 (i.e., fbink -W A2 -i img.png) actually crushes it to a bitonal result?

@tcrs
Copy link
Contributor Author

tcrs commented Jan 26, 2020

Okay, I've hopefully untangled the get_wfm_mode mapping...

Thanks :)

As a quick test, because it might come in handy for KOReader to have a definitive answer on that front, can you check if displaying an image w/ A2 (i.e., fbink -W A2 -i img.png) actually crushes it to a bitonal result?

Yea it looks like it does, drawing with A2 on a cleared screen just draws the black bits in the image. Running again with the default settings draws full details.

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 26, 2020

@tcrs: Yay!

That'll allow me to play with the constant names a bit in the header to make this all slightly less confusing, and this is good to go, thanks :).

I'll be tagging a release soon-ish, but if that doesn't happen soon enough for the KOReader bits, don't hesitate to bump FBInk to a post-merge commit in koreader-base (i.e., the master branch is currently and will be kept in a sane state) ;).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 26, 2020

As an additional test, does something similar happens with GL16, or do you get proper shades of gray?

(I'm wondering if it's actually GL16, or GC4).

In either case, it's a far less interesting mode in practice (well, GL16 has its use in theory, but not in practice on a device with GL16_FAST), and it can be a bit weird, so do try after a separate screen clear (because if the fb content doesn't "change", both of 'em are optimized away, so a double-refresh with those is essentially a no-op, even if the content was actually redrawn, as long as it's identical).

@tcrs
Copy link
Contributor Author

tcrs commented Jan 27, 2020

As an additional test, does something similar happens with GL16, or do you get proper shades of gray?

(I'm wondering if it's actually GL16, or GC4).

In either case, it's a-W GL16 -i fbink_image.png far less interesting mode in practice (well, GL16 has its use in theory, but not in practice on a device with GL16_FAST), and it can be a bit weird, so do try after a separate screen clear (because if the fb content doesn't "change", both of 'em are optimized away, so a double-refresh with those is essentially a no-op, even if the content was actually redrawn, as long as it's identical).

./fbink -c; ./fbink -W GL16 -i fbink_image.png draws the image but it flickers constantly for about 10 seconds then settles into a poor reproduction of the image but with a few gray shades. Looks pretty worrying when it is happening! GL16_FAST looks basically the same to my eyes (lots of flickering followed by a bad image).

I saw a similar effect when I was first porting koreader (and just choosing the waveform modes at random).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 27, 2020

Huh. That's... weird :D. But good to know nonetheless, thanks ;).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 27, 2020

Sidebar: if you (or anyone else with shell access to a reMarkable, really) want to dig into this further, I can whip up the usual strace patch/build to decode mxcfb ioctls, and then it's just a matter of strace'ing the official app's ioctls while doing various different things to see what exactly it's using and when ;).

(This is slightly more practical that what the libremarkable guys have been doing, which is an LD_PRELOAD hack, AFAICT).

familiar...

A2, at least, appears correct and usable, which is good, as it's the one
most likely to be useful of those two ;).
Also like on other platforms, set the REGAL flag for REAGLD.
Like on other platforms, this is probably a no-op and/or broken ;).
@NiLuJe NiLuJe merged commit faa2df0 into NiLuJe:master Jan 27, 2020
@NiLuJe
Copy link
Owner

NiLuJe commented Jan 27, 2020

Okay, said strace patch is done ;).

It should then be as easy as running ./strace -fitv -e trace=ioctl -X verbose -p $(pidof xochitl) to see what makes it tick ;).

strace-remarkable.tar.gz

(Hopefully, I didn't do anything stupid. If I did, strace will segfault on the first mxcfb ioctl ^^.).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 28, 2020

Hmm, see also ffcd983

Fair warning: I'm terrible at this stuff, and I don't have an IDA Pro license, so this is cobbled together via objdump ;).

Speaking of, @tcrs, I wouldn't mind an updated copy of that (libqsgepaper.a & xochitl), as what's available in the libremarkale repo is over two years old ;).

EDIT: Oh, but libqsgepaper.a is part of the SDK :).

@tcrs
Copy link
Contributor Author

tcrs commented Jan 28, 2020

Here's a few captures using that strace binary & the options you said. I grepped all the mxcfb ioctls out of the full trace (there's constant trace noise from some networking stuff going on).

This one is me just moving around the ui, opening settings, searching etc.
ui.log

This is drawing a load of random squiggles and then erasing most of them again
drawing.log

This is rendering a single page of a pdf (xochitl really does take about 30s to do that)...
pdf.log

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 28, 2020

Oh, cool, thanks ;).

That seems to confirm what I dug out of libqsgepaper.a, and that the dither_mode/quant_bit fields are used uninitialized here (as is alt_buffer_data), which leads to a lot of confusing garbage if you try to make sense of it ;p.
And it shines a light on that weird TEMP constant, which appears to only be used for Mono/DU.

The only question mark left being that "Highlight" mode (currently mapped to REAGL), which I'd take to mean A2?
How does it fare with image content w/ FBInk (same test as before ;)).

EDIT: While we're there, I wouldn't mind a test of DU, too (fair warning: if it behaves like on other devices, it may not actually end up displaying much of the image at all).

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 29, 2020

Oh, err, it turns out the actual header is part of the SDK... \o/

#ifndef EPFRAMEBUFFER_H
#define EPFRAMEBUFFER_H

#include <QtCore/QElapsedTimer>
#include <QtCore/QFile>
#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <QtGui/QImage>

#include <atomic>
#include <mutex>

class EPFrameBuffer : public QObject
{
    Q_OBJECT

    // Testing results:
    // 0: ~780ms, initialize to white
    // 1: ~170ms, mono, no flashing
    // 2: ~460ms, 15 grayscale, flashing all pixels white -> black pixels
    // 3: ~460ms, 15, grayscale, flashing all pixels white -> black pixels
    // 4: ~460ms, 4 grayscale, flashing all pixels white -> black pixels
    // 5: ~460ms, 4 grayscale, flashing all pixels white -> black pixels
    // 6: ~135ms, no flashing
    // 7: ~300ms, white, 2 gray, 1 black, no flashing, stuck black?
    // 8: ~435ms, fast flashing, all gray, highlight, several grays, lowest color - 1 gets stuck
    // 9: ~2365ms, lots of flashing, delta something?

    enum Waveform {
        /** Display initialization
          * All -> white
          * 2000ms
          * ~780ms stall in driver
          * Supposedly low ghosting, high ghosting in practice.
          */
        INIT = 0,

        /**
          * Monochrome menu, text input, pen input
          * All -> black/white
          * 260ms to complete
          * 170ms stall in driver
          * Low ghosting
          */
        DU = 1,

        /** High quality images
          * All -> all
          * 480ms to complete
          * 460ms stall in driver
          * Very low ghosting
          */
        GC16 = 2,

        /** Text with white background
          * 16 -> 16
          * 480ms to complete
          * 460ms stall in driver
          * Medium ghosting
          *
          * Local update when white to white, Global update when 16 gray levels
          * For drawing anti-aliased text with reduced flash. This waveform makes full screen update
          * - the entire display except pixels staying in white will update as the new image is
          * written.
          */
        GL16 = 3,

        /** Text with white background
          * All -> all
          * 480ms to complete
          * 460ms stall in driver
          * Low ghosting
          *
          * Global Update
          * For drawing anti-aliased text with reduced flash and image artifacts (used in
          * conjunction with an image preprocessing algorithm, very little ghosting). Drawing time
          * is around 600ms. This waveform makes full screen update - all the pixels are updated or
          * cleared. Use this for anti-aliased text.
          */
        GLR16 = 4,

        /** Text and graphics with white background
          * All -> all
          * 480ms to complete
          * 460ms stall in driver
          * Low ghosting
          *
          * Global Update
          * For drawing anti-aliased text with reduced flash and image artifacts (used in
          * conjunction with an image preprocessing algorithm, very little ghosting) even more
          * compared to the GLR16 mode. Drawing time is around 600ms. This waveform makes full
          * screen update - all the pixels are updated or cleared. Use this for anti-aliased text.
          */
        GLD16 = 5,

        /** Fast page flipping at reduced contrast
          * [0, 29, 30, 31] -> [0, 30]
          * 120ms to complete
          * 135ms stall in driver
          * Medium ghosting
          *
          * Local Update
          * For drawing black and white 2-color images. This waveform supports transitions from and
          * to black or white only. It cannot be used to update to any graytone other than black or
          * white. Drawing time is around 120ms. This waveform makes partial screen update - it
          * updates only changed pixels. Image quality is reduced in exchange for the quicker
          * response time. This waveform can be used for fast updates and simple animation.
          */
        A2 = 6,

        /** Anti-aliased text in menus, touch and pen input
          * All -> [0, 10, 20, 30]
          * 290ms to complete
          * 300ms stall in driver
          *
          * No flashing, black seems to be stuck afterwards?
          */
        DU4 = 7,

        /** Unknown1
          * 435ms stall in driver
          *
          * Fast flashing, all gray, highlight?
          * Multiple grays
          * Next to lowest color gets stuck
          */
        UNKNOWN = 8,

        /** Init?
          * 2365ms stall in driver
          *
          * Lots of flashing, seems to do some delta updates (inverting unchanged?)
          */
        INIT2 = 9
    };

public:
    static EPFrameBuffer *instance();

    /// Which waveforms we use for different kinds of updates
    enum WaveformMode {
        Initialize = INIT,
        Mono = DU,
        Grayscale = GL16,
        HighQualityGrayscale = GC16,
        Highlight = UNKNOWN
    };

    enum UpdateMode {
        PartialUpdate = 0x0,
        FullUpdate = 0x1
    };

    static QImage *framebuffer() {
        return &instance()->m_fb;
    }

    Q_INVOKABLE static void setForceFull(bool force) { instance()->m_forceFull = force; }
    static bool isForceFull() { return instance()->m_forceFull; }

    int lastUpdateId() const { return m_lastUpdateId; }

    void setSuspended(bool suspended) { m_suspended = suspended; }
    bool isSuspended() const {
        std::lock_guard<std::mutex> locker(fbMutex);
        return m_suspended;
    }

    mutable std::mutex fbMutex;

    qint64 timeSinceLastUpdate() const;

public slots:
    static void clearScreen();
    static void sendUpdate(QRect rect, WaveformMode waveform, UpdateMode mode, bool sync = false);
    static void waitForLastUpdate();

private:
    EPFrameBuffer();
    QImage m_fb;
    QFile m_deviceFile;
    bool m_forceFull = false;
    bool m_suspended = false;
    int m_lastUpdateId = 0;

    std::mutex m_timerLock;
    QElapsedTimer m_lastUpdateTimer;
};

#endif // EPFRAMEBUFFER_H

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 29, 2020

Okay, so I've updated the mappings according to that...

Which means we're unfortunately back to square one as far as A2 is concerned...

So, mildly intrigued how fbink -cfw && fbink -W A2 -i img.png fares (compared mainly to DU & REAGL).

On the vague chance the REAGL ones behave like on Kindle, you may need to make 'em flashing/FULL (-f) for them to behave properly. In which case, they won't behave very nicely when refreshing identical content, hence the full clear beforehand ;)...

@tcrs
Copy link
Contributor Author

tcrs commented Jan 30, 2020

Okay, so I've updated the mappings according to that...

Which means we're unfortunately back to square one as far as A2 is concerned...

So, mildly intrigued how fbink -cfw && fbink -W A2 -i img.png fares (compared mainly to DU & REAGL).

On the vague chance the REAGL ones behave like on Kindle, you may need to make 'em flashing/FULL (-f) for them to behave properly. In which case, they won't behave very nicely when refreshing identical content, hence the full clear beforehand ;)...

I built fbink from master and tried ./fbink -cfw && ./fbink -W A2 -i fbink_image.png and ./fbink -cfw && ./fbink -W A2 -f -i fbink_image.png. Both do ~10s of disturbing flickering of the update area and then settle down to a (different but pretty poor) representation of the image (but using multiple gray shades). REAGL/REAGLD behave the same as A2 but with different image reproduction after settling (REGL seems to end up more or less inverted).

So no idea what that means!

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 30, 2020

Huh. For reference, if I take my usual eInk dithering torture test, except in Grayscale:

Forma_Gray

That's roughly how I expect it to get rendered with DU or A2:

Forma_DU


Soo, I'm guessing a full recap is in order, with a test of every waveform mode, in order: DU, GC16, GL16 (which I expect to work properly, as far as crazy flashing is concerned ^^), and then REAGL, REAGLD, A2, DU4, UNKNOWN, INIT2.

I'm mainly concerned with identifying where the "actual" A2 behavior is hiding (if any).


FWIW, GC16 & GL16 should render something like the first picture here (i.e., full of banding).


CC @canselcik, because most of what was said in this PR might come in handy for libremarkable in one shape or form (also, more guinea pigs :D).

@tcrs
Copy link
Contributor Author

tcrs commented Jan 31, 2020

OK, something funny is going on! I tested all the modes with

./fbink -fk && ./fbink -W MODE -i img.jpg

I took a load of pictures, which ended up with DU & REAGL looking like the example DU/A2 image you posted, GC16 & GL16 ended up banded grayscale. All the other modes did terrible flickering for 10s and settled into a banded randomly inverted image.

Then I thought I'd double check and ran the tests again. Now they all produce something which looks like GC16 without any crazy flickering. Am I doing something stupid in my testing here?

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 31, 2020

I've sometimes seen weird things happening w/ A2 , but not to that extent ;).

That said, I'd check with the -w flag (on both sides): this ensures FBInk will block until the driver has completely finished dealing with the refresh, which should prevent the driver from deciding to merge a couple of refreshes together, which would ultimately affect the effective waveform selection ;).
(Especially since -fk will default to GC16, and when merging updates, the waveform with the highest quality wins).

FWIW, REAGL behaving similarly to DU is consistent with the very first test you did when I originally asked about A2. (It also vaguely makes sense as it's the next ID after the properly identified modes (i.e., those used by xochitl)).

@tcrs
Copy link
Contributor Author

tcrs commented Jan 31, 2020

Ah yes the -w option on the clear makes things consistent and match my first run. I think on the first run I was running the clear as a separate command (rather than linking them with &&) so there would have been a longer pause between the two. Makes sense now, mystery solved thanks!

Using ./fbink -fk -w && ./fbink -w -W MODE -i eink_test.png I get the results: DU & REAGL look like the example DU/A2 image you posted, GC16 & GL16 end up banded grayscale like the image you pointed to.

All the other modes have terrible flickering for 10s and settle into a banded randomly inverted image like this:
flicker_modes
and also timeout waiting for the update to complete.

@NiLuJe
Copy link
Owner

NiLuJe commented Jan 31, 2020

Whew, mystery solved ;).

Many thanks for the tests!

I'll tweak the mapping for this A2 trickery and update the documentation to strongly discourage anyone from trying other values, then, thanks!

Because, ouch, that's some weird output there :D.

@hdhbdh

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants