|
@@ -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(¤t_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
|