drm_hwcomposer: Implement getDisplayPhysicalOrientation()
Implement ComposerClient::getDisplayPhysicalOrientation() by querying
the DRM display panel orientation property and translating the result to
the correct common::Transform enum value.
The result is used by SurfaceFlinger to correctly rotate the image
before displaying it to the user.
Signed-off-by: Tim Van Patten <timvp@google.com>
diff --git a/compositor/ColorInfo.h b/compositor/DisplayInfo.h
similarity index 81%
rename from compositor/ColorInfo.h
rename to compositor/DisplayInfo.h
index 1afda07..bbcbff8 100644
--- a/compositor/ColorInfo.h
+++ b/compositor/DisplayInfo.h
@@ -36,3 +36,13 @@
kRgbWideFloat,
kBt601Ycc,
};
+
+/**
+ * Display panel orientation property values.
+ */
+enum PanelOrientation {
+ kModePanelOrientationNormal = 0,
+ kModePanelOrientationBottomUp,
+ kModePanelOrientationLeftUp,
+ kModePanelOrientationRightUp
+};
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index c8736f2..20896ed 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -21,7 +21,7 @@
#include <memory>
#include <optional>
-#include "compositor/ColorInfo.h"
+#include "compositor/DisplayInfo.h"
#include "compositor/DrmKmsPlan.h"
#include "compositor/LayerData.h"
#include "drm/DrmPlane.h"
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 5371513..c46effa 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -27,6 +27,7 @@
#include <sstream>
#include "DrmDevice.h"
+#include "compositor/DisplayInfo.h"
#include "utils/log.h"
#ifndef DRM_MODE_CONNECTOR_SPI
@@ -136,6 +137,26 @@
GetConnectorProperty("content type", &content_type_property_,
/*is_optional=*/true);
+ if (GetConnectorProperty("panel orientation", &panel_orientation_,
+ /*is_optional=*/true)) {
+ panel_orientation_
+ .AddEnumToMapReverse("Normal",
+ PanelOrientation::kModePanelOrientationNormal,
+ panel_orientation_enum_map_);
+ panel_orientation_
+ .AddEnumToMapReverse("Upside Down",
+ PanelOrientation::kModePanelOrientationBottomUp,
+ panel_orientation_enum_map_);
+ panel_orientation_
+ .AddEnumToMapReverse("Left Side Up",
+ PanelOrientation::kModePanelOrientationLeftUp,
+ panel_orientation_enum_map_);
+ panel_orientation_
+ .AddEnumToMapReverse("Right Side Up",
+ PanelOrientation::kModePanelOrientationRightUp,
+ panel_orientation_enum_map_);
+ }
+
return true;
}
@@ -241,4 +262,26 @@
return true;
}
+
+std::optional<PanelOrientation> DrmConnector::GetPanelOrientation() {
+ if (!panel_orientation_.GetValue().has_value()) {
+ ALOGW("No panel orientation property available.");
+ return {};
+ }
+
+ /* The value_or(0) satisfies the compiler warning. However,
+ * panel_orientation_.GetValue() is guaranteed to have a value since we check
+ * has_value() and return early otherwise.
+ */
+ uint64_t panel_orientation_value = panel_orientation_.GetValue().value_or(0);
+
+ if (panel_orientation_enum_map_.count(panel_orientation_value) == 1) {
+ return panel_orientation_enum_map_[panel_orientation_value];
+ }
+
+ ALOGE("Unknown panel orientation: panel_orientation = %lu",
+ panel_orientation_value);
+ return {};
+}
+
} // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 9186f07..be84ae3 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -26,8 +26,7 @@
#include "DrmMode.h"
#include "DrmProperty.h"
#include "DrmUnique.h"
-
-#include "compositor/ColorInfo.h"
+#include "compositor/DisplayInfo.h"
namespace android {
@@ -118,6 +117,10 @@
return writeback_out_fence_;
}
+ auto &GetPanelOrientationProperty() const {
+ return panel_orientation_;
+ }
+
auto IsConnected() const {
return connector_->connection == DRM_MODE_CONNECTED;
}
@@ -130,11 +133,13 @@
return connector_->mmHeight;
};
+ auto GetPanelOrientation() -> std::optional<PanelOrientation>;
+
private:
DrmConnector(DrmModeConnectorUnique connector, DrmDevice *drm, uint32_t index)
: connector_(std::move(connector)),
drm_(drm),
- index_in_res_array_(index){};
+ index_in_res_array_(index) {};
DrmModeConnectorUnique connector_;
DrmDevice *const drm_;
@@ -157,7 +162,9 @@
DrmProperty writeback_pixel_formats_;
DrmProperty writeback_fb_id_;
DrmProperty writeback_out_fence_;
+ DrmProperty panel_orientation_;
std::map<Colorspace, uint64_t> colorspace_enum_map_;
+ std::map<uint64_t, PanelOrientation> panel_orientation_enum_map_;
};
} // namespace android
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index 031918a..0ea9143 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -125,4 +125,22 @@
return true;
}
+std::optional<std::string> DrmProperty::GetEnumNameFromValue(
+ uint64_t value) const {
+ if (enums_.empty()) {
+ ALOGE("No enum values for property: %s", name_.c_str());
+ return {};
+ }
+
+ for (const auto &it : enums_) {
+ if (it.value == value) {
+ return it.name;
+ }
+ }
+
+ ALOGE("Property '%s' has no matching enum for value: %lu", name_.c_str(),
+ value);
+ return {};
+}
+
} // namespace android
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index 516518b..2683ad8 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -64,10 +64,16 @@
auto AddEnumToMap(const std::string &name, E key, std::map<E, uint64_t> &map)
-> bool;
+ template <class E>
+ auto AddEnumToMapReverse(const std::string &name, E value,
+ std::map<uint64_t, E> &map) -> bool;
+
explicit operator bool() const {
return id_ != 0;
}
+ auto GetEnumNameFromValue(uint64_t value) const -> std::optional<std::string>;
+
private:
class DrmPropertyEnum {
public:
@@ -104,4 +110,18 @@
return false;
}
+template <class E>
+auto DrmProperty::AddEnumToMapReverse(const std::string &name, E value,
+ std::map<uint64_t, E> &map) -> bool {
+ uint64_t enum_value = UINT64_MAX;
+ int err = 0;
+ std::tie(enum_value, err) = GetEnumValueWithName(name);
+ if (err == 0) {
+ map[enum_value] = value;
+ return true;
+ }
+
+ return false;
+}
+
} // namespace android
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 7f65e65..6797c56 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -24,10 +24,15 @@
#include "backend/Backend.h"
#include "backend/BackendManager.h"
#include "bufferinfo/BufferInfoGetter.h"
+#include "compositor/DisplayInfo.h"
+#include "drm/DrmConnector.h"
+#include "drm/DrmDisplayPipeline.h"
#include "drm/DrmHwc.h"
#include "utils/log.h"
#include "utils/properties.h"
+using ::android::DrmDisplayPipeline;
+
namespace android {
std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
@@ -196,6 +201,23 @@
return HWC2::Error::None;
}
+std::optional<PanelOrientation> HwcDisplay::getDisplayPhysicalOrientation() {
+ if (IsInHeadlessMode()) {
+ // The pipeline can be nullptr in headless mode, so return the default
+ // "normal" mode.
+ return PanelOrientation::kModePanelOrientationNormal;
+ }
+
+ DrmDisplayPipeline &pipeline = GetPipe();
+ if (pipeline.connector == nullptr || pipeline.connector->Get() == nullptr) {
+ ALOGW(
+ "No display pipeline present to query the panel orientation property.");
+ return {};
+ }
+
+ return pipeline.connector->Get()->GetPanelOrientation();
+}
+
HWC2::Error HwcDisplay::ChosePreferredConfig() {
HWC2::Error err{};
if (type_ == HWC2::DisplayType::Virtual) {
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index c568a73..4680ca9 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -23,7 +23,7 @@
#include <sstream>
#include "HwcDisplayConfigs.h"
-#include "compositor/ColorInfo.h"
+#include "compositor/DisplayInfo.h"
#include "compositor/FlatteningController.h"
#include "compositor/LayerData.h"
#include "drm/DrmAtomicStateManager.h"
@@ -198,6 +198,8 @@
virtual_disp_height_ = height;
}
+ auto getDisplayPhysicalOrientation() -> std::optional<PanelOrientation>;
+
private:
HwcDisplayConfigs configs_;
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 848c587..87ec006 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -42,6 +42,7 @@
#include <hardware/hwcomposer_defs.h>
#include "bufferinfo/BufferInfo.h"
+#include "compositor/DisplayInfo.h"
#include "hwc2_device/HwcDisplay.h"
#include "hwc2_device/HwcDisplayConfigs.h"
#include "hwc2_device/HwcLayer.h"
@@ -909,13 +910,40 @@
ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(
int64_t display_id, common::Transform* orientation) {
DEBUG_FUNC();
+
+ if (orientation == nullptr) {
+ ALOGE("Invalid 'orientation' pointer.");
+ return ToBinderStatus(hwc3::Error::kBadParameter);
+ }
+
const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
HwcDisplay* display = GetDisplay(display_id);
if (display == nullptr) {
return ToBinderStatus(hwc3::Error::kBadDisplay);
}
- *orientation = common::Transform::NONE;
+ PanelOrientation
+ drm_orientation = display->getDisplayPhysicalOrientation().value_or(
+ PanelOrientation::kModePanelOrientationNormal);
+
+ switch (drm_orientation) {
+ case PanelOrientation::kModePanelOrientationNormal:
+ *orientation = common::Transform::NONE;
+ break;
+ case PanelOrientation::kModePanelOrientationBottomUp:
+ *orientation = common::Transform::ROT_180;
+ break;
+ case PanelOrientation::kModePanelOrientationLeftUp:
+ *orientation = common::Transform::ROT_270;
+ break;
+ case PanelOrientation::kModePanelOrientationRightUp:
+ *orientation = common::Transform::ROT_90;
+ break;
+ default:
+ ALOGE("Unknown panel orientation value: %d", drm_orientation);
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
return ndk::ScopedAStatus::ok();
}