getFunction = HookDevGetFunction;
}
-HWC2::Error DrmHwcTwo::Init() {
- int ret = resource_manager_.Init();
- if (ret) {
- ALOGE("Can't initialize the resource manager %d", ret);
- return HWC2::Error::NoResources;
- }
-
- DrmDevice *drm = resource_manager_.GetDrmDevice(HWC_DISPLAY_PRIMARY);
- std::shared_ptr<Importer> importer = resource_manager_.GetImporter(
- HWC_DISPLAY_PRIMARY);
+HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
+ HWC2::DisplayType type) {
+ DrmDevice *drm = resource_manager_.GetDrmDevice(displ);
+ std::shared_ptr<Importer> importer = resource_manager_.GetImporter(displ);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
-
- displays_.emplace(std::piecewise_construct,
- std::forward_as_tuple(HWC_DISPLAY_PRIMARY),
+ displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
std::forward_as_tuple(&resource_manager_, drm, importer,
- HWC_DISPLAY_PRIMARY,
- HWC2::DisplayType::Physical));
+ displ, type));
- DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
+ DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
if (!crtc) {
- ALOGE("Failed to get crtc for display %d",
- static_cast<int>(HWC_DISPLAY_PRIMARY));
+ ALOGE("Failed to get crtc for display %d", static_cast<int>(displ));
return HWC2::Error::BadDisplay;
}
-
std::vector<DrmPlane *> display_planes;
for (auto &plane : drm->planes()) {
if (plane->GetCrtcSupported(*crtc))
display_planes.push_back(plane.get());
}
- displays_.at(HWC_DISPLAY_PRIMARY).Init(&display_planes);
+ displays_.at(displ).Init(&display_planes);
return HWC2::Error::None;
}
+HWC2::Error DrmHwcTwo::Init() {
+ int rv = resource_manager_.Init();
+ if (rv) {
+ ALOGE("Can't initialize the resource manager %d", rv);
+ return HWC2::Error::NoResources;
+ }
+
+ HWC2::Error ret = HWC2::Error::None;
+ for (int i = 0; i < resource_manager_.getDisplayCount(); i++) {
+ ret = CreateDisplay(i, HWC2::DisplayType::Physical);
+ if (ret != HWC2::Error::None) {
+ ALOGE("Failed to create display %d with error %d", i, ret);
+ return ret;
+ }
+ }
+
+ auto &drmDevices = resource_manager_.getDrmDevices();
+ for (auto &device : drmDevices) {
+ device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
+ }
+ return ret;
+}
+
template <typename... Args>
static inline HWC2::Error unsupported(char const *func, Args... /*args*/) {
ALOGV("Unsupported function: %s", func);
hwc2_function_pointer_t function) {
supported(__func__);
auto callback = static_cast<HWC2::Callback>(descriptor);
+
+ if (!function) {
+ callbacks_.erase(callback);
+ return HWC2::Error::None;
+ }
+
callbacks_.emplace(callback, HwcCallback(data, function));
switch (callback) {
auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function);
hotplug(data, HWC_DISPLAY_PRIMARY,
static_cast<int32_t>(HWC2::Connection::Connected));
+ auto &drmDevices = resource_manager_.getDrmDevices();
+ for (auto &device : drmDevices)
+ HandleInitialHotplugState(device.get());
break;
}
case HWC2::Callback::Vsync: {
supported(__func__);
}
+void DrmHwcTwo::HwcDisplay::ClearDisplay() {
+ compositor_.ClearDisplay();
+}
+
HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
supported(__func__);
planner_ = Planner::CreateInstance(drm_);
return HWC2::Error::BadDisplay;
}
+ ret = vsync_worker_.Init(drm_, display);
+ if (ret) {
+ ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
+ return HWC2::Error::BadDisplay;
+ }
+
+ return ChosePreferredConfig();
+}
+
+HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
// Fetch the number of modes from the display
uint32_t num_configs;
HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
err = GetDisplayConfigs(&num_configs, &default_config);
if (err != HWC2::Error::None)
return err;
-
- ret = vsync_worker_.Init(drm_, display);
- if (ret) {
- ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
- return HWC2::Error::BadDisplay;
- }
-
return SetActiveConfig(default_config);
}
ALOGE("Failed to queue dpms composition on %d", ret);
return HWC2::Error::BadConfig;
}
- if (connector_->active_mode().id() == 0)
- connector_->set_active_mode(*mode);
+
+ connector_->set_active_mode(*mode);
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
layer->SetTransform(static_cast<int32_t>(transform_));
}
+void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
+ auto cb = callbacks_.find(HWC2::Callback::Hotplug);
+ if (cb == callbacks_.end())
+ return;
+
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(cb->second.func);
+ hotplug(cb->second.data, displayid,
+ (state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+ : HWC2_CONNECTION_DISCONNECTED));
+}
+
+void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
+ for (auto &conn : drmDevice->connectors()) {
+ if (conn->state() != DRM_MODE_CONNECTED)
+ continue;
+ HandleDisplayHotplug(conn->display(), conn->state());
+ }
+}
+
+void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
+ for (auto &conn : drm_->connectors()) {
+ drmModeConnection old_state = conn->state();
+ drmModeConnection cur_state = conn->UpdateModes()
+ ? DRM_MODE_UNKNOWNCONNECTION
+ : conn->state();
+
+ if (cur_state == old_state)
+ continue;
+
+ ALOGI("%s event @%" PRIu64 " for connector %u on display %d",
+ cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
+ conn->id(), conn->display());
+
+ int display_id = conn->display();
+ if (cur_state == DRM_MODE_CONNECTED) {
+ auto &display = hwc2_->displays_.at(display_id);
+ display.ChosePreferredConfig();
+ } else {
+ auto &display = hwc2_->displays_.at(display_id);
+ display.ClearDisplay();
+ }
+
+ hwc2_->HandleDisplayHotplug(display_id, cur_state);
+ }
+}
+
// static
int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) {
unsupported(__func__);
HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data,
hwc2_function_pointer_t func);
+ void ClearDisplay();
// HWC Hooks
HWC2::Error AcceptDisplayChanges();
int32_t *fences);
HWC2::Error PresentDisplay(int32_t *retire_fence);
HWC2::Error SetActiveConfig(hwc2_config_t config);
+ HWC2::Error ChosePreferredConfig();
HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
int32_t dataspace, hwc_region_t damage);
HWC2::Error SetColorMode(int32_t mode);
uint32_t frame_no_ = 0;
};
+ class DrmHotplugHandler : public DrmEventHandler {
+ public:
+ DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm)
+ : hwc2_(hwc2), drm_(drm) {
+ }
+ void HandleEvent(uint64_t timestamp_us);
+
+ private:
+ DrmHwcTwo *hwc2_;
+ DrmDevice *drm_;
+ };
+
static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) {
return static_cast<DrmHwcTwo *>(dev);
}
uint32_t GetMaxVirtualDisplayCount();
HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
hwc2_function_pointer_t function);
+ HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type);
+ void HandleDisplayHotplug(hwc2_display_t displayid, int state);
+ void HandleInitialHotplugState(DrmDevice *drmDevice);
ResourceManager resource_manager_;
std::map<hwc2_display_t, HwcDisplay> displays_;