Skip to content

Fix frontlight toggle not ramping, but immediately turning off on Sage#10305

Merged
NiLuJe merged 18 commits into
masterfrom
unknown repository
Apr 30, 2023
Merged

Fix frontlight toggle not ramping, but immediately turning off on Sage#10305
NiLuJe merged 18 commits into
masterfrom
unknown repository

Conversation

@ghost

@ghost ghost commented Apr 7, 2023

Copy link
Copy Markdown

On my Sage toggling Frontlight on gives a smooth brightness ramp; but toggling it off is a jump in brightness.

This PR fixes that behavioir:
*) Toggling FL on is not changed
*) Toggling FL of does a ramp (with an exponential decay, to make it smooth :) as the observer should like. Anyway not tested on other devices as a Sage).

More infos are in the comments.


This change is Reviewable

@ghost ghost marked this pull request as ready for review April 7, 2023 22:10
@ghost ghost requested review from Frenzie, NiLuJe, pazos and poire-z as code owners April 7, 2023 22:10
@ghost ghost added this to the 2023.04 milestone Apr 7, 2023
@NiLuJe

NiLuJe commented Apr 8, 2023

Copy link
Copy Markdown
Member

What starting frontlight level are you usually testing from?

I never noticed this, but I'm mostly using fairly low brigthness levels (~20%). I'm somewhat wary of touching it, because getting it to behave more-or-less correctly without more eggregious issues was kind of a bitch ;p.
On the other hand, I see nothing wrong with this approach (besides the large sleep at the end, and me needing to do maths to compute how long this actually takes ;p (we don't want this to take too long).

I'll give it a try on a few devices ;).

(Unrelated sidebar: I've always been wary of my nasty hackish approach w/ runInSubprocess here, I've often pondered about just writing a dumb standalone script that sends the ioctl via ffi [we already do it for WiFi/BT power in the startup script] and that we just os.execute, and simply update the various PowerD state variables after the fact).

@NiLuJe

NiLuJe commented Apr 8, 2023

Copy link
Copy Markdown
Member

Oh, and do you observe a similar behavior for the USBMS frontlight toggle? (Because that's using a much nicer ramp, because it's slower, as there are none of the timing constraints I mentioned earlier there).

@ghost

ghost commented Apr 9, 2023

Copy link
Copy Markdown
Author

I am using a high brightness (~60).

The USBMS frontlight toggle works much better (almost perfect).

@ghost ghost marked this pull request as draft April 9, 2023 14:58
@ghost

ghost commented Apr 9, 2023

Copy link
Copy Markdown
Author

In the last commit I have changed the whole ramping thing to UIManager scheduled tasks.

The new property "UIManager" can be used in the other powerd's (kindle, Android), too.

We could also drop the whole sub process thing and do a simple setIntensity(zero/max) if UIManager is not initialized on the first (few) calls.

And the good thing is, it is easy to abort the whole ramp.

A few test have to be done, so draft by now.

Comment thread frontend/device/generic/powerd.lua Outdated
last_aux_capacity_pull_time = time.s(-61), -- timestamp of last pull

is_fl_on = false, -- whether the frontlight is on
UIManager = nil -- will be updated when available

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit torn on that one ;).

I understand the reasoning, but I'm not necessarily a fan of it.

If we can't think of anything better, I would at least rename it to ui_mgr to make it clear it's not our usual module-local.

(There's no real technical issues, though, given that UIManager is a singleton. The testsuite might rain on your parade, though).

Comment thread frontend/device/kobo/powerd.lua Outdated

-- This ramp down goes faster on high intensity and slower at the end.
-- The user will notice a linear brightness change.
-- The whole function gets calles at max log(100)/log(0.75) = 17 times,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: called ;).

And thanks for dumbing down the maths for us there, I appreciate it ;).

Comment thread frontend/device/kobo/powerd.lua Outdated
Comment on lines +327 to +343
-- On some devices (Sage) setting intensity to zero happens immediately,
-- which will lead to a jump and not a ramp. So we postpone the last change by 0.5s to get it smooth
self.UIManager:scheduleIn(0.5, self._postponedSetIntensityHW, self, end_intensity)
-- no reschedule here, as we are done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably still need a Device check, because a lot of the older devices have the opposite issue: no matter the timing or the previous brightness level, switching from on to off incurs an extra delay, so this would make it much worse ;).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much, much worse, yes.

