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 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 ?