Runtime multidsplay handling through virtio gpu
Bug: 184849633
* Display change listener
* Add/Del/Modify secondary displays at runtime. When hotplug is called
with DISCONNECTED, surfaceFlinger will call hwc2 to destroy layer, stop
vsync.
Test: add/modify/del display at runtime
Change-Id: Ia8a1230c615ef6359213d6297d43dfd5eec37bc2
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index 29eff18..2254d2f 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -46,6 +46,7 @@
emulator_hwcomposer_c_includes += \
device/generic/goldfish-opengl/host/include/libOpenglRender \
+ device/generic/goldfish-opengl/android-emu \
device/generic/goldfish-opengl/shared/OpenglCodecCommon \
device/generic/goldfish-opengl/system/OpenglSystemCommon \
device/generic/goldfish-opengl/system/include \
diff --git a/system/hwc2/Common.h b/system/hwc2/Common.h
index 4313a78..949708d 100644
--- a/system/hwc2/Common.h
+++ b/system/hwc2/Common.h
@@ -25,7 +25,7 @@
#include <log/log.h>
// Uncomment to enable additional debug logging.
-// #define DEBUG_RANCHU_HWC
+//#define DEBUG_RANCHU_HWC
#if defined(DEBUG_RANCHU_HWC)
#define DEBUG_LOG ALOGE
@@ -39,4 +39,4 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
-#endif
\ No newline at end of file
+#endif
diff --git a/system/hwc2/Composer.h b/system/hwc2/Composer.h
index 795504f..1b65f3a 100644
--- a/system/hwc2/Composer.h
+++ b/system/hwc2/Composer.h
@@ -24,7 +24,6 @@
#include "Common.h"
namespace android {
-
class Device;
class Display;
@@ -32,7 +31,13 @@
public:
virtual ~Composer() {}
- virtual HWC2::Error init() = 0;
+ using HotplugCallback =
+ std::function<void(bool /*connected*/, uint32_t /*id*/,
+ uint32_t /*width*/, uint32_t /*height*/,
+ uint32_t /*dpiX*/, uint32_t /*dpiY*/,
+ uint32_t /*refreshRate*/)>;
+
+ virtual HWC2::Error init(const HotplugCallback& cb) = 0;
using AddDisplayToDeviceFunction =
std::function<HWC2::Error(std::unique_ptr<Display>)>;
@@ -43,6 +48,11 @@
Device* device,
const AddDisplayToDeviceFunction& addDisplayToDeviceFn) = 0;
+ virtual HWC2::Error createDisplay(
+ Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+ uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+ const AddDisplayToDeviceFunction& addDisplayToDeviceFn) = 0;
+
virtual HWC2::Error onDisplayDestroy(Display* display) = 0;
virtual HWC2::Error onDisplayClientTargetSet(Display* display) = 0;
@@ -61,4 +71,4 @@
} // namespace android
-#endif
\ No newline at end of file
+#endif
diff --git a/system/hwc2/Device.cpp b/system/hwc2/Device.cpp
index fa6362f..29ae17f 100644
--- a/system/hwc2/Device.cpp
+++ b/system/hwc2/Device.cpp
@@ -61,7 +61,14 @@
mComposer = std::make_unique<HostComposer>();
}
- HWC2::Error error = mComposer->init();
+ HWC2::Error error = mComposer->init(
+ [this](bool connected, uint32_t id,
+ uint32_t width, uint32_t height,
+ uint32_t dpiX, uint32_t dpiY,
+ uint32_t refreshRate) {
+ handleHotplug(connected, id, width, height, dpiX, dpiY, refreshRate);
+ });
+
if (error != HWC2::Error::None) {
ALOGE("%s failed to initialize Composer", __FUNCTION__);
return HWC2::Error::NoResources;
@@ -107,6 +114,32 @@
return HWC2::Error::None;
}
+HWC2::Error Device::createDisplay(uint32_t displayId, uint32_t width,
+ uint32_t height, uint32_t dpiX, uint32_t dpiY,
+ uint32_t refreshRate) {
+ if (!mComposer) {
+ ALOGE("%s composer not initialized!", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ auto addDisplayLockedFn = [this](std::unique_ptr<Display> display) {
+ auto displayId = display->getId();
+ DEBUG_LOG("%s: adding display:%" PRIu64, __FUNCTION__, displayId);
+ mDisplays.emplace(displayId, std::move(display));
+ return HWC2::Error::None;
+ };
+
+ HWC2::Error error = mComposer->createDisplay(this, displayId, width, height,
+ dpiX, dpiY, refreshRate,
+ addDisplayLockedFn);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s composer failed to create displays", __FUNCTION__);
+ return error;
+ }
+
+ return HWC2::Error::None;
+}
+
HWC2::Error Device::destroyDisplays() {
DEBUG_LOG("%s", __FUNCTION__);
@@ -472,10 +505,38 @@
return HWC2::Error::None;
}
+bool Device::handleHotplug(bool connected, uint32_t id, uint32_t width,
+ uint32_t height, uint32_t dpiX, uint32_t dpiY,
+ uint32_t refreshRate) {
+ std::unique_lock<std::mutex> lock(mStateMutex);
+ if (mCallbacks[HWC2::Callback::Hotplug].pointer == nullptr) {
+ return false;
+ }
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(mCallbacks[HWC2::Callback::Hotplug].pointer);
+ auto hotplugConnect = static_cast<int32_t>(HWC2::Connection::Connected);
+ auto hotplugDisconnect = static_cast<int32_t>(HWC2::Connection::Disconnected);
+ Display* display = getDisplay(id);
+ if (display) {
+ // if existed, disconnect first
+ ALOGD("callback hotplugDisconnect display %" PRIu32, id);
+ hotplug(mCallbacks[HWC2::Callback::Hotplug].data, id, hotplugDisconnect);
+ display->lock();
+ mComposer->onDisplayDestroy(display);
+ display->unlock();
+ }
+ if (connected) {
+ createDisplay(id, width, height, dpiX, dpiY, refreshRate);
+ ALOGD("callback hotplugConnect display %" PRIu32, id);
+ hotplug(mCallbacks[HWC2::Callback::Hotplug].data, id, hotplugConnect);
+ };
+
+ return true;
+}
+
Display* Device::getDisplay(hwc2_display_t id) {
auto display = mDisplays.find(id);
if (display == mDisplays.end()) {
- ALOGE("Failed to get display for id=%d", (uint32_t)id);
+ ALOGW("Failed to get display for id=%d", (uint32_t)id);
return nullptr;
}
return display->second.get();
diff --git a/system/hwc2/Device.h b/system/hwc2/Device.h
index 7dae04b0..1b9cf50 100644
--- a/system/hwc2/Device.h
+++ b/system/hwc2/Device.h
@@ -53,9 +53,19 @@
HWC2::Error createDisplays();
+ HWC2::Error createDisplay(uint32_t displayId, uint32_t width,
+ uint32_t height, uint32_t dpiX, uint32_t dpiY,
+ uint32_t refreshRate);
+
+ Display* getDisplay(hwc2_display_t displayId);
+
private:
HWC2::Error destroyDisplays();
+ bool handleHotplug(bool connected, uint32_t id, uint32_t width,
+ uint32_t height, uint32_t dpiX, uint32_t dpiY,
+ uint32_t refreshRate);
+
void getCapabilities(uint32_t* outCount, int32_t* outCapabilities);
static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
int32_t* outCapabilities);
@@ -71,8 +81,6 @@
return static_cast<T>(((*device).*func)(std::forward<Args>(args)...));
}
- Display* getDisplay(hwc2_display_t displayId);
-
// Wrapper to call a specific function on a specific display.
template <typename HookType, HookType func, typename... Args>
static int32_t displayHook(hwc2_device_t* dev, hwc2_display_t displayId,
diff --git a/system/hwc2/Display.cpp b/system/hwc2/Display.cpp
index 786ce2a..f97dbc2 100644
--- a/system/hwc2/Display.cpp
+++ b/system/hwc2/Display.cpp
@@ -27,7 +27,6 @@
namespace {
std::atomic<hwc2_config_t> sNextConfigId{0};
-std::atomic<hwc2_display_t> sNextDisplayId{0};
bool IsValidColorMode(android_color_mode_t mode) {
switch (mode) {
@@ -61,10 +60,10 @@
} // namespace
-Display::Display(Device& device, Composer* composer)
+Display::Display(Device& device, Composer* composer, hwc2_display_t id)
: mDevice(device),
mComposer(composer),
- mId(sNextDisplayId++),
+ mId(id),
mVsyncThread(new VsyncThread(*this)) {}
Display::~Display() {}
@@ -97,6 +96,30 @@
return HWC2::Error::None;
}
+HWC2::Error Display::updateParameters(uint32_t width, uint32_t height, uint32_t dpiX,
+ uint32_t dpiY, uint32_t refreshRateHz) {
+ DEBUG_LOG("%s updating display:%" PRIu64
+ " width:%d height:%d dpiX:%d dpiY:%d refreshRateHz:%d",
+ __FUNCTION__, mId, width, height, dpiX, dpiY, refreshRateHz);
+
+ 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::Width, width);
+ it->second.setAttribute(HWC2::Attribute::Height, height);
+ it->second.setAttribute(HWC2::Attribute::DpiX, dpiX * 1000);
+ it->second.setAttribute(HWC2::Attribute::DpiY, dpiY * 1000);
+
+ return HWC2::Error::None;
+}
+
Layer* Display::getLayer(hwc2_layer_t layerId) {
auto it = mLayers.find(layerId);
if (it == mLayers.end()) {
@@ -216,6 +239,8 @@
const Config& config = it->second;
*outValue = config.getAttribute(attribute);
+ DEBUG_LOG("%s: display:%" PRIu64 " attribute:%s value is %" PRIi32,
+ __FUNCTION__, mId, attributeString.c_str(), *outValue);
return HWC2::Error::None;
}
diff --git a/system/hwc2/Display.h b/system/hwc2/Display.h
index 910cf5a..277933a 100644
--- a/system/hwc2/Display.h
+++ b/system/hwc2/Display.h
@@ -37,7 +37,7 @@
class Display {
public:
- Display(Device& device, Composer* composer);
+ Display(Device& device, Composer* composer, hwc2_display_t id);
~Display();
Display(const Display& display) = delete;
@@ -49,6 +49,9 @@
HWC2::Error init(uint32_t width, uint32_t height, uint32_t dpiX,
uint32_t dpiY, uint32_t refreshRateHz);
+ HWC2::Error updateParameters(uint32_t width, uint32_t height, uint32_t dpiX,
+ uint32_t dpiY, uint32_t refreshRateHz);
+
hwc2_display_t getId() const { return mId; }
Layer* getLayer(hwc2_layer_t layerHandle);
@@ -108,6 +111,8 @@
uint32_t* outCapabilities);
HWC2::Error getDisplayBrightnessSupport(bool* out_support);
HWC2::Error setDisplayBrightness(float brightness);
+ void lock() { mStateMutex.lock(); }
+ void unlock() { mStateMutex.unlock(); }
private:
class Config {
diff --git a/system/hwc2/DrmPresenter.cpp b/system/hwc2/DrmPresenter.cpp
index 56eee8e..b31e73c 100644
--- a/system/hwc2/DrmPresenter.cpp
+++ b/system/hwc2/DrmPresenter.cpp
@@ -17,14 +17,21 @@
#include "DrmPresenter.h"
#include <cros_gralloc_handle.h>
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+using android::base::guest::ReadWriteLock;
+using android::base::guest::AutoReadLock;
+using android::base::guest::AutoWriteLock;
namespace android {
DrmPresenter::DrmPresenter() {}
-bool DrmPresenter::init() {
+bool DrmPresenter::init(const HotplugCallback& cb) {
DEBUG_LOG("%s", __FUNCTION__);
+ mHotplugCallback = cb;
mFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
if (mFd < 0) {
ALOGE("%s HWC2::Error opening DrmPresenter device: %d", __FUNCTION__,
@@ -35,33 +42,49 @@
int univRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (univRet) {
ALOGE("%s: fail to set universal plane %d\n", __FUNCTION__, univRet);
+ return false;
}
int atomicRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_ATOMIC, 1);
if (atomicRet) {
ALOGE("%s: fail to set atomic operation %d, %d\n", __FUNCTION__, atomicRet,
errno);
- }
- ALOGD("%s: Did set universal planes and atomic cap\n", __FUNCTION__);
-
- bool configRet = configDrmElements();
- if (configRet) {
- ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
- } else {
- ALOGD("%s: Failed to initialize DRM backend", __FUNCTION__);
+ return false;
}
- return configRet;
+ {
+ AutoWriteLock lock(mStateMutex);
+ bool configRet = configDrmElementsLocked();
+ if (configRet) {
+ ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
+ } else {
+ ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
+ return false;
+ }
+ }
+
+ mDrmEventListener.reset(new DrmEventListener(*this));
+ mDrmEventListener->run("", ANDROID_PRIORITY_URGENT_DISPLAY);
+
+ return true;
}
-void DrmPresenter::clearDrmElements() {
+void DrmPresenter::clearDrmElementsLocked() {
+ for (auto& c : mConnectors) {
+ if (c.mModeBlobId) {
+ if (drmModeDestroyPropertyBlob(mFd, c.mModeBlobId)) {
+ ALOGE("%s: Error destroy PropertyBlob %" PRIu32, __func__, c.mModeBlobId);
+ }
+ }
+ }
mConnectors.clear();
mCrtcs.clear();
mPlanes.clear();
}
-bool DrmPresenter::configDrmElements() {
+bool DrmPresenter::configDrmElementsLocked() {
drmModeRes* res;
+ static const int32_t kUmPerInch = 25400;
res = drmModeGetResources(mFd);
if (res == nullptr) {
@@ -71,7 +94,7 @@
return false;
}
- ALOGI(
+ ALOGD(
"drmModeRes count fbs %d crtc %d connector %d encoder %d min w %d max w "
"%d min h %d max h %d",
res->count_fbs, res->count_crtcs, res->count_connectors,
@@ -94,16 +117,10 @@
if (!strcmp(crtcProp->name, "OUT_FENCE_PTR")) {
crtc.mFencePropertyId = crtcProp->prop_id;
- ALOGI("%s: Crtc %" PRIu32 " fence property id: %" PRIu32, __FUNCTION__,
- crtc.mId, crtcProp->prop_id);
} else if (!strcmp(crtcProp->name, "ACTIVE")) {
crtc.mActivePropertyId = crtcProp->prop_id;
- ALOGI("%s: Crtc %" PRIu32 " active property id: %" PRIu32, __FUNCTION__,
- crtc.mId, crtcProp->prop_id);
} else if (!strcmp(crtcProp->name, "MODE_ID")) {
crtc.mModePropertyId = crtcProp->prop_id;
- ALOGI("%s: Crtc %" PRIu32 " mode property id: %" PRIu32, __FUNCTION__,
- crtc.mId, crtcProp->prop_id);
}
drmModeFreeProperty(crtcProp);
@@ -121,7 +138,7 @@
drmModePlanePtr p = drmModeGetPlane(mFd, planeRes->planes[i]);
plane.mId = p->plane_id;
- ALOGI(
+ ALOGD(
"%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d "
"possible ctrcs 0x%x",
__FUNCTION__, p->plane_id, p->crtc_id, p->fb_id, p->crtc_x, p->crtc_y,
@@ -137,48 +154,26 @@
if (!strcmp(planeProp->name, "CRTC_ID")) {
plane.mCrtcPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " crtc property %u", __FUNCTION__, plane.mId,
- planeProp->prop_id);
} else if (!strcmp(planeProp->name, "FB_ID")) {
plane.mFbPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " fb property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "CRTC_X")) {
plane.mCrtcXPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " crtc X property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "CRTC_Y")) {
plane.mCrtcYPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " crtc Y property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "CRTC_W")) {
plane.mCrtcWPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " crtc W property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "CRTC_H")) {
plane.mCrtcHPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " crtc H property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "SRC_X")) {
plane.mSrcXPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " src X property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "SRC_Y")) {
plane.mSrcYPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " src Y property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "SRC_W")) {
plane.mSrcWPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " src W property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "SRC_H")) {
plane.mSrcHPropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " src H property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
} else if (!strcmp(planeProp->name, "type")) {
plane.mTypePropertyId = planeProp->prop_id;
- ALOGD("%s: plane %" PRIu32 " type property id %" PRIu32, __FUNCTION__,
- plane.mId, planeProp->prop_id);
uint64_t type = planeProp->values[0];
switch (type) {
case DRM_PLANE_TYPE_OVERLAY:
@@ -203,27 +198,22 @@
bool isPrimaryOrOverlay = plane.mType == DRM_PLANE_TYPE_OVERLAY ||
plane.mType == DRM_PLANE_TYPE_PRIMARY;
- if (isPrimaryOrOverlay && ((1 << 0) & p->possible_crtcs)) {
- ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
- __FUNCTION__, plane.mId, p->possible_crtcs);
- }
-
- if (plane.mType == DRM_PLANE_TYPE_OVERLAY ||
- plane.mType == DRM_PLANE_TYPE_PRIMARY) {
- // TODO: correctly convert mask.
- uint32_t crtcIndex = p->possible_crtcs - 1;
-
- DrmCrtc& crtc = mCrtcs[crtcIndex];
-
- if (crtc.mPlaneId == -1) {
- crtc.mPlaneId = plane.mId;
- ALOGE("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
- __FUNCTION__, plane.mId, crtc.mId);
+ if (isPrimaryOrOverlay) {
+ for (uint32_t j = 0; j < mCrtcs.size(); j++) {
+ if ((0x1 << j) & p->possible_crtcs) {
+ ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
+ __FUNCTION__, plane.mId, p->possible_crtcs);
+ if (mCrtcs[j].mPlaneId == -1) {
+ mCrtcs[j].mPlaneId = plane.mId;
+ ALOGD("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
+ __FUNCTION__, plane.mId, j);
+ break;
+ }
+ }
}
}
drmModeFreePlane(p);
-
mPlanes[plane.mId] = plane;
}
drmModeFreePlaneResources(planeRes);
@@ -243,8 +233,6 @@
drmModeGetProperty(mFd, connectorProps->props[connectorPropIndex]);
if (!strcmp(connectorProp->name, "CRTC_ID")) {
connector.mCrtcPropertyId = connectorProp->prop_id;
- ALOGD("%s: connector %" PRIu32 " crtc prop id %" PRIu32, __FUNCTION__,
- connector.mId, connectorProp->prop_id);
}
drmModeFreeProperty(connectorProp);
}
@@ -258,14 +246,22 @@
connector.mId, errno);
return false;
}
+ connector.connection = c->connection;
+ if (c->count_modes > 0) {
+ memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
+ drmModeCreatePropertyBlob(mFd, &connector.mMode, sizeof(connector.mMode),
+ &connector.mModeBlobId);
- memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
+ // Dots per 1000 inches
+ connector.dpiX = c->mmWidth ? (c->mmWidth * kUmPerInch * 10) / c->modes[0].hdisplay : -1;
+ // Dots per 1000 inches
+ connector.dpiY = c->mmHeight ? (c->mmHeight * kUmPerInch * 10) / c->modes[0].vdisplay : -1;
+ }
+ ALOGD("%s connector %" PRIu32 " dpiX %" PRIi32 " dpiY %" PRIi32 " connection %d",
+ __FUNCTION__, connector.mId, connector.dpiX, connector.dpiY, connector.connection);
drmModeFreeConnector(c);
- drmModeCreatePropertyBlob(mFd, &connector.mMode, sizeof(connector.mMode),
- &connector.mModeBlobId);
-
connector.mRefreshRateAsFloat =
1000.0f * connector.mMode.clock /
((float)connector.mMode.vtotal * (float)connector.mMode.htotal);
@@ -296,7 +292,6 @@
strerror(errno), errno);
return -1;
}
- ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
return 0;
}
@@ -322,10 +317,49 @@
return ret;
}
-bool DrmPresenter::supportComposeWithoutPost() { return true; }
+bool DrmPresenter::handleHotPlug() {
+ std::vector<DrmConnector> oldConnectors(mConnectors);
+ {
+ AutoReadLock lock(mStateMutex);
+ oldConnectors.assign(mConnectors.begin(), mConnectors.end());
+ }
+ {
+ AutoWriteLock lock(mStateMutex);
+ clearDrmElementsLocked();
+ configDrmElementsLocked();
+ }
-HWC2::Error DrmPresenter::flushToDisplay(int display, hwc_drm_bo_t& bo,
- int* outSyncFd) {
+ AutoReadLock lock(mStateMutex);
+ for (int i = 0; i < mConnectors.size(); i++) {
+ bool changed = oldConnectors[i].dpiX != mConnectors[i].dpiX ||
+ oldConnectors[i].dpiY != mConnectors[i].dpiY ||
+ oldConnectors[i].connection != mConnectors[i].connection ||
+ oldConnectors[i].mMode.hdisplay != mConnectors[i].mMode.hdisplay ||
+ oldConnectors[i].mMode.vdisplay != mConnectors[i].mMode.vdisplay;
+ if (changed) {
+ if (i == 0) {
+ ALOGE("%s: Ignoring changes to display:0 which is not configurable by "
+ "multi-display interface.", __FUNCTION__);
+ continue;
+ }
+
+ bool connected = mConnectors[i].connection == DRM_MODE_CONNECTED ? true : false;
+ if (mHotplugCallback) {
+ mHotplugCallback(connected, i,
+ mConnectors[i].mMode.hdisplay,
+ mConnectors[i].mMode.vdisplay,
+ mConnectors[i].dpiX,
+ mConnectors[i].dpiY,
+ mConnectors[i].mRefreshRateAsInteger);
+ }
+ }
+ }
+ return true;
+}
+
+HWC2::Error DrmPresenter::flushToDisplay(int display, hwc_drm_bo_t& bo, int* outSyncFd) {
+ AutoReadLock lock(mStateMutex);
+
DrmConnector& connector = mConnectors[display];
DrmCrtc& crtc = mCrtcs[display];
@@ -470,4 +504,95 @@
return mDrmPresenter.flushToDisplay(display, mBo, outFlushDoneSyncFd);
}
+DrmPresenter::DrmEventListener::DrmEventListener(DrmPresenter& presenter)
+ : mPresenter(presenter) {
+ mEventFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+ if (mEventFd < 0) {
+ ALOGE("Failed to open uevent socket: %s", strerror(errno));
+ return;
+ }
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0xFFFFFFFF;
+
+ int ret = bind(mEventFd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret) {
+ ALOGE("Failed to bind uevent socket: %s", strerror(errno));
+ return;
+ }
+
+ FD_ZERO(&mFds);
+ FD_SET(mPresenter.mFd, &mFds);
+ FD_SET(mEventFd, &mFds);
+ mMaxFd = std::max(mPresenter.mFd, mEventFd);
+}
+
+DrmPresenter::DrmEventListener::~DrmEventListener() {
+ if (mEventFd >= 0) {
+ close(mEventFd);
+ }
+}
+
+bool DrmPresenter::DrmEventListener::threadLoop() {
+ int ret;
+ do {
+ ret = select(mMaxFd + 1, &mFds, NULL, NULL, NULL);
+ } while (ret == -1 && errno == EINTR);
+
+ // if (FD_ISSET(mPresenter.mFd, &mFds)) {
+ // TODO: handle drm related events
+ // }
+
+ if (FD_ISSET(mEventFd, &mFds)) {
+ UEventHandler();
+ }
+ return true;
+}
+
+void DrmPresenter::DrmEventListener::UEventHandler() {
+ char buffer[1024];
+ int ret;
+
+ struct timespec ts;
+ uint64_t timestamp = 0;
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (!ret) {
+ timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+ } else {
+ ALOGE("Failed to get monotonic clock on hotplug %d", ret);
+ }
+
+ while (true) {
+ ret = read(mEventFd, &buffer, sizeof(buffer));
+ if (ret == 0) {
+ return;
+ } else if (ret < 0) {
+ ALOGE("Got error reading uevent %d", ret);
+ return;
+ }
+
+ bool drmEvent = false, hotplugEvent = false;
+ for (int i = 0; i < ret;) {
+ char *event = buffer + i;
+ if (strcmp(event, "DEVTYPE=drm_minor")) {
+ drmEvent = true;
+ } else if (strcmp(event, "HOTPLUG=1")) {
+ hotplugEvent = true;
+ }
+
+ i += strlen(event) + 1;
+ }
+
+ if (drmEvent && hotplugEvent) {
+ processHotplug(timestamp);
+ }
+ }
+}
+
+void DrmPresenter::DrmEventListener::processHotplug(uint64_t timestamp) {
+ ALOGD("hotplug event %" PRIu64, timestamp);
+ mPresenter.handleHotPlug();
+}
} // namespace android
diff --git a/system/hwc2/DrmPresenter.h b/system/hwc2/DrmPresenter.h
index 0c3b5b1..26d3d94 100644
--- a/system/hwc2/DrmPresenter.h
+++ b/system/hwc2/DrmPresenter.h
@@ -17,13 +17,16 @@
#ifndef ANDROID_HWC_DRMPRESENTER_H
#define ANDROID_HWC_DRMPRESENTER_H
+#include <map>
+#include <memory>
+#include <vector>
+
#include <include/drmhwcgralloc.h>
+#include <utils/Thread.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <map>
-#include <vector>
-
+#include "android/base/synchronization/AndroidLock.h"
#include "Common.h"
namespace android {
@@ -63,21 +66,29 @@
DrmPresenter(DrmPresenter&&) = delete;
DrmPresenter& operator=(DrmPresenter&&) = delete;
- bool init();
- void clearDrmElements();
- bool configDrmElements();
+ using HotplugCallback =
+ std::function<void(bool /*connected*/, uint32_t /*id*/,
+ uint32_t /*width*/, uint32_t /*height*/,
+ uint32_t /*dpiX*/, uint32_t /*dpiY*/,
+ uint32_t /*refreshRate*/)>;
+
+ bool init(const HotplugCallback& cb);
+
+ void clearDrmElementsLocked();
+ bool configDrmElementsLocked();
int getDrmFB(hwc_drm_bo_t& bo);
int clearDrmFB(hwc_drm_bo_t& bo);
- bool supportComposeWithoutPost();
+
uint32_t refreshRate() const { return mConnectors[0].mRefreshRateAsInteger; }
+ bool handleHotPlug();
HWC2::Error flushToDisplay(int display, hwc_drm_bo_t& fb, int* outSyncFd);
private:
// Drm device.
int32_t mFd = -1;
-
+ HotplugCallback mHotplugCallback;
struct DrmPlane {
uint32_t mId = -1;
uint32_t mCrtcPropertyId = -1;
@@ -110,11 +121,30 @@
uint32_t mId = -1;
uint32_t mCrtcPropertyId = -1;
drmModeModeInfo mMode;
- uint32_t mModeBlobId;
+ int32_t dpiX;
+ int32_t dpiY;
+ drmModeConnection connection;
+ uint32_t mModeBlobId = 0;
float mRefreshRateAsFloat;
uint32_t mRefreshRateAsInteger;
};
std::vector<DrmConnector> mConnectors;
+
+ class DrmEventListener : public Thread {
+ public:
+ DrmEventListener(DrmPresenter& presenter);
+ virtual ~DrmEventListener();
+ private:
+ bool threadLoop() final;
+ void UEventHandler();
+ void processHotplug(uint64_t timestamp);
+ DrmPresenter& mPresenter;
+ int mEventFd;
+ int mMaxFd;
+ fd_set mFds;
+ };
+ std::unique_ptr<DrmEventListener> mDrmEventListener;
+ android::base::guest::ReadWriteLock mStateMutex;
};
} // namespace android
diff --git a/system/hwc2/GuestComposer.cpp b/system/hwc2/GuestComposer.cpp
index cf4bc52..d4db808 100644
--- a/system/hwc2/GuestComposer.cpp
+++ b/system/hwc2/GuestComposer.cpp
@@ -380,10 +380,10 @@
} // namespace
-HWC2::Error GuestComposer::init() {
+HWC2::Error GuestComposer::init(const HotplugCallback& cb) {
DEBUG_LOG("%s", __FUNCTION__);
- if (!mDrmPresenter.init()) {
+ if (!mDrmPresenter.init(cb)) {
ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
return HWC2::Error::NoResources;
}
@@ -410,81 +410,101 @@
ALOGE("%s failed to get display configs from system prop", __FUNCTION__);
return error;
}
-
+ uint32_t id = 0;
for (const auto& displayConfig : displayConfigs) {
- auto display = std::make_unique<Display>(*device, this);
- if (display == nullptr) {
- ALOGE("%s failed to allocate display", __FUNCTION__);
- return HWC2::Error::NoResources;
- }
-
- auto displayId = display->getId();
-
- error = display->init(displayConfig.width, //
- displayConfig.height, //
- displayConfig.dpiX, //
- displayConfig.dpiY, //
- displayConfig.refreshRateHz);
+ error = createDisplay(device,
+ id,
+ displayConfig.width,
+ displayConfig.height,
+ displayConfig.dpiX,
+ displayConfig.dpiY,
+ displayConfig.refreshRateHz,
+ addDisplayToDeviceFn);
if (error != HWC2::Error::None) {
- ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__,
- displayId);
+ ALOGE("%s: failed to create display %d", __FUNCTION__, id);
return error;
}
- auto it = mDisplayInfos.find(displayId);
- if (it != mDisplayInfos.end()) {
- ALOGE("%s: display:%" PRIu64 " already created?", __FUNCTION__,
- displayId);
+ ++id;
+ }
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::createDisplay(
+ Device* device, uint32_t id, uint32_t width, uint32_t height,
+ uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+ const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
+
+
+ auto display = std::make_unique<Display>(*device, this, id);
+ if (display == nullptr) {
+ ALOGE("%s failed to allocate display", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ auto displayId = display->getId();
+
+ HWC2::Error error = display->init(width, height, dpiX, dpiY, refreshRateHz);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__,
+ displayId);
+ return error;
+ }
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it != mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " already created?", __FUNCTION__,
+ displayId);
+ }
+
+ GuestComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
+
+ uint32_t bufferStride;
+ buffer_handle_t bufferHandle;
+
+ auto status = GraphicBufferAllocator::get().allocate(
+ width, //
+ height, //
+ PIXEL_FORMAT_RGBA_8888, //
+ /*layerCount=*/1, //
+ GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN |
+ GraphicBuffer::USAGE_SW_WRITE_OFTEN, //
+ &bufferHandle, //
+ &bufferStride, //
+ "RanchuHwc");
+ if (status != OK) {
+ ALOGE("%s failed to allocate composition buffer for display:%" PRIu64,
+ __FUNCTION__, displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ displayInfo.compositionResultBuffer = bufferHandle;
+
+ displayInfo.compositionResultDrmBuffer = std::make_unique<DrmBuffer>(
+ displayInfo.compositionResultBuffer, mDrmPresenter);
+
+ if (displayId == 0) {
+ int flushSyncFd = -1;
+
+ HWC2::Error flushError =
+ displayInfo.compositionResultDrmBuffer->flushToDisplay(displayId,
+ &flushSyncFd);
+ if (flushError != HWC2::Error::None) {
+ ALOGW(
+ "%s: Initial display flush failed. HWComposer assuming that we are "
+ "running in QEMU without a display and disabling presenting.",
+ __FUNCTION__);
+ mPresentDisabled = true;
+ } else {
+ close(flushSyncFd);
}
+ }
- GuestComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
-
- uint32_t bufferStride;
- buffer_handle_t bufferHandle;
-
- auto status = GraphicBufferAllocator::get().allocate(
- displayConfig.width, //
- displayConfig.height, //
- PIXEL_FORMAT_RGBA_8888, //
- /*layerCount=*/1, //
- GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN |
- GraphicBuffer::USAGE_SW_WRITE_OFTEN, //
- &bufferHandle, //
- &bufferStride, //
- "RanchuHwc");
- if (status != OK) {
- ALOGE("%s failed to allocate composition buffer for display:%" PRIu64,
- __FUNCTION__, displayId);
- return HWC2::Error::NoResources;
- }
-
- displayInfo.compositionResultBuffer = bufferHandle;
-
- displayInfo.compositionResultDrmBuffer = std::make_unique<DrmBuffer>(
- displayInfo.compositionResultBuffer, mDrmPresenter);
-
- if (displayId == 0) {
- int flushSyncFd = -1;
-
- HWC2::Error flushError =
- displayInfo.compositionResultDrmBuffer->flushToDisplay(displayId,
- &flushSyncFd);
- if (flushError != HWC2::Error::None) {
- ALOGW(
- "%s: Initial display flush failed. HWComposer assuming that we are "
- "running in QEMU without a display and disabling presenting.",
- __FUNCTION__);
- mPresentDisabled = true;
- } else {
- close(flushSyncFd);
- }
- }
-
- error = addDisplayToDeviceFn(std::move(display));
- if (error != HWC2::Error::None) {
- ALOGE("%s failed to add display:%" PRIu64, __FUNCTION__, displayId);
- return error;
- }
+ error = addDisplayToDeviceFn(std::move(display));
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to add display:%" PRIu64, __FUNCTION__, displayId);
+ return error;
}
return HWC2::Error::None;
diff --git a/system/hwc2/GuestComposer.h b/system/hwc2/GuestComposer.h
index c3e6eae..930cbee 100644
--- a/system/hwc2/GuestComposer.h
+++ b/system/hwc2/GuestComposer.h
@@ -35,12 +35,17 @@
GuestComposer(GuestComposer&&) = delete;
GuestComposer& operator=(GuestComposer&&) = delete;
- HWC2::Error init() override;
+ HWC2::Error init(const HotplugCallback& cb) override;
HWC2::Error createDisplays(
Device* device,
const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+ HWC2::Error createDisplay(
+ Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+ uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+ const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+
HWC2::Error onDisplayDestroy(Display*) override;
HWC2::Error onDisplayClientTargetSet(Display*) override {
@@ -110,4 +115,4 @@
} // namespace android
-#endif
\ No newline at end of file
+#endif
diff --git a/system/hwc2/HostComposer.cpp b/system/hwc2/HostComposer.cpp
index ad7f663..f280eb3 100644
--- a/system/hwc2/HostComposer.cpp
+++ b/system/hwc2/HostComposer.cpp
@@ -172,13 +172,13 @@
} // namespace
-HWC2::Error HostComposer::init() {
+HWC2::Error HostComposer::init(const HotplugCallback& cb) {
mIsMinigbm = isMinigbmFromProperty();
if (!mIsMinigbm) {
mSyncDeviceFd = goldfish_sync_open();
}
- if (!mDrmPresenter.init()) {
+ if (!mDrmPresenter.init(cb)) {
ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
// Non-fatal for HostComposer.
@@ -221,7 +221,7 @@
int refreshRateHz = getVsyncHzFromProperty();
- auto display = std::make_unique<Display>(*device, this);
+ auto display = std::make_unique<Display>(*device, this, 0);
if (display == nullptr) {
ALOGE("%s failed to allocate display", __FUNCTION__);
return HWC2::Error::NoResources;
@@ -251,6 +251,81 @@
return HWC2::Error::None;
}
+HWC2::Error HostComposer::createDisplay(
+ Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+ uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+ const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
+
+ HWC2::Error error;
+ Display* display = device->getDisplay(displayId);
+ if (display) {
+ ALOGD("%s display %d already existed, then update", __func__, displayId);
+ }
+
+ uint32_t actualHostDisplayId = displayId;
+ DEFINE_AND_VALIDATE_HOST_CONNECTION
+ hostCon->lock();
+ rcEnc->rcCreateDisplay(rcEnc, &actualHostDisplayId);
+ rcEnc->rcSetDisplayPose(rcEnc, actualHostDisplayId, -1, -1, width, height);
+ hostCon->unlock();
+
+ if (actualHostDisplayId != displayId) {
+ ALOGW(
+ "Something wrong with host displayId allocation, expected %d "
+ "but received %d",
+ displayId, actualHostDisplayId);
+ }
+
+ if (!display) {
+ auto newDisplay = std::make_unique<Display>(*device, this, displayId);
+ if (newDisplay == nullptr) {
+ ALOGE("%s failed to allocate display", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ error = newDisplay->init(width, height, dpiX, dpiY, refreshRateHz);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to initialize display:%" PRIu32, __FUNCTION__,
+ displayId);
+ return error;
+ }
+
+ error = createHostComposerDisplayInfo(newDisplay.get(), actualHostDisplayId);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to initialize host info for display:%" PRIu32,
+ __FUNCTION__, displayId);
+ return error;
+ }
+
+ error = addDisplayToDeviceFn(std::move(newDisplay));
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to add display:%" PRIu32, __FUNCTION__, displayId);
+ return error;
+ }
+ } else {
+ display->lock();
+ // update display parameters
+ error = display->updateParameters(width, height, dpiX, dpiY, refreshRateHz);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to update display:%" PRIu32, __FUNCTION__,
+ displayId);
+ display->unlock();
+ return error;
+ }
+
+ error = createHostComposerDisplayInfo(display, actualHostDisplayId);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to initialize host info for display:%" PRIu32,
+ __FUNCTION__, displayId);
+ display->unlock();
+ return error;
+ }
+ display->unlock();
+ }
+
+ return HWC2::Error::None;
+}
+
HWC2::Error HostComposer::createSecondaryDisplays(
Device* device, const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
HWC2::Error error = HWC2::Error::None;
@@ -286,7 +361,7 @@
static constexpr const uint32_t kHostDisplayIdStart = 6;
- uint32_t secondaryDisplayIndex = 0;
+ uint32_t secondaryDisplayIndex = 1;
while (!propIntParts.empty()) {
int width = propIntParts[1];
int height = propIntParts[2];
@@ -297,7 +372,7 @@
propIntParts.erase(propIntParts.begin(), propIntParts.begin() + 5);
uint32_t expectedHostDisplayId =
- kHostDisplayIdStart + secondaryDisplayIndex;
+ kHostDisplayIdStart + secondaryDisplayIndex - 1;
uint32_t actualHostDisplayId = 0;
DEFINE_AND_VALIDATE_HOST_CONNECTION
@@ -314,7 +389,7 @@
expectedHostDisplayId, actualHostDisplayId);
}
- auto display = std::make_unique<Display>(*device, this);
+ auto display = std::make_unique<Display>(*device, this, secondaryDisplayIndex++);
if (display == nullptr) {
ALOGE("%s failed to allocate display", __FUNCTION__);
return HWC2::Error::NoResources;
@@ -423,6 +498,13 @@
HostComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
+ if (displayId != 0 ) {
+ DEFINE_AND_VALIDATE_HOST_CONNECTION
+ hostCon->lock();
+ rcEnc->rcDestroyDisplay(rcEnc, displayInfo.hostDisplayId);
+ hostCon->unlock();
+ }
+
FreeDisplayColorBuffer(displayInfo.compositionResultBuffer);
mDisplayInfos.erase(it);
@@ -466,6 +548,8 @@
if (hostCompositionV1 || hostCompositionV2) {
// Support Device and SolidColor, otherwise, fallback all layers to Client.
bool fallBack = false;
+ //TODO: use local var compositiontype, avoid call getCompositionType() many
+ //times
for (auto& layer : layers) {
if (layer->getCompositionType() == HWC2::Composition::Invalid) {
// Log error for unused layers, layer leak?
@@ -554,7 +638,7 @@
if (displayClientTarget.getBuffer() != nullptr) {
if (mIsMinigbm) {
int retireFence;
- displayInfo.clientTargetDrmBuffer->flushToDisplay(0, &retireFence);
+ displayInfo.clientTargetDrmBuffer->flushToDisplay(display->getId(), &retireFence);
*outRetireFence = dup(retireFence);
close(retireFence);
} else {
@@ -589,6 +673,7 @@
int releaseLayersCount = 0;
for (auto layer : layers) {
+ //TODO: use local var composisitonType to store getCompositionType()
if (layer->getCompositionType() != HWC2::Composition::Device &&
layer->getCompositionType() != HWC2::Composition::SolidColor) {
ALOGE("%s: Unsupported composition types %d layer %u", __FUNCTION__,
@@ -714,7 +799,7 @@
hostCon->unlock();
if (mIsMinigbm) {
- displayInfo.compositionResultDrmBuffer->flushToDisplay(0, &retire_fd);
+ displayInfo.compositionResultDrmBuffer->flushToDisplay(display->getId(), &retire_fd);
} else {
goldfish_sync_queue_work(mSyncDeviceFd, sync_handle, thread_handle,
&retire_fd);
@@ -738,7 +823,7 @@
// we set all layers Composition::Client, so do nothing.
if (mIsMinigbm) {
int retireFence;
- displayInfo.clientTargetDrmBuffer->flushToDisplay(0, &retireFence);
+ displayInfo.clientTargetDrmBuffer->flushToDisplay(display->getId(), &retireFence);
*outRetireFence = dup(retireFence);
close(retireFence);
} else {
@@ -763,4 +848,4 @@
hostCon->unlock();
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/system/hwc2/HostComposer.h b/system/hwc2/HostComposer.h
index 31188d3..fe4a49f 100644
--- a/system/hwc2/HostComposer.h
+++ b/system/hwc2/HostComposer.h
@@ -34,12 +34,17 @@
HostComposer(HostComposer&&) = delete;
HostComposer& operator=(HostComposer&&) = delete;
- HWC2::Error init() override;
+ HWC2::Error init(const HotplugCallback& cb) override;
HWC2::Error createDisplays(
Device* device,
const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+ HWC2::Error createDisplay(
+ Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+ uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+ const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+
HWC2::Error onDisplayDestroy(Display* display) override;
HWC2::Error onDisplayClientTargetSet(Display* display) override;
@@ -92,4 +97,4 @@
} // namespace android
-#endif
\ No newline at end of file
+#endif