Comment thread frontend/device/kobo/powerd.lua Outdated
self.UIManager:unschedule(self.turnOffFrontlightRamp)
self.UIManager:unschedule(self.turnOnFrontlightRamp)
self.UIManager:unschedule(self.setIntensityHW)
self.fl_rump_running = false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: fun typo there ;o). (rump means ass, essentially ^^).

Comment thread frontend/device/kobo/powerd.lua Outdated

function KoboPowerD:_postponedSetIntensityHW(end_intensity)
self:setIntensityHW(end_intensity)
self.running = false

@NiLuJe NiLuJe Apr 9, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually checked anywhere? Or was it supposed to be fl_ramp_running?

@NiLuJe

NiLuJe commented Apr 9, 2023

Copy link
Copy Markdown
Member

I definitely like this much better, thanks!

And...

We could also drop the whole sub process thing and do a simple setIntensity(zero/max) if UIManager is not initialized on the first (few) calls.

Yeah, definitely, go for it!

Comment thread frontend/device/generic/powerd.lua Outdated
function BasePowerD:readyUI()
self.UIManager = require("ui/uimanager")
UIManager = require("ui/uimanager")
self:readyUIHW()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

über nit: you can also simply pass the UIManager reference along, much like what _setEventHandlers does ;).


Another random idea I had last night would have been to move the full implementation to Generic (while keeping it opt-in, and only actually used on Kobo), with a few knobs via arguments to allow implementations to choose the scheduling frequency and the final delay, if any.

I'm perfectly happy with what you've done here, though, especially since I don't really see us using this on other platforms (I think Kindles do the ramp for us, for example). ;).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will resolve the über nit and sleep/think about a move of the ramp to generic/powerd.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, that was just a random 3AM idea, I'm perfectly fine with what you've done here ;).

Comment thread frontend/device/kobo/powerd.lua Outdated
Comment on lines +354 to +362
-- NOTE: This is essentially what setIntensityHW does, except we don't actually touch the FL,
-- we only sync the state of the main process with the final state of what we're doing in the forks.
-- And update hw_intensity in our actual process ;).
self.hw_intensity = self.fl_min
-- NOTE: And don't forget to update sysfs_light, too, as a real setIntensityHW would via setBrightness
if self.fl then
self.fl.current_brightness = self.fl_min
end
self:_decideFrontlightState()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary anymore, since everything happens in the main thread now ;).

(Ditto for the other ramp).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the whole gymnastics is necessary (at least for the down ramp).

If the user toggles fl with right left corner tap, the ramp starts. If the user taps again during the down ramp (roughly <1s) the notification "fl off" is shown again. This is easy to reproduce, and annoying.
With that code a tap again toggles fl on, which seems to be what the user wants.

