aboutsummaryrefslogtreecommitdiff
path: root/hwc2_device/HwcDisplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hwc2_device/HwcDisplay.cpp')
-rw-r--r--hwc2_device/HwcDisplay.cpp361
1 files changed, 208 insertions, 153 deletions
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 8936136..cedac19 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -20,6 +20,7 @@
#include "HwcDisplay.h"
#include "DrmHwcTwo.h"
+#include "backend/Backend.h"
#include "backend/BackendManager.h"
#include "bufferinfo/BufferInfoGetter.h"
#include "utils/log.h"
@@ -68,8 +69,12 @@ std::string HwcDisplay::Dump() {
" VSync remains";
}
+ std::string connector_name = IsInHeadlessMode()
+ ? "NULL-DISPLAY"
+ : GetPipe().connector->Get()->GetName();
+
std::stringstream ss;
- ss << "- Display on: " << connector_->name() << "\n"
+ ss << "- Display on: " << connector_name << "\n"
<< " Flattening state: " << flattening_state_str << "\n"
<< "Statistics since system boot:\n"
<< DumpDelta(total_stats_) << "\n\n"
@@ -80,12 +85,9 @@ std::string HwcDisplay::Dump() {
return ss.str();
}
-HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
- hwc2_display_t handle, HWC2::DisplayType type,
+HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
DrmHwcTwo *hwc2)
: hwc2_(hwc2),
- resource_manager_(resource_manager),
- drm_(drm),
handle_(handle),
type_(type),
color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
@@ -97,108 +99,72 @@ HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
// clang-format on
}
-void HwcDisplay::ClearDisplay() {
- if (IsInHeadlessMode()) {
- ALOGE("%s: Headless mode, should never reach here: ", __func__);
- return;
- }
+HwcDisplay::~HwcDisplay() = default;
- AtomicCommitArgs a_args = {.clear_active_composition = true};
- compositor_.ExecuteAtomicCommit(a_args);
-}
+void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
+ pipeline_ = pipeline;
-HWC2::Error HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
- int display = static_cast<int>(handle_);
- int ret = compositor_.Init(resource_manager_, display);
- if (ret) {
- ALOGE("Failed display compositor init for display %d (%d)", display, ret);
- return HWC2::Error::NoResources;
- }
-
- // Split up the given display planes into primary and overlay to properly
- // interface with the composition
- char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
- property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
- "1");
- bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10);
- for (auto &plane : *planes) {
- if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY)
- primary_planes_.push_back(plane);
- else if (use_overlay_planes && (plane)->GetType() == DRM_PLANE_TYPE_OVERLAY)
- overlay_planes_.push_back(plane);
- }
-
- crtc_ = drm_->GetCrtcForDisplay(display);
- if (!crtc_) {
- ALOGE("Failed to get crtc for display %d", display);
- return HWC2::Error::BadDisplay;
- }
+ if (pipeline != nullptr) {
+ ChosePreferredConfig();
+ Init();
- connector_ = drm_->GetConnectorForDisplay(display);
- if (!connector_) {
- ALOGE("Failed to get connector for display %d", display);
- return HWC2::Error::BadDisplay;
+ hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
+ } else {
+ backend_.reset();
+ vsync_worker_.Init(nullptr, [](int64_t) {});
+ SetClientTarget(nullptr, -1, 0, {});
+ if (handle_ != kPrimaryDisplay) {
+ hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
+ }
}
+}
- ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) {
+HWC2::Error HwcDisplay::Init() {
+ int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
- /* vsync callback */
-#if PLATFORM_SDK_VERSION > 29
- if (hwc2_->vsync_2_4_callback_.first != nullptr &&
- hwc2_->vsync_2_4_callback_.second != nullptr) {
- hwc2_vsync_period_t period_ns{};
+ if (vsync_event_en_) {
+ uint32_t period_ns{};
GetDisplayVsyncPeriod(&period_ns);
- hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second,
- handle_, timestamp, period_ns);
- } else
-#endif
- if (hwc2_->vsync_callback_.first != nullptr &&
- hwc2_->vsync_callback_.second != nullptr) {
- hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_,
- timestamp);
+ hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+ }
+ if (vsync_flattening_en_) {
+ ProcessFlatenningVsyncInternal();
+ }
+ if (vsync_tracking_en_) {
+ last_vsync_ts_ = timestamp;
+ }
+ if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
+ vsync_worker_.VSyncControl(false);
}
});
- if (ret) {
- ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
+ if (ret && ret != -EALREADY) {
+ ALOGE("Failed to create event worker for d=%d %d\n", int(handle_), ret);
return HWC2::Error::BadDisplay;
}
- ret = flattening_vsync_worker_
- .Init(drm_, display, [this](int64_t /*timestamp*/) {
- const std::lock_guard<std::mutex> lock(
- hwc2_->GetResMan().GetMainLock());
- /* Frontend flattening */
- if (flattenning_state_ >
- ClientFlattenningState::ClientRefreshRequested &&
- --flattenning_state_ ==
- ClientFlattenningState::ClientRefreshRequested &&
- hwc2_->refresh_callback_.first != nullptr &&
- hwc2_->refresh_callback_.second != nullptr) {
- hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second,
- handle_);
- flattening_vsync_worker_.VSyncControl(false);
- }
- });
- if (ret) {
- ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
- return HWC2::Error::BadDisplay;
- }
-
- ret = BackendManager::GetInstance().SetBackendForDisplay(this);
- if (ret) {
- ALOGE("Failed to set backend for d=%d %d\n", display, ret);
- return HWC2::Error::BadDisplay;
+ if (!IsInHeadlessMode()) {
+ ret = BackendManager::GetInstance().SetBackendForDisplay(this);
+ if (ret) {
+ ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
+ return HWC2::Error::BadDisplay;
+ }
}
client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
- return ChosePreferredConfig();
+ return HWC2::Error::None;
}
HWC2::Error HwcDisplay::ChosePreferredConfig() {
- HWC2::Error err = configs_.Update(*connector_);
- if (!IsInHeadlessMode() && err != HWC2::Error::None)
+ HWC2::Error err{};
+ if (!IsInHeadlessMode()) {
+ err = configs_.Update(*pipeline_->connector->Get());
+ } else {
+ configs_.FillHeadless();
+ }
+ if (!IsInHeadlessMode() && err != HWC2::Error::None) {
return HWC2::Error::BadDisplay;
+ }
return SetActiveConfig(configs_.preferred_config_id);
}
@@ -217,18 +183,19 @@ HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
}
HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
- if (!get_layer(layer))
+ if (!get_layer(layer)) {
return HWC2::Error::BadLayer;
+ }
layers_.erase(layer);
return HWC2::Error::None;
}
HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
- if (configs_.hwc_configs.count(configs_.active_config_id) == 0)
+ if (configs_.hwc_configs.count(staged_mode_config_id_) == 0)
return HWC2::Error::BadConfig;
- *config = configs_.active_config_id;
+ *config = staged_mode_config_id_;
return HWC2::Error::None;
}
@@ -258,12 +225,13 @@ HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height,
int32_t /*format*/,
int32_t dataspace) {
- std::pair<uint32_t, uint32_t> min = drm_->min_resolution();
- std::pair<uint32_t, uint32_t> max = drm_->max_resolution();
if (IsInHeadlessMode()) {
return HWC2::Error::None;
}
+ std::pair<uint32_t, uint32_t> min = pipeline_->device->GetMinResolution();
+ std::pair<uint32_t, uint32_t> max = pipeline_->device->GetMaxResolution();
+
if (width < min.first || height < min.second)
return HWC2::Error::Unsupported;
@@ -293,7 +261,7 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
int conf = static_cast<int>(config);
if (configs_.hwc_configs.count(conf) == 0) {
- ALOGE("Could not find active mode for %d", conf);
+ ALOGE("Could not find mode #%d", conf);
return HWC2::Error::BadConfig;
}
@@ -330,7 +298,7 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
case HWC2::Attribute::ConfigGroup:
/* Dispite ConfigGroup is a part of HWC2.4 API, framework
* able to request it even if service @2.1 is used */
- *value = hwc_config.group_id;
+ *value = int(hwc_config.group_id);
break;
#endif
default:
@@ -363,7 +331,11 @@ HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
std::ostringstream stream;
- stream << "display-" << connector_->id();
+ if (IsInHeadlessMode()) {
+ stream << "null-display";
+ } else {
+ stream << "display-" << GetPipe().connector->Get()->GetId();
+ }
std::string string = stream.str();
size_t length = string.length();
if (!name) {
@@ -441,6 +413,26 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::None;
}
+ int PrevModeVsyncPeriodNs = static_cast<int>(
+ 1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
+
+ auto mode_update_commited_ = false;
+ if (staged_mode_ &&
+ staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
+ client_layer_.SetLayerDisplayFrame(
+ (hwc_rect_t){.left = 0,
+ .top = 0,
+ .right = static_cast<int>(staged_mode_->h_display()),
+ .bottom = static_cast<int>(staged_mode_->v_display())});
+
+ configs_.active_config_id = staged_mode_config_id_;
+
+ a_args.display_mode = *staged_mode_;
+ if (!a_args.test_only) {
+ mode_update_commited_ = true;
+ }
+ }
+
// order the layers by z-order
bool use_client_layer = false;
uint32_t client_z_order = UINT32_MAX;
@@ -471,7 +463,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
DrmHwcLayer layer;
l.second->PopulateDrmLayer(&layer);
- int ret = layer.ImportBuffer(drm_);
+ int ret = layer.ImportBuffer(GetPipe().device);
if (ret) {
ALOGE("Failed to import layer, ret=%d", ret);
return HWC2::Error::NoResources;
@@ -479,29 +471,21 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
composition_layers.emplace_back(std::move(layer));
}
- auto composition = std::make_shared<DrmDisplayComposition>(crtc_);
-
- // TODO(nobody): Don't always assume geometry changed
- int ret = composition->SetLayers(composition_layers.data(),
- composition_layers.size());
- if (ret) {
- ALOGE("Failed to set layers in the composition ret=%d", ret);
- return HWC2::Error::BadLayer;
- }
-
- std::vector<DrmPlane *> primary_planes(primary_planes_);
- std::vector<DrmPlane *> overlay_planes(overlay_planes_);
- ret = composition->Plan(&primary_planes, &overlay_planes);
- if (ret) {
- ALOGV("Failed to plan the composition ret=%d", ret);
+ /* Store plan to ensure shared planes won't be stolen by other display
+ * in between of ValidateDisplay() and PresentDisplay() calls
+ */
+ current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
+ std::move(composition_layers));
+ if (!current_plan_) {
+ if (!a_args.test_only) {
+ ALOGE("Failed to create DrmKmsPlan");
+ }
return HWC2::Error::BadConfig;
}
- a_args.composition = composition;
- if (staged_mode) {
- a_args.display_mode = *staged_mode;
- }
- ret = compositor_.ExecuteAtomicCommit(a_args);
+ a_args.composition = current_plan_;
+
+ int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
if (ret) {
if (!a_args.test_only)
@@ -509,8 +493,13 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::BadParameter;
}
- if (!a_args.test_only) {
- staged_mode.reset();
+ if (mode_update_commited_) {
+ staged_mode_.reset();
+ vsync_tracking_en_ = false;
+ if (last_vsync_ts_ != 0) {
+ hwc2_->SendVsyncPeriodTimingChangedEventToClient(
+ handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
+ }
}
return HWC2::Error::None;
@@ -548,30 +537,24 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
- int conf = static_cast<int>(config);
-
- if (configs_.hwc_configs.count(conf) == 0) {
- ALOGE("Could not find active mode for %d", conf);
+HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
+ int64_t change_time) {
+ if (configs_.hwc_configs.count(config) == 0) {
+ ALOGE("Could not find active mode for %u", config);
return HWC2::Error::BadConfig;
}
- auto &mode = configs_.hwc_configs[conf].mode;
-
- staged_mode = mode;
-
- configs_.active_config_id = conf;
-
- // Setup the client layer's dimensions
- hwc_rect_t display_frame = {.left = 0,
- .top = 0,
- .right = static_cast<int>(mode.h_display()),
- .bottom = static_cast<int>(mode.v_display())};
- client_layer_.SetLayerDisplayFrame(display_frame);
+ staged_mode_ = configs_.hwc_configs[config].mode;
+ staged_mode_change_time_ = change_time;
+ staged_mode_config_id_ = config;
return HWC2::Error::None;
}
+HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
+ return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs());
+}
+
/* Find API details at:
* https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
*/
@@ -656,7 +639,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
* true, as the next composition frame will implicitly activate
* the display
*/
- return compositor_.ActivateDisplayUsingDPMS() == 0
+ return GetPipe().atomic_state_manager->ActivateDisplayUsingDPMS() == 0
? HWC2::Error::None
: HWC2::Error::BadParameter;
break;
@@ -668,7 +651,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
return HWC2::Error::BadParameter;
};
- int err = compositor_.ExecuteAtomicCommit(a_args);
+ int err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
if (err) {
ALOGE("Failed to apply the dpms composition err=%d", err);
return HWC2::Error::BadParameter;
@@ -677,7 +660,10 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
}
HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
- vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
+ vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
+ if (vsync_event_en_) {
+ vsync_worker_.VSyncControl(true);
+ }
return HWC2::Error::None;
}
@@ -706,11 +692,25 @@ std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() {
return ordered_layers;
}
+HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
+ uint32_t *outVsyncPeriod /* ns */) {
+ return GetDisplayAttribute(configs_.active_config_id,
+ HWC2_ATTRIBUTE_VSYNC_PERIOD,
+ (int32_t *)(outVsyncPeriod));
+}
+
#if PLATFORM_SDK_VERSION > 29
HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
- if (connector_->internal())
+ if (IsInHeadlessMode()) {
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
- else if (connector_->external())
+ return HWC2::Error::None;
+ }
+ /* Primary display should be always internal,
+ * otherwise SF will be unhappy and will crash
+ */
+ if (GetPipe().connector->Get()->IsInternal() || handle_ == kPrimaryDisplay)
+ *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
+ else if (GetPipe().connector->Get()->IsExternal())
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
else
return HWC2::Error::BadConfig;
@@ -718,22 +718,38 @@ HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
- hwc2_vsync_period_t *outVsyncPeriod /* ns */) {
- return GetDisplayAttribute(configs_.active_config_id,
- HWC2_ATTRIBUTE_VSYNC_PERIOD,
- (int32_t *)(outVsyncPeriod));
-}
-
HWC2::Error HwcDisplay::SetActiveConfigWithConstraints(
- hwc2_config_t /*config*/,
+ hwc2_config_t config,
hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
hwc_vsync_period_change_timeline_t *outTimeline) {
if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
return HWC2::Error::BadParameter;
}
- return HWC2::Error::BadConfig;
+ uint32_t current_vsync_period{};
+ GetDisplayVsyncPeriod(&current_vsync_period);
+
+ if (vsyncPeriodChangeConstraints->seamlessRequired) {
+ return HWC2::Error::SeamlessNotAllowed;
+ }
+
+ outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints
+ ->desiredTimeNanos -
+ current_vsync_period;
+ auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos);
+ if (ret != HWC2::Error::None) {
+ return ret;
+ }
+
+ outTimeline->refreshRequired = true;
+ outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints
+ ->desiredTimeNanos;
+
+ last_vsync_ts_ = 0;
+ vsync_tracking_en_ = true;
+ vsync_worker_.VSyncControl(true);
+
+ return HWC2::Error::None;
}
HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
@@ -765,11 +781,18 @@ HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
uint32_t *outDataSize,
uint8_t *outData) {
- auto blob = connector_->GetEdidBlob();
+ if (IsInHeadlessMode()) {
+ return HWC2::Error::None;
+ }
+ auto blob = GetPipe().connector->Get()->GetEdidBlob();
+
+ *outPort = handle_ - 1;
if (!blob) {
- ALOGE("Failed to get edid property value.");
- return HWC2::Error::Unsupported;
+ if (outData == nullptr) {
+ *outDataSize = 0;
+ }
+ return HWC2::Error::None;
}
if (outData) {
@@ -778,7 +801,6 @@ HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
} else {
*outDataSize = blob->length;
}
- *outPort = connector_->id();
return HWC2::Error::None;
}
@@ -851,4 +873,37 @@ void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
backend_ = std::move(backend);
}
+/* returns true if composition should be sent to client */
+bool HwcDisplay::ProcessClientFlatteningState(bool skip) {
+ int flattenning_state = flattenning_state_;
+ if (flattenning_state == ClientFlattenningState::Disabled) {
+ return false;
+ }
+
+ if (skip) {
+ flattenning_state_ = ClientFlattenningState::NotRequired;
+ return false;
+ }
+
+ if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) {
+ flattenning_state_ = ClientFlattenningState::Flattened;
+ return true;
+ }
+
+ vsync_flattening_en_ = true;
+ vsync_worker_.VSyncControl(true);
+ flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
+ return false;
+}
+
+void HwcDisplay::ProcessFlatenningVsyncInternal() {
+ if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
+ --flattenning_state_ == ClientFlattenningState::ClientRefreshRequested &&
+ hwc2_->refresh_callback_.first != nullptr &&
+ hwc2_->refresh_callback_.second != nullptr) {
+ hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
+ vsync_flattening_en_ = false;
+ }
+}
+
} // namespace android