Use a separate hwcomposer hidl instance for vr flinger
Improve robustness of vr flinger <--> surface flinger switching by
having vr flinger use a separate hardware composer hidl instance instead
of sharing the instance with surface flinger. Sharing the hardware
composer instance has proven to be error prone, with situations where
both the vr flinger thread and surface flinger main thread would write
to the composer at the same time, causing hard to diagnose
crashes (b/62925812).
Instead of sharing the hardware composer instance, when switching to vr
flinger we now delete the existing instance, create a new instance
directed to the vr hardware composer shim, and vr flinger creates its
own composer instance connected to the real hardware composer. By
creating a separate composer instance for vr flinger, crashes like the
ones found in b/62925812 are no longer impossible.
Most of the changes in this commit are related to enabling surface
flinger to delete HWComposer instances cleanly. In particular:
- Previously the hardware composer callbacks (which come in on a
hwbinder thread) would land in HWC2::Device and bubble up to the
SurfaceFlinger object. But with the new behavior the HWC2::Device
might be dead or in the process of being destroyed, so instead we have
SurfaceFlinger receive the composer callbacks directly, and forward
them to HWComposer and HWC2::Device. We include a composer id field in
the callbacks so surface flinger can ignore stale callbacks from dead
composer instances.
- Object ownership for HWC2::Display and HWC2::Layer was shared by
passing around shared_ptrs to these objects. This was problematic
because they referenced and used the HWC2::Device, which can now be
destroyed when switching to vr flinger. Simplify the ownership model
by having HWC2::Device own (via unique_ptr<>) instances of
HWC2::Display, which owns (again via unique_ptr<>) instances of
HWC2::Layer. In cases where we previously passed std::shared_ptr<> to
HWC2::Display or HWC2::Layer, instead pass non-owning HWC2::Display*
and HWC2::Layer* pointers. This ensures clean composer instance
teardown with no stale references to the deleted HWC2::Device.
- When the hardware composer instance is destroyed and the HWC2::Layers
are removed, notify the android::Layer via a callback, so it can
remove the HWC2::Layer from its internal table of hardware composer
layers. This removes the burden to explicitly clear out all hardware
composer layers when switching to vr flinger, which has been a source
of bugs.
- We were missing an mStateLock lock in
SurfaceFlinger::setVsyncEnabled(), which was necessary to ensure we
were setting vsync on the correct hardware composer instance. Once
that lock was added, surface flinger would sometimes deadlock when
transitioning to vr flinger, because the surface flinger main thread
would acquire mStateLock and then EventControlThread::mMutex, whereas
the event control thread would acquire the locks in the opposite
order. The changes in EventControlThread.cpp are to ensure it doesn't
hold a lock on EventControlThread::mMutex while calling
setVsyncEnabled(), to avoid the deadlock.
I found that without a composer callback registered in vr flinger the
vsync_event file wasn't getting vsync timestamps written, so vr flinger
would get stuck in an infinite loop trying to parse a vsync
timestamp. Since we need to have a callback anyway I changed the code in
hardware_composer.cpp to get the vsync timestamp from the callback, as
surface flinger does. I confirmed the timestamps are the same with
either method, and this lets us remove some extra code for extracting
the vsync timestamp that (probably) wasn't compatible with all devices
we want to run on anyway. I also added a timeout to the vysnc wait so
we'll see an error message in the log if we fail to wait for vsync,
instead of looping forever.
Bug: 62925812
Test: - Confirmed surface flinger <--> vr flinger switching is robust by
switching devices on and off hundreds of times and observing no
hardware composer related issues, surface flinger crashes, or
hardware composer service crashes.
- Confirmed 2d in vr works as before by going through the OOBE flow on a
standalone. This also exercises virtual display creation and usage
through surface flinger.
- Added logs to confirm perfect layer/display cleanup when destroying
hardware composer instances.
- Tested normal 2d phone usage to confirm basic layer create/destroy
functionality works as before.
- Monitored surface flinger file descriptor usage across dozens of
surface flinger <--> vr flinger transitions and observed no file
descriptor leaks.
- Confirmed the HWC1 code path still compiles.
- Ran the surface flinger tests and confirmed there are no new test
failures.
- Ran the hardware composer hidl in passthrough mode on a Marlin and
confirmed it works.
- Ran CTS tests for virtual displays and confirmed they all pass.
- Tested Android Auto and confirmed basic graphics functionality still
works.
Change-Id: I17dc0e060bfb5cb447ffbaa573b279fc6d2d8bd1
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 733edc6..f350762 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -40,10 +40,8 @@
DisplayService::DisplayService(Hwc2::Composer* hidl,
RequestDisplayCallback request_display_callback)
: BASE("DisplayService",
- Endpoint::Create(display::DisplayProtocol::kClientPath)),
- hardware_composer_(hidl, request_display_callback),
- request_display_callback_(request_display_callback) {
- hardware_composer_.Initialize();
+ Endpoint::Create(display::DisplayProtocol::kClientPath)) {
+ hardware_composer_.Initialize(hidl, request_display_callback);
}
bool DisplayService::IsInitialized() const {
@@ -398,10 +396,6 @@
return {0};
}
-void DisplayService::OnHardwareComposerRefresh() {
- hardware_composer_.OnHardwareComposerRefresh();
-}
-
void DisplayService::SetDisplayConfigurationUpdateNotifier(
DisplayConfigurationUpdateNotifier update_notifier) {
update_notifier_ = update_notifier;
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 6efe264..55e33ab 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -72,8 +72,6 @@
void GrantDisplayOwnership() { hardware_composer_.Enable(); }
void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
- void OnHardwareComposerRefresh();
-
private:
friend BASE;
friend DisplaySurface;
@@ -119,7 +117,6 @@
pdx::Status<void> HandleSurfaceMessage(pdx::Message& message);
HardwareComposer hardware_composer_;
- RequestDisplayCallback request_display_callback_;
EpollEventDispatcher dispatcher_;
DisplayConfigurationUpdateNotifier update_notifier_;
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 11c1370..f9a5dcd 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -28,6 +28,8 @@
#include <private/dvr/clock_ns.h>
#include <private/dvr/ion_buffer.h>
+using android::hardware::Return;
+using android::hardware::Void;
using android::pdx::LocalHandle;
using android::pdx::rpc::EmptyVariant;
using android::pdx::rpc::IfAnyOf;
@@ -42,9 +44,6 @@
const char kBacklightBrightnessSysFile[] =
"/sys/class/leds/lcd-backlight/brightness";
-const char kPrimaryDisplayVSyncEventFile[] =
- "/sys/class/graphics/fb0/vsync_event";
-
const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp";
const char kDvrPerformanceProperty[] = "sys.dvr.performance";
@@ -86,22 +85,11 @@
} // anonymous namespace
-// Layer static data.
-Hwc2::Composer* Layer::hwc2_hidl_;
-const HWCDisplayMetrics* Layer::display_metrics_;
-
// HardwareComposer static data;
constexpr size_t HardwareComposer::kMaxHardwareLayers;
HardwareComposer::HardwareComposer()
- : HardwareComposer(nullptr, RequestDisplayCallback()) {}
-
-HardwareComposer::HardwareComposer(
- Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback)
- : initialized_(false),
- hwc2_hidl_(hwc2_hidl),
- request_display_callback_(request_display_callback),
- callbacks_(new ComposerCallback) {}
+ : initialized_(false), request_display_callback_(nullptr) {}
HardwareComposer::~HardwareComposer(void) {
UpdatePostThreadState(PostThreadState::Quit, true);
@@ -109,16 +97,19 @@
post_thread_.join();
}
-bool HardwareComposer::Initialize() {
+bool HardwareComposer::Initialize(
+ Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
if (initialized_) {
ALOGE("HardwareComposer::Initialize: already initialized.");
return false;
}
+ request_display_callback_ = request_display_callback;
+
HWC::Error error = HWC::Error::None;
Hwc2::Config config;
- error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
+ error = hidl->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
if (error != HWC::Error::None) {
ALOGE("HardwareComposer: Failed to get current display config : %d",
@@ -126,8 +117,8 @@
return false;
}
- error =
- GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_);
+ error = GetDisplayMetrics(hidl, HWC_DISPLAY_PRIMARY, config,
+ &native_display_metrics_);
if (error != HWC::Error::None) {
ALOGE(
@@ -149,9 +140,6 @@
display_transform_ = HWC_TRANSFORM_NONE;
display_metrics_ = native_display_metrics_;
- // Pass hwc instance and metrics to setup globals for Layer.
- Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_);
-
post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
LOG_ALWAYS_FATAL_IF(
!post_thread_event_fd_,
@@ -210,15 +198,11 @@
}
void HardwareComposer::OnPostThreadResumed() {
- hwc2_hidl_->resetCommands();
+ hidl_.reset(new Hwc2::Composer("default"));
+ hidl_callback_ = new ComposerCallback;
+ hidl_->registerCallback(hidl_callback_);
- // HIDL HWC seems to have an internal race condition. If we submit a frame too
- // soon after turning on VSync we don't get any VSync signals. Give poor HWC
- // implementations a chance to enable VSync before we continue.
- EnableVsync(false);
- std::this_thread::sleep_for(100ms);
EnableVsync(true);
- std::this_thread::sleep_for(100ms);
// TODO(skiazyk): We need to do something about accessing this directly,
// supposedly there is a backlight service on the way.
@@ -240,9 +224,12 @@
}
active_layer_count_ = 0;
- EnableVsync(false);
+ if (hidl_) {
+ EnableVsync(false);
+ }
- hwc2_hidl_->resetCommands();
+ hidl_callback_ = nullptr;
+ hidl_.reset(nullptr);
// Trigger target-specific performance mode change.
property_set(kDvrPerformanceProperty, "idle");
@@ -252,21 +239,21 @@
uint32_t num_types;
uint32_t num_requests;
HWC::Error error =
- hwc2_hidl_->validateDisplay(display, &num_types, &num_requests);
+ hidl_->validateDisplay(display, &num_types, &num_requests);
if (error == HWC2_ERROR_HAS_CHANGES) {
// TODO(skiazyk): We might need to inspect the requested changes first, but
// so far it seems like we shouldn't ever hit a bad state.
// error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
// display);
- error = hwc2_hidl_->acceptDisplayChanges(display);
+ error = hidl_->acceptDisplayChanges(display);
}
return error;
}
-int32_t HardwareComposer::EnableVsync(bool enabled) {
- return (int32_t)hwc2_hidl_->setVsyncEnabled(
+HWC::Error HardwareComposer::EnableVsync(bool enabled) {
+ return hidl_->setVsyncEnabled(
HWC_DISPLAY_PRIMARY,
(Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
: HWC2_VSYNC_DISABLE));
@@ -274,7 +261,7 @@
HWC::Error HardwareComposer::Present(hwc2_display_t display) {
int32_t present_fence;
- HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence);
+ HWC::Error error = hidl_->presentDisplay(display, &present_fence);
// According to the documentation, this fence is signaled at the time of
// vsync/DMA for physical displays.
@@ -288,20 +275,21 @@
return error;
}
-HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display,
+HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* hidl,
+ hwc2_display_t display,
hwc2_config_t config,
hwc2_attribute_t attribute,
int32_t* out_value) const {
- return hwc2_hidl_->getDisplayAttribute(
+ return hidl->getDisplayAttribute(
display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
}
HWC::Error HardwareComposer::GetDisplayMetrics(
- hwc2_display_t display, hwc2_config_t config,
+ Hwc2::Composer* hidl, hwc2_display_t display, hwc2_config_t config,
HWCDisplayMetrics* out_metrics) const {
HWC::Error error;
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH,
+ error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_WIDTH,
&out_metrics->width);
if (error != HWC::Error::None) {
ALOGE(
@@ -310,7 +298,7 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT,
+ error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_HEIGHT,
&out_metrics->height);
if (error != HWC::Error::None) {
ALOGE(
@@ -319,7 +307,8 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD,
+ error = GetDisplayAttribute(hidl, display, config,
+ HWC2_ATTRIBUTE_VSYNC_PERIOD,
&out_metrics->vsync_period_ns);
if (error != HWC::Error::None) {
ALOGE(
@@ -328,7 +317,7 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X,
+ error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_X,
&out_metrics->dpi.x);
if (error != HWC::Error::None) {
ALOGE(
@@ -337,7 +326,7 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y,
+ error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_Y,
&out_metrics->dpi.y);
if (error != HWC::Error::None) {
ALOGE(
@@ -374,7 +363,7 @@
if (post_thread_resumed_) {
stream << "Hardware Composer Debug Info:" << std::endl;
- stream << hwc2_hidl_->dumpDebugInfo();
+ stream << hidl_->dumpDebugInfo();
}
return stream.str();
@@ -446,8 +435,8 @@
std::vector<Hwc2::Layer> out_layers;
std::vector<int> out_fences;
- error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
- &out_fences);
+ error = hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
+ &out_fences);
ALOGE_IF(error != HWC::Error::None,
"HardwareComposer::PostLayers: Failed to get release fences: %s",
error.to_string().c_str());
@@ -546,7 +535,7 @@
}
int HardwareComposer::PostThreadPollInterruptible(
- const pdx::LocalHandle& event_fd, int requested_events) {
+ const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) {
pollfd pfd[2] = {
{
.fd = event_fd.Get(),
@@ -561,7 +550,7 @@
};
int ret, error;
do {
- ret = poll(pfd, 2, -1);
+ ret = poll(pfd, 2, timeout_ms);
error = errno;
ALOGW_IF(ret < 0,
"HardwareComposer::PostThreadPollInterruptible: Error during "
@@ -571,6 +560,8 @@
if (ret < 0) {
return -error;
+ } else if (ret == 0) {
+ return -ETIMEDOUT;
} else if (pfd[0].revents != 0) {
return 0;
} else if (pfd[1].revents != 0) {
@@ -623,114 +614,17 @@
}
}
-// Reads the timestamp of the last vsync from the display driver.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) {
- const int event_fd = primary_display_vsync_event_fd_.Get();
- int ret, error;
-
- // The driver returns data in the form "VSYNC=<timestamp ns>".
- std::array<char, 32> data;
- data.fill('\0');
-
- // Seek back to the beginning of the event file.
- ret = lseek(event_fd, 0, SEEK_SET);
- if (ret < 0) {
- error = errno;
- ALOGE(
- "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: "
- "%s",
- strerror(error));
- return -error;
- }
-
- // Read the vsync event timestamp.
- ret = read(event_fd, data.data(), data.size());
- if (ret < 0) {
- error = errno;
- ALOGE_IF(
- error != EAGAIN,
- "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: "
- "%s",
- strerror(error));
- return -error;
- }
-
- ret = sscanf(data.data(), "VSYNC=%" PRIu64,
- reinterpret_cast<uint64_t*>(timestamp));
- if (ret < 0) {
- error = errno;
- ALOGE(
- "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: "
- "%s",
- strerror(error));
- return -error;
- }
-
- return 0;
-}
-
-// Blocks until the next vsync event is signaled by the display driver.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::BlockUntilVSync() {
- // Vsync is signaled by POLLPRI on the fb vsync node.
- return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI);
-}
-
// Waits for the next vsync and returns the timestamp of the vsync event. If
// vsync already passed since the last call, returns the latest vsync timestamp
-// instead of blocking. This method updates the last_vsync_timeout_ in the
-// process.
-//
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
+// instead of blocking.
int HardwareComposer::WaitForVSync(int64_t* timestamp) {
- int error;
-
- // Get the current timestamp and decide what to do.
- while (true) {
- int64_t current_vsync_timestamp;
- error = ReadVSyncTimestamp(¤t_vsync_timestamp);
- if (error < 0 && error != -EAGAIN)
- return error;
-
- if (error == -EAGAIN) {
- // Vsync was turned off, wait for the next vsync event.
- error = BlockUntilVSync();
- if (error < 0 || error == kPostThreadInterrupted)
- return error;
-
- // Try again to get the timestamp for this new vsync interval.
- continue;
- }
-
- // Check that we advanced to a later vsync interval.
- if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) {
- *timestamp = last_vsync_timestamp_ = current_vsync_timestamp;
- return 0;
- }
-
- // See how close we are to the next expected vsync. If we're within 1ms,
- // sleep for 1ms and try again.
- const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
- const int64_t threshold_ns = 1000000; // 1ms
-
- const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame;
- const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs();
-
- if (distance_to_vsync_est > threshold_ns) {
- // Wait for vsync event notification.
- error = BlockUntilVSync();
- if (error < 0 || error == kPostThreadInterrupted)
- return error;
- } else {
- // Sleep for a short time (1 millisecond) before retrying.
- error = SleepUntil(GetSystemClockNs() + threshold_ns);
- if (error < 0 || error == kPostThreadInterrupted)
- return error;
- }
+ int error = PostThreadPollInterruptible(
+ hidl_callback_->GetVsyncEventFd(), POLLIN, /*timeout_ms*/ 1000);
+ if (error == kPostThreadInterrupted || error < 0) {
+ return error;
+ } else {
+ *timestamp = hidl_callback_->GetVsyncTime();
+ return 0;
}
}
@@ -749,7 +643,8 @@
return -error;
}
- return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN);
+ return PostThreadPollInterruptible(
+ vsync_sleep_timer_fd_, POLLIN, /*timeout_ms*/ -1);
}
void HardwareComposer::PostThread() {
@@ -772,15 +667,6 @@
strerror(errno));
#endif // ENABLE_BACKLIGHT_BRIGHTNESS
- // Open the vsync event node for the primary display.
- // TODO(eieio): Move this into a platform-specific class.
- primary_display_vsync_event_fd_ =
- LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
- ALOGE_IF(!primary_display_vsync_event_fd_,
- "HardwareComposer: Failed to open vsync event node for primary "
- "display: %s",
- strerror(errno));
-
// Open the wait pingpong status node for the primary display.
// TODO(eieio): Move this into a platform-specific class.
primary_display_wait_pp_fd_ =
@@ -951,7 +837,8 @@
// The bottom layer is opaque, other layers blend.
HWC::BlendMode blending =
layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage;
- layers_[layer_index].Setup(surfaces[layer_index], blending,
+ layers_[layer_index].Setup(surfaces[layer_index], native_display_metrics_,
+ hidl_.get(), blending,
display_transform_, HWC::Composition::Device,
layer_index);
display_surfaces_.push_back(surfaces[layer_index]);
@@ -979,30 +866,6 @@
vsync_callback_ = callback;
}
-void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/,
- hwc2_display_t /*display*/) {
- // TODO(eieio): implement invalidate callbacks.
-}
-
-void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/,
- hwc2_display_t /*display*/,
- int64_t /*timestamp*/) {
- ATRACE_NAME(__PRETTY_FUNCTION__);
- // Intentionally empty. HWC may require a callback to be set to enable vsync
- // signals. We bypass this callback thread by monitoring the vsync event
- // directly, but signals still need to be enabled.
-}
-
-void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/,
- hwc2_display_t /*display*/,
- hwc2_connection_t /*connected*/) {
- // TODO(eieio): implement display hotplug callbacks.
-}
-
-void HardwareComposer::OnHardwareComposerRefresh() {
- // TODO(steventhomas): Handle refresh.
-}
-
void HardwareComposer::SetBacklightBrightness(int brightness) {
if (backlight_brightness_fd_) {
std::array<char, 32> text;
@@ -1011,18 +874,59 @@
}
}
-void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl,
- const HWCDisplayMetrics* metrics) {
- hwc2_hidl_ = hwc2_hidl;
- display_metrics_ = metrics;
+HardwareComposer::ComposerCallback::ComposerCallback() {
+ vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ LOG_ALWAYS_FATAL_IF(
+ !vsync_event_fd_,
+ "Failed to create vsync event fd : %s",
+ strerror(errno));
+}
+
+Return<void> HardwareComposer::ComposerCallback::onHotplug(
+ Hwc2::Display /*display*/,
+ IComposerCallback::Connection /*conn*/) {
+ return Void();
+}
+
+Return<void> HardwareComposer::ComposerCallback::onRefresh(
+ Hwc2::Display /*display*/) {
+ return hardware::Void();
+}
+
+Return<void> HardwareComposer::ComposerCallback::onVsync(
+ Hwc2::Display display, int64_t timestamp) {
+ if (display == HWC_DISPLAY_PRIMARY) {
+ std::lock_guard<std::mutex> lock(vsync_mutex_);
+ vsync_time_ = timestamp;
+ int error = eventfd_write(vsync_event_fd_.Get(), 1);
+ LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd");
+ }
+ return Void();
+}
+
+const pdx::LocalHandle&
+HardwareComposer::ComposerCallback::GetVsyncEventFd() const {
+ return vsync_event_fd_;
+}
+
+int64_t HardwareComposer::ComposerCallback::GetVsyncTime() {
+ std::lock_guard<std::mutex> lock(vsync_mutex_);
+ eventfd_t event;
+ eventfd_read(vsync_event_fd_.Get(), &event);
+ LOG_ALWAYS_FATAL_IF(vsync_time_ < 0,
+ "Attempt to read vsync time before vsync event");
+ int64_t return_val = vsync_time_;
+ vsync_time_ = -1;
+ return return_val;
}
void Layer::Reset() {
- if (hwc2_hidl_ != nullptr && hardware_composer_layer_) {
- hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
+ if (hidl_ != nullptr && hardware_composer_layer_) {
+ hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
hardware_composer_layer_ = 0;
}
+ hidl_ = nullptr;
z_order_ = 0;
blending_ = HWC::BlendMode::None;
transform_ = HWC::Transform::None;
@@ -1034,29 +938,35 @@
}
void Layer::Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_order) {
+ const HWCDisplayMetrics& display_metrics,
+ Hwc2::Composer* hidl, HWC::BlendMode blending,
+ HWC::Transform transform, HWC::Composition composition_type,
+ size_t z_order) {
Reset();
+ hidl_ = hidl;
z_order_ = z_order;
blending_ = blending;
transform_ = transform;
composition_type_ = HWC::Composition::Invalid;
target_composition_type_ = composition_type;
source_ = SourceSurface{surface};
- CommonLayerSetup();
+ CommonLayerSetup(display_metrics);
}
void Layer::Setup(const std::shared_ptr<IonBuffer>& buffer,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_order) {
+ const HWCDisplayMetrics& display_metrics,
+ Hwc2::Composer* hidl, HWC::BlendMode blending,
+ HWC::Transform transform, HWC::Composition composition_type,
+ size_t z_order) {
Reset();
+ hidl_ = hidl;
z_order_ = z_order;
blending_ = blending;
transform_ = transform;
composition_type_ = HWC::Composition::Invalid;
target_composition_type_ = composition_type;
source_ = SourceBuffer{buffer};
- CommonLayerSetup();
+ CommonLayerSetup(display_metrics);
}
void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) {
@@ -1076,7 +986,7 @@
return source_.Visit(Visitor{});
}
-void Layer::UpdateLayerSettings() {
+void Layer::UpdateLayerSettings(const HWCDisplayMetrics& display_metrics) {
if (!IsLayerSetup()) {
ALOGE(
"HardwareComposer::Layer::UpdateLayerSettings: Attempt to update "
@@ -1087,7 +997,7 @@
HWC::Error error;
hwc2_display_t display = HWC_DISPLAY_PRIMARY;
- error = hwc2_hidl_->setLayerCompositionType(
+ error = hidl_->setLayerCompositionType(
display, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
ALOGE_IF(
@@ -1095,7 +1005,7 @@
"Layer::UpdateLayerSettings: Error setting layer composition type: %s",
error.to_string().c_str());
- error = hwc2_hidl_->setLayerBlendMode(
+ error = hidl_->setLayerBlendMode(
display, hardware_composer_layer_,
blending_.cast<Hwc2::IComposerClient::BlendMode>());
ALOGE_IF(error != HWC::Error::None,
@@ -1104,41 +1014,39 @@
// TODO(eieio): Use surface attributes or some other mechanism to control
// the layer display frame.
- error = hwc2_hidl_->setLayerDisplayFrame(
+ error = hidl_->setLayerDisplayFrame(
display, hardware_composer_layer_,
- {0, 0, display_metrics_->width, display_metrics_->height});
+ {0, 0, display_metrics.width, display_metrics.height});
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer display frame: %s",
error.to_string().c_str());
- error = hwc2_hidl_->setLayerVisibleRegion(
+ error = hidl_->setLayerVisibleRegion(
display, hardware_composer_layer_,
- {{0, 0, display_metrics_->width, display_metrics_->height}});
+ {{0, 0, display_metrics.width, display_metrics.height}});
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer visible region: %s",
error.to_string().c_str());
- error =
- hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
+ error = hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
error.to_string().c_str());
- error =
- hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
+ error = hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting z_ order: %s",
error.to_string().c_str());
}
-void Layer::CommonLayerSetup() {
+void Layer::CommonLayerSetup(const HWCDisplayMetrics& display_metrics) {
HWC::Error error =
- hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
+ hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
ALOGE_IF(
error != HWC::Error::None,
"Layer::CommonLayerSetup: Failed to create layer on primary display: %s",
error.to_string().c_str());
- UpdateLayerSettings();
+ UpdateLayerSettings(display_metrics);
}
void Layer::Prepare() {
@@ -1157,12 +1065,12 @@
if (!handle.get()) {
if (composition_type_ == HWC::Composition::Invalid) {
composition_type_ = HWC::Composition::SolidColor;
- hwc2_hidl_->setLayerCompositionType(
+ hidl_->setLayerCompositionType(
HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
- hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
- layer_color);
+ hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+ layer_color);
} else {
// The composition type is already set. Nothing else to do until a
// buffer arrives.
@@ -1170,15 +1078,15 @@
} else {
if (composition_type_ != target_composition_type_) {
composition_type_ = target_composition_type_;
- hwc2_hidl_->setLayerCompositionType(
+ hidl_->setLayerCompositionType(
HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
}
HWC::Error error{HWC::Error::None};
- error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_, 0, handle,
- acquire_fence_.Get());
+ error = hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY,
+ hardware_composer_layer_, 0, handle,
+ acquire_fence_.Get());
ALOGE_IF(error != HWC::Error::None,
"Layer::Prepare: Error setting layer buffer: %s",
@@ -1187,9 +1095,9 @@
if (!surface_rect_functions_applied_) {
const float float_right = right;
const float float_bottom = bottom;
- error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_,
- {0, 0, float_right, float_bottom});
+ error = hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
+ hardware_composer_layer_,
+ {0, 0, float_right, float_bottom});
ALOGE_IF(error != HWC::Error::None,
"Layer::Prepare: Error setting layer source crop: %s",
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index a0c50e1..fc0efee 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -54,11 +54,6 @@
public:
Layer() {}
- // Sets up the global state used by all Layer instances. This must be called
- // before using any Layer methods.
- static void InitializeGlobals(Hwc2::Composer* hwc2_hidl,
- const HWCDisplayMetrics* metrics);
-
// Releases any shared pointers and fence handles held by this instance.
void Reset();
@@ -72,6 +67,7 @@
// HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
// |index| is the index of this surface in the DirectDisplaySurface array.
void Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
+ const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl,
HWC::BlendMode blending, HWC::Transform transform,
HWC::Composition composition_type, size_t z_roder);
@@ -83,9 +79,10 @@
// |transform| receives HWC_TRANSFORM_* values.
// |composition_type| receives either HWC_FRAMEBUFFER for most layers or
// HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
- void Setup(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
- HWC::Transform transform, HWC::Composition composition_type,
- size_t z_order);
+ void Setup(const std::shared_ptr<IonBuffer>& buffer,
+ const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl,
+ HWC::BlendMode blending, HWC::Transform transform,
+ HWC::Composition composition_type, size_t z_order);
// Layers that use a direct IonBuffer should call this each frame to update
// which buffer will be used for the next PostLayers.
@@ -121,7 +118,7 @@
bool IsLayerSetup() const { return !source_.empty(); }
// Applies all of the settings to this layer using the hwc functions
- void UpdateLayerSettings();
+ void UpdateLayerSettings(const HWCDisplayMetrics& display_metrics);
int GetSurfaceId() const {
int surface_id = -1;
@@ -142,10 +139,9 @@
}
private:
- void CommonLayerSetup();
+ void CommonLayerSetup(const HWCDisplayMetrics& display_metrics);
- static Hwc2::Composer* hwc2_hidl_;
- static const HWCDisplayMetrics* display_metrics_;
+ Hwc2::Composer* hidl_ = nullptr;
// The hardware composer layer and metrics to use during the prepare cycle.
hwc2_layer_t hardware_composer_layer_ = 0;
@@ -263,11 +259,10 @@
static constexpr size_t kMaxHardwareLayers = 4;
HardwareComposer();
- HardwareComposer(Hwc2::Composer* hidl,
- RequestDisplayCallback request_display_callback);
~HardwareComposer();
- bool Initialize();
+ bool Initialize(Hwc2::Composer* hidl,
+ RequestDisplayCallback request_display_callback);
bool IsInitialized() const { return initialized_; }
@@ -281,11 +276,6 @@
// Get the HMD display metrics for the current display.
display::Metrics GetHmdDisplayMetrics() const;
- HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config,
- hwc2_attribute_t attributes,
- int32_t* out_value) const;
- HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config,
- HWCDisplayMetrics* out_metrics) const;
std::string Dump();
void SetVSyncCallback(VSyncCallback callback);
@@ -308,34 +298,31 @@
int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
- void OnHardwareComposerRefresh();
-
private:
- int32_t EnableVsync(bool enabled);
+ HWC::Error GetDisplayAttribute(Hwc2::Composer* hidl, hwc2_display_t display,
+ hwc2_config_t config,
+ hwc2_attribute_t attributes,
+ int32_t* out_value) const;
+ HWC::Error GetDisplayMetrics(Hwc2::Composer* hidl, hwc2_display_t display,
+ hwc2_config_t config,
+ HWCDisplayMetrics* out_metrics) const;
+
+ HWC::Error EnableVsync(bool enabled);
class ComposerCallback : public Hwc2::IComposerCallback {
public:
- ComposerCallback() {}
-
- hardware::Return<void> onHotplug(Hwc2::Display /*display*/,
- Connection /*connected*/) override {
- // TODO(skiazyk): depending on how the server is implemented, we might
- // have to set it up to synchronize with receiving this event, as it can
- // potentially be a critical event for setting up state within the
- // hwc2 module. That is, we (technically) should not call any other hwc
- // methods until this method has been called after registering the
- // callbacks.
- return hardware::Void();
- }
-
- hardware::Return<void> onRefresh(Hwc2::Display /*display*/) override {
- return hardware::Void();
- }
-
- hardware::Return<void> onVsync(Hwc2::Display /*display*/,
- int64_t /*timestamp*/) override {
- return hardware::Void();
- }
+ ComposerCallback();
+ hardware::Return<void> onHotplug(Hwc2::Display display,
+ Connection conn) override;
+ hardware::Return<void> onRefresh(Hwc2::Display display) override;
+ hardware::Return<void> onVsync(Hwc2::Display display,
+ int64_t timestamp) override;
+ const pdx::LocalHandle& GetVsyncEventFd() const;
+ int64_t GetVsyncTime();
+ private:
+ std::mutex vsync_mutex_;
+ pdx::LocalHandle vsync_event_fd_;
+ int64_t vsync_time_ = -1;
};
HWC::Error Validate(hwc2_display_t display);
@@ -364,17 +351,18 @@
void UpdatePostThreadState(uint32_t state, bool suspend);
// Blocks until either event_fd becomes readable, or we're interrupted by a
- // control thread. Any errors are returned as negative errno values. If we're
- // interrupted, kPostThreadInterrupted will be returned.
+ // control thread, or timeout_ms is reached before any events occur. Any
+ // errors are returned as negative errno values, with -ETIMEDOUT returned in
+ // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be
+ // returned.
int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
- int requested_events);
+ int requested_events,
+ int timeout_ms);
- // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made
- // on the post thread that can be interrupted by a control thread. If
- // interrupted, these calls return kPostThreadInterrupted.
+ // WaitForVSync and SleepUntil are blocking calls made on the post thread that
+ // can be interrupted by a control thread. If interrupted, these calls return
+ // kPostThreadInterrupted.
int ReadWaitPPState();
- int BlockUntilVSync();
- int ReadVSyncTimestamp(int64_t* timestamp);
int WaitForVSync(int64_t* timestamp);
int SleepUntil(int64_t wakeup_timestamp);
@@ -398,11 +386,9 @@
bool initialized_;
- // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own
- // this pointer.
- Hwc2::Composer* hwc2_hidl_;
+ std::unique_ptr<Hwc2::Composer> hidl_;
+ sp<ComposerCallback> hidl_callback_;
RequestDisplayCallback request_display_callback_;
- sp<ComposerCallback> callbacks_;
// Display metrics of the physical display.
HWCDisplayMetrics native_display_metrics_;
@@ -433,7 +419,8 @@
std::thread post_thread_;
// Post thread state machine and synchronization primitives.
- PostThreadStateType post_thread_state_{PostThreadState::Idle};
+ PostThreadStateType post_thread_state_{
+ PostThreadState::Idle | PostThreadState::Suspended};
std::atomic<bool> post_thread_quiescent_{true};
bool post_thread_resumed_{false};
pdx::LocalHandle post_thread_event_fd_;
@@ -444,9 +431,6 @@
// Backlight LED brightness sysfs node.
pdx::LocalHandle backlight_brightness_fd_;
- // Primary display vsync event sysfs node.
- pdx::LocalHandle primary_display_vsync_event_fd_;
-
// Primary display wait_pingpong state sysfs node.
pdx::LocalHandle primary_display_wait_pp_fd_;
@@ -478,12 +462,6 @@
static constexpr int kPostThreadInterrupted = 1;
- static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display);
- static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display,
- int64_t timestamp);
- static void HwcHotplug(hwc2_callback_data_t callbackData,
- hwc2_display_t display, hwc2_connection_t connected);
-
HardwareComposer(const HardwareComposer&) = delete;
void operator=(const HardwareComposer&) = delete;
};
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index e7f41a7..33cbc84 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -29,9 +29,6 @@
void GrantDisplayOwnership();
void SeizeDisplayOwnership();
- // Called on a binder thread.
- void OnHardwareComposerRefresh();
-
// dump all vr flinger state.
std::string Dump();
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 56405de..fcf94f0 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -133,10 +133,6 @@
display_service_->SeizeDisplayOwnership();
}
-void VrFlinger::OnHardwareComposerRefresh() {
- display_service_->OnHardwareComposerRefresh();
-}
-
std::string VrFlinger::Dump() {
// TODO(karthikrs): Add more state information here.
return display_service_->DumpState(0/*unused*/);