(I was not able to reproduce the behavior on the on ramp maybe cause it is shorter. Anyway leaving both in is symmetric.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, yeah, that makes sense; I'd possibly simply rejig the comments a bit then ;).

@ghost ghost Apr 11, 2023

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, please forget my comment above. This was the original idea, why I have inserted/moved the code above.

Now there is a check in isFrontlightOnHW()

return self.hw_intensity > 0 and not self.fl_ramp_down_running

which does the job even better.

@ghost ghost marked this pull request as ready for review April 11, 2023 14:29
@ghost ghost changed the title Fix frontlight toggle not ramp, but immediately turning of on Sage Fix frontlight toggle not ramping, but immediately turning off on Sage Apr 12, 2023
@ghost

ghost commented Apr 17, 2023

Copy link
Copy Markdown
Author

Ready to merge?

@poire-z

poire-z commented Apr 17, 2023

Copy link
Copy Markdown
Contributor

Not ignoring you and your 2 PRs (this and #10306) - but as I'm not familiar with the code involved, nothing to say :) but no objection!
No risk with them (possibly the ramp change on various devices ?), and a stable release being near (as due 10 days ago :) - @Frenzie : when do you plan for it?

@Frenzie

Frenzie commented Apr 17, 2023 via email

Copy link
Copy Markdown
Member

@NiLuJe

NiLuJe commented Apr 17, 2023

Copy link
Copy Markdown
Member

Oops, forgot about it. I'd like to test it on a few devices first (will probably do that tomorrow).

@NiLuJe NiLuJe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't bother with my nits just yet, as I'm liable to fix them during testing later tonight ;).

Reviewed 2 of 3 files at r3, 1 of 1 files at r4, all commit messages.
Reviewable status: all files reviewed, 6 unresolved discussions (waiting on @Frenzie, @pazos, @poire-z, and @zwim)


frontend/device/generic/powerd.lua line 46 at r4 (raw file):

function BasePowerD:readyUI()
    UIManager = require("ui/uimanager")
    self:readyUIHW()

nit: Pass the UIManager ref along, like in setEventHandlers


frontend/device/kobo/device.lua line 172 at r4 (raw file):

    frontlight_settings = {
        wait_before_turn_off_s = 0.0, -- time to wait before turning FL off.
    },

This doesn't quite work as a default for devices where we actually set frontlight_settings, because when we do, we create an all new table, so this is effectively gone and never accessed.

(i.e., this needs to either move to PowerD, or not be inside a subtable).

EDIT: Oh, I see the nil is handled when this is actually checked, so this ends up effectively being dead code; I'd just handle the comment/documentation in the one case that needs it.

Code quote:

    frontlight_settings = {
        wait_before_turn_off_s = 0.0, -- time to wait before turning FL off.
    },

frontend/device/kobo/powerd.lua line 348 at r4 (raw file):

    if UIManager then
        -- Do nothing, if the ramp is allready running

nit: already


frontend/device/kobo/powerd.lua line 359 at r4 (raw file):

end

-- This is fairly the same functionallity as in Kobo's turnOnFrontlightHW().

nit: functionality


frontend/device/kobo/powerd.lua line 360 at r4 (raw file):

-- This is fairly the same functionallity as in Kobo's turnOnFrontlightHW().
-- The whole function gets calles at 100/5 + 1 = 21 times,

nit: called

@poire-z

poire-z commented Apr 29, 2023

Copy link
Copy Markdown
Contributor

@zwim @hius07 : now that v2023.04 is out for > 24 hours, feel free to (squash &) merge your waiting PRs (with proper title & short summary adjusted to the final result :).

@ghost

ghost commented Apr 30, 2023

Copy link
Copy Markdown
Author

@NiLuJe Do you want to merge thus, as you have done the latest changes?

@NiLuJe NiLuJe merged commit 00b3594 into koreader:master Apr 30, 2023
@ghost ghost deleted the fixLightOff branch May 1, 2023 08:36
@poire-z

poire-z commented May 4, 2023

Copy link
Copy Markdown
Contributor

On my Sage toggling Frontlight on gives a smooth brightness ramp; but toggling it off is a jump in brightness.

This keeps working on my GloHD, when toggling frontlight.
But when Suspend'ing, I get no ramping (full frontlight on a white background - white bg I don't remember I got it previously - and then the cover image and frontlight off).
When Resume'ing, I get the ramping.

I may have some frontlight related bits (although none related to ramping) that may be at play - but before I investigate if it's just me, does anybody else not get the ramping on Suspend?

@poire-z

poire-z commented May 4, 2023

Copy link
Copy Markdown
Contributor

But when Suspend'ing, I get no ramping (full frontlight on a white background - white bg I don't remember I got it previously - and then the cover image and frontlight off).

Checking in a dark room :) and I actually do see the ramping - but it's happening on a quite black cover, so wasn't really noticable.
I think it's that (new?) full white background with full light that is surprising.

@NiLuJe

NiLuJe commented May 4, 2023

Copy link
Copy Markdown
Member

The flash to white before the screensaver has always been there, what's changed is that the frontlight ramp could start earlier than it does now (depending on screen, ambient temperature and wifi shenanigans), so now you actually do see it, always (as well as the actual screensaver), and ramping happens dead last, always.

@poire-z

poire-z commented May 4, 2023

Copy link
Copy Markdown
Contributor

I understand - and I guess I can understand the reason (showing wifi off info before shutting the light).

It also feels a bit inconsistent:

  • suspend: white screen + screensaver - and then only light ramp down
  • resume: light ramp starting but not fully on - screensaver visible, then text visible, then light goes on to full level (it feels things may here be happening all at the same time)

I'm not sure now how it was before, but it felt smoother having it all happening at the same time, giving a view on the screensaver (and white flash) when light was lower.
I tried to move the self.powerd:beforeSuspend() at top where it was before, but it's even uglier.

Anyway, no big deal - but no big smoothness either :)
It's probably just me being allergic to change.

@NiLuJe

NiLuJe commented May 4, 2023

Copy link
Copy Markdown
Member

The main problem is we can't actually do it all together, especially on older, UP devices, as it will either affect the refresh timing, or the wifi teardown timing (which is crash-prone on some of the more broken NTX boards), or the ramp's smoothness ;).

