Dedupe near-identical EDID modes by resolution and refresh rate
This commit is contained in:
parent
22ba81cf61
commit
fbaba3b2b4
1 changed files with 54 additions and 24 deletions
|
|
@ -21,9 +21,11 @@
|
||||||
#include <drm/drm_mode.h>
|
#include <drm/drm_mode.h>
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
@ -265,6 +267,26 @@ std::string DrmConnector::GetName() const {
|
||||||
return "None";
|
return "None";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Some EDIDs describe the same effective resolution/refresh-rate as two
|
||||||
|
// distinct raw mode entries -- e.g. a detailed-timing "preferred" mode plus a
|
||||||
|
// CEA-861 mode for the same nominal timing, differing only in blanking or in
|
||||||
|
// the DRM_MODE_TYPE_PREFERRED bit. A byte-for-byte comparison (DrmMode::
|
||||||
|
// operator==) treats these as separate modes, so both survive into the mode
|
||||||
|
// list. That leaves which mode is "preferred" ambiguous between the kernel's
|
||||||
|
// initial modeset and drm_hwcomposer's own selection, which is the suspected
|
||||||
|
// cause of a mid-boot mode switch (visible as overscan until HDMI is
|
||||||
|
// replugged) and of framework APIs like Display.getSystemPreferredDisplayMode()
|
||||||
|
// intermittently returning null (TvSettings NPE on the Resolution screen).
|
||||||
|
constexpr float kDuplicateModeRateEpsilonHz = 0.05F;
|
||||||
|
|
||||||
|
bool IsSameEffectiveMode(const DrmMode &existing, const DrmMode &candidate) {
|
||||||
|
return existing.SameSize(candidate) &&
|
||||||
|
std::abs(existing.GetVRefresh() - candidate.GetVRefresh()) <
|
||||||
|
kDuplicateModeRateEpsilonHz;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int DrmConnector::UpdateModes() {
|
int DrmConnector::UpdateModes() {
|
||||||
std::string force_mode = Properties::GetForceMode();
|
std::string force_mode = Properties::GetForceMode();
|
||||||
uint32_t xres = 0, yres = 0, rate = 0;
|
uint32_t xres = 0, yres = 0, rate = 0;
|
||||||
|
|
@ -287,35 +309,43 @@ int DrmConnector::UpdateModes() {
|
||||||
|
|
||||||
modes_.clear();
|
modes_.clear();
|
||||||
for (int i = 0; i < connector_->count_modes; ++i) {
|
for (int i = 0; i < connector_->count_modes; ++i) {
|
||||||
bool exists = false;
|
DrmMode m(&connector_->modes[i]);
|
||||||
for (const DrmMode &mode : modes_) {
|
ALOGV("Supported mode %dx%d@%fHz for display in connector %s",
|
||||||
if (mode == connector_->modes[i]) {
|
m.GetRawMode().hdisplay, m.GetRawMode().vdisplay,
|
||||||
exists = true;
|
m.GetVRefresh(), GetName().c_str());
|
||||||
break;
|
|
||||||
|
auto existing = std::find_if(modes_.begin(), modes_.end(),
|
||||||
|
[&m](const DrmMode &other) {
|
||||||
|
return IsSameEffectiveMode(other, m);
|
||||||
|
});
|
||||||
|
if (existing != modes_.end()) {
|
||||||
|
// Keep whichever duplicate carries the EDID's PREFERRED flag.
|
||||||
|
if ((m.GetRawMode().type & DRM_MODE_TYPE_PREFERRED) != 0 &&
|
||||||
|
(existing->GetRawMode().type & DRM_MODE_TYPE_PREFERRED) == 0) {
|
||||||
|
ALOGD("Mode %dx%d@%fHz for display in connector %s duplicated; "
|
||||||
|
"keeping the PREFERRED entry",
|
||||||
|
m.GetRawMode().hdisplay, m.GetRawMode().vdisplay,
|
||||||
|
m.GetVRefresh(), GetName().c_str());
|
||||||
|
*existing = m;
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exists) {
|
if (xres && yres) {
|
||||||
DrmMode m(&connector_->modes[i]);
|
if (!rate && m.GetRawMode().hdisplay == xres
|
||||||
ALOGV("Supported mode %dx%d@%fHz for display in connector %s",
|
&& m.GetRawMode().vdisplay == yres) {
|
||||||
m.GetRawMode().hdisplay, m.GetRawMode().vdisplay,
|
rate = m.GetVRefresh();
|
||||||
m.GetVRefresh(), GetName().c_str());
|
}
|
||||||
if (xres && yres) {
|
if (m.GetRawMode().hdisplay != xres
|
||||||
if (!rate && m.GetRawMode().hdisplay == xres
|
|| m.GetRawMode().vdisplay != yres
|
||||||
&& m.GetRawMode().vdisplay == yres) {
|
|| m.GetVRefresh() != rate) {
|
||||||
rate = m.GetVRefresh();
|
continue;
|
||||||
}
|
|
||||||
if (m.GetRawMode().hdisplay != xres
|
|
||||||
|| m.GetRawMode().vdisplay != yres
|
|
||||||
|| m.GetVRefresh() != rate) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ALOGD("Add mode %dx%d@%fHz for display in connector %s",
|
|
||||||
m.GetRawMode().hdisplay, m.GetRawMode().vdisplay,
|
|
||||||
m.GetVRefresh(), GetName().c_str());
|
|
||||||
modes_.emplace_back(m);
|
|
||||||
}
|
}
|
||||||
|
ALOGD("Add mode %dx%d@%fHz for display in connector %s",
|
||||||
|
m.GetRawMode().hdisplay, m.GetRawMode().vdisplay,
|
||||||
|
m.GetVRefresh(), GetName().c_str());
|
||||||
|
modes_.emplace_back(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue