canselcik / libremarkable

The only public framework for developing applications with native refresh support for Remarkable Tablet
MIT License
609 stars 57 forks source link

No rendering without xochitl #32

Closed vmx closed 4 years ago

vmx commented 4 years ago

Nothing gets rendered on the display if xochitl wasn't started at least once.

Steps to reproduce:

  1. Deploy demo application on device
  2. ssh to device
  3. systemctl disable xochitl
  4. reboot
  5. ssh to device
  6. ./demo (you won't see the demo, but it is running, e.g. touch events are logged)
  7. Kill ./demo (e.g. with ctrl-c)
  8. xochitl
  9. Kill xochitl (e.g. with ctrl-c)
  10. ./demo (now you can also see the demo)

Any help on how to get started debugging this problem would be appreciated.

vmx commented 4 years ago

More information: I've tried to run https://github.com/NiLuJe/FBInk (the one bundled with https://github.com/koreader/koreader) and without having xochitl run first, I get a MXCFB_SEND_UPDATE: Operation not permitted!, which I don't get when xochitl was started once.

Eeems commented 4 years ago

@vmx Have you tried running something like draft first?

vmx commented 4 years ago

@Eeems I haven't tried draft (I didn't want to go through the build process). But I just tried Koreader and it does the same screen "flashing" when started as xochitl and afterwards I can run the demo application. So I guess some commands need to be sent at the beginning to initialize the screen.

vmx commented 4 years ago

Progress. If I set the bitdepth from the default 16 to 8 via ./fbdepth -d 8 and start the demo, it renders something, but somehow screwed up. When I then restart the demo, it renders properly.

Eeems commented 4 years ago

@Eeems I haven't tried draft (I didn't want to go through the build process). But I just tried Koreader and it does the same screen "flashing" when started as xochitl and afterwards I can run the demo application. So I guess some commands need to be sent at the beginning to initialize the screen.

@vmx which is why I'm suggesting to run draft first to see if that handles setting up things properly.

canselcik commented 4 years ago

This is interesting. It might be some sort of new initialization sequence that is introduced with the later firmware. First time I'm hearing of this issue.

The initial screen flashing you are describing feels like it might be the WAVEFORM_MODE_INIT, which wasn't in any way required as far as I remember.

vmx commented 4 years ago

@Eeems, would it be easier to get information how it is done from draft rather than xochitl? draft is using the native libraries (AFAICT), so I wouldn't expect much difference/new insights compared to xochitl.

BTW: It's not 16 vs. 8 bits, it's whatever fbdepth is doing. When I set it to 8 and back to 16 I get the same effect as with setting it just to 8.

Eeems commented 4 years ago

Yes it should be easier to pull the information from draft as you could change the code and recompile to test your theories.

I wouldn't be surprised if the code is in one of the following repos: https://github.com/reMarkable/epaper-qpa or https://github.com/reMarkable/qt5-qpa-epaper

vmx commented 4 years ago

From the logging of xochitl it looks to me that it might be the FBIOPUT_VSCREENINFO that does the magic.

Has anyone of you a working version of the spy example and could start xochitl with it and post the output of the first few seconds?

vmx commented 4 years ago

Status update. I created a minimal example that is using QT and the reMarkable toolchain: https://github.com/vmx/remarkable-minimal-render. That one displays correctly.

I've tweaked libremarkable to be as close to the ioctl() calls as possible. There is only a slight difference left when it comes to the first mxcfb_send_update call. libremarkable differs in quant_bit and the alt_buffer_data. Here's some example of that call from minimal-render:

mxcfb_send_update(fd: 11, updateData: mxcfb_update_data {
    update_region: mxcfb_rect {
        top: 0,
        left: 0,
        width: 1404,
        height: 1872,
    },
    waveform_mode: 3,
    update_mode: 0,
    update_marker: 1,
    temp: 4096,
    flags: 0,
    dither_mode: 0,
    quant_bit: 2122396396,
    alt_buffer_data: mxcfb_alt_buffer_data {
        phys_addr: 1983586516,
        width: 2122396424,
        height: 222556,
        alt_update_region: mxcfb_rect {
            top: 0,
            left: 2628288,
            width: 28574968,
            height: 1996257204,
        },
    },
}) = 0

