- Fixes segfault during client switch.
- Allows to run VTS on Android-11.
VTS Results:
============================================
arm64-v8a VtsHalGraphicsComposerV2_1TargetTest: [53 tests / 42808 msec]
armeabi-v7a VtsHalGraphicsComposerV2_1TargetTest: [53 tests / 33353 msec]
=============== Summary ===============
2/2 modules completed
Total Tests : 106
PASSED : 106
FAILED : 0
============================================
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
namespace android {
-class DrmVsyncCallback : public VsyncCallback {
- public:
- DrmVsyncCallback(hwc2_callback_data_t data, hwc2_function_pointer_t hook)
- : data_(data), hook_(hook) {
- }
-
- void Callback(int display, int64_t timestamp) {
- auto hook = reinterpret_cast<HWC2_PFN_VSYNC>(hook_);
- hook(data_, display, timestamp);
- }
-
- private:
- hwc2_callback_data_t data_;
- hwc2_function_pointer_t hook_;
-};
-
DrmHwcTwo::DrmHwcTwo() {
common.tag = HARDWARE_DEVICE_TAG;
common.version = HWC_DEVICE_API_VERSION_2_0;
hwc2_callback_data_t data,
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) {
+ switch (static_cast<HWC2::Callback>(descriptor)) {
case HWC2::Callback::Hotplug: {
+ SetHotplugCallback(data, function);
auto &drmDevices = resource_manager_.getDrmDevices();
for (auto &device : drmDevices)
HandleInitialHotplugState(device.get());
return SetActiveConfig(connector_->get_preferred_mode_id());
}
-HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback(
+void DrmHwcTwo::HwcDisplay::RegisterVsyncCallback(
hwc2_callback_data_t data, hwc2_function_pointer_t func) {
supported(__func__);
- auto callback = std::make_shared<DrmVsyncCallback>(data, func);
- vsync_worker_.RegisterCallback(std::move(callback));
- return HWC2::Error::None;
+ vsync_worker_.RegisterClientCallback(data, func);
}
void DrmHwcTwo::HwcDisplay::RegisterRefreshCallback(
hwc2_callback_data_t data, hwc2_function_pointer_t func) {
supported(__func__);
- auto hook = reinterpret_cast<HWC2_PFN_REFRESH>(func);
- compositor_.SetRefreshCallback([data, hook](int display) {
- hook(data, static_cast<hwc2_display_t>(display));
- });
+ compositor_.SetRefreshCallback(data, func);
}
HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
}
void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
- auto cb = callbacks_.find(HWC2::Callback::Hotplug);
- if (cb == callbacks_.end())
- return;
+ const std::lock_guard<std::mutex> lock(hotplug_callback_lock);
- 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));
+ if (hotplug_callback_hook_ && hotplug_callback_data_)
+ hotplug_callback_hook_(hotplug_callback_data_, displayid,
+ state == DRM_MODE_CONNECTED
+ ? HWC2_CONNECTION_CONNECTED
+ : HWC2_CONNECTION_DISCONNECTED);
}
void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
HWC2::Error Init();
+ hwc2_callback_data_t hotplug_callback_data_ = NULL;
+ HWC2_PFN_HOTPLUG hotplug_callback_hook_ = NULL;
+ std::mutex hotplug_callback_lock;
+
+ void SetHotplugCallback(hwc2_callback_data_t data,
+ hwc2_function_pointer_t hook) {
+ const std::lock_guard<std::mutex> lock(hotplug_callback_lock);
+ hotplug_callback_data_ = data;
+ hotplug_callback_hook_ = reinterpret_cast<HWC2_PFN_HOTPLUG>(hook);
+ }
+
class HwcLayer {
public:
HWC2::Composition sf_type() const {
android_dataspace_t dataspace_ = HAL_DATASPACE_UNKNOWN;
};
- struct HwcCallback {
- HwcCallback(hwc2_callback_data_t d, hwc2_function_pointer_t f)
- : data(d), func(f) {
- }
- hwc2_callback_data_t data;
- hwc2_function_pointer_t func;
- };
-
class HwcDisplay {
public:
HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
HwcDisplay(const HwcDisplay &) = delete;
HWC2::Error Init(std::vector<DrmPlane *> *planes);
- HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data,
- hwc2_function_pointer_t func);
+ void RegisterVsyncCallback(hwc2_callback_data_t data,
+ hwc2_function_pointer_t func);
void RegisterRefreshCallback(hwc2_callback_data_t data,
hwc2_function_pointer_t func);
HWC2::Error CreateComposition(bool test);
ResourceManager resource_manager_;
std::map<hwc2_display_t, HwcDisplay> displays_;
- std::map<HWC2::Callback, HwcCallback> callbacks_;
std::string mDumpString;
};
}
int DrmDisplayCompositor::FlattenOnClient() {
- if (refresh_display_cb_) {
+ const std::lock_guard<std::mutex> lock(refresh_callback_lock);
+
+ if (refresh_callback_hook_ && refresh_callback_data_) {
{
AutoLock lock(&lock_, __func__);
if (!IsFlatteningNeeded()) {
"No writeback connector available, "
"falling back to client composition");
SetFlattening(FlatteningState::kClientRequested);
- refresh_display_cb_(display_);
+ refresh_callback_hook_(refresh_callback_data_, display_);
return 0;
} else {
ALOGV("No writeback connector available");
int Init(ResourceManager *resource_manager, int display);
- template <typename Fn>
- void SetRefreshCallback(Fn &&refresh_cb) {
- refresh_display_cb_ = std::forward<Fn>(refresh_cb);
+ hwc2_callback_data_t refresh_callback_data_ = NULL;
+ HWC2_PFN_REFRESH refresh_callback_hook_ = NULL;
+ std::mutex refresh_callback_lock;
+
+ void SetRefreshCallback(hwc2_callback_data_t data,
+ hwc2_function_pointer_t hook) {
+ const std::lock_guard<std::mutex> lock(refresh_callback_lock);
+ refresh_callback_data_ = data;
+ refresh_callback_hook_ = reinterpret_cast<HWC2_PFN_REFRESH>(hook);
}
std::unique_ptr<DrmDisplayComposition> CreateComposition() const;
Unlock();
}
+void VSyncWorker::RegisterClientCallback(hwc2_callback_data_t data,
+ hwc2_function_pointer_t hook) {
+ Lock();
+ vsync_callback_data_ = data;
+ vsync_callback_hook_ = reinterpret_cast<HWC2_PFN_VSYNC>(hook);
+ Unlock();
+}
+
void VSyncWorker::VSyncControl(bool enabled) {
Lock();
enabled_ = enabled;
(int64_t)vblank.reply.tval_usec * 1000;
}
- /*
- * VSync could be disabled during routine execution so it could potentially
- * lead to crash since callback's inner hook could be invalid anymore. We have
- * no control over lifetime of this hook, therefore we can't rely that it'll
- * be valid after vsync disabling.
- *
- * Blocking VSyncControl to wait until routine
- * will finish execution is logically correct way to fix this issue, but it
- * creates visible lags and stutters, so we have to resort to other ways of
- * mitigating this issue.
- *
- * Doing check before attempt to invoke callback drastically shortens the
- * window when such situation could happen and that allows us to practically
- * avoid this issue.
- *
- * Please note that issue described below is different one and it is related
- * to RegisterCallback, not to disabling vsync via VSyncControl.
- */
if (!enabled_)
return;
- /*
- * There's a race here where a change in callback_ will not take effect until
- * the next subsequent requested vsync. This is unavoidable since we can't
- * call the vsync hook while holding the thread lock.
- *
- * We could shorten the race window by caching callback_ right before calling
- * the hook. However, in practice, callback_ is only updated once, so it's not
- * worth the overhead.
- */
+
if (callback)
callback->Callback(display, timestamp);
+
+ Lock();
+ if (enabled_ && vsync_callback_hook_ && vsync_callback_data_)
+ vsync_callback_hook_(vsync_callback_data_, display, timestamp);
+ Unlock();
+
last_timestamp_ = timestamp;
}
} // namespace android
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
+#include <hardware/hwcomposer2.h>
#include <stdint.h>
#include <map>
int Init(DrmDevice *drm, int display);
void RegisterCallback(std::shared_ptr<VsyncCallback> callback);
+ void RegisterClientCallback(hwc2_callback_data_t data,
+ hwc2_function_pointer_t hook);
void VSyncControl(bool enabled);
int display_;
std::atomic_bool enabled_;
int64_t last_timestamp_;
+
+ hwc2_callback_data_t vsync_callback_data_ = NULL;
+ HWC2_PFN_VSYNC vsync_callback_hook_ = NULL;
};
} // namespace android