kfix / ddcctl

DDC monitor controls (brightness) for Mac OSX command line
GNU General Public License v3.0
1.86k stars 150 forks source link

Wanted: access DDC on M1 (ARM) platform Macs #86

Open thekeith opened 3 years ago

thekeith commented 3 years ago

Please update to allow an ARM64 target compatible with Apple Silicon Macs. Current implementation fails to compile, even when running terminal in Rosetta 2 mode.

Steps to reproduce:

  1. Clone repo onto M1 Mac
  2. Open terminal in Rosetta 2 mode
  3. Attempt to compile with "make intel"
  4. Fails silently

Output:

ddcctl % make intel
rm -f *.o ddcctl
cc -Wall -Wno-unused-variable -DkDDCMinReplyDelay=1 -c -o DDC.o DDC.c
cc -Wall -Wno-unused-variable -DkDDCMinReplyDelay=1 -o ddcctl -lobjc -framework IOKit -framework AppKit -framework Foundation DDC.o ddcctl.m

Notes: I do understand that this is likely just due to the Apple GPU simply not being a valid target here, and get it if this ticket isn't super high priority.

kieselit commented 3 years ago

Interesting, I don't have issues compiling ddcctl with "make intel" even on my M1 Mac, but the resulting binary does not work like expected (which I in turn expected, because I compiled with "make intel" even though it's an Apple Silicon Mac, because there currently is no Apple Silicon implementation). The program starts, shows the help, for example, and it even recognizes my external display, but it can't change the display's brightness or contrast. It can't poll the display's EDID apparently.

I would love to get Apple Silicon support in the future! :)

jclusso commented 3 years ago

I wish I understood more about how this works. FWIW I was able to build this without Rosetta for all variants. Just can't figure out how to resolve the EDID error.

kfix commented 3 years ago

what does make framebuffers displaylist say on your M1 machines?

kfix commented 3 years ago

rosetta emulation isn't helping here, make intel refers to tuning a constant for Intel GPUs, not the runtime arch.

we could do something like this so we don't have to build to a specific vendor anymore, but that's a side issue.

the bigger deal is that IOFramebuffer and I2C userspace support is (guessing) a stub on ARM

emanueldima commented 3 years ago

My test with MacBook Air M1 connected to an external Dell monitor:

➜  make intel
rm -f *.o ddcctl
cc -Wall -Wno-unused-variable -DkDDCMinReplyDelay=1 -c -o DDC.o DDC.c
cc -Wall -Wno-unused-variable -DkDDCMinReplyDelay=1 -o ddcctl -lobjc -framework IOKit -framework AppKit -framework Foundation DDC.o ddcctl.m

