summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sdm/libs/hwc2/Android.mk3
-rw-r--r--sdm/libs/hwc2/display_null.cpp68
-rw-r--r--sdm/libs/hwc2/display_null.h107
-rw-r--r--sdm/libs/hwc2/hwc_display.cpp1
-rw-r--r--sdm/libs/hwc2/hwc_display.h3
-rw-r--r--sdm/libs/hwc2/hwc_display_external.cpp64
-rw-r--r--sdm/libs/hwc2/hwc_display_external.h6
-rw-r--r--sdm/libs/hwc2/hwc_session.cpp164
-rw-r--r--sdm/libs/hwc2/hwc_session.h14
9 files changed, 338 insertions, 92 deletions
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index 592dc027..9f1f3c77 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -39,7 +39,8 @@ LOCAL_SRC_FILES := hwc_session.cpp \
hwc_callbacks.cpp \
../hwc/cpuhint.cpp \
../hwc/hwc_socket_handler.cpp \
- hwc_tonemapper.cpp
+ hwc_tonemapper.cpp \
+ display_null.cpp
ifneq ($(TARGET_USES_GRALLOC1), true)
LOCAL_SRC_FILES += ../hwc/hwc_buffer_allocator.cpp
diff --git a/sdm/libs/hwc2/display_null.cpp b/sdm/libs/hwc2/display_null.cpp
new file mode 100644
index 00000000..16f4da66
--- /dev/null
+++ b/sdm/libs/hwc2/display_null.cpp
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "display_null.h"
+
+#define __CLASS__ "DisplayNull"
+
+namespace sdm {
+
+DisplayError DisplayNull::Commit(LayerStack *layer_stack) {
+ for (Layer *layer : layer_stack->layers) {
+ if (layer->composition != kCompositionGPUTarget) {
+ layer->composition = kCompositionSDE;
+ layer->input_buffer.release_fence_fd = -1;
+ }
+ }
+ layer_stack->retire_fence_fd = -1;
+
+ return kErrorNone;
+}
+
+DisplayError DisplayNull::GetDisplayState(DisplayState *state) {
+ *state = state_;
+ return kErrorNone;
+}
+
+DisplayError DisplayNull::SetDisplayState(DisplayState state) {
+ state_ = state;
+ return kErrorNone;
+}
+
+DisplayError DisplayNull::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) {
+ fb_config_ = variable_info;
+ return kErrorNone;
+}
+
+DisplayError DisplayNull::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) {
+ *variable_info = fb_config_;
+ return kErrorNone;
+}
+
+} // namespace sdm
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
new file mode 100644
index 00000000..fa88c281
--- /dev/null
+++ b/sdm/libs/hwc2/display_null.h
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_NULL_H__
+#define __DISPLAY_NULL_H__
+
+#include <core/display_interface.h>
+#include <string>
+#include <vector>
+
+namespace sdm {
+
+#define MAKE_NO_OP(virtual_method_name) \
+ virtual DisplayError virtual_method_name { return kErrorNone; }
+
+class DisplayNull : public DisplayInterface {
+ public:
+ virtual ~DisplayNull() { }
+ virtual DisplayError Commit(LayerStack *layer_stack);
+ virtual DisplayError GetDisplayState(DisplayState *state);
+ virtual DisplayError SetDisplayState(DisplayState state);
+ virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info);
+ virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info);
+ virtual bool IsUnderscanSupported() { return true; }
+ virtual void SetIdleTimeoutMs(uint32_t active_ms) { }
+ virtual bool IsPrimaryDisplay() { return true; }
+
+ void SetActive(bool active) {
+ active_ = active;
+ }
+
+ bool IsActive() {
+ return active_;
+ }
+
+ MAKE_NO_OP(Prepare(LayerStack *))
+ MAKE_NO_OP(Flush())
+ MAKE_NO_OP(GetNumVariableInfoConfigs(uint32_t *))
+ MAKE_NO_OP(GetConfig(uint32_t, DisplayConfigVariableInfo *))
+ MAKE_NO_OP(GetConfig(DisplayConfigFixedInfo *))
+ MAKE_NO_OP(GetActiveConfig(uint32_t *))
+ MAKE_NO_OP(GetVSyncState(bool *))
+ MAKE_NO_OP(SetActiveConfig(uint32_t))
+ MAKE_NO_OP(SetActiveConfig(DisplayConfigVariableInfo *))
+ MAKE_NO_OP(SetMaxMixerStages(uint32_t))
+ MAKE_NO_OP(ControlPartialUpdate(bool, uint32_t *))
+ MAKE_NO_OP(DisablePartialUpdateOneFrame())
+ MAKE_NO_OP(SetDisplayMode(uint32_t))
+ MAKE_NO_OP(SetPanelBrightness(int))
+ MAKE_NO_OP(CachePanelBrightness(int))
+ MAKE_NO_OP(OnMinHdcpEncryptionLevelChange(uint32_t))
+ MAKE_NO_OP(ColorSVCRequestRoute(const PPDisplayAPIPayload &, PPDisplayAPIPayload *,
+ PPPendingParams *))
+ MAKE_NO_OP(GetColorModeCount(uint32_t *))
+ MAKE_NO_OP(GetColorModes(uint32_t *, std::vector<std::string> *))
+ MAKE_NO_OP(GetColorModeAttr(const std::string &, AttrVal *))
+ MAKE_NO_OP(SetColorMode(const std::string &))
+ MAKE_NO_OP(SetColorModeById(int32_t))
+ MAKE_NO_OP(SetColorTransform(const uint32_t, const double *))
+ MAKE_NO_OP(GetDefaultColorMode(std::string *))
+ MAKE_NO_OP(ApplyDefaultDisplayMode())
+ MAKE_NO_OP(SetCursorPosition(int, int))
+ MAKE_NO_OP(GetRefreshRateRange(uint32_t *, uint32_t *))
+ MAKE_NO_OP(SetRefreshRate(uint32_t, bool))
+ MAKE_NO_OP(GetPanelBrightness(int *))
+ MAKE_NO_OP(SetVSyncState(bool))
+ MAKE_NO_OP(SetMixerResolution(uint32_t, uint32_t))
+ MAKE_NO_OP(GetMixerResolution(uint32_t *, uint32_t *))
+ MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &))
+ MAKE_NO_OP(GetDisplayPort(DisplayPort *))
+ MAKE_NO_OP(SetCompositionState(LayerComposition, bool))
+
+ private:
+ bool active_ = false;
+ DisplayState state_ = kStateOff;
+ DisplayConfigVariableInfo fb_config_ = {};
+};
+
+} // namespace sdm
+
+#endif // __DISPLAY_NULL_H__
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 69b0acd8..f3c81f24 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1598,6 +1598,7 @@ void HWCDisplay::MarkLayersForGPUBypass() {
auto layer = hwc_layer->GetSDMLayer();
layer->composition = kCompositionSDE;
}
+ validated_ = true;
}
void HWCDisplay::MarkLayersForClientComposition() {
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 9ee78112..b70f1608 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -159,6 +159,9 @@ class HWCDisplay : public DisplayEventHandler {
return INT32(status);
}
+ virtual int SetState(bool connected) {
+ return kErrorNotSupported;
+ }
int SetPanelBrightness(int level);
int GetPanelBrightness(int *level);
int ToggleScreenUpdates(bool enable);
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index a8f8480f..e89451d5 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -64,6 +64,7 @@ int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buf
error = hwc_display_external->GetMixerResolution(&external_width, &external_height);
if (error != kErrorNone) {
+ Destroy(hwc_display_external);
return -EINVAL;
}
@@ -215,4 +216,65 @@ void HWCDisplayExternal::GetDownscaleResolution(uint32_t primary_width, uint32_t
}
}
+int HWCDisplayExternal::SetState(bool connected) {
+ DisplayError error = kErrorNone;
+ DisplayState state = kStateOff;
+ DisplayConfigVariableInfo fb_config = {};
+
+ if (connected) {
+ if (display_null_.IsActive()) {
+ error = core_intf_->CreateDisplay(type_, this, &display_intf_);
+ if (error != kErrorNone) {
+ DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p",
+ error, type_, this, &display_intf_);
+ return -EINVAL;
+ }
+
+ // Restore HDMI attributes when display is reconnected.
+ // This is to ensure that surfaceflinger & sdm are in sync.
+ display_null_.GetFrameBufferConfig(&fb_config);
+ int status = SetFrameBufferResolution(fb_config.x_pixels, fb_config.y_pixels);
+ if (status) {
+ DLOGW("Set frame buffer config failed. Error = %d", error);
+ return -1;
+ }
+
+ display_null_.GetDisplayState(&state);
+ display_intf_->SetDisplayState(state);
+
+ SetVsyncEnabled(HWC2::Vsync::Enable);
+
+ display_null_.SetActive(false);
+ DLOGI("Display is connected successfully.");
+ } else {
+ DLOGI("Display is already connected.");
+ }
+ } else {
+ if (!display_null_.IsActive()) {
+ // Preserve required attributes of HDMI display that surfaceflinger sees.
+ // Restore HDMI attributes when display is reconnected.
+ display_intf_->GetDisplayState(&state);
+ display_null_.SetDisplayState(state);
+
+ error = display_intf_->GetFrameBufferConfig(&fb_config);
+ if (error != kErrorNone) {
+ DLOGW("Get frame buffer config failed. Error = %d", error);
+ return -1;
+ }
+ display_null_.SetFrameBufferConfig(fb_config);
+
+ SetVsyncEnabled(HWC2::Vsync::Disable);
+ core_intf_->DestroyDisplay(display_intf_);
+ display_intf_ = &display_null_;
+
+ display_null_.SetActive(true);
+ DLOGI("Display is disconnected successfully.");
+ } else {
+ DLOGI("Display is already disconnected.");
+ }
+ }
+
+ return 0;
+}
+
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 802a77c8..7aa84b2c 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,6 +31,7 @@
#define __HWC_DISPLAY_EXTERNAL_H__
#include "hwc_display.h"
+#include "display_null.h"
namespace sdm {
@@ -47,6 +48,7 @@ class HWCDisplayExternal : public HWCDisplay {
virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
virtual HWC2::Error Present(int32_t *out_retire_fence);
virtual void SetSecureDisplay(bool secure_display_active);
+ virtual int SetState(bool connected);
private:
HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
@@ -54,6 +56,8 @@ class HWCDisplayExternal : public HWCDisplay {
void ApplyScanAdjustment(hwc_rect_t *display_frame);
static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
uint32_t *virtual_width, uint32_t *virtual_height);
+
+ DisplayNull display_null_;
};
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index a6739b2a..b305a9ad 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -96,9 +96,7 @@ int HWCSession::Init() {
StartServices();
- buffer_allocator_ = new HWCBufferAllocator();
-
- DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), buffer_allocator_,
+ DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
&buffer_sync_handler_, &socket_handler_,
&core_intf_);
if (error != kErrorNone) {
@@ -106,20 +104,31 @@ int HWCSession::Init() {
return -EINVAL;
}
- // Read which display is first, and create it and store it in primary slot
- // TODO(user): This will need to be redone for HWC2 - right now we validate only
- // the primary physical path
- HWDisplayInterfaceInfo hw_disp_info;
+ // If HDMI display is primary display, defer display creation until hotplug event is received.
+ HWDisplayInterfaceInfo hw_disp_info = {};
error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
- if (error == kErrorNone && hw_disp_info.type == kHDMI && hw_disp_info.is_connected) {
- // HDMI is primary display. If already connected, then create it and store in
- // primary display slot. If not connected, create a NULL display for now.
- status = HWCDisplayExternal::Create(core_intf_, buffer_allocator_, &callbacks_, qservice_,
- &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ if (error != kErrorNone) {
+ CoreInterface::DestroyCore();
+ DLOGE("Primary display type not recognized. Error = %d", error);
+ return -EINVAL;
+ }
+
+ if (hw_disp_info.type == kHDMI) {
+ status = 0;
+ hdmi_is_primary_ = true;
+ // Create display if it is connected, else wait for hotplug connect event.
+ if (hw_disp_info.is_connected) {
+ status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
+ &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ }
} else {
// Create and power on primary display
- status = HWCDisplayPrimary::Create(core_intf_, buffer_allocator_, &callbacks_, qservice_,
+ status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
&hwc_display_[HWC_DISPLAY_PRIMARY]);
+ color_mgr_ = HWCColorManager::CreateColorManager(&buffer_allocator_);
+ if (!color_mgr_) {
+ DLOGW("Failed to load HWCColorManager.");
+ }
}
if (status) {
@@ -127,19 +136,6 @@ int HWCSession::Init() {
return status;
}
- color_mgr_ = HWCColorManager::CreateColorManager(buffer_allocator_);
- if (!color_mgr_) {
- DLOGW("Failed to load HWCColorManager.");
- }
-
- if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
- DLOGE("Failed to start = %s, error = %s", uevent_thread_name_, strerror(errno));
- HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
- hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
- CoreInterface::DestroyCore();
- return -errno;
- }
-
struct rlimit fd_limit = {};
getrlimit(RLIMIT_NOFILE, &fd_limit);
fd_limit.rlim_cur = fd_limit.rlim_cur * 2;
@@ -149,31 +145,38 @@ int HWCSession::Init() {
DLOGW("Unable to increase fd limit - err:%d, %s", errno, strerror(errno));
}
}
+
+ std::thread uevent_thread(HWCUeventThread, this);
+ uevent_thread_.swap(uevent_thread);
+
return 0;
}
int HWCSession::Deinit() {
- HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
- hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
+ HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+ if (primary_display) {
+ if (hdmi_is_primary_) {
+ HWCDisplayExternal::Destroy(primary_display);
+ } else {
+ HWCDisplayPrimary::Destroy(primary_display);
+ }
+ }
+ hwc_display_[HWC_DISPLAY_PRIMARY] = nullptr;
+
if (color_mgr_) {
color_mgr_->DestroyColorManager();
}
- uevent_thread_exit_ = true;
+
DLOGD("Terminating uevent thread");
- // TODO(user): on restarting HWC in the same process, the uevent thread does not restart
- // cleanly.
- Sys::pthread_cancel_(uevent_thread_);
+ uevent_thread_exit_ = true;
+ // todo(user): add a local event to interrupt thread execution and join.
+ uevent_thread_.detach();
DisplayError error = CoreInterface::DestroyCore();
if (error != kErrorNone) {
DLOGE("Display core de-initialization failed. Error = %d", error);
}
- if (buffer_allocator_ != nullptr) {
- delete buffer_allocator_;
- }
- buffer_allocator_ = nullptr;
-
return 0;
}
@@ -436,8 +439,13 @@ int32_t HWCSession::RegisterCallback(hwc2_device_t *device, int32_t descriptor,
auto desc = static_cast<HWC2::Callback>(descriptor);
auto error = hwc_session->callbacks_.Register(desc, callback_data, pointer);
DLOGD("Registering callback: %s", to_string(desc).c_str());
- if (descriptor == HWC2_CALLBACK_HOTPLUG)
- hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected);
+ if (descriptor == HWC2_CALLBACK_HOTPLUG) {
+ // If primary display (HDMI) is not created yet, wait for it to be hotplugged.
+ if (hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected);
+ }
+ }
+
return INT32(error);
}
@@ -719,7 +727,7 @@ HWC2::Error HWCSession::CreateVirtualDisplayObject(uint32_t width, uint32_t heig
if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
return HWC2::Error::NoResources;
}
- auto status = HWCDisplayVirtual::Create(core_intf_, buffer_allocator_, &callbacks_, width,
+ auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width,
height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
// TODO(user): validate width and height support
if (status)
@@ -738,7 +746,7 @@ int32_t HWCSession::ConnectDisplay(int disp) {
hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
if (disp == HWC_DISPLAY_EXTERNAL) {
- status = HWCDisplayExternal::Create(core_intf_, buffer_allocator_, &callbacks_, primary_width,
+ status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, primary_width,
primary_height, qservice_, false, &hwc_display_[disp]);
} else {
DLOGE("Invalid display type");
@@ -1341,34 +1349,35 @@ void HWCSession::ResetPanel() {
int HWCSession::HotPlugHandler(bool connected) {
int status = 0;
bool notify_hotplug = false;
- bool hdmi_primary = false;
// To prevent sending events to client while a lock is held, acquire scope locks only within
// below scope so that those get automatically unlocked after the scope ends.
- {
+ do {
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+ // If HDMI is primary but not created yet (first time), create it and notify surfaceflinger.
+ // if it is already created, but got disconnected/connected again,
+ // just toggle display status and do not notify surfaceflinger.
+ // If HDMI is not primary, create/destroy external display normally.
+ if (hdmi_is_primary_) {
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetState(connected);
+ } else {
+ status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
+ qservice_, &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ notify_hotplug = true;
+ }
+
+ break;
+ }
+
+ // Primary display must be connected for HDMI as secondary cases.
if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
DLOGE("Primary display is not connected.");
return -1;
}
- HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
- HWCDisplay *external_display = NULL;
-
- if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) {
- external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
- hdmi_primary = true;
- }
-
- // If primary display connected is a NULL display, then replace it with the external display
if (connected) {
- // If we are in HDMI as primary and the primary display just got plugged in
- if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
- DLOGE("HDMI is already connected");
- return -1;
- }
-
// Connect external display if virtual display is not connected.
// Else, defer external display connection and process it when virtual display
// tears down; Do not notify SurfaceFlinger since connection is deferred now.
@@ -1386,39 +1395,28 @@ int HWCSession::HotPlugHandler(bool connected) {
// Do not return error if external display is not in connected status.
// Due to virtual display concurrency, external display connection might be still pending
// but hdmi got disconnected before pending connection could be processed.
-
- if (hdmi_primary) {
- assert(external_display != NULL);
- uint32_t x_res, y_res;
- external_display->GetFrameBufferResolution(&x_res, &y_res);
- // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases
- // for HDMI as primary
- external_display->SetVsyncEnabled(HWC2::Vsync::Disable);
- HWCDisplayExternal::Destroy(external_display);
-
- // In HWC2, primary displays can be hotplugged out
+ if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+ status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
notify_hotplug = true;
- } else {
- if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
- status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
- notify_hotplug = true;
- }
- external_pending_connect_ = false;
}
+ external_pending_connect_ = false;
}
- }
+ } while (0);
- if (connected && notify_hotplug) {
- // trigger screen refresh to ensure sufficient resources are available to process new
- // new display connection.
+ if (connected) {
callbacks_.Refresh(0);
- uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
- usleep(vsync_period * 2 / 1000);
+
+ if (!hdmi_is_primary_) {
+ // wait for sufficient time to ensure sufficient resources are available to process new
+ // new display connection.
+ uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
+ usleep(vsync_period * 2 / 1000);
+ }
}
+
// notify client
- // Handle HDMI as primary here
if (notify_hotplug) {
- callbacks_.Hotplug(HWC_DISPLAY_EXTERNAL,
+ callbacks_.Hotplug(hdmi_is_primary_ ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL,
connected ? HWC2::Connection::Connected : HWC2::Connection::Disconnected);
}
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index be4494ee..cd9831d9 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -23,6 +23,7 @@
#include <vendor/display/config/1.0/IDisplayConfig.h>
#include <core/core_interface.h>
#include <utils/locker.h>
+#include <thread>
#include "hwc_callbacks.h"
#include "hwc_layers.h"
@@ -188,23 +189,24 @@ class HWCSession : hwc2_device_t, public IDisplayConfig, public qClient::BnQClie
android::status_t SetColorModeById(const android::Parcel *input_parcel);
static Locker locker_;
- CoreInterface *core_intf_ = NULL;
- HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {NULL};
+ CoreInterface *core_intf_ = nullptr;
+ HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
HWCCallbacks callbacks_;
- pthread_t uevent_thread_;
+ std::thread uevent_thread_;
bool uevent_thread_exit_ = false;
const char *uevent_thread_name_ = "HWC_UeventThread";
- HWCBufferAllocator *buffer_allocator_;
+ HWCBufferAllocator buffer_allocator_;
HWCBufferSyncHandler buffer_sync_handler_;
- HWCColorManager *color_mgr_ = NULL;
+ HWCColorManager *color_mgr_ = nullptr;
bool reset_panel_ = false;
bool secure_display_active_ = false;
bool external_pending_connect_ = false;
bool new_bw_mode_ = false;
bool need_invalidate_ = false;
int bw_mode_release_fd_ = -1;
- qService::QService *qservice_ = NULL;
+ qService::QService *qservice_ = nullptr;
HWCSocketHandler socket_handler_;
+ bool hdmi_is_primary_ = false;
};
} // namespace sdm