aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--system/hwc2/Android.mk4
-rw-r--r--system/hwc2/Common.cpp6
-rw-r--r--system/hwc2/Common.h1
-rw-r--r--system/hwc2/Device.cpp123
-rw-r--r--system/hwc2/Device.h5
-rw-r--r--system/hwc2/Display.cpp288
-rw-r--r--system/hwc2/Display.h74
-rw-r--r--system/hwc2/DisplayConfig.cpp124
-rw-r--r--system/hwc2/DisplayConfig.h84
-rw-r--r--system/hwc2/DisplayFinder.cpp120
-rw-r--r--system/hwc2/DisplayFinder.h14
-rw-r--r--system/hwc2/DrmPresenter.h2
-rw-r--r--system/hwc2/HostComposer.cpp8
-rw-r--r--system/hwc2/VsyncThread.cpp193
-rw-r--r--system/hwc2/VsyncThread.h86
15 files changed, 810 insertions, 322 deletions
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index 4f1be502..e9090df4 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -61,6 +61,7 @@ emulator_hwcomposer2_src_files := \
Common.cpp \
Device.cpp \
Display.cpp \
+ DisplayConfig.cpp \
DisplayFinder.cpp \
Drm.cpp \
DrmPresenter.cpp \
@@ -69,6 +70,7 @@ emulator_hwcomposer2_src_files := \
HostComposer.cpp \
HostUtils.cpp \
Layer.cpp \
+ VsyncThread.cpp \
include $(CLEAR_VARS)
@@ -85,7 +87,7 @@ LOCAL_MODULE_RELATIVE_PATH := $(emulator_hwcomposer_relative_path)
LOCAL_MODULE := hwcomposer.ranchu
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_VINTF_FRAGMENTS := android.hardware.graphics.composer@2.3.xml
+LOCAL_VINTF_FRAGMENTS := android.hardware.graphics.composer@2.4.xml
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../LICENSE
LOCAL_MODULE_TAGS := optional
diff --git a/system/hwc2/Common.cpp b/system/hwc2/Common.cpp
index b323b665..19217411 100644
--- a/system/hwc2/Common.cpp
+++ b/system/hwc2/Common.cpp
@@ -21,3 +21,9 @@
bool IsCuttlefish() {
return android::base::GetProperty("ro.product.board", "") == "cutf";
}
+
+bool IsCuttlefishFoldable() {
+ return IsCuttlefish() &&
+ android::base::GetProperty("ro.product.name", "").find("foldable") !=
+ std::string::npos;
+} \ No newline at end of file
diff --git a/system/hwc2/Common.h b/system/hwc2/Common.h
index 770c87f1..e8432135 100644
--- a/system/hwc2/Common.h
+++ b/system/hwc2/Common.h
@@ -40,5 +40,6 @@
#undef HWC2_USE_CPP11
bool IsCuttlefish();
+bool IsCuttlefishFoldable();
#endif
diff --git a/system/hwc2/Device.cpp b/system/hwc2/Device.cpp
index 1f06f439..eaf8bbad 100644
--- a/system/hwc2/Device.cpp
+++ b/system/hwc2/Device.cpp
@@ -105,9 +105,8 @@ HWC2::Error Device::createDisplays() {
return error;
}
- for (const auto& iter: displays) {
-
- error = createDisplay(iter.configs, iter.activeConfigId);
+ for (const auto& iter : displays) {
+ error = createDisplay(iter.displayId, iter.activeConfigId, iter.configs);
if (error != HWC2::Error::None) {
ALOGE("%s failed to create display from config", __FUNCTION__);
return error;
@@ -117,8 +116,9 @@ HWC2::Error Device::createDisplays() {
return HWC2::Error::None;
}
-HWC2::Error Device::createDisplay(const std::vector<DisplayConfig>& configs,
- int activeConfig) {
+HWC2::Error Device::createDisplay(hwc2_display_t displayId,
+ hwc2_config_t activeConfigId,
+ const std::vector<DisplayConfig>& configs) {
DEBUG_LOG("%s", __FUNCTION__);
if (!mComposer) {
@@ -126,23 +126,21 @@ HWC2::Error Device::createDisplay(const std::vector<DisplayConfig>& configs,
return HWC2::Error::NoResources;
}
- uint32_t displayId = configs[0].id;
- auto display = std::make_unique<Display>(*this, mComposer.get(),
- displayId);
+ auto display = std::make_unique<Display>(mComposer.get(), displayId);
if (display == nullptr) {
ALOGE("%s failed to allocate display", __FUNCTION__);
return HWC2::Error::NoResources;
}
- HWC2::Error error = display->init(configs, activeConfig);
+ HWC2::Error error = display->init(configs, activeConfigId);
if (error != HWC2::Error::None) {
- ALOGE("%s failed to initialize display:%" PRIu32, __FUNCTION__, displayId);
+ ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__, displayId);
return error;
}
error = mComposer->onDisplayCreate(display.get());
if (error != HWC2::Error::None) {
- ALOGE("%s failed to register display:%" PRIu32 " with composer",
+ ALOGE("%s failed to register display:%" PRIu64 " with composer",
__FUNCTION__, displayId);
return error;
}
@@ -354,6 +352,33 @@ hwc2_function_pointer_t Device::getFunction(int32_t desc) {
return asFP<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
displayHook<decltype(&Display::setDisplayBrightness),
&Display::setDisplayBrightness, float>);
+ case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod:
+ return asFP<HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD>(
+ displayHook<decltype(&Display::getDisplayVsyncPeriod),
+ &Display::getDisplayVsyncPeriod, hwc2_vsync_period_t*>);
+ case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS>(
+ displayHook<decltype(&Display::setActiveConfigWithConstraints),
+ &Display::setActiveConfigWithConstraints, hwc2_config_t,
+ hwc_vsync_period_change_constraints_t*,
+ hwc_vsync_period_change_timeline_t*>);
+ case HWC2::FunctionDescriptor::GetDisplayConnectionType:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>(
+ displayHook<decltype(&Display::getDisplayConnectionType),
+ &Display::getDisplayConnectionType, uint32_t*>);
+ case HWC2::FunctionDescriptor::SetAutoLowLatencyMode:
+ return asFP<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>(
+ displayHook<decltype(&Display::setAutoLowLatencyMode),
+ &Display::setAutoLowLatencyMode, bool>);
+ case HWC2::FunctionDescriptor::GetSupportedContentTypes:
+ return asFP<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>(
+ displayHook<decltype(&Display::getSupportedContentTypes),
+ &Display::getSupportedContentTypes, uint32_t*,
+ uint32_t*>);
+ case HWC2::FunctionDescriptor::SetContentType:
+ return asFP<HWC2_PFN_SET_CONTENT_TYPE>(
+ displayHook<decltype(&Display::setContentType),
+ &Display::setContentType, int32_t>);
// Layer functions
case HWC2::FunctionDescriptor::SetCursorPosition:
@@ -455,64 +480,50 @@ uint32_t Device::getMaxVirtualDisplayCount() {
return 0;
}
-static bool IsHandledCallback(HWC2::Callback descriptor) {
- switch (descriptor) {
- case HWC2::Callback::Hotplug: {
- return true;
- }
- case HWC2::Callback::Refresh: {
- return true;
- }
- case HWC2::Callback::Vsync: {
- return true;
- }
- case HWC2::Callback::Vsync_2_4: {
- return false;
- }
- case HWC2::Callback::VsyncPeriodTimingChanged: {
- return false;
- }
- case HWC2::Callback::Invalid: {
- return false;
- }
- case HWC2::Callback::SeamlessPossible: {
- return false;
- }
- }
- return false;
-}
-
HWC2::Error Device::registerCallback(int32_t desc,
hwc2_callback_data_t callbackData,
- hwc2_function_pointer_t pointer) {
+ hwc2_function_pointer_t callbackPointer) {
const auto callbackType = static_cast<HWC2::Callback>(desc);
const auto callbackTypeString = to_string(callbackType);
DEBUG_LOG("%s callback %s", __FUNCTION__, callbackTypeString.c_str());
- if (!IsHandledCallback(callbackType)) {
- ALOGE("%s unhandled callback: %s", __FUNCTION__,
- callbackTypeString.c_str());
- return HWC2::Error::BadParameter;
- }
-
std::unique_lock<std::mutex> lock(mStateMutex);
- if (pointer != nullptr) {
- mCallbacks[callbackType] = {callbackData, pointer};
+ if (callbackPointer != nullptr) {
+ mCallbacks[callbackType] = {callbackData, callbackPointer};
} else {
mCallbacks.erase(callbackType);
- return HWC2::Error::None;
}
- if (callbackType == HWC2::Callback::Hotplug) {
+ if (callbackType == HWC2::Callback::Vsync) {
+ auto callback = reinterpret_cast<HWC2_PFN_VSYNC>(callbackPointer);
+ for (const auto& [displayId, display] : mDisplays) {
+ display->setVsyncCallback(callback, callbackData);
+ }
+ } else if (callbackType == HWC2::Callback::Vsync_2_4) {
+ auto callback = reinterpret_cast<HWC2_PFN_VSYNC_2_4>(callbackPointer);
+ for (const auto& [displayId, display] : mDisplays) {
+ display->setVsync24Callback(callback, callbackData);
+ }
+ } else if (callbackType == HWC2::Callback::Hotplug) {
+ if (callbackPointer == nullptr) {
+ return HWC2::Error::None;
+ }
+
// Callback without the state lock held
lock.unlock();
- auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackPointer);
auto hotplugConnect = static_cast<int32_t>(HWC2::Connection::Connected);
for (const auto& [displayId, display] : mDisplays) {
ALOGI("%s hotplug connecting display:%" PRIu64, __FUNCTION__, displayId);
hotplug(callbackData, displayId, hotplugConnect);
}
+ } else if (callbackType == HWC2::Callback::Refresh) {
+ // Not used
+ } else {
+ ALOGE("%s unhandled callback: %s", __FUNCTION__,
+ callbackTypeString.c_str());
+ return HWC2::Error::BadParameter;
}
return HWC2::Error::None;
@@ -539,11 +550,13 @@ bool Device::handleHotplug(bool connected, uint32_t id, uint32_t width,
display->unlock();
}
if (connected) {
- std::vector<DisplayConfig> config;
- config.push_back({static_cast<int>(id), static_cast<int>(width),
+ hwc2_display_t displayId = static_cast<hwc2_display_t>(id);
+ hwc2_config_t configId = static_cast<hwc2_config_t>(id);
+ std::vector<DisplayConfig> configs = {
+ DisplayConfig(configId, static_cast<int>(width),
static_cast<int>(height), static_cast<int>(dpiX),
- static_cast<int>(dpiY), static_cast<int>(refreshRate)});
- createDisplay(config, 0);
+ static_cast<int>(dpiY), static_cast<int>(refreshRate))};
+ createDisplay(displayId, configId, configs);
ALOGD("callback hotplugConnect display %" PRIu32 " width %" PRIu32
" height %" PRIu32 " dpiX %" PRIu32 " dpiY %" PRIu32 "fps %" PRIu32,
id, width, height, dpiX, dpiY, refreshRate);
@@ -598,7 +611,7 @@ static struct hw_module_methods_t hwc2_module_methods = {
hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 2,
- .version_minor = 3,
+ .version_minor = 4,
.id = HWC_HARDWARE_MODULE_ID,
.name = "goldfish HWC2 module",
.author = "The Android Open Source Project",
diff --git a/system/hwc2/Device.h b/system/hwc2/Device.h
index b49d1a0f..812d5e9b 100644
--- a/system/hwc2/Device.h
+++ b/system/hwc2/Device.h
@@ -53,8 +53,9 @@ class Device : public hwc2_device_t {
HWC2::Error createDisplays();
- HWC2::Error createDisplay(const std::vector<DisplayConfig>& configs,
- int activeConfig);
+ HWC2::Error createDisplay(hwc2_display_t displayId,
+ hwc2_config_t activeConfigId,
+ const std::vector<DisplayConfig>& configs);
Display* getDisplay(hwc2_display_t displayId);
diff --git a/system/hwc2/Display.cpp b/system/hwc2/Display.cpp
index b373ca9c..9d754cba 100644
--- a/system/hwc2/Display.cpp
+++ b/system/hwc2/Display.cpp
@@ -30,8 +30,6 @@ namespace {
using android::hardware::graphics::common::V1_0::ColorTransform;
-std::atomic<hwc2_config_t> sNextConfigId{0};
-
bool IsValidColorMode(android_color_mode_t mode) {
switch (mode) {
case HAL_COLOR_MODE_NATIVE: // Fall-through
@@ -64,46 +62,37 @@ bool isValidPowerMode(HWC2::PowerMode mode) {
} // namespace
-Display::Display(Device& device, Composer* composer, hwc2_display_t id)
- : mDevice(device),
- mComposer(composer),
- mId(id),
- mVsyncThread(new VsyncThread(*this)) {}
+Display::Display(Composer* composer, hwc2_display_t id)
+ : mComposer(composer), mId(id), mVsyncThread(new VsyncThread(id)) {}
Display::~Display() {}
HWC2::Error Display::init(const std::vector<DisplayConfig>& configs,
- int activeConfig,
+ hwc2_config_t activeConfigId,
const std::optional<std::vector<uint8_t>>& edid) {
- ALOGD("%s initializing display:%" PRIu64
- " width:%d height:%d dpiX:%d dpiY:%d refreshRateHz:%d",
- __FUNCTION__, mId, configs[activeConfig].width,
- configs[activeConfig].height,
- configs[activeConfig].dpiX,
- configs[activeConfig].dpiY,
- configs[activeConfig].refreshRateHz);
-
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
- mVsyncPeriod = 1000 * 1000 * 1000 / configs[activeConfig].refreshRateHz;
- mVsyncThread->run("", ANDROID_PRIORITY_URGENT_DISPLAY);
-
- for (hwc2_config_t id = 0; id < configs.size(); id++) {
- Config config(id);
- config.setAttribute(HWC2::Attribute::VsyncPeriod,
- 1000 * 1000 * 1000 / configs[id].refreshRateHz);
- config.setAttribute(HWC2::Attribute::Width, configs[id].width);
- config.setAttribute(HWC2::Attribute::Height, configs[id].height);
- config.setAttribute(HWC2::Attribute::DpiX, configs[id].dpiX * 1000);
- config.setAttribute(HWC2::Attribute::DpiY, configs[id].dpiY * 1000);
- mConfigs.emplace(id, config);
+ for (const DisplayConfig& config : configs) {
+ mConfigs.emplace(config.getId(), config);
}
- mActiveConfigId = activeConfig;
- mActiveColorMode = HAL_COLOR_MODE_NATIVE;
- mColorModes.emplace((android_color_mode_t)HAL_COLOR_MODE_NATIVE);
+ mActiveConfigId = activeConfigId;
mEdid = edid;
+ auto it = mConfigs.find(activeConfigId);
+ if (it == mConfigs.end()) {
+ ALOGE("%s: display:%" PRIu64 "missing config:%" PRIu32, __FUNCTION__, mId,
+ activeConfigId);
+ return HWC2::Error::NoResources;
+ }
+
+ const auto& activeConfig = it->second;
+ const auto activeConfigString = activeConfig.toString();
+ ALOGD("%s initializing display:%" PRIu64 " with config:%s", __FUNCTION__, mId,
+ activeConfigString.c_str());
+
+ mVsyncThread->start(activeConfig.getVsyncPeriod());
+
return HWC2::Error::None;
}
@@ -116,14 +105,13 @@ HWC2::Error Display::updateParameters(
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
- mVsyncPeriod = 1000 * 1000 * 1000 / refreshRateHz;
-
auto it = mConfigs.find(*mActiveConfigId);
if (it == mConfigs.end()) {
ALOGE("%s: failed to find config %" PRIu32, __func__, *mActiveConfigId);
return HWC2::Error::NoResources;
}
- it->second.setAttribute(HWC2::Attribute::VsyncPeriod, mVsyncPeriod);
+ it->second.setAttribute(HWC2::Attribute::VsyncPeriod,
+ 1000 * 1000 * 1000 / refreshRateHz);
it->second.setAttribute(HWC2::Attribute::Width, width);
it->second.setAttribute(HWC2::Attribute::Height, height);
it->second.setAttribute(HWC2::Attribute::DpiX, dpiX * 1000);
@@ -256,7 +244,7 @@ HWC2::Error Display::getDisplayAttributeEnum(hwc2_config_t configId,
return HWC2::Error::BadConfig;
}
- const Config& config = it->second;
+ const DisplayConfig& config = it->second;
*outValue = config.getAttribute(attribute);
DEBUG_LOG("%s: display:%" PRIu64 " attribute:%s value is %" PRIi32,
__FUNCTION__, mId, attributeString.c_str(), *outValue);
@@ -506,23 +494,11 @@ HWC2::Error Display::setActiveConfig(hwc2_config_t configId) {
DEBUG_LOG("%s: display:%" PRIu64 " setting active config to %" PRIu32,
__FUNCTION__, mId, configId);
- std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
- if (mConfigs.find(configId) == mConfigs.end()) {
- ALOGE("%s: display:%" PRIu64 " bad config:%" PRIu32, __FUNCTION__, mId,
- configId);
- return HWC2::Error::BadConfig;
- }
-
- if (mActiveConfigId != configId) {
- if (mComposer == nullptr) {
- ALOGE("%s: display:%" PRIu64 " missing composer", __FUNCTION__, mId);
- return HWC2::Error::NoResources;
- }
- mActiveConfigId = configId;
- return mComposer->onActiveConfigChange(this);
- }
- return HWC2::Error::None;
+ hwc_vsync_period_change_constraints_t constraints;
+ constraints.desiredTimeNanos = 0;
+ constraints.seamlessRequired = false;
+ hwc_vsync_period_change_timeline_t timeline;
+ return setActiveConfigWithConstraints(configId, &constraints, &timeline);
}
HWC2::Error Display::setClientTarget(buffer_handle_t target,
@@ -623,8 +599,8 @@ HWC2::Error Display::setPowerMode(int32_t intMode) {
if (IsCuttlefish()) {
if (int fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC); fd != -1) {
std::ostringstream stream;
- stream << "VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED display="
- << mId << " mode=" << modeString;
+ stream << "VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED display=" << mId
+ << " mode=" << modeString;
std::string message = stream.str();
write(fd, message.c_str(), message.length());
close(fd);
@@ -646,10 +622,48 @@ HWC2::Error Display::setVsyncEnabled(int32_t intEnable) {
}
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
- DEBUG_LOG("%s: display:%" PRIu64 " setting vsync locked to %s", __FUNCTION__,
- mId, enableString.c_str());
+ return mVsyncThread->setVsyncEnabled(enable == HWC2::Vsync::Enable);
+}
+
+HWC2::Error Display::setVsyncCallback(HWC2_PFN_VSYNC callback,
+ hwc2_callback_data_t data) {
+ DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, mId);
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ return mVsyncThread->setVsyncCallback(callback, data);
+}
+
+HWC2::Error Display::setVsync24Callback(HWC2_PFN_VSYNC_2_4 callback,
+ hwc2_callback_data_t data) {
+ DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, mId);
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ return mVsyncThread->setVsync24Callback(callback, data);
+}
+
+HWC2::Error Display::getDisplayVsyncPeriod(
+ hwc2_vsync_period_t* outVsyncPeriod) {
+ DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, mId);
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
- mVsyncEnabled = enable;
+ if (!mActiveConfigId) {
+ ALOGE("%s : display:%" PRIu64 " no active config", __FUNCTION__, mId);
+ return HWC2::Error::BadConfig;
+ }
+
+ const auto it = mConfigs.find(*mActiveConfigId);
+ if (it == mConfigs.end()) {
+ ALOGE("%s : display:%" PRIu64 " failed to find active config:%" PRIu32,
+ __FUNCTION__, mId, *mActiveConfigId);
+ return HWC2::Error::BadConfig;
+ }
+ const DisplayConfig& activeConfig = it->second;
+
+ *outVsyncPeriod = static_cast<hwc2_vsync_period_t>(
+ activeConfig.getAttribute(HWC2::Attribute::VsyncPeriod));
return HWC2::Error::None;
}
@@ -735,7 +749,7 @@ HWC2::Error Display::getClientTargetSupport(uint32_t width, uint32_t height,
return HWC2::Error::Unsupported;
}
- const Config& activeConfig = it->second;
+ const DisplayConfig& activeConfig = it->second;
const uint32_t activeConfigWidth =
static_cast<uint32_t>(activeConfig.getAttribute(HWC2::Attribute::Width));
const uint32_t activeConfigHeight =
@@ -914,123 +928,95 @@ HWC2::Error Display::setDisplayBrightness(float brightness) {
return HWC2::Error::Unsupported;
}
-void Display::Config::setAttribute(HWC2::Attribute attribute, int32_t value) {
- mAttributes[attribute] = value;
-}
+HWC2::Error Display::setActiveConfigWithConstraints(
+ hwc2_config_t configId,
+ hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints,
+ hwc_vsync_period_change_timeline_t* outTimeline) {
+ DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, mId);
-int32_t Display::Config::getAttribute(HWC2::Attribute attribute) const {
- if (mAttributes.count(attribute) == 0) {
- return -1;
- }
- return mAttributes.at(attribute);
-}
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-std::string Display::Config::toString() const {
- std::string output;
+ if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
+ return HWC2::Error::BadParameter;
+ }
- auto widthIt = mAttributes.find(HWC2::Attribute::Width);
- if (widthIt != mAttributes.end()) {
- output += " w:" + std::to_string(widthIt->second);
+ if (mConfigs.find(configId) == mConfigs.end()) {
+ ALOGE("%s: display:%" PRIu64 " bad config:%" PRIu32, __FUNCTION__, mId,
+ configId);
+ return HWC2::Error::BadConfig;
}
- auto heightIt = mAttributes.find(HWC2::Attribute::Height);
- if (heightIt != mAttributes.end()) {
- output += " h:" + std::to_string(heightIt->second);
+ if (mActiveConfigId == configId) {
+ return HWC2::Error::None;
}
+ mActiveConfigId = configId;
- auto vsyncIt = mAttributes.find(HWC2::Attribute::VsyncPeriod);
- if (vsyncIt != mAttributes.end()) {
- output += " vsync:" + std::to_string(1e9 / vsyncIt->second);
+ if (mComposer == nullptr) {
+ ALOGE("%s: display:%" PRIu64 " missing composer", __FUNCTION__, mId);
+ return HWC2::Error::NoResources;
}
- auto dpiXIt = mAttributes.find(HWC2::Attribute::DpiX);
- if (dpiXIt != mAttributes.end()) {
- output += " dpi-x:" + std::to_string(dpiXIt->second / 1000.0f);
+ HWC2::Error error = mComposer->onActiveConfigChange(this);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s: display:%" PRIu64 " composer failed to handle config change",
+ __FUNCTION__, mId);
+ return error;
}
- auto dpiYIt = mAttributes.find(HWC2::Attribute::DpiY);
- if (dpiYIt != mAttributes.end()) {
- output += " dpi-y:" + std::to_string(dpiYIt->second / 1000.0f);
+ hwc2_vsync_period_t vsyncPeriod;
+ error = getDisplayVsyncPeriod(&vsyncPeriod);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s: display:%" PRIu64 " composer failed to handle config change",
+ __FUNCTION__, mId);
+ return error;
}
- return output;
+ return mVsyncThread->scheduleVsyncUpdate(
+ vsyncPeriod, vsyncPeriodChangeConstraints, outTimeline);
}
-// VsyncThread function
-bool Display::VsyncThread::threadLoop() {
- struct timespec rt;
- if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
- ALOGE("%s: error in vsync thread clock_gettime: %s", __FUNCTION__,
- strerror(errno));
- return true;
+HWC2::Error Display::getDisplayConnectionType(uint32_t* outType) {
+ if (IsCuttlefishFoldable()) {
+ // Workaround to force all displays to INTERNAL for cf_x86_64_foldable.
+ // TODO(b/193568008): Allow configuring internal/external per display.
+ *outType = HWC2_DISPLAY_CONNECTION_TYPE_INTERNAL;
+ } else {
+ // Other devices default to the first display INTERNAL, others EXTERNAL.
+ *outType = mId == 0 ? HWC2_DISPLAY_CONNECTION_TYPE_INTERNAL
+ : HWC2_DISPLAY_CONNECTION_TYPE_EXTERNAL;
}
- const int logInterval = 60;
- int64_t lastLogged = rt.tv_sec;
- int sent = 0;
- int lastSent = 0;
- bool vsyncEnabled = false;
-
- struct timespec wait_time;
- wait_time.tv_sec = 0;
- wait_time.tv_nsec = mDisplay.mVsyncPeriod;
- const int64_t kOneRefreshNs = mDisplay.mVsyncPeriod;
- const int64_t kOneSecondNs = 1000ULL * 1000ULL * 1000ULL;
- int64_t lastTimeNs = -1;
- int64_t phasedWaitNs = 0;
- int64_t currentNs = 0;
-
- while (true) {
- clock_gettime(CLOCK_MONOTONIC, &rt);
- currentNs = rt.tv_nsec + rt.tv_sec * kOneSecondNs;
-
- if (lastTimeNs < 0) {
- phasedWaitNs = currentNs + kOneRefreshNs;
- } else {
- phasedWaitNs =
- kOneRefreshNs * ((currentNs - lastTimeNs) / kOneRefreshNs + 1) +
- lastTimeNs;
- }
-
- wait_time.tv_sec = phasedWaitNs / kOneSecondNs;
- wait_time.tv_nsec = phasedWaitNs - wait_time.tv_sec * kOneSecondNs;
+ return HWC2::Error::None;
+}
- int ret;
- do {
- ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wait_time, NULL);
- } while (ret == -1 && errno == EINTR);
+HWC2::Error Display::setAutoLowLatencyMode(bool /*on*/) {
+ DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, mId);
- lastTimeNs = phasedWaitNs;
+ return HWC2::Error::Unsupported;
+}
- std::unique_lock<std::recursive_mutex> lock(mDisplay.mStateMutex);
- vsyncEnabled = (mDisplay.mVsyncEnabled == HWC2::Vsync::Enable);
- lock.unlock();
+HWC2::Error Display::getSupportedContentTypes(
+ uint32_t* outNumSupportedContentTypes,
+ const uint32_t* /*outSupportedContentTypes*/) {
+ DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, mId);
- if (!vsyncEnabled) {
- continue;
- }
+ if (outNumSupportedContentTypes != nullptr) {
+ *outNumSupportedContentTypes = 0;
+ }
- lock.lock();
- const auto& callbackInfo =
- mDisplay.mDevice.mCallbacks[HWC2::Callback::Vsync];
- auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
- lock.unlock();
+ return HWC2::Error::None;
+}
- if (vsync) {
- DEBUG_LOG("%s: display:%" PRIu64 " calling vsync", __FUNCTION__,
- mDisplay.mId);
- vsync(callbackInfo.data, mDisplay.mId, lastTimeNs);
- }
+HWC2::Error Display::setContentType(int32_t contentTypeRaw) {
+ auto contentType = static_cast<HWC2::ContentType>(contentTypeRaw);
+ auto contentTypeString = to_string(contentType);
+ DEBUG_LOG("%s: display:%" PRIu64 " content type:%s", __FUNCTION__, mId,
+ contentTypeString.c_str());
- int64_t lastSentInterval = rt.tv_sec - lastLogged;
- if (lastSentInterval >= logInterval) {
- DEBUG_LOG("sent %d syncs in %" PRId64 "s", sent - lastSent,
- lastSentInterval);
- lastLogged = rt.tv_sec;
- lastSent = sent;
- }
- ++sent;
+ if (contentType != HWC2::ContentType::None) {
+ return HWC2::Error::Unsupported;
}
- return false;
+
+ return HWC2::Error::None;
}
} // namespace android
diff --git a/system/hwc2/Display.h b/system/hwc2/Display.h
index 47291c7e..65c20a3b 100644
--- a/system/hwc2/Display.h
+++ b/system/hwc2/Display.h
@@ -18,9 +18,9 @@
#define ANDROID_HWC_DISPLAY_H
#include <android/hardware/graphics/common/1.0/types.h>
-#include <utils/Thread.h>
#include <array>
+#include <mutex>
#include <optional>
#include <set>
#include <thread>
@@ -29,9 +29,11 @@
#include "Common.h"
#include "Composer.h"
+#include "DisplayConfig.h"
#include "DisplayFinder.h"
#include "FencedBuffer.h"
#include "Layer.h"
+#include "VsyncThread.h"
namespace android {
@@ -45,7 +47,7 @@ struct ColorTransformWithMatrix {
class Display {
public:
- Display(Device& device, Composer* composer, hwc2_display_t id);
+ Display(Composer* composer, hwc2_display_t id);
~Display();
Display(const Display& display) = delete;
@@ -54,7 +56,8 @@ class Display {
Display(Display&& display) = delete;
Display& operator=(Display&& display) = delete;
- HWC2::Error init(const std::vector<DisplayConfig>& configs, int activeConfig,
+ HWC2::Error init(
+ const std::vector<DisplayConfig>& configs, hwc2_config_t activeConfigId,
const std::optional<std::vector<uint8_t>>& edid = std::nullopt);
HWC2::Error updateParameters(
@@ -116,6 +119,17 @@ class Display {
HWC2::Error setOutputBuffer(buffer_handle_t buffer, int32_t releaseFence);
HWC2::Error setPowerMode(int32_t mode);
HWC2::Error setVsyncEnabled(int32_t enabled);
+ HWC2::Error setVsyncCallback(HWC2_PFN_VSYNC callback,
+ hwc2_callback_data_t data);
+ HWC2::Error setVsync24Callback(HWC2_PFN_VSYNC_2_4 callback,
+ hwc2_callback_data_t data);
+ HWC2::Error getDisplayVsyncPeriod(hwc2_vsync_period_t* outVsyncPeriod);
+ HWC2::Error setActiveConfigWithConstraints(
+ hwc2_config_t config,
+ hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints,
+ hwc_vsync_period_change_timeline_t* timeline);
+ HWC2::Error getDisplayConnectionType(uint32_t* outType);
+
HWC2::Error validate(uint32_t* outNumTypes, uint32_t* outNumRequests);
HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
@@ -128,33 +142,15 @@ class Display {
uint32_t* outCapabilities);
HWC2::Error getDisplayBrightnessSupport(bool* out_support);
HWC2::Error setDisplayBrightness(float brightness);
+ HWC2::Error setAutoLowLatencyMode(bool on);
+ HWC2::Error getSupportedContentTypes(
+ uint32_t* outNumSupportedContentTypes,
+ const uint32_t* outSupportedContentTypes);
+ HWC2::Error setContentType(int32_t contentType);
void lock() { mStateMutex.lock(); }
void unlock() { mStateMutex.unlock(); }
private:
- class Config {
- public:
- Config(hwc2_config_t configId) : mId(configId) {}
-
- Config(const Config& display) = default;
- Config& operator=(const Config& display) = default;
-
- Config(Config&& display) = default;
- Config& operator=(Config&& display) = default;
-
- hwc2_config_t getId() const { return mId; }
- void setId(hwc2_config_t id) { mId = id; }
-
- int32_t getAttribute(HWC2::Attribute attribute) const;
- void setAttribute(HWC2::Attribute attribute, int32_t value);
-
- std::string toString() const;
-
- private:
- hwc2_config_t mId;
- std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
- };
-
// Stores changes requested from the device upon calling prepare().
// Handles change request to:
// - Layer composition type.
@@ -194,23 +190,6 @@ class Display {
std::unordered_map<hwc2_layer_t, HWC2::LayerRequest> mLayerRequests;
};
- // Generate sw vsync signal
- class VsyncThread : public Thread {
- public:
- VsyncThread(Display& display) : mDisplay(display) {}
- virtual ~VsyncThread() {}
-
- VsyncThread(const VsyncThread&) = default;
- VsyncThread& operator=(const VsyncThread&) = default;
-
- VsyncThread(VsyncThread&&) = default;
- VsyncThread& operator=(VsyncThread&&) = default;
-
- private:
- Display& mDisplay;
- bool threadLoop() final;
- };
-
private:
// The state of this display should only be modified from
// SurfaceFlinger's main loop, with the exception of when dump is
@@ -218,14 +197,11 @@ class Display {
// call, all public calls into Display must acquire this mutex.
mutable std::recursive_mutex mStateMutex;
- Device& mDevice;
Composer* mComposer = nullptr;
const hwc2_display_t mId;
std::string mName;
HWC2::DisplayType mType = HWC2::DisplayType::Physical;
HWC2::PowerMode mPowerMode = HWC2::PowerMode::Off;
- HWC2::Vsync mVsyncEnabled = HWC2::Vsync::Invalid;
- uint32_t mVsyncPeriod;
sp<VsyncThread> mVsyncThread;
FencedBuffer mClientTarget;
// Will only be non-null after the Display has been validated and
@@ -239,9 +215,9 @@ class Display {
std::vector<hwc2_display_t> mReleaseLayerIds;
std::vector<int32_t> mReleaseFences;
std::optional<hwc2_config_t> mActiveConfigId;
- std::unordered_map<hwc2_config_t, Config> mConfigs;
- std::set<android_color_mode_t> mColorModes;
- android_color_mode_t mActiveColorMode;
+ std::unordered_map<hwc2_config_t, DisplayConfig> mConfigs;
+ std::set<android_color_mode_t> mColorModes = {HAL_COLOR_MODE_NATIVE};
+ android_color_mode_t mActiveColorMode = HAL_COLOR_MODE_NATIVE;
std::optional<ColorTransformWithMatrix> mColorTransform;
std::optional<std::vector<uint8_t>> mEdid;
};
diff --git a/system/hwc2/DisplayConfig.cpp b/system/hwc2/DisplayConfig.cpp
new file mode 100644
index 00000000..b05f9076
--- /dev/null
+++ b/system/hwc2/DisplayConfig.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DisplayConfig.h"
+
+#include <unordered_map>
+
+namespace {
+
+template <class T>
+inline void hashCombine(size_t& hash, const T& value) {
+ std::hash<T> hasher;
+ hash ^= hasher(value) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
+}
+
+} // namespace
+
+void DisplayConfig::setAttribute(HWC2::Attribute attribute, int32_t value) {
+ if (attribute == HWC2::Attribute::Width) {
+ mWidth = value;
+ }
+ if (attribute == HWC2::Attribute::Height) {
+ mHeight = value;
+ }
+ if (attribute == HWC2::Attribute::DpiX) {
+ mDpiX = value;
+ }
+ if (attribute == HWC2::Attribute::DpiY) {
+ mDpiY = value;
+ }
+ if (attribute == HWC2::Attribute::VsyncPeriod) {
+ mVsyncPeriodNanos = value;
+ }
+ if (attribute == HWC2::Attribute::ConfigGroup) {
+ mConfigGroup = value;
+ }
+}
+
+int32_t DisplayConfig::getAttribute(HWC2::Attribute attribute) const {
+ if (attribute == HWC2::Attribute::Width) {
+ return mWidth;
+ }
+ if (attribute == HWC2::Attribute::Height) {
+ return mHeight;
+ }
+ if (attribute == HWC2::Attribute::DpiX) {
+ return mDpiX;
+ }
+ if (attribute == HWC2::Attribute::DpiY) {
+ return mDpiY;
+ }
+ if (attribute == HWC2::Attribute::VsyncPeriod) {
+ return mVsyncPeriodNanos;
+ }
+ if (attribute == HWC2::Attribute::ConfigGroup) {
+ return mConfigGroup;
+ }
+ return -1;
+}
+
+std::string DisplayConfig::toString() const {
+ std::string output;
+ output += " w:" + std::to_string(mWidth);
+ output += " h:" + std::to_string(mHeight);
+ output += " dpi-x:" + std::to_string(mDpiX / 1000.0f);
+ output += " dpi-y:" + std::to_string(mDpiY / 1000.0f);
+ output += " vsync:" + std::to_string(1e9 / mVsyncPeriodNanos);
+ output += " config-group:" + std::to_string(mConfigGroup);
+ return output;
+}
+
+/*static*/
+void DisplayConfig::addConfigGroups(std::vector<DisplayConfig>* configs) {
+ // From /hardware/interfaces/graphics/composer/2.4/IComposerClient.hal:
+ // "Configurations which share the same config group are similar in all
+ // attributes except for the vsync period."
+ struct ConfigForGroupHash {
+ size_t operator()(const DisplayConfig& config) const {
+ size_t hash = 0;
+ hashCombine(hash, config.mWidth);
+ hashCombine(hash, config.mHeight);
+ hashCombine(hash, config.mDpiX);
+ hashCombine(hash, config.mDpiY);
+ return hash;
+ }
+ };
+ struct ConfigForGroupEq {
+ size_t operator()(const DisplayConfig& a, const DisplayConfig& b) const {
+ if (a.mWidth != b.mWidth) {
+ return a.mWidth < b.mWidth;
+ }
+ if (a.mHeight != b.mHeight) {
+ return a.mHeight < b.mHeight;
+ }
+ if (a.mDpiX != b.mDpiX) {
+ return a.mDpiX < b.mDpiX;
+ }
+ return a.mDpiY < b.mDpiY;
+ }
+ };
+
+ std::unordered_map<DisplayConfig, int32_t, ConfigForGroupHash,
+ ConfigForGroupEq>
+ configToConfigGroup;
+
+ for (auto& config : *configs) {
+ auto [it, inserted] =
+ configToConfigGroup.try_emplace(config, configToConfigGroup.size());
+ config.setConfigGroup(it->second);
+ }
+} \ No newline at end of file
diff --git a/system/hwc2/DisplayConfig.h b/system/hwc2/DisplayConfig.h
new file mode 100644
index 00000000..f7502d70
--- /dev/null
+++ b/system/hwc2/DisplayConfig.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC_DISPLAYCONFIG_H
+#define ANDROID_HWC_DISPLAYCONFIG_H
+
+#include <android/hardware/graphics/common/1.0/types.h>
+
+#include <vector>
+
+#include "Common.h"
+
+class DisplayConfig {
+ public:
+ DisplayConfig(hwc2_config_t configId) : mId(configId) {}
+
+ DisplayConfig(hwc2_config_t configId, int32_t width, int32_t height,
+ int32_t dpiX, int32_t dpiY, int32_t vsyncPeriodNanos)
+ : mId(configId),
+ mWidth(width),
+ mHeight(height),
+ mDpiX(dpiX),
+ mDpiY(dpiY),
+ mVsyncPeriodNanos(vsyncPeriodNanos) {}
+
+ DisplayConfig(const DisplayConfig& other) = default;
+ DisplayConfig& operator=(DisplayConfig& other) = default;
+
+ DisplayConfig(DisplayConfig&& other) = default;
+ DisplayConfig& operator=(DisplayConfig&& other) = default;
+
+ hwc2_config_t getId() const { return mId; }
+ void setId(hwc2_config_t id) { mId = id; }
+
+ int32_t getAttribute(HWC2::Attribute attribute) const;
+ void setAttribute(HWC2::Attribute attribute, int32_t value);
+
+ int32_t getWidth() const { return mWidth; }
+ void setWidth(int32_t width) { mWidth = width; }
+
+ int32_t getHeight() const { return mHeight; }
+ void getHeight(int32_t height) { mHeight = height; }
+
+ int32_t getDpiX() const { return mDpiX; }
+ void setDpiX(int32_t dpi) { mDpiX = dpi; }
+
+ int32_t getDpiY() const { return mDpiY; }
+ void setDpiY(int32_t dpi) { mDpiY = dpi; }
+
+ int32_t getVsyncPeriod() const { return mVsyncPeriodNanos; }
+ void setVsyncPeriod(int32_t vsync) { mVsyncPeriodNanos = vsync; }
+
+ int32_t getConfigGroup() const { return mConfigGroup; }
+ void setConfigGroup(int32_t group) { mConfigGroup = group; }
+
+ std::string toString() const;
+
+ static void addConfigGroups(std::vector<DisplayConfig>* configs);
+
+ private:
+ hwc2_config_t mId;
+
+ int32_t mWidth;
+ int32_t mHeight;
+ int32_t mDpiX;
+ int32_t mDpiY;
+ int32_t mVsyncPeriodNanos;
+ int32_t mConfigGroup;
+};
+
+#endif \ No newline at end of file
diff --git a/system/hwc2/DisplayFinder.cpp b/system/hwc2/DisplayFinder.cpp
index 87a93f35..2a5655c6 100644
--- a/system/hwc2/DisplayFinder.cpp
+++ b/system/hwc2/DisplayFinder.cpp
@@ -27,25 +27,36 @@
namespace android {
namespace {
+constexpr int32_t HertzToPeriodNanos(uint32_t hertz) {
+ return 1000 * 1000 * 1000 / hertz;
+}
+
HWC2::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>& displays) {
DEBUG_LOG("%s", __FUNCTION__);
// TODO: replace with initializing directly from DRM info.
const auto deviceConfig = cuttlefish::GetDeviceConfig();
- int displayId = 0;
+ hwc2_display_t displayId = 0;
+ hwc2_config_t configId = 0;
for (const auto& deviceDisplayConfig : deviceConfig.display_config()) {
DisplayMultiConfigs display = {
- .id = displayId,
- .activeConfigId = 0,
- .configs = {{displayId,
- deviceDisplayConfig.width(),
- deviceDisplayConfig.height(),
- deviceDisplayConfig.dpi(),
- deviceDisplayConfig.dpi(),
- deviceDisplayConfig.refresh_rate_hz()}},
+ .displayId = displayId,
+ .activeConfigId = configId,
+ .configs =
+ {
+ DisplayConfig(configId, //
+ deviceDisplayConfig.width(), //
+ deviceDisplayConfig.height(), //
+ deviceDisplayConfig.dpi(), //
+ deviceDisplayConfig.dpi(), //
+ HertzToPeriodNanos(
+ deviceDisplayConfig.refresh_rate_hz()) //
+ ), //
+ },
};
displays.push_back(display);
+ ++configId;
++displayId;
}
@@ -68,45 +79,43 @@ static int getVsyncHzFromProperty() {
return static_cast<int>(vsyncPeriod);
}
-HWC2::Error findGoldfishPrimaryDisplay(std::vector<DisplayMultiConfigs>& displays) {
+HWC2::Error findGoldfishPrimaryDisplay(
+ std::vector<DisplayMultiConfigs>& displays) {
DEBUG_LOG("%s", __FUNCTION__);
DEFINE_AND_VALIDATE_HOST_CONNECTION
hostCon->lock();
- int activeConfigId;
- const int refreshRateHz = getVsyncHzFromProperty();
+ const int32_t vsyncPeriodNanos = HertzToPeriodNanos(getVsyncHzFromProperty());
DisplayMultiConfigs display;
- display.id = 0;
+ display.displayId = 0;
if (rcEnc->hasHWCMultiConfigs()) {
- int count= rcEnc->rcGetFBDisplayConfigsCount(rcEnc);
+ int count = rcEnc->rcGetFBDisplayConfigsCount(rcEnc);
if (count <= 0) {
- ALOGE("%s failed to allocate primary display, config count %d", __func__, count);
+ ALOGE("%s failed to allocate primary display, config count %d", __func__,
+ count);
return HWC2::Error::NoResources;
}
display.activeConfigId = rcEnc->rcGetFBDisplayActiveConfig(rcEnc);
- for(int configId = 0; configId < count; configId++) {
- display.configs.push_back({
- 0,
- rcEnc->rcGetFBDisplayConfigsParam(
- rcEnc, configId, FB_WIDTH),
- rcEnc->rcGetFBDisplayConfigsParam(
- rcEnc, configId, FB_HEIGHT),
- rcEnc->rcGetFBDisplayConfigsParam(
- rcEnc, configId, FB_XDPI),
- rcEnc->rcGetFBDisplayConfigsParam(
- rcEnc, configId, FB_YDPI),
- refreshRateHz,
- });
+ for (int configId = 0; configId < count; configId++) {
+ display.configs.push_back(DisplayConfig(
+ configId, //
+ rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_WIDTH), //
+ rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_HEIGHT), //
+ rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_XDPI), //
+ rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_YDPI), //
+ vsyncPeriodNanos //
+ ));
}
} else {
display.activeConfigId = 0;
- display.configs.push_back({
- 0,
- rcEnc->rcGetFBParam(rcEnc, FB_WIDTH),
- rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT),
- rcEnc->rcGetFBParam(rcEnc, FB_XDPI),
- rcEnc->rcGetFBParam(rcEnc, FB_YDPI),
- refreshRateHz});
+ display.configs.push_back(DisplayConfig(
+ 0, //
+ rcEnc->rcGetFBParam(rcEnc, FB_WIDTH), //
+ rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT), //
+ rcEnc->rcGetFBParam(rcEnc, FB_XDPI), //
+ rcEnc->rcGetFBParam(rcEnc, FB_YDPI), //
+ vsyncPeriodNanos //
+ ));
}
hostCon->unlock();
@@ -115,7 +124,8 @@ HWC2::Error findGoldfishPrimaryDisplay(std::vector<DisplayMultiConfigs>& display
return HWC2::Error::None;
}
-HWC2::Error findGoldfishSecondaryDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC2::Error findGoldfishSecondaryDisplays(
+ std::vector<DisplayMultiConfigs>& displays) {
DEBUG_LOG("%s", __FUNCTION__);
static constexpr const char kExternalDisplayProp[] =
@@ -147,21 +157,23 @@ HWC2::Error findGoldfishSecondaryDisplays(std::vector<DisplayMultiConfigs>& disp
propIntParts.push_back(propIntPart);
}
- int secondaryDisplayId = 1;
+ hwc2_display_t secondaryDisplayId = 1;
+ hwc2_config_t secondaryConfigId = 1;
while (!propIntParts.empty()) {
DisplayMultiConfigs display;
- display.id = secondaryDisplayId;
+ display.displayId = secondaryDisplayId;
display.activeConfigId = 0;
- display.configs.push_back(DisplayConfig{
- .id = secondaryDisplayId,
- .width = propIntParts[1],
- .height = propIntParts[2],
- .dpiX = propIntParts[3],
- .dpiY = propIntParts[3],
- .refreshRateHz = 160,
- });
+ display.configs.push_back(DisplayConfig(
+ secondaryConfigId, //
+ /*width=*/propIntParts[1], //
+ /*heighth=*/propIntParts[2], //
+ /*dpiXh=*/propIntParts[3], //
+ /*dpiYh=*/propIntParts[3], //
+ /*vsyncPeriod=*/HertzToPeriodNanos(160) //
+ ));
displays.push_back(display);
+ ++secondaryConfigId;
++secondaryDisplayId;
propIntParts.erase(propIntParts.begin(), propIntParts.begin() + 5);
@@ -188,11 +200,23 @@ HWC2::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>& displays) {
} // namespace
HWC2::Error findDisplays(std::vector<DisplayMultiConfigs>& displays) {
+ HWC2::Error error = HWC2::Error::None;
if (IsCuttlefish()) {
- return findCuttlefishDisplays(displays);
+ error = findCuttlefishDisplays(displays);
} else {
- return findGoldfishDisplays(displays);
+ error = findGoldfishDisplays(displays);
+ }
+
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to find displays", __FUNCTION__);
+ return error;
+ }
+
+ for (auto& display : displays) {
+ DisplayConfig::addConfigGroups(&display.configs);
}
+
+ return HWC2::Error::None;
}
} // namespace android
diff --git a/system/hwc2/DisplayFinder.h b/system/hwc2/DisplayFinder.h
index 44a09a60..b9e1b19e 100644
--- a/system/hwc2/DisplayFinder.h
+++ b/system/hwc2/DisplayFinder.h
@@ -20,21 +20,13 @@
#include <vector>
#include "Common.h"
+#include "DisplayConfig.h"
namespace android {
-struct DisplayConfig {
- int id;
- int width;
- int height;
- int dpiX;
- int dpiY;
- int refreshRateHz;
-};
-
struct DisplayMultiConfigs {
- int id;
- int activeConfigId;
+ hwc2_display_t displayId;
+ hwc2_config_t activeConfigId;
// Modes that this display can be configured to use.
std::vector<DisplayConfig> configs;
};
diff --git a/system/hwc2/DrmPresenter.h b/system/hwc2/DrmPresenter.h
index d65ce9d1..da511954 100644
--- a/system/hwc2/DrmPresenter.h
+++ b/system/hwc2/DrmPresenter.h
@@ -26,9 +26,9 @@
#include <memory>
#include <vector>
-#include "drmhwcgralloc.h"
#include "Common.h"
#include "android/base/synchronization/AndroidLock.h"
+#include "drmhwcgralloc.h"
namespace android {
diff --git a/system/hwc2/HostComposer.cpp b/system/hwc2/HostComposer.cpp
index d0e1ba6e..ede56976 100644
--- a/system/hwc2/HostComposer.cpp
+++ b/system/hwc2/HostComposer.cpp
@@ -203,7 +203,7 @@ HWC2::Error HostComposer::createHostComposerDisplayInfo(
displayInfo.hostDisplayId = hostDisplayId;
if (displayInfo.compositionResultBuffer) {
- FreeDisplayColorBuffer(displayInfo.compositionResultBuffer);
+ FreeDisplayColorBuffer(displayInfo.compositionResultBuffer);
}
displayInfo.compositionResultBuffer =
AllocateDisplayColorBuffer(displayWidth, displayHeight);
@@ -572,7 +572,7 @@ HWC2::Error HostComposer::presentDisplay(Display* display,
p2->numLayers = numLayer;
}
- void *buffer;
+ void* buffer;
uint32_t bufferSize;
if (hostCompositionV1) {
buffer = (void*)p;
@@ -676,8 +676,8 @@ HWC2::Error HostComposer::onActiveConfigChange(Display* display) {
DEBUG_LOG("%s: display:%" PRIu64, __FUNCTION__, display->getId());
HWC2::Error error = createHostComposerDisplayInfo(display, display->getId());
if (error != HWC2::Error::None) {
- ALOGE("%s failed to update host info for display:%" PRIu64,
- __FUNCTION__, display->getId());
+ ALOGE("%s failed to update host info for display:%" PRIu64, __FUNCTION__,
+ display->getId());
return error;
}
return HWC2::Error::None;
diff --git a/system/hwc2/VsyncThread.cpp b/system/hwc2/VsyncThread.cpp
new file mode 100644
index 00000000..dbefcc65
--- /dev/null
+++ b/system/hwc2/VsyncThread.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VsyncThread.h"
+
+#include <thread>
+
+namespace android {
+namespace {
+
+std::chrono::time_point<std::chrono::steady_clock> asTimePoint(int64_t nanos) {
+ return std::chrono::time_point<std::chrono::steady_clock>(
+ std::chrono::nanoseconds(nanos));
+}
+
+hwc2_vsync_period_t asNanos(std::chrono::nanoseconds duration) {
+ return duration.count();
+}
+
+int64_t asNanos(std::chrono::time_point<std::chrono::steady_clock> time) {
+ std::chrono::time_point<std::chrono::steady_clock> zero(
+ std::chrono::nanoseconds(0));
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(time - zero)
+ .count();
+}
+
+// Returns the timepoint of the next vsync after the 'now' timepoint that is
+// a multiple of 'vsyncPeriod' in-phase/offset-from 'previousSync'.
+//
+// Some examples:
+// * vsyncPeriod=50ns previousVsync=500ns now=510ns => 550ns
+// * vsyncPeriod=50ns previousVsync=300ns now=510ns => 550ns
+// * vsyncPeriod=50ns previousVsync=500ns now=550ns => 550ns
+std::chrono::time_point<std::chrono::steady_clock> GetNextVsyncInPhase(
+ std::chrono::nanoseconds vsyncPeriod,
+ std::chrono::time_point<std::chrono::steady_clock> previousVsync,
+ std::chrono::time_point<std::chrono::steady_clock> now) {
+ const auto elapsed = std::chrono::nanoseconds(now - previousVsync);
+ const auto nextMultiple = (elapsed / vsyncPeriod) + 1;
+ return previousVsync + (nextMultiple * vsyncPeriod);
+}
+
+} // namespace
+
+VsyncThread::VsyncThread(hwc2_display_t id) : mDisplayId(id) {
+ mPreviousVsync = std::chrono::steady_clock::now() - mVsyncPeriod;
+}
+
+HWC2::Error VsyncThread::start(hwc2_vsync_period_t vsyncPeriod) {
+ DEBUG_LOG("%s for display:%" PRIu64, __FUNCTION__, mDisplayId);
+
+ mVsyncPeriod = std::chrono::nanoseconds(vsyncPeriod);
+
+ const std::string threadName =
+ "display_" + std::to_string(mDisplayId) + "_vsync_thread";
+ this->run(threadName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error VsyncThread::setVsyncCallback(HWC2_PFN_VSYNC callback,
+ hwc2_callback_data_t callbackData) {
+ DEBUG_LOG("%s for display:%" PRIu64, __FUNCTION__, mDisplayId);
+
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ mVsyncCallback = callback;
+ mVsyncCallbackData = callbackData;
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error VsyncThread::setVsync24Callback(HWC2_PFN_VSYNC_2_4 callback,
+ hwc2_callback_data_t callbackData) {
+ DEBUG_LOG("%s for display:%" PRIu64, __FUNCTION__, mDisplayId);
+
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ mVsync24Callback = callback;
+ mVsync24CallbackData = callbackData;
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error VsyncThread::setVsyncEnabled(bool enabled) {
+ DEBUG_LOG("%s for display:%" PRIu64 " enabled:%d", __FUNCTION__, mDisplayId,
+ enabled);
+
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ mVsyncEnabled = enabled;
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error VsyncThread::scheduleVsyncUpdate(
+ hwc2_vsync_period_t newVsyncPeriod,
+ hwc_vsync_period_change_constraints_t* newVsyncPeriodConstraints,
+ hwc_vsync_period_change_timeline_t* outTimeline) {
+ DEBUG_LOG("%s for display:%" PRIu64, __FUNCTION__, mDisplayId);
+
+ PendingUpdate update;
+ update.period = std::chrono::nanoseconds(newVsyncPeriod);
+ update.updateAfter = asTimePoint(newVsyncPeriodConstraints->desiredTimeNanos);
+
+ std::unique_lock<std::mutex> lock(mStateMutex);
+ mPendingUpdate.emplace(std::move(update));
+
+ auto nextVsync =
+ GetNextVsyncInPhase(mVsyncPeriod, mPreviousVsync, update.updateAfter);
+
+ outTimeline->newVsyncAppliedTimeNanos = asNanos(nextVsync);
+ outTimeline->refreshRequired = false;
+ outTimeline->refreshTimeNanos = 0;
+
+ return HWC2::Error::None;
+}
+
+std::chrono::nanoseconds VsyncThread::updateVsyncPeriodLocked(
+ std::chrono::time_point<std::chrono::steady_clock> now) {
+ if (mPendingUpdate && now > mPendingUpdate->updateAfter) {
+ mVsyncPeriod = mPendingUpdate->period;
+ mPendingUpdate.reset();
+ }
+
+ return mVsyncPeriod;
+}
+
+bool VsyncThread::threadLoop() {
+ DEBUG_LOG("%s: for display:%" PRIu64 " started", __FUNCTION__, mDisplayId);
+
+ std::chrono::nanoseconds vsyncPeriod = mVsyncPeriod;
+
+ int vsyncs = 0;
+ auto previousLog = std::chrono::steady_clock::now();
+ while (true) {
+ auto now = std::chrono::steady_clock::now();
+
+ auto nextVsync = GetNextVsyncInPhase(vsyncPeriod, mPreviousVsync, now);
+ std::this_thread::sleep_until(nextVsync);
+
+ {
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ mPreviousVsync = nextVsync;
+
+ // Display has finished refreshing at previous vsync period. Update the
+ // vsync period if there was a pending update.
+ vsyncPeriod = updateVsyncPeriodLocked(mPreviousVsync);
+ }
+
+ if (mVsyncEnabled) {
+ if (mVsync24Callback) {
+ DEBUG_LOG("%s: for display:%" PRIu64 " calling vsync_2_4", __FUNCTION__,
+ mDisplayId);
+ mVsync24Callback(mVsync24CallbackData, mDisplayId, asNanos(nextVsync),
+ asNanos(vsyncPeriod));
+ } else if (mVsyncCallback) {
+ DEBUG_LOG("%s: for display:%" PRIu64 " calling vsync", __FUNCTION__,
+ mDisplayId);
+ mVsyncCallback(mVsyncCallbackData, mDisplayId, asNanos(nextVsync));
+ }
+ }
+
+ static constexpr const int kLogIntervalSeconds = 60;
+ if (now > (previousLog + std::chrono::seconds(kLogIntervalSeconds))) {
+ DEBUG_LOG("%s: for display:%" PRIu64 " send %" PRIu32
+ " in last %d seconds",
+ __FUNCTION__, mDisplayId, vsyncs, kLogIntervalSeconds);
+ previousLog = now;
+ vsyncs = 0;
+ }
+ ++vsyncs;
+ }
+
+ DEBUG_LOG("%s: for display:%" PRIu64 " started", __FUNCTION__, mDisplayId);
+ return false;
+}
+
+} // namespace android
diff --git a/system/hwc2/VsyncThread.h b/system/hwc2/VsyncThread.h
new file mode 100644
index 00000000..e7c237c9
--- /dev/null
+++ b/system/hwc2/VsyncThread.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC_VSYNCTHREAD_H
+#define ANDROID_HWC_VSYNCTHREAD_H
+
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <utils/Thread.h>
+
+#include <chrono>
+#include <mutex>
+#include <optional>
+
+#include "Common.h"
+
+namespace android {
+
+// Generates Vsync signals in software.
+class VsyncThread : public Thread {
+ public:
+ VsyncThread(hwc2_display_t id);
+ virtual ~VsyncThread() {}
+
+ VsyncThread(const VsyncThread&) = default;
+ VsyncThread& operator=(const VsyncThread&) = default;
+
+ VsyncThread(VsyncThread&&) = default;
+ VsyncThread& operator=(VsyncThread&&) = default;
+
+ HWC2::Error start(hwc2_vsync_period_t period);
+
+ HWC2::Error setVsyncCallback(HWC2_PFN_VSYNC callback,
+ hwc2_callback_data_t callbackData);
+ HWC2::Error setVsync24Callback(HWC2_PFN_VSYNC_2_4 callback,
+ hwc2_callback_data_t callbackData);
+
+ HWC2::Error setVsyncEnabled(bool enabled);
+
+ HWC2::Error scheduleVsyncUpdate(
+ hwc2_vsync_period_t newVsyncPeriod,
+ hwc_vsync_period_change_constraints_t* newVsyncPeriodChangeConstraints,
+ hwc_vsync_period_change_timeline_t* timeline);
+
+ private:
+ bool threadLoop() final;
+
+ std::chrono::nanoseconds updateVsyncPeriodLocked(
+ std::chrono::time_point<std::chrono::steady_clock> now);
+
+ const hwc2_display_t mDisplayId;
+
+ std::mutex mStateMutex;
+
+ HWC2_PFN_VSYNC mVsyncCallback;
+ hwc2_callback_data_t mVsyncCallbackData = nullptr;
+
+ HWC2_PFN_VSYNC_2_4 mVsync24Callback;
+ hwc2_callback_data_t mVsync24CallbackData = nullptr;
+
+ bool mVsyncEnabled = false;
+ std::chrono::nanoseconds mVsyncPeriod;
+ std::chrono::time_point<std::chrono::steady_clock> mPreviousVsync;
+
+ struct PendingUpdate {
+ std::chrono::nanoseconds period;
+ std::chrono::time_point<std::chrono::steady_clock> updateAfter;
+ };
+ std::optional<PendingUpdate> mPendingUpdate;
+};
+
+} // namespace android
+
+#endif \ No newline at end of file