➜  ./ddcctl
D: NSScreen #2 (1200x1600 90°) 95.00 DPI
I: found 1 external display
2020-11-26 15:26:35.810 ddcctl[32667:680154] Usage:
ddcctl  -d <1-..>  [display#]
    -w 100000  [delay usecs between settings]

----- Basic settings -----
    -b <1-..>  [brightness]
    -c <1-..>  [contrast]
    -rbc       [reset brightness and contrast]

----- Settings that don't always work -----
    -m <1|2>   [mute speaker OFF/ON]
    -v <1-254> [speaker volume]
    -i <1-18>  [select input source]
    -p <1|2-5> [power on | standby/off]
    -o         [read-only orientation]

----- Settings (testing) -----
    -rg <1-..>  [red gain]
    -gg <1-..>  [green gain]
    -bg <1-..>  [blue gain]
    -rrgb       [reset color]

----- Setting grammar -----
    -X ?       (query value of setting X)
    -X NN      (put setting X to NN)
    -X <NN>-   (decrease setting X by NN)
    -X <NN>+   (increase setting X by NN)

➜  make framebuffers displaylist
ioreg -c IOFramebuffer -k IOFBI2CInterfaceIDs -b -f -l -r -d 1
ioreg -c IODisplayConnect -b -f -r -l -i -d 2
jclusso commented 3 years ago

@kfix here you go. This is to a Dell 2718Q.


$ ./ddcctl
D: NSScreen #1 (2560x1440 0°) HiDPI
D: NSScreen #2 (2560x1440 0°) HiDPI
I: found 2 external displays
2020-11-26 09:34:03.394 ddcctl[31747:5363539] Usage:
ddcctl  -d <1-..>  [display#]
        -w 100000  [delay usecs between settings]

----- Basic settings -----
        -b <1-..>  [brightness]
        -c <1-..>  [contrast]
        -rbc       [reset brightness and contrast]

----- Settings that don't always work -----
        -m <1|2>   [mute speaker OFF/ON]
        -v <1-254> [speaker volume]
        -i <1-18>  [select input source]
        -p <1|2-5> [power on | standby/off]
        -o         [read-only orientation]

----- Settings (testing) -----
        -rg <1-..>  [red gain]
        -gg <1-..>  [green gain]
        -bg <1-..>  [blue gain]
        -rrgb       [reset color]

----- Setting grammar -----
        -X ?       (query value of setting X)
        -X NN      (put setting X to NN)
        -X <NN>-   (decrease setting X by NN)
        -X <NN>+   (increase setting X by NN)

$ make framebuffers displaylist
ioreg -c IOFramebuffer -k IOFBI2CInterfaceIDs -b -f -l -r -d 1
ioreg -c IODisplayConnect -b -f -r -l -i -d 2```
kfix commented 3 years ago

I should update the "found external display" message because its only a count of high-level NSScreen objects, not the lower-level IOFramebuffers to send DDC (I2C) to.

Based on that empty ioreg output, it doesn't look like they (IOFramebuffer) are being exposed - at least not in the same way as we expect on X86.

can an M1-owner run system_profiler SPDisplaysDataType?

jclusso commented 3 years ago

@kfix here you go.


$ system_profiler SPDisplaysDataType
Graphics/Displays:

    Apple M1:

      Chipset Model: Apple M1
      Type: GPU
      Bus: Built-In
      Total Number of Cores: 8
      Vendor: Apple (0x106b)
      Metal Family: Supported, Metal GPUFamily Apple 7
      Displays:
        DELL U2718Q:
          Resolution: 5120 x 2880 (5K/UHD+ - Ultra High Definition Plus)
          UI Looks like: 2560 x 1440 @ 60Hz
          Main Display: Yes
          Mirror: Off
          Online: Yes
          Automatically Adjust Brightness: Yes
        DELL U2718Q:
          Resolution: 5120 x 2880 (5K/UHD+ - Ultra High Definition Plus)
          UI Looks like: 2560 x 1440 @ 60Hz
          Mirror: Off
          Online: Yes
          Automatically Adjust Brightness: Yes```
kfix commented 3 years ago

ooh, I just found that system_profiler SPDisplaysDataType -xml displays WAY more info, including displayID and IOFramebuffer paths on x86.

please attach that as a text file!

jclusso commented 3 years ago

@kfix here you go. display_data.txt

Mention me and I'll respond as fast as I can. Just turned notifications on for my phone. Will be around for a bit today.

kfix commented 3 years ago

Thanks, I'm down for the holidays as well. Its why I had some time to work on this..

It looks like there isn't any info in the M1 dump about IORegistryEntry paths,EDID, etc etc.

For comparison, here's the dump on my MBP 15" 2018: MBP_15_2018_SPDisplays.txt

Hopefully Apple gives us something to work with in a future MacOS-on-ARM version?

jclusso commented 3 years ago

@kfix so we're SOL right now I guess? Any thoughts about some sort of config for the EDID and obtaining it manually some how?

kfix commented 3 years ago

@jclusso It might stash the blob somewhere so we could parse it and display some info, but we still don't have a path to the I2C device to send control & query commands.

I'm not surprised things are a bit more obscured & abstracted on the M1. Various forums relay similar problems with other apps that do the same kind of things (SwitchResX)

jclusso commented 3 years ago

@kfix what does that other information look like. I can obtain the EDIDs by doing this ioreg -lw0 | grep "EDID UUID" -B 20

I'm not 100% familiar with what information we need, but here is the output of this. I'd give the whole ioreg -lw0 but it's huge and I don't know if any information I shouldn't share is in that.

$ ioreg -lw0 | grep "EDID UUID" -B 20
    | |   |   |   "BlendOutputCSCMethod" = 0
    | |   |   |   "IOMFBBrightnessCompensationEnable" = No
    | |   |   |   "ChargeValuesReset" = No
    | |   |   |   "VideoClock" = 297000000
    | |   |   |   "IdleCachingMethod" = 2
    | |   |   |   "DisplayPipePlaneBaseAlignment" = {"DefaultStride"=0,"LinearX_Alignment"=64,"LinearY_Alignment"=1,"PlaneBaseAlignmentLinear"=64}
    | |   |   |   "RuntimeProperty::registerTraceEnable" = No
    | |   |   |   "DisplayHeight" = 2160
    | |   |   |   "color-accuracy-index" = 0
    | |   |   |   "PDCGlobalTemp" = 0
    | |   |   |   "APTEnableEvents" = No
    | |   |   |   "ALSSSupported" = No
    | |   |   |   "IdleState" = 5
    | |   |   |   "APTLimitRefreshRate" = No
    | |   |   |   "IOMFBSupportsYFlip" = Yes
    | |   |   |   "IOMFBMaxSrcPixels" = {"PixelClock"=533333328,"MaxSrcRectTotal"=20971520,"MaxSrcBufferHeight"=16384,"IOMFBMaxCompressedSizeInBytes"=0,"VideoClock"=74250000,"MaxSrcRectWidth"=5120,"MaxSrcBufferWidth"=16384,"MaxVideoSrcDownscalingWidth"=27582}
    | |   |   |   "DisplayAttributes" = {"ProductAttributes"={"ManufacturerID"="DEL","YearOfManufacture"=2017,"SerialNumber"=811151436,"ProductName"="DELL U2718Q","AlphanumericSerialNumber"="4K8X77720Y0L","LegacyManufacturerID"=4268,"ProductID"=41193,"WeekOfManufacture"=27},"Chromaticity"={"Red"={"X"=41920,"Y"=21632},"Green"={"X"=19648,"Y"=39296},"Blue"={"X"=9856,"Y"=3904}},"DefaultWhitePoint"={"X"=20544,"Y"=21568,"Gamma"=144179},"SupportsStandby"=Yes,"PreciseAspectRatio"=114220,"MaxHorizontalImageSize"=61,"DefaultColorSpaceIsSRGB"=Yes,"SupportsSuspend"=Yes,"SupportsActiveOff"=Yes,"MaxVerticalImageSize"=35,"WhitePoints"=({"X"=20544,"Y"=21568,"Gamma"=144179}),"HasHDMILegacyEDID"=No,"NativeFormatVerticalPixels"=2160,"ContinuousFrequencySupport"="None","AspectRatio"=15,"NativeFormatHorizontalPixels"=3840}
    | |   |   |   "APTPDCEnablePM" = Yes
    | |   |   |   "SPLCSupported" = No
    | |   |   |   "APTPanicOnStuckPolarity" = No
    | |   |   |   "EDID UUID" = "10ACE9A0-0000-0000-1B1B-0103803D2378"
--
    | |   |   |   "BlendOutputCSCMethod" = 0
    | |   |   |   "IOMFBBrightnessCompensationEnable" = No
    | |   |   |   "ChargeValuesReset" = No
    | |   |   |   "VideoClock" = 0
    | |   |   |   "IdleCachingMethod" = 2
    | |   |   |   "DisplayPipePlaneBaseAlignment" = {"DefaultStride"=0,"LinearX_Alignment"=64,"LinearY_Alignment"=1,"PlaneBaseAlignmentLinear"=64}
    | |   |   |   "RuntimeProperty::registerTraceEnable" = No
    | |   |   |   "DisplayHeight" = 2160
    | |   |   |   "color-accuracy-index" = 0
    | |   |   |   "PDCGlobalTemp" = 0
    | |   |   |   "APTEnableEvents" = No
    | |   |   |   "ALSSSupported" = No
    | |   |   |   "IdleState" = 5
    | |   |   |   "APTLimitRefreshRate" = No
    | |   |   |   "IOMFBSupportsYFlip" = Yes
    | |   |   |   "IOMFBMaxSrcPixels" = {"PixelClock"=0,"MaxSrcRectTotal"=25165824,"MaxSrcBufferHeight"=16384,"IOMFBMaxCompressedSizeInBytes"=0,"VideoClock"=0,"MaxSrcRectWidth"=6144,"MaxSrcBufferWidth"=16384,"MaxVideoSrcDownscalingWidth"=0}
    | |   |   |   "DisplayAttributes" = {"ProductAttributes"={"ManufacturerID"="DEL","YearOfManufacture"=2017,"SerialNumber"=809055564,"ProductName"="DELL U2718Q","AlphanumericSerialNumber"="4K8X776T095L","LegacyManufacturerID"=4268,"ProductID"=41196,"WeekOfManufacture"=26},"Chromaticity"={"Red"={"X"=41920,"Y"=21632},"Green"={"X"=19648,"Y"=39296},"Blue"={"X"=9856,"Y"=3904}},"DefaultWhitePoint"={"X"=20544,"Y"=21568,"Gamma"=144179},"SupportsStandby"=Yes,"PreciseAspectRatio"=114220,"MaxHorizontalImageSize"=61,"DefaultColorSpaceIsSRGB"=Yes,"SupportsSuspend"=No,"SupportsActiveOff"=No,"MaxVerticalImageSize"=35,"WhitePoints"=({"X"=20544,"Y"=21568,"Gamma"=144179}),"HasHDMILegacyEDID"=No,"NativeFormatVerticalPixels"=2160,"ContinuousFrequencySupport"="None","AspectRatio"=15,"NativeFormatHorizontalPixels"=3840}
    | |   |   |   "APTPDCEnablePM" = Yes
    | |   |   |   "SPLCSupported" = No
    | |   |   |   "APTPanicOnStuckPolarity" = No
    | |   |   |   "EDID UUID" = "10ACECA0-0000-0000-1A1B-0104B53D2378"
jclusso commented 3 years ago

@kfix also not sure if what's going on over here would be of any interest. Seems they are talking about some sort of Apple bug that needs to be fixed. I don't know how they're doing stuff in comparison.

kfix commented 3 years ago

Gonna keep guessing that "IOMFB" is short for IOMobileFramebuffer.

"IOMFB" also Seems to show up in iOS logdumps.

The GPU code that Apple might have ported from iThingsOS -> macOS probably didn't expose I2C apis to pesky app developers 😜

jclusso commented 3 years ago

Wouldn't they have to expose it somehow on the MacBook Pro. Somehow the OS has to be able to control the screen brightness... right?

ATG1209 commented 3 years ago

Is there an update of the possibility to bring this to M1 architecture?

kfix commented 3 years ago

I'll lock the thread if people want to keep asking when there's obviously no update...

gwww commented 3 years ago

I just read a comment on the app QuickShade (on app store) where controls worked on a M1. I have not found anything as to how it was accomplished.

carbncl commented 3 years ago

Quoting from Lunar issue:

QuickShade adds a software black overlay over the whole screen which renders colors incorrectly, decreases contrast linearly instead of exponentially, and keeps the monitor LED backlight at the same strength which consumes more power and can heat up the monitor panel depending on how much time the monitor is kept on.

jkpe commented 3 years ago

QuickShade adds a software black overlay over the whole screen which renders colors incorrectly, decreases contrast linearly instead of exponentially, and keeps the monitor LED backlight at the same strength which consumes more power and can heat up the monitor panel depending on how much time the monitor is kept on.

Beats going into my monitor’s menu and adjusting the brightness

carbncl commented 3 years ago

Beats going into my monitor’s menu and adjusting the brightness

Indeed, It's incredible how they can make these menus so unusable, so I'm using QuickShade as well, but missing Lunar/ddcctl ¯\_(ツ)_/¯

imajes commented 3 years ago

hey, adding a comment to watch but also i'm more than happy to run commands on a m1 and to help debug/test.

adams-family commented 3 years ago

+1

My life depends on ddcctl multiple times a day :)

HyperCed commented 3 years ago

Any news with I2C interface on IOMobileFramebuffer with MacOS 11.3 ?

sfdye commented 3 years ago

Same here, just got a m1 mac mini yesterday, now I can jump from my intel 16 inch macbook pro to the m1 mac mini using ddcctl but not the other way around.

Let me know you need more info/test on the m1

photovirus commented 3 years ago

Quoting my comment from Lunar issue, as we're all in this together:

Please do note that Apple has sent a survey for M1 Mac users on May 5 via Feedback Assistant (it's preinstalled in macOS betas). I have mentioned inaccessible DDC there.

I think we can make the difference, should enough people chime in with the problem.

joshvasquez commented 3 years ago

Might worth relooking into the issue now with beta 2 MacOS Monterey. Per the issue from lunar, it's at least partially functional with DDC.

tao-j commented 3 years ago

A working solution of DDC on M1

https://gist.github.com/tao-j/c7a3c1ec7c2f59ebe45d161d620d9169

HyperCed commented 3 years ago

Is that working on Big Sur or only on Monterey ? I tried the code on the link on my Mac Mini M1 with 11.4 and it did not seem to work.

dguerri commented 3 years ago

Is that working on Big Sur or only on Monterey ?

The API works on Big Sur too, but on Mac Mini M1 you need additional logic to select an external display (or the external display).

See the thread on Lunar for more info.

waydabber commented 3 years ago

Hey, just to let you know,

here is a small console tool for basic command line DDC control on the M1 Mini:

https://github.com/waydabber/m1ddc

here is a complete implementation of the matching logic and all the required basics in Swift (made it for MonitorControl but as it is self contained it can be used in a generic fashion):

https://github.com/MonitorControl/MonitorControl/blob/master/MonitorControl/Support/Arm64DDC.swift

These might be helpful for the ddcctl implementation as well. :)

kfix commented 3 years ago

@waydabber if you could add a LICENCE file, that'd be helpful when it comes time for me to ~copypaste~ use that.

I don't have an M1 yet - holding out for the next M1Air - so no timetable on that.

waydabber commented 3 years ago

Hi @kfix - MonitorControl uses MIT license. Added it to m1ddc as well. :)