The previous approach was designed to preserve the refresh timing above all (while attempting not to upset wifi too much), at the detriment of the frontlight appearance.

The current one attempts to properly separate each step, so it may appear to take longer. I happen to like being able to actually see the cover for a bit, FWIW ;o).

@NiLuJe

NiLuJe commented May 4, 2023

Copy link
Copy Markdown
Member

As for the resume behavior, there's just basically less stuff happening (no wifi involved, even if restore wifi is enabled), no extra flashes; and the PWM drivers happen to have different timing properties for off -> on than on -> off.

I haven't noticed any stuttering specifically related to how we do it vs. the ramp itself in a vacuum on any of the devices I can test on, but since they all do behave extremely differently, I can't really rule that out either ;). So it's entirely possible the PWM controller found on your device doesn't like it as much as before.

So, yeah, it's faster and a lot more tied together, and I also happen to like that (while I don't care about delays when going to suspend, because you're not using the device; I feel like getting you to a ready state ASAP on resume is rather more critical).

@poire-z

poire-z commented May 4, 2023

Copy link
Copy Markdown
Contributor

and I also happen to like that (while I don't care about delays when going to suspend, because you're not using the device; I feel like getting you to a ready state ASAP on resume is rather more critical).

Well, on suspend, seeing the (white screen! +) cover with full light on is less essential: you know what you've been just reading. (and seeing that white screen full light on feels like illuminating the whole room when I hit the torch button by error on my phone :)

On resume, we see the cover at very low light for 1 second (so, hardly seeing it now when testing in the dark). It's on resume - resuming after a day or a week - that seeing it (even 1s, but with full light) might be more useful: that's what I had been reading, i nearly forgot - ready state here you are (otherwise, I may need to go into Book information) :)

But yes, the ramp is indeed quicker and smoother.

@NiLuJe

NiLuJe commented May 4, 2023

Copy link
Copy Markdown
Member

It feels like most of this might be very subjective then ;o).

What might be more universal is the point about the flash to white; I don't particularly notice it because, while I do read mainly in the dark, my frontlight levels are rather low (... because of the aforementioned "I read in the dark" thing, granted ;p).

On the other hand, a white background is what you were seeing right before, so... eh :/. What's jarring might be the flash more than anything else (unfortunately, it's rather necessary to avoid the cover becoming a ghostfest).

Dunno, I'll see how I feel after a bit more usage ;o).

@poire-z

poire-z commented May 4, 2023

Copy link
Copy Markdown
Contributor

What might be more universal is the point about the white flash;

