drm-hwcomposer issues
https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues
2022-01-13T13:03:51Z
https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/22
DRM Interlaced and "similar" modes are merged into single modes, leading to s...
2022-01-13T13:03:51Z
Neil Armstrong
DRM Interlaced and "similar" modes are merged into single modes, leading to selecting the wrong mode
In the process of bringing up the Amlogic Meson G12A for AOSP and drm-hwcomposer,
I'm having a very suspicious behavior from the Android Graphics stack and the DRM
modes handling.
The initial behavior was:
My 1080p Samsung TV reports t...
In the process of bringing up the Amlogic Meson G12A for AOSP and drm-hwcomposer,
I'm having a very suspicious behavior from the Android Graphics stack and the DRM
modes handling.
The initial behavior was:
My 1080p Samsung TV reports the following modes: (using modetest)
```
1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 148352 flags: phsync, pvsync; type: driver
1920x1080i 60 1920 2008 2052 2200 1080 1084 1094 1125 74250 flags: phsync, pvsync, interlace; type: driver
1920x1080i 60 1920 2008 2052 2200 1080 1084 1094 1125 74176 flags: phsync, pvsync, interlace; type: driver
1920x1080 50 1920 2448 2492 2640 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: driver
1920x1080i 50 1920 2448 2492 2640 1080 1084 1094 1125 74250 flags: phsync, pvsync, interlace; type: driver
1920x1080 30 1920 2008 2052 2200 1080 1084 1089 1125 74250 flags: phsync, pvsync; type: driver
1920x1080 30 1920 2008 2052 2200 1080 1084 1089 1125 74176 flags: phsync, pvsync; type: driver
1920x1080 25 1920 2448 2492 2640 1080 1084 1089 1125 74250 flags: phsync, pvsync; type: driver
1920x1080 24 1920 2558 2602 2750 1080 1084 1089 1125 74250 flags: phsync, pvsync; type: driver
1920x1080 24 1920 2558 2602 2750 1080 1084 1089 1125 74176 flags: phsync, pvsync; type: driver
1600x900 60 1600 1624 1704 1800 900 901 904 1000 108000 flags: phsync, pvsync; type: driver
1280x1024 75 1280 1296 1440 1688 1024 1025 1028 1066 135000 flags: phsync, pvsync; type: driver
1280x1024 60 1280 1328 1440 1688 1024 1025 1028 1066 108000 flags: phsync, pvsync; type: driver
1366x768 60 1366 1436 1579 1792 768 771 774 798 85500 flags: phsync, pvsync; type: driver
1152x864 75 1152 1216 1344 1600 864 865 868 900 108000 flags: phsync, pvsync; type: driver
1280x720 60 1280 1390 1430 1650 720 725 730 750 74250 flags: phsync, pvsync; type: driver
1280x720 60 1280 1390 1430 1650 720 725 730 750 74176 flags: phsync, pvsync; type: driver
1280x720 50 1280 1720 1760 1980 720 725 730 750 74250 flags: phsync, pvsync; type: driver
1024x768 70 1024 1048 1184 1328 768 771 777 806 75000 flags: nhsync, nvsync; type: driver
800x600 75 800 816 896 1056 600 601 604 625 49500 flags: phsync, pvsync; type: driver
720x576 50 720 732 796 864 576 581 586 625 27000 flags: nhsync, nvsync; type: driver
720x480 60 720 736 798 858 480 489 495 525 27000 flags: nhsync, nvsync; type: driver
640x480 75 640 656 720 840 480 481 484 500 31500 flags: nhsync, nvsync; type: driver
640x480 73 640 664 704 832 480 489 492 520 31500 flags: nhsync, nvsync; type: driver
```
Using AOSP master, drm-hwc-two initializes and reports the following modes:
```
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 0 mode.id=1 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 1 mode.id=2 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 2 mode.id=3 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 3 mode.id=7 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 4 mode.id=10 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 5 mode.id=11 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 6 mode.id=12 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 7 mode.id=13 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 8 mode.id=14 => 1920x1080
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 9 mode.id=15 => 1600x900
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 10 mode.id=16 => 1280x1024
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 11 mode.id=17 => 1280x1024
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 12 mode.id=18 => 1366x768
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 13 mode.id=19 => 1152x864
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 14 mode.id=20 => 1280x720
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 15 mode.id=21 => 1280x720
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 16 mode.id=22 => 1280x720
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 17 mode.id=23 => 1280x720
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 18 mode.id=24 => 1280x720
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 19 mode.id=25 => 1024x768
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 20 mode.id=26 => 800x600
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 21 mode.id=27 => 720x576
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 22 mode.id=28 => 720x480
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 23 mode.id=29 => 640x480
01-01 00:00:10.469 2364 2364 E hwc-drm-two: GetDisplayConfigs() 24 mode.id=30 => 640x480
```
The reported configs are:
```
DisplayManagerService: Display device added: DisplayDeviceInfo{"Built-in Screen": uniqueId="local:0", 1920 x 1080, modeId 18, defaultModeId 18, supportedModes [{id=1, width=640, height=480, fps=73.0}, {id=2, width=640, height=480, fps=75.0}, {id=3, width=720, height=480, fps=60.0}, {id=4, width=720, height=576, fps=50.0}, {id=5, width=800, height=600, fps=75.0}, {id=6, width=1024, height=768, fps=70.0}, {id=7, width=1280, height=720, fps=50.0}, {id=8, width=1280, height=720, fps=60.0}, {id=9, width=1152, height=864, fps=75.0}, {id=10, width=1366, height=768, fps=60.0}, {id=11, width=1280, height=1024, fps=60.0}, {id=12, width=1280, height=1024, fps=75.0}, {id=13, width=1600, height=900, fps=60.0}, {id=14, width=1920, height=1080, fps=24.0}, {id=15, width=1920, height=1080, fps=25.0}, {id=16, width=1920, height=1080, fps=30.0}, {id=17, width=1920, height=1080, fps=50.0}, {id=18, width=1920, height=1080, fps=60.0}], colorMode 0, supportedColorModes [0], HdrCapabilities android.view.Display$HdrCapabilities@40f16308, density 102, 101.6 x 101.6 dpi, appVsyncOff 1000000, presDeadline 16666667, touch INTERNAL, rotation 0, type BUILT_IN, state UNKNOWN, FLAG_DEFAULT_DISPLAY, FLAG_ROTATES_WITH_CONTENT, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}
```
We can see most of the mode have been "merged", and looking at the following behavior, only the "higher" drm-hwc-two internal ID has been kept.
Then `bootanim` starts and drm-hwcomposer selects the correct EDID preferred mode (1):
```
01-01 00:00:11.787 2378 2378 I SurfaceFlinger: Enter boot animation
01-01 00:00:12.037 2365 2365 E hwc-drm-two: GetActiveConfig() mode.id=1
```
Then `bootanim` stops, and the UI takes over, but strangely, the mode `6` (1920x1080i) is selected:
```
06-04 12:16:02.568 2364 2364 E hwc-drm-two: SetActiveConfig(6)
06-04 12:36:32.450 2377 2377 D SurfaceFlinger: Set active config mode=24, type=0 flinger=0xfc1d07049000
06-04 12:16:02.568 2364 2364 E hwc-drm-display-compositor: Create blob_id 45
06-04 12:16:02.782 2364 2364 E hwc-drm-two: GetActiveConfig() mode.id=6
```
Here 6 is mode.id=12 => 1920x1080, it can be explained because the 6 first modes were "merged" in a single 1920x1080 mode, keeping only the last mode id (6).
My findings are:
* Interlaced modes are not handled *at all*, so dropping them should be the ultimate solution until handled in the uppper layers
* `vrefresh` is used from the integer format reported by the kernel, but in our case, the TV reports some 1000/1001 US modes, and HWC2 and upper does some mode merging and these modes are mixed with the standard modes, but keeping the worst/wrong DRM-HWC mode id
With the following changes, things are better:
```
--- a/drmhwctwo.cpp
+++ b/drmhwctwo.cpp
@@ -399,17 +399,18 @@ HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
}
}
- auto num_modes = static_cast<uint32_t>(connector_->modes().size());
- if (!configs) {
- *num_configs = num_modes;
- return HWC2::Error::None;
- }
-
uint32_t idx = 0;
for (const DrmMode &mode : connector_->modes()) {
- if (idx >= *num_configs)
+ if (configs && idx >= *num_configs)
break;
- configs[idx++] = mode.id();
+ /* Drop interlaced modes */
+ if (mode.flags() & DRM_MODE_FLAG_INTERLACE)
+ continue;
+ if (configs) {
+ configs[idx++] = mode.id();
+ } else {
+ idx++;
+ }
}
*num_configs = idx;
return HWC2::Error::None;
```
and
```
--- a/drmmode.cpp
+++ b/drmmode.cpp
@@ -122,8 +122,8 @@ uint32_t DrmMode::v_scan() const {
}
float DrmMode::v_refresh() const {
- return v_refresh_ ? v_refresh_ * 1.0f
- : clock_ / (float)(v_total_ * h_total_) * 1000.0f;
+ // Always recalculate refresh to report correct float rate
+ return clock_ / (float)(v_total_ * h_total_) * 1000.0f;
}
uint32_t DrmMode::flags() const {
```
Then we get:
```
DisplayManagerService: Display device added: DisplayDeviceInfo{"Built-in Screen": uniqueId="local:0", 1920 x 1080, modeId 21, defaultModeId 21, supportedModes [{id=1, width=640, height=480, fps=72.8088}, {id=2, width=640, height=480, fps=75.0}, {id=3, width=720, height=480, fps=59.94006}, {id=4, width=720, height=576, fps=50.0}, {id=5, width=1280, height=720, fps=50.0}, {id=6, width=1280, height=720, fps=59.9402}, {id=7, width=1280, height=720, fps=60.0}, {id=8, width=1152, height=864, fps=75.0}, {id=9, width=1366, height=768, fps=59.789543}, {id=10, width=1280, height=1024, fps=60.019737}, {id=11, width=1280, height=1024, fps=75.02467}, {id=12, width=1600, height=900, fps=60.0}, {id=13, width=1920, height=1080, fps=29.9701}, {id=14, width=1920, height=1080, fps=30.0}, {id=15, width=1920, height=1080, fps=23.97608}, {id=16, width=800, height=600, fps=75.0}, {id=17, width=1920, height=1080, fps=59.9402}, {id=18, width=1920, height=1080, fps=50.0}, {id=19, width=1920, height=1080, fps=24.0}, {id=20, width=1024, height=768, fps=70.06936}, {id=21, width=1920, height=1080, fps=60.0}, {id=22, width=1920, height=1080, fps=25.0}], colorMode 0, supportedColorModes [0], HdrCapabilities android.view.Display$HdrCapabilities@40f16308, density 102, 101.6 x 101.6 dpi, appVsyncOff 1000000, presDeadline 16666667, touch INTERNAL, rotation 0, type BUILT_IN, state UNKNOWN, FLAG_DEFAULT_DISPLAY, FLAG_ROTATES_WITH_CONTENT, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}
```
Now refresh rates are correctly reported, and modes are less "merged", interlaced modes are no more present.
But still, the preferred mode is still not selected:
```
06-04 12:50:51.551 2373 2373 D SurfaceFlinger: Set active config mode=23, type=0 flinger=0xfb5400e49000
06-04 12:50:51.551 2364 2395 E hwc-drm-two: SetActiveConfig(2)
06-04 12:50:51.551 2364 2395 E hwc-drm-display-compositor: Create blob_id 45
```
since the mode "1" is the HDMI preferred mode, and the mode "2" is the legacy EDID timings, but "1" should be selected.
Using a 4k UHD TV with 4:4:4 modes, these modes are merged with the 4:2:0 modes and the 4:4:4 preferred mode is never used after the bootanim.
Maybe at some point, the uppers layers should keep all the different modes ?