kfix commented 2 years ago

just got an M2Air, so maybe i'll get to this soon!

brunbjoern commented 1 year ago

Any progress on supporting Apple silicon? (asking humbly)

owens-ben commented 1 year ago

i humbly request this feature! it actually works on one of my LG 4k displays but not the other

HyperCed commented 1 year ago

You can use this tool which works great ! It requires to connect the screen with DisplayPort. https://github.com/MonitorControl/MonitorControl#readme

I also make a version of NativeDisplayBrightness which works with Mac M1: https://superced.rb38.eu/files/NativeDisplayBrightnessWithM1Support.zip

I think it's possible to use the same tips for this project.

owens-ben commented 1 year ago

Im actually able to accomplish everything but changing the inputs on one of my displays. At this point I'm invested in HDMI (have an expensive dock and stuff) so I can't switch the DP. HDMI doesn't seem to be the problem though as it works fine on one of the LG 4k monitors.

tigattack commented 1 year ago

I've been using this, @owens-ben: https://github.com/waydabber/m1ddc

Works great for switching inputs, setting brightness/contrast, etc. on my LG displays connected with DP over Type-C.

waydabber commented 9 months ago

Just a note until Apple Silcion support is added: you can use BetterDisplay's CLI as well to send arbitrary DDC commands:

https://github.com/waydabber/BetterDisplay/wiki/Integration-features,-CLI

Key differences:

Hardware support:

Some additional stuff: