digitaltrails / vdu_controls

VDU controls - a control panel for monitor brightness/contrast/...
GNU General Public License v3.0
103 stars 4 forks source link

Set brightness while dragging the slider #75

Closed nahoj closed 1 month ago

nahoj commented 4 months ago

Thank you for the response-time increase in v2.0.0, it's great!

With this, I think it would practical to set the brigtness (or any setting) in real time while dragging a slider, without waiting for the mouse release.

This would make it possible to release the slider exactly on the right value instead of trying a few to find the right one.

Cheers

digitaltrails commented 4 months ago

Good suggestion.

I'll probably wait to see what the fallout is from the faster response time. It may be that it will cause issues for some combinations of hardware/drivers/VDUs/cables.

Once ddcutil 2.1+ is widely distributed, it should help stability achieve faster response times.

I could add yet another option to enable/disable such a UI feature. The script might yet break the 10000 line barrier :-)

digitaltrails commented 4 months ago

libddcutil 2.1.[45] fixes/changes are still ongoing.

Some notes in the meantime:

The way to go with this is probably to measure the interval between mouse events and only issue setvcp at a sustainable interval.

Because there are a lot of unknowns around how quickly various drivers and monitors can respond, I'd better put in a an option and default it to off (to maximise the chance that new users have an OK experience out of the box). Or maybe an option for a interval with zero meaning no changes while dragging.

digitaltrails commented 3 months ago
digitaltrails commented 3 months ago

I'm not going to add and option. Because the D-Bus service is probably not yet widely used, allowing change while dragging is not likely to affect many users, it will be the set behaviour if the service is in use. I will add an option one if anyone mentions that it causes problems.

digitaltrails commented 3 months ago

The ambient-light level slider handles all N monitors, adjusting+setting more than about one or two monitors while dragging is too slow. Maybe one-monitor could be a special case where dragging+setting is enabled - might be confusing though. Leave as is for now.

Part of the problem is that each drag would start a background thread to do the adjustment work. It's possible a rewrite to handle dragging without threading would speed things up.

digitaltrails commented 2 months ago

Closing this as complete, except for ambient brightness, all sliders now update while dragging. By implementing background thread to do the updates this is now the case across the board, for both ddcutil and ddcutil-service.

digitaltrails commented 2 months ago

Due to concerns raised about VDU lifespan, presumably because of NVRAM lifespan, I've throttled back the UI dragging/spinning updates to one update per second.

This might also affect the UI experience addressed in #81 because the 1 second interval reduces the smoothness (the interval delay is implemented in the queuing code for the non-blocking setvcp).

Even more conservatively, I've added a transitions setting that can enable/disable all updates while dragging or spinning. I've not yet decided if it will default to on or off.

There currently isn't a setting in the GUI that can change the one second interval, but there is a VDU_CONTROLS_UI_INTERVAL_SECS environment variable that can be set to a floating point values such as 0.5 seconds.

I've also updated the README.MD and man pages, both mentioning the possible issue, and outlining mitigations, such as using presets instead or dragging sliders.

These changes may possibly be over the top. However this brings vdu_controls into line with KDE6 PowerDevil (which aims to move to no dragging updates and 0.5 second delay before settings are applied) and ddcutil ddcui (1 second interval on dragging updates).

denilsonsa commented 2 months ago

Hi! I have some feedback that is semi-related to this issue, and semi-off-topic.

I was writing a little tool to map the knobs from a MIDI device to volume controls, and also use them to change the display brightness. Given how slow it was to manually call ddcutil binary each time, I decided to just send a dbus message to ddcutil-service instead. The point is: displays are slow. I had to implement some deboucing/throttling logic.

And here's how it's related to dragging the UI slider: it also generates a lot of events, and we want to throttle it down and limit the amount of VDU/DDC updates sent per unit of time. So, you also need to implement such logic on the vdu_controls side.

My proposal is to implement a debouncing/throttling logic in the ddcutil-service instead. This way, the logic could be written once, well-tested in one place, and shared between any clients.

What do you think?

digitaltrails commented 2 months ago

...

My proposal is to implement a debouncing/throttling logic in the ddcutil-service instead. This way, the logic could be written once, well-tested in one place, and shared between any clients.

What do you think?

The primary reason I would not recommend moving any kind of debouncing/throttling into ddcuti-service is that network bus traffic should be minimised. Even though this is a local bus, various D-Bus tutorials and documents recommend minimizing the traffic.

Looking at gdbus in particular, this is probably good advice. A gdbus service is single threaded and calls are blocking, flooding the service could freeze out other users.

For a design point of view, I think it's cleaner to handle the UI component issues, such as throttling, in the UI. Partly due to consideration of separation of concerns, it seems to make sense to keep UI problems in the UI. Partly because it's only some aspects of the UI that need throttling, things like sliders and spinners, other operations, such as restoring a preset, need not be throttled (as far as I'm aware it's not the speed of writes that's the issue for NVRAM, just the quantity of writes).

In vdu_controls, I do the throttling in the UI. In the VduControlBase base-class I implemented an ui_change_vdu_attribute() which (via the controller) places the request on a python3 queue.Queue. A separate VduControllerAsyncSetter task thread processes the queue.Queue collecting the latest/last request for each VDU+VCP-code into a dictionary. If transitioning is disabled the thread loops waiting for the queue to quiesce before exiting, if transitioning is enabled, the loop exits once a second. On exiting the loop, the collected operations are passed to ddcutil, then the task repeats. If I was sure only one control would ever be active at the same time, then the dictionary would not be needed (I could just always keep the last op in the queue).

It's a lot easier to code queues and dictionaries in a higher level language. That's another reason to avoid moving them into the C code, but it's not the major reason.

When thinking about how a dial might work, if you took the conservative future KDE-6 powerdevil approach, no setvcp should be issued until the dial stops. If you took the ddcutil ddcui approach you'd throttle to one update per second, is that sufficient for a dial, perhaps it's not worth it, but I suppose feedback from small/slow movements to achieve an exact value might be useful.

On the other hand with modern VDUs with HDR, I guess such VDUs might allow for a lot of changes to brightness. I suppose they might not write all changes to NVRAM, for example a VDU with it's own ambient-light sensor would never need to save brightness, it can just calculate it.

Personally, all my LCD VDUs have survived to the point where they are relegated to a storage cupboard. My current right-hand VDU is 15 years old, my left-hand VDU is HDR and about 5 years old. It's only in the last 5 years that HDR super-bright back-lights have prompted me to constantly adjust the brightness. First by on-board controls, later by scripts, and since 2021 by vdu_controls. It will be a couple of more years before I reach a reasonable product life-span under the constant adjustment regime, perhaps I will exhaust NVRAM before then, but I hope not. None of my VDU rise above the mid-price tier, so I'm not particularly fussed at this point.

denilsonsa commented 2 months ago

all my LCD VDUs have survived to the point where they are relegated to a storage cupboard […] It will be a couple of more years before I reach a reasonable product life-span under the constant adjustment regime, perhaps I will exhaust NVRAM before then, but I hope not.

Yeah. The NVRAM is probably some kind of EEPROM or Flash memory. And people from Arduboy are not worried about it, even though Arduboy itself requires re-flashing the entire memory every time the player wants to change the game. Sure, the chip inside the displays is different than inside Arduboy, so the specs are different, but very likely the product will outlast its NVRAM lifespan. (Specially after you implemented some basic throttling.)

In other words, I get your point. My throttling/debouncing implementation was similar to yours. And I didn't know about flooding the D-Bus bus. Thanks!

(And that's enough semi-off-topic-semi-on-topic discussion, I'll shut up now.) 😄

digitaltrails commented 2 months ago

(And that's enough semi-off-topic-semi-on-topic discussion, I'll shut up now.) 😄

I found it a useful exercise in thinking through the issue (only having noticed it late this week when reading about the plans for KDE6 power-devel).

It's also possible modern VDUs and devices such as Arduboy are using a more robust NVRAM, apparently the PS2 uses FRAM which is practically infinitely rewritable (and there's something called MRAM as well).

It would be nice to find someone who actually knows what NVRAM typically goes inside a typical low/mid range VDU. This could be a non-issue that is just forcing me to back off to poorer end-user experience.

denilsonsa commented 2 months ago

It would be nice to find someone who actually knows what NVRAM typically goes inside a typical low/mid range VDU.

I guess we will never know. Engineers who design those displays are very few, and unlikely to find this question. And even if they find, they may not be able to disclose the details due to company secrets. And even if they do, it will only apply to a fraction of the displays.

It's (unfortunately) fair to assume we will never get an answer.

This could be a non-issue that is just forcing me to back off to poorer end-user experience.

Well, kind of. As you said, the UI has to throttle down the updates anyway to avoid congesting dbus.

digitaltrails commented 2 months ago

Well, kind of. As you said, the UI has to throttle down the updates anyway to avoid congesting dbus.

If I could use 0.5 seconds, it looks pretty good. Ideally more toward 0.25, which is just above the time taken to do a setvcp which is 0.18, but I suppose that might block others out. I'm not too happy with 1.0. Maybe I will add a transition parameter with a default of 1.0 and a big warning popup about buyer beware, but there are already too many options.

digitaltrails commented 2 months ago

I've tweaked sliders and spinners so that they no longer update the VDU while being continuously dragged or spun at high rates of change. They now only update the VDU when the dragging/spinning slows to the kind of change needed for fine adjustment or stepping. This is fully automatic, no settings are required.

The heuristic is to wait for the input events queue to quiesce for 0.25 seconds. This effectively means the user has stopped dragging/spinning, or is dragging/spinning at around 1 unit change per 0.25 seconds. This also corresponds to slightly over the maximum rate that ddcutil-service can apply changes to a VDU. This also works for the arrow keys when applied to the same controls.

digitaltrails commented 1 month ago

Released the changes in 2.0.3