Oh, so the white is a flash (I'm used to seeing black flashes), and not an explicite white paint from us?
For me, that white flahs stays a lot longer than the regular black flashes.
Could it be that our starting frontlight ramp is delaying the second half of the flash - and a :waitForVSync() after the flash refresh is issued, before the ramp starts, could make it flash quicker?

@NiLuJe

NiLuJe commented May 5, 2023

Copy link
Copy Markdown
Member

Nope, it's a standard flash to a white screen, then a flash to the screensaver. The flash itself is always the same ;o).

(I thought I'd edited it to say "flash to white" instead, but apparently not ;p).

@offset-torque

Copy link
Copy Markdown

On my Libra, Toggle button in the brightness dialog and Toggle frontlight gesture works differently now.

  • Gesture: Immediate switch (as before)
  • Button: Two level switching (Hi-Lo--Off--Lo-Hi)

I guess this two level switching is coming from the smooth ramping code.
But with only one intermediate level, it looks like glitching now.
No big deal for me (I generally use a gesture), just reporting.

@NiLuJe

NiLuJe commented May 31, 2023

Copy link
Copy Markdown
Member

I don't think I can reproduce on any of my devices, but it sorta makes sense, with the button, as it might be racing against at least a couple of refreshes.

EDIT: Hmm, probably specific to the Libra (& its cohort of broken friends) because of the EPDC races workarounds, the refreshes are fenced properly on my devices with non-hobbled display drivers...

@offset-torque

Copy link
Copy Markdown
kobo_backlight_toggle.mp4

Looks like this. Slow motion video to make it more visible to the camera.
Gesture toggle is instant. Also turn on with button is instant.
Only "turning off with button" acts like this it seems.

@NiLuJe

NiLuJe commented May 31, 2023

Copy link
Copy Markdown
Member

EDIT: Hmm, probably specific to the Libra (& its cohort of broken friends) because of the EPDC races workarounds, the refreshes are fenced properly on my devices with non-hobbled display drivers...

You can try to (temporarily) drop the workarounds by removing the hasReliableMxcWaitFor devcap override to test that theory...

NiLuJe added a commit to NiLuJe/koreader that referenced this pull request Jun 19, 2023
NiLuJe added a commit to NiLuJe/koreader that referenced this pull request Jun 23, 2023
NiLuJe added a commit that referenced this pull request Jun 25, 2023
Fix #10588
Regression since #10305

While we're there, rejig the FL toggle callback shenanigans so that implementation details don't leak through to *other* implementations.
(i.e., leave the Kobo mess in Kobo land, with only a minimal impact on the public API and its implementation).
NiLuJe added a commit to NiLuJe/koreader that referenced this pull request Nov 25, 2023
* afterResume had *two* different implementations, so the historical one
  that handled frontlight fixups no longer ran
  (regression since koreader#10426)
* isFrontlightOn was completely broken, for a couple of reasons:
  * There was no is isFrontlightOnHW implementation, so when it ran, it
    mostly always thought the frontlight was on, because
    self.fl_intensity doesn't change on toggle off.
  * _decideFrontlightState was never called on Kindle,
    so isFrontlightOnHW was never really called, making isFrontlightOn
    completely useless. Call it in setIntensityHW's coda, as it ought to
    be. And properly document that.

Generic *was* calling _decideFrontlightState is setIntensity, but
*before* actually setting the frontlight, which makes no goddamn sense,
so get rid of that, too.

* Also fix frontlight toggle notifications (regression since koreader#10305)

TL;DR: The PowerD API being a mess strikes again.
Frenzie pushed a commit that referenced this pull request Nov 25, 2023
* afterResume had *two* different implementations, so the historical one
  that handled frontlight fixups no longer ran
  (regression since #10426)
* isFrontlightOn was completely broken, for a couple of reasons:
  * There was no is isFrontlightOnHW implementation, so when it ran, it
    mostly always thought the frontlight was on, because
    self.fl_intensity doesn't change on toggle off.
  * _decideFrontlightState was never called on Kindle,
    so isFrontlightOnHW was never really called, making isFrontlightOn
    completely useless. Call it in setIntensityHW's coda, as it ought to
    be. And properly document that.

Generic *was* calling _decideFrontlightState is setIntensity, but
*before* actually setting the frontlight, which makes no goddamn sense,
so get rid of that, too.

* Also fix frontlight toggle notifications (regression since #10305)

TL;DR: The PowerD API being a mess strikes again.
0xstillb pushed a commit to 0xstillb/koreader-thai that referenced this pull request May 9, 2026
* Rewrite the loop mechanism to use scheduled tasks instead of a single blocking-ish subprocess.
* Change the actual logic to be more pleasing to the eye, especially on newer devices, as those *may* natively ramp on set; and fix a bad interaction with that behavior that could lead to no ramp at all on ramp down.
* Simplify Generic's Suspend handling to deal with the refresh ordering in a saner manner. The screensaver might be visible a tad longer than before this change before the frontlight actually ramps off.
0xstillb pushed a commit to 0xstillb/koreader-thai that referenced this pull request May 9, 2026
…ader#10597)

Fix koreader#10588
Regression since koreader#10305

While we're there, rejig the FL toggle callback shenanigans so that implementation details don't leak through to *other* implementations.
(i.e., leave the Kobo mess in Kobo land, with only a minimal impact on the public API and its implementation).
0xstillb pushed a commit to 0xstillb/koreader-thai that referenced this pull request May 9, 2026
* afterResume had *two* different implementations, so the historical one
  that handled frontlight fixups no longer ran
  (regression since koreader#10426)
* isFrontlightOn was completely broken, for a couple of reasons:
  * There was no is isFrontlightOnHW implementation, so when it ran, it
    mostly always thought the frontlight was on, because
    self.fl_intensity doesn't change on toggle off.
  * _decideFrontlightState was never called on Kindle,
    so isFrontlightOnHW was never really called, making isFrontlightOn
    completely useless. Call it in setIntensityHW's coda, as it ought to
    be. And properly document that.

Generic *was* calling _decideFrontlightState is setIntensity, but
*before* actually setting the frontlight, which makes no goddamn sense,
so get rid of that, too.

* Also fix frontlight toggle notifications (regression since koreader#10305)

TL;DR: The PowerD API being a mess strikes again.
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.

5 participants