The numbers in quant_bit and alt_buffer_data seem to be pointers and not actual values. They also differ between runs. I currently have no idea what this is about, so if anyone has any ideas, please let me know.

Please also note that I know get the expected refreshing of the screen and it renders "something", but it's not the epected text, but it looks a bit garbled.

vmx commented 4 years ago

Or it is just uninitialized data and it doesn't care about those values.

canselcik commented 4 years ago

@vmx I believe that's uninitialized data. As you guessed, it should care about alt_buffer_data if and only if we are doing an overlay or something along the lines of double-buffering where we use a part of the framebuffer to actually draw on the screen and using the remaining of the framebuffer to prepare the next frame or a part of the next frame.

Looks like the ioctl call you captured is doing a full-screen WAVEFORM_MODE_GC16_FAST.

And as far as I remember, quant_bit is actually not doing much, if anything at all in https://github.com/canselcik/libremarkable/blob/master/reference-material/mxc_epdc_fb.c. It does stuff in https://github.com/canselcik/libremarkable/blob/master/reference-material/mxc_epdc_v2_fb.c#L2606-L2634 but that's not the one used in the kernel that ships with the tablet.

Even in the v2 scenario, the quant_bit is only used if and only if dithering is requested by EPDC_FLAG_USE_DITHERING_PASSTHROUGH < upd_desc_list->upd_data.dither_mode and upd_desc_list->upd_data.dither_mode < EPDC_FLAG_USE_DITHERING_MAX.

vmx commented 4 years ago

Looks like the ioctl call you captured is doing a full-screen WAVEFORM_MODE_GC16_FAST.

Yes, I changed the code in appctx.rs that clears the screen to use that. Sadly that still didn't make it fully work.

canselcik commented 4 years ago

So as far as I can tell, the behavior you're describing is essentially the screen content is written to the framebuffer itself but the partial refresh ioctl is not making the display refresh for you. Which is something I haven't had an issue with before.

I'd recommend adding some additional logging to the partial_update codepath and seeing what they get called with. Also I'd recommend trying the full_refresh to see if that'll actually get the contents of the framebuffer to render on the screen.

vmx commented 4 years ago

Some more info (I didn't really change anything since my last comment). When starting the minimal example flashes the display the same way as with the QT minimal example. Though it renders garbled. When I kill the application and restart it again, it renders correctly.

I dumped the framebuffer on the first start of the app, but the output is the correct one. So it writes the right bytes, but it renders them wrong (I had hoped I can post a screenshot of that garbled output).

Also when I start the application the second time, the output from libspy.so is the same as the first time (well, not for the original values, but after the FBIOPUT_VSCREENINFO calls).

vmx commented 4 years ago

I forgot to mention, that it's the same garbled rendering on the first start and correct rendering when killed and started again also with the demo application.

canselcik commented 4 years ago

@vmx A photo of the garbled rendering might actually prove to be very useful in this case. I have seen many different ways the output might be garbled.

Did it look like it was offset like each row was shifted by a constant offset into a certain direction, with the same offset for each row?

vmx commented 4 years ago

Good news, I found the issues. Here's an excerpt from the commit message that describes the solution:

In order to fix this problem, pixclock is set to 6250. This will result in the expected flashing of the display as when starting other applications. Though the rendering will be garbled/corrupted.

In order to fix that, the fix screen info needs to be read after the var screen info was set. The fix screen info returns the number of lines based on the rotation of the screen. Right after starting the reMarkable the screen is set to landscape mode. libremarkable sets it to portrait mode via the var screen info, which changes the line length of the fix screen info.