From 7480c060cb3466d97ec3125d61bbace153f534c8 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 21 Mar 2017 00:04:15 +0000 Subject: [PATCH] Revert "Tie vr flinger to persistent vr mode" This reverts commit f43d13e4e35ae7d3cdafc4b97c819669d42cef78. Change-Id: Ib67db8e51b7ea2dbbe6faccce36962bf5b44a6e2 --- include/vr/vr_manager/vr_manager.h | 28 -- libs/vr/libdisplay/display_client.cpp | 23 + .../include/private/dvr/display_client.h | 3 + .../libdisplay/include/private/dvr/display_rpc.h | 4 + libs/vr/libvr_manager/vr_manager.cpp | 50 -- libs/vr/libvrflinger/display_service.cpp | 28 +- libs/vr/libvrflinger/display_service.h | 13 +- libs/vr/libvrflinger/hardware_composer.cpp | 558 +++++++++++---------- libs/vr/libvrflinger/hardware_composer.h | 130 ++--- libs/vr/libvrflinger/include/dvr/vr_flinger.h | 36 +- libs/vr/libvrflinger/vr_flinger.cpp | 96 ++-- services/surfaceflinger/Android.mk | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 91 ++-- services/surfaceflinger/SurfaceFlinger.h | 13 +- services/surfaceflinger/VrStateCallbacks.cpp | 30 ++ services/surfaceflinger/VrStateCallbacks.h | 37 ++ services/vr/vr_window_manager/application.cpp | 6 +- services/vr/vr_window_manager/application.h | 4 +- 18 files changed, 565 insertions(+), 586 deletions(-) create mode 100644 services/surfaceflinger/VrStateCallbacks.cpp create mode 100644 services/surfaceflinger/VrStateCallbacks.h diff --git a/include/vr/vr_manager/vr_manager.h b/include/vr/vr_manager/vr_manager.h index 9df2c6bac5..0c5da19ded 100644 --- a/include/vr/vr_manager/vr_manager.h +++ b/include/vr/vr_manager/vr_manager.h @@ -41,28 +41,6 @@ public: }; -// Must be kept in sync with interface defined in -// IPersistentVrStateCallbacks.aidl. - -class IPersistentVrStateCallbacks : public IInterface { -public: - DECLARE_META_INTERFACE(PersistentVrStateCallbacks) - - virtual void onPersistentVrStateChanged(bool enabled) = 0; -}; - -enum PersistentVrStateCallbacksTransaction { - ON_PERSISTENT_VR_STATE_CHANGED = IBinder::FIRST_CALL_TRANSACTION, -}; - -class BnPersistentVrStateCallbacks - : public BnInterface { -public: - status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags = 0) override; -}; - - // Must be kept in sync with interface defined in IVrManager.aidl. class IVrManager : public IInterface { @@ -71,18 +49,12 @@ public: virtual void registerListener(const sp& cb) = 0; virtual void unregisterListener(const sp& cb) = 0; - virtual void registerPersistentVrStateListener( - const sp& cb) = 0; - virtual void unregisterPersistentVrStateListener( - const sp& cb) = 0; virtual bool getVrModeState() = 0; }; enum VrManagerTransaction { REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION, UNREGISTER_LISTENER, - REGISTER_PERSISTENT_VR_STATE_LISTENER, - UNREGISTER_PERSISTENT_VR_STATE_LISTENER, GET_VR_MODE_STATE, }; diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp index 9a3edef3de..dcdd99493c 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -248,6 +248,29 @@ int DisplayClient::GetLastFrameEdsTransform(LateLatchOutput* ll_out) { return 0; } +int DisplayClient::EnterVrMode() { + auto status = InvokeRemoteMethod(); + if (!status) { + ALOGE( + "DisplayClient::EnterVrMode: Failed to set display service to Vr mode"); + return -status.error(); + } + + return 0; +} + +int DisplayClient::ExitVrMode() { + auto status = InvokeRemoteMethod(); + if (!status) { + ALOGE( + "DisplayClient::ExitVrMode: Failed to revert display service from Vr " + "mode"); + return -status.error(); + } + + return 0; +} + std::unique_ptr DisplayClient::CreateDisplaySurface( int width, int height, int format, int usage, int flags) { return DisplaySurfaceClient::Create(width, height, format, usage, flags); diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h index 3a6e3b6d87..e1471c3c23 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_client.h +++ b/libs/vr/libdisplay/include/private/dvr/display_client.h @@ -105,6 +105,9 @@ class DisplayClient : public pdx::ClientBase { // Pull the latest eds pose data from the display service renderer int GetLastFrameEdsTransform(LateLatchOutput* ll_out); + int EnterVrMode(); + int ExitVrMode(); + std::unique_ptr CreateDisplaySurface( int width, int height, int format, int usage, int flags); diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h index 2d1bbd8ee7..465fbaed6b 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h +++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h @@ -217,6 +217,8 @@ struct DisplayRPC { kOpGetMetadataBuffer, kOpCreateVideoMeshSurface, kOpVideoMeshSurfaceCreateProducerQueue, + kOpEnterVrMode, + kOpExitVrMode, kOpSetViewerParams }; @@ -243,6 +245,8 @@ struct DisplayRPC { PDX_REMOTE_METHOD(VideoMeshSurfaceCreateProducerQueue, kOpVideoMeshSurfaceCreateProducerQueue, LocalChannelHandle(Void)); + PDX_REMOTE_METHOD(EnterVrMode, kOpEnterVrMode, int(Void)); + PDX_REMOTE_METHOD(ExitVrMode, kOpExitVrMode, int(Void)); PDX_REMOTE_METHOD(SetViewerParams, kOpSetViewerParams, void(const ViewerParams& viewer_params)); }; diff --git a/libs/vr/libvr_manager/vr_manager.cpp b/libs/vr/libvr_manager/vr_manager.cpp index 5cfc22eec3..d24cbb5a1a 100644 --- a/libs/vr/libvr_manager/vr_manager.cpp +++ b/libs/vr/libvr_manager/vr_manager.cpp @@ -53,40 +53,6 @@ status_t BnVrStateCallbacks::onTransact(uint32_t code, const Parcel& data, return BBinder::onTransact(code, data, reply, flags); } -// Must be kept in sync with interface defined in -// IPersistentVrStateCallbacks.aidl. - -class BpPersistentVrStateCallbacks - : public BpInterface { - public: - explicit BpPersistentVrStateCallbacks(const sp& impl) - : BpInterface(impl) {} - - void onPersistentVrStateChanged(bool enabled) { - Parcel data, reply; - data.writeInterfaceToken( - IPersistentVrStateCallbacks::getInterfaceDescriptor()); - data.writeBool(enabled); - remote()->transact(ON_PERSISTENT_VR_STATE_CHANGED, - data, &reply, IBinder::FLAG_ONEWAY); - } -}; - -IMPLEMENT_META_INTERFACE(PersistentVrStateCallbacks, - "android.service.vr.IPersistentVrStateCallbacks"); - -status_t BnPersistentVrStateCallbacks::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - switch(code) { - case ON_PERSISTENT_VR_STATE_CHANGED: { - CHECK_INTERFACE(IPersistentVrStateCallbacks, data, reply); - onPersistentVrStateChanged(data.readBool()); - return OK; - } - } - return BBinder::onTransact(code, data, reply, flags); -} - // Must be kept in sync with interface defined in IVrManager.aidl. class BpVrManager : public BpInterface { @@ -108,22 +74,6 @@ class BpVrManager : public BpInterface { remote()->transact(UNREGISTER_LISTENER, data, NULL); } - void registerPersistentVrStateListener( - const sp& cb) override { - Parcel data; - data.writeInterfaceToken(IVrManager::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(cb)); - remote()->transact(REGISTER_PERSISTENT_VR_STATE_LISTENER, data, NULL); - } - - void unregisterPersistentVrStateListener( - const sp& cb) override { - Parcel data; - data.writeInterfaceToken(IVrManager::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(cb)); - remote()->transact(UNREGISTER_PERSISTENT_VR_STATE_LISTENER, data, NULL); - } - bool getVrModeState() override { Parcel data, reply; data.writeInterfaceToken(IVrManager::getInterfaceDescriptor()); diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index b5210c965d..fdb84c5069 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -21,8 +21,7 @@ using android::pdx::rpc::WrapBuffer; namespace android { namespace dvr { -DisplayService::DisplayService() - : DisplayService(nullptr) {} +DisplayService::DisplayService() : DisplayService(nullptr) {} DisplayService::DisplayService(Hwc2::Composer* hidl) : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)), @@ -75,6 +74,16 @@ int DisplayService::HandleMessage(pdx::Message& message) { *this, &DisplayService::OnCreateSurface, message); return 0; + case DisplayRPC::EnterVrMode::Opcode: + DispatchRemoteMethod( + *this, &DisplayService::OnEnterVrMode, message); + return 0; + + case DisplayRPC::ExitVrMode::Opcode: + DispatchRemoteMethod( + *this, &DisplayService::OnExitVrMode, message); + return 0; + case DisplayRPC::SetViewerParams::Opcode: DispatchRemoteMethod( *this, &DisplayService::OnSetViewerParams, message); @@ -173,6 +182,16 @@ DisplayRPC::ByteBuffer DisplayService::OnGetEdsCapture(pdx::Message& message) { return WrapBuffer(std::move(buffer)); } +int DisplayService::OnEnterVrMode(pdx::Message& /*message*/) { + hardware_composer_.Resume(); + return 0; +} + +int DisplayService::OnExitVrMode(pdx::Message& /*message*/) { + hardware_composer_.Suspend(); + return 0; +} + void DisplayService::OnSetViewerParams(pdx::Message& message, const ViewerParams& view_params) { Compositor* compositor = hardware_composer_.GetCompositor(); @@ -271,7 +290,7 @@ DisplayService::GetVisibleDisplaySurfaces() const { return visible_surfaces; } -void DisplayService::UpdateActiveDisplaySurfaces() { +int DisplayService::UpdateActiveDisplaySurfaces() { auto visible_surfaces = GetVisibleDisplaySurfaces(); // Sort the surfaces based on manager z order first, then client z order. @@ -302,8 +321,7 @@ void DisplayService::UpdateActiveDisplaySurfaces() { if (surface->client_blur_behind()) blur_requested = true; } - - hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces)); + return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces)); } void DisplayService::OnHardwareComposerRefresh() { diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index c93488aee0..9d116c1440 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -36,7 +36,7 @@ class DisplayService : public pdx::ServiceBase { // Updates the list of actively displayed surfaces. This must be called after // any change to client/manager attributes that affect visibility or z order. - void UpdateActiveDisplaySurfaces(); + int UpdateActiveDisplaySurfaces(); template void ForEachDisplaySurface(A action) const { @@ -60,8 +60,13 @@ class DisplayService : public pdx::ServiceBase { return hardware_composer_.display_metrics(); } - void GrantDisplayOwnership() { hardware_composer_.Enable(); } - void SeizeDisplayOwnership() { hardware_composer_.Disable(); } + void SetActive(bool activated) { + if (activated) { + hardware_composer_.Resume(); + } else { + hardware_composer_.Suspend(); + } + } void OnHardwareComposerRefresh(); @@ -80,6 +85,8 @@ class DisplayService : public pdx::ServiceBase { DisplayRPC::ByteBuffer OnGetEdsCapture(pdx::Message& message); + int OnEnterVrMode(pdx::Message& message); + int OnExitVrMode(pdx::Message& message); void OnSetViewerParams(pdx::Message& message, const ViewerParams& view_params); // Called by DisplaySurface to signal that a surface property has changed and diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index da45859a97..53c2ac29b4 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -103,13 +103,12 @@ HardwareComposer::HardwareComposer(Hwc2::Composer* hwc2_hidl) : initialized_(false), hwc2_hidl_(hwc2_hidl), display_transform_(HWC_TRANSFORM_NONE), - active_surfaces_updated_(false), + display_surfaces_updated_(false), + hardware_layers_need_update_(false), active_layer_count_(0), gpu_layer_(nullptr), - post_thread_enabled_(false), - post_thread_running_(false), - post_thread_quit_requested_(false), - post_thread_interrupt_event_fd_(-1), + post_thread_state_(PostThreadState::kPaused), + terminate_post_thread_event_fd_(-1), backlight_brightness_fd_(-1), primary_display_vsync_event_fd_(-1), primary_display_wait_pp_fd_(-1), @@ -125,12 +124,7 @@ HardwareComposer::HardwareComposer(Hwc2::Composer* hwc2_hidl) } HardwareComposer::~HardwareComposer(void) { - std::unique_lock lock(post_thread_mutex_); - if (post_thread_.joinable()) { - post_thread_quit_requested_ = true; - post_thread_cond_var_.notify_all(); - post_thread_.join(); - } + Suspend(); } bool HardwareComposer::Initialize() { @@ -173,56 +167,24 @@ bool HardwareComposer::Initialize() { display_transform_ = HWC_TRANSFORM_NONE; display_metrics_ = native_display_metrics_; - post_thread_interrupt_event_fd_.Reset( - eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - LOG_ALWAYS_FATAL_IF( - !post_thread_interrupt_event_fd_, - "HardwareComposer: Failed to create interrupt event fd : %s", - strerror(errno)); - - post_thread_ = std::thread(&HardwareComposer::PostThread, this); - initialized_ = true; return initialized_; } -void HardwareComposer::Enable() { - std::lock_guard lock(post_thread_mutex_); - post_thread_enabled_ = true; - post_thread_cond_var_.notify_all(); -} - -void HardwareComposer::Disable() { - std::unique_lock lock(post_thread_mutex_); - post_thread_enabled_ = false; - if (post_thread_running_) { - // Write to the interrupt fd to get fast interrupt of the post thread - int error = eventfd_write(post_thread_interrupt_event_fd_.Get(), 1); - ALOGW_IF(error, - "HardwareComposer::Disable: could not write post " - "thread interrupt event fd : %s", - strerror(errno)); - - post_thread_cond_var_.wait(lock, [this] { return !post_thread_running_; }); - - // Read the interrupt fd to clear its state - uint64_t interrupt_count= 0; - error = eventfd_read(post_thread_interrupt_event_fd_.Get(), - &interrupt_count); - ALOGW_IF(error, - "HardwareComposer::Disable: could not read post " - "thread interrupt event fd : %s", - strerror(errno)); +bool HardwareComposer::Resume() { + std::lock_guard post_thread_lock(post_thread_state_mutex_); + if (post_thread_state_ == PostThreadState::kRunning) { + return false; } -} -bool HardwareComposer::PostThreadHasWork() { - return !display_surfaces_.empty() || - (active_surfaces_updated_ && !active_surfaces_.empty()); -} + std::lock_guard layer_lock(layer_mutex_); + + int32_t ret = HWC2_ERROR_NONE; + + // Always turn off vsync when we start. + EnableVsync(false); -void HardwareComposer::OnPostThreadResumed() { constexpr int format = HAL_PIXEL_FORMAT_RGBA_8888; constexpr int usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER; @@ -236,33 +198,97 @@ void HardwareComposer::OnPostThreadResumed() { layer->Initialize(hwc2_hidl_.get(), &native_display_metrics_); } +#if ENABLE_BACKLIGHT_BRIGHTNESS + // TODO(hendrikw): This isn't required at the moment. It's possible that there + // is another method to access this when needed. + // Open the backlight brightness control sysfs node. + backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR); + ALOGW_IF(!backlight_brightness_fd_, + "HardwareComposer: Failed to open backlight brightness control: %s", + 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_ = + LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY); + ALOGE_IF( + !primary_display_wait_pp_fd_, + "HardwareComposer: Failed to open wait_pp node for primary display: %s", + strerror(errno)); + + // Create a timerfd based on CLOCK_MONOTINIC. + vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0)); + LOG_ALWAYS_FATAL_IF( + !vsync_sleep_timer_fd_, + "HardwareComposer: Failed to create vsync sleep timerfd: %s", + strerror(errno)); + // Connect to pose service. pose_client_ = dvrPoseCreate(); ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client"); - EnableVsync(true); + terminate_post_thread_event_fd_.Reset( + eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF( + !terminate_post_thread_event_fd_, + "HardwareComposer: Failed to create terminate PostThread event fd : %s", + strerror(errno)); - // TODO(skiazyk): We need to do something about accessing this directly, - // supposedly there is a backlight service on the way. - // TODO(steventhomas): When we change the backlight setting, will surface - // flinger (or something else) set it back to its original value once we give - // control of the display back to surface flinger? - SetBacklightBrightness(255); + post_thread_state_ = PostThreadState::kRunning; + post_thread_state_cond_var_.notify_all(); - // Initialize the GPU compositor. - LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()), - "Failed to initialize the compositor"); + // If get_id() is the default thread::id object, it has not been created yet + if (post_thread_.get_id() == std::thread::id()) { + post_thread_ = std::thread(&HardwareComposer::PostThread, this); + } else { + UpdateDisplayState(); + } - // Trigger target-specific performance mode change. - property_set(kDvrPerformanceProperty, "performance"); + return true; } -void HardwareComposer::OnPostThreadPaused() { +bool HardwareComposer::Suspend() { + std::unique_lock post_thread_lock(post_thread_state_mutex_); + if (post_thread_state_ == PostThreadState::kPaused) { + return false; + } + + post_thread_state_ = PostThreadState::kPauseRequested; + + int error = eventfd_write(terminate_post_thread_event_fd_.Get(), 1); + ALOGE_IF(error, + "HardwareComposer::Suspend: could not write post " + "thread termination event fd : %d", + error); + + post_thread_state_cond_var_.wait( + post_thread_lock, + [this] { return post_thread_state_ == PostThreadState::kPaused; }); + terminate_post_thread_event_fd_.Close(); + + // Wait for any pending layer operations to finish + std::lock_guard layer_lock(layer_mutex_); + + EnableVsync(false); + + backlight_brightness_fd_.Close(); + primary_display_vsync_event_fd_.Close(); + primary_display_wait_pp_fd_.Close(); + vsync_sleep_timer_fd_.Close(); retire_fence_fds_.clear(); gpu_layer_ = nullptr; - // We have to destroy the layers to fully clear hwc device state before - // handing off back to surface flinger + // We have to destroy the layers before we close the hwc device for (size_t i = 0; i < kMaxHardwareLayers; ++i) { layers_[i]->Reset(); } @@ -271,26 +297,12 @@ void HardwareComposer::OnPostThreadPaused() { framebuffer_target_.reset(); - display_surfaces_.clear(); - compositor_surfaces_.clear(); - - // Since we're clearing display_surfaces_ we'll need an update. - active_surfaces_updated_ = true; + //hwc2_hidl_.reset(); - if (pose_client_) { + if (pose_client_) dvrPoseDestroy(pose_client_); - pose_client_ = nullptr; - } - - EnableVsync(false); - - frame_time_history_.ResetWithSeed(GuessFrameTime(0)); - frame_time_backlog_.clear(); - - compositor_.Shutdown(); - // Trigger target-specific performance mode change. - property_set(kDvrPerformanceProperty, "idle"); + return true; } DisplayMetrics HardwareComposer::GetHmdDisplayMetrics() const { @@ -507,48 +519,82 @@ void HardwareComposer::PostLayers(bool /*is_geometry_changed*/) { } } -void HardwareComposer::SetDisplaySurfaces( +// TODO(skiazyk): This is a work-around for the fact that we currently do not +// handle the case when new surfaces are introduced when displayd is not +// in an active state. A proper-solution will require re-structuring +// displayd a little, but hopefully this is sufficient for now. +// For example, could this be handled in |UpdateLayerSettings| instead? +void HardwareComposer::UpdateDisplayState() { + const bool has_display_surfaces = display_surfaces_.size() > 0; + + if (has_display_surfaces) { + EnableVsync(true); + } + + // TODO(skiazyk): We need to do something about accessing this directly, + // supposedly there is a backlight service on the way. + SetBacklightBrightness(255); + + // Trigger target-specific performance mode change. + property_set(kDvrPerformanceProperty, has_display_surfaces ? "performance" : "idle"); +} + +int HardwareComposer::SetDisplaySurfaces( std::vector> surfaces) { + // The double lock is necessary because we access both the display surfaces + // and post_thread_state_. + std::lock_guard post_thread_state_lock(post_thread_state_mutex_); + std::lock_guard layer_lock(layer_mutex_); + ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd", surfaces.size()); - std::unique_lock lock(post_thread_mutex_); - active_surfaces_ = std::move(surfaces); - active_surfaces_updated_ = true; - if (post_thread_enabled_) - post_thread_cond_var_.notify_all(); -} -int HardwareComposer::PostThreadPollInterruptible(int event_fd) { - pollfd pfd[2] = { - { - .fd = event_fd, .events = POLLPRI | POLLIN, .revents = 0, - }, - { - .fd = post_thread_interrupt_event_fd_.Get(), - .events = POLLPRI | POLLIN, - .revents = 0, - }, - }; - int ret, error; - do { - ret = poll(pfd, 2, -1); - error = errno; - ALOGW_IF(ret < 0, - "HardwareComposer::PostThreadPollInterruptible: Error during " - "poll(): %s (%d)", - strerror(error), error); - } while (ret < 0 && error == EINTR); + // Figure out whether we need to update hardware layers. If this surface + // change does not add or remove hardware layers we can avoid display hiccups + // by gracefully updating only the GPU compositor layers. + // hardware_layers_need_update_ is reset to false by the Post thread. + int old_gpu_layer_count = 0; + int new_gpu_layer_count = 0; + // Look for new hardware layers and count new GPU layers. + for (const auto& surface : surfaces) { + if (!(surface->flags() & + DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) + ++new_gpu_layer_count; + else if (std::find(display_surfaces_.begin(), display_surfaces_.end(), + surface) == display_surfaces_.end()) + // This is a new hardware layer, we need to update. + hardware_layers_need_update_ = true; + } + // Look for deleted hardware layers or compositor layers. + for (const auto& surface : display_surfaces_) { + if (!(surface->flags() & + DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) + ++old_gpu_layer_count; + else if (std::find(surfaces.begin(), surfaces.end(), surface) == + surfaces.end()) + // This is a deleted hardware layer, we need to update. + hardware_layers_need_update_ = true; + } + // Check for compositor hardware layer transition. + if ((!old_gpu_layer_count && new_gpu_layer_count) || + (old_gpu_layer_count && !new_gpu_layer_count)) + hardware_layers_need_update_ = true; - if (ret < 0) { - return -error; - } else if (pfd[0].revents != 0) { - return 0; - } else if (pfd[1].revents != 0) { - ALOGI("VrHwcPost thread interrupted"); - return kPostThreadInterrupted; - } else { - return 0; + display_surfaces_ = std::move(surfaces); + display_surfaces_updated_ = true; + + // Set the chosen layer order for all surfaces. + for (size_t i = 0; i < display_surfaces_.size(); ++i) { + display_surfaces_[i]->SetLayerOrder(static_cast(i)); } + + // TODO(skiazyk): fix this so that it is handled seamlessly with dormant/non- + // dormant state. + if (post_thread_state_ == PostThreadState::kRunning) { + UpdateDisplayState(); + } + + return 0; } // Reads the value of the display driver wait_pingpong state. Returns 0 or 1 @@ -644,8 +690,35 @@ int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) { // 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() { - return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get()); +int HardwareComposer::BlockUntilVSync(/*out*/ bool* suspend_requested) { + *suspend_requested = false; + const int event_fd = primary_display_vsync_event_fd_.Get(); + pollfd pfd[2] = { + { + .fd = event_fd, .events = POLLPRI, .revents = 0, + }, + // This extra event fd is to ensure that we can break out of this loop to + // pause the thread even when vsync is disabled, and thus no events on the + // vsync fd are being generated. + { + .fd = terminate_post_thread_event_fd_.Get(), + .events = POLLPRI | POLLIN, + .revents = 0, + }, + }; + int ret, error; + do { + ret = poll(pfd, 2, -1); + error = errno; + ALOGW_IF(ret < 0, + "HardwareComposer::BlockUntilVSync: Error while waiting for vsync " + "event: %s (%d)", + strerror(error), error); + } while (ret < 0 && error == EINTR); + + if (ret >= 0 && pfd[1].revents != 0) + *suspend_requested = true; + return ret < 0 ? -error : 0; } // Waits for the next vsync and returns the timestamp of the vsync event. If @@ -667,8 +740,9 @@ int HardwareComposer::WaitForVSync(int64_t* timestamp) { if (error == -EAGAIN) { // Vsync was turned off, wait for the next vsync event. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) + bool suspend_requested = false; + error = BlockUntilVSync(&suspend_requested); + if (error < 0 || suspend_requested) return error; // Try again to get the timestamp for this new vsync interval. @@ -691,14 +765,13 @@ int HardwareComposer::WaitForVSync(int64_t* timestamp) { if (distance_to_vsync_est > threshold_ns) { // Wait for vsync event notification. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) + bool suspend_requested = false; + error = BlockUntilVSync(&suspend_requested); + if (error < 0 || suspend_requested) return error; } else { - // Sleep for a short time (1 millisecond) before retrying. - error = SleepUntil(GetSystemClockNs() + 1000000); - if (error < 0 || error == kPostThreadInterrupted) - return error; + // Sleep for a short time before retrying. + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } } @@ -718,12 +791,21 @@ int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { return -error; } - return PostThreadPollInterruptible(timer_fd); + // Wait for the timer by reading the expiration count. + uint64_t expiration_count; + ret = read(timer_fd, &expiration_count, sizeof(expiration_count)); + if (ret < 0) { + ALOGE("HardwareComposer::SleepUntil: Failed to wait for timerfd: %s", + strerror(error)); + return -error; + } + + return 0; } void HardwareComposer::PostThread() { // NOLINTNEXTLINE(runtime/int) - prctl(PR_SET_NAME, reinterpret_cast("VrHwcPost"), 0, 0, 0); + prctl(PR_SET_NAME, reinterpret_cast("PostThread"), 0, 0, 0); // Set the scheduler to SCHED_FIFO with high priority. int error = dvrSetSchedulerClass(0, "graphics:high"); @@ -737,40 +819,12 @@ void HardwareComposer::PostThread() { "HardwareComposer::PostThread: Failed to set cpu partition: %s", strerror(-error)); -#if ENABLE_BACKLIGHT_BRIGHTNESS - // TODO(hendrikw): This isn't required at the moment. It's possible that there - // is another method to access this when needed. - // Open the backlight brightness control sysfs node. - backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR); - ALOGW_IF(!backlight_brightness_fd_, - "HardwareComposer: Failed to open backlight brightness control: %s", - 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_ = - LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY); - ALOGW_IF( - !primary_display_wait_pp_fd_, - "HardwareComposer: Failed to open wait_pp node for primary display: %s", - strerror(errno)); + // Force the layers to be setup at least once. + display_surfaces_updated_ = true; - // Create a timerfd based on CLOCK_MONOTINIC. - vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0)); - LOG_ALWAYS_FATAL_IF( - !vsync_sleep_timer_fd_, - "HardwareComposer: Failed to create vsync sleep timerfd: %s", - strerror(errno)); + // Initialize the GPU compositor. + LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()), + "Failed to initialize the compositor"); const int64_t ns_per_frame = display_metrics_.vsync_period_ns; const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame); @@ -784,48 +838,41 @@ void HardwareComposer::PostThread() { right_eye_photon_offset_ns = property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns); - compositor_surfaces_.reserve(2); + // The list of surfaces the compositor should attempt to render. This is set + // at the start of each frame. + std::vector> compositor_surfaces; + compositor_surfaces.reserve(2); + // Our history of frame times. This is used to get a better estimate of how + // long the next frame will take, to set a schedule for EDS. + FrameTimeHistory frame_time_history; + + // The backlog is used to allow us to start rendering the next frame before + // the previous frame has finished, and still get an accurate measurement of + // frame duration. + std::vector frame_time_backlog; constexpr int kFrameTimeBacklogMax = 2; - frame_time_backlog_.reserve(kFrameTimeBacklogMax); + frame_time_backlog.reserve(kFrameTimeBacklogMax); // Storage for retrieving fence info. FenceInfoBuffer fence_info_buffer; - bool was_running = false; - while (1) { ATRACE_NAME("HardwareComposer::PostThread"); { - std::unique_lock lock(post_thread_mutex_); - while (!post_thread_enabled_ || post_thread_quit_requested_ || - !PostThreadHasWork()) { - if (was_running) { - const char* pause_reason = "unknown"; - if (!post_thread_enabled_) - pause_reason = "disabled"; - else if (post_thread_quit_requested_) - pause_reason = "quit requested"; - else if (!PostThreadHasWork()) - pause_reason = "no work"; - ALOGI("VrHwcPost thread paused. Reason: %s.", pause_reason); - OnPostThreadPaused(); - was_running = false; - } - post_thread_running_ = false; - post_thread_cond_var_.notify_all(); - if (post_thread_quit_requested_) - return; - post_thread_cond_var_.wait(lock); + std::unique_lock post_thread_lock(post_thread_state_mutex_); + if (post_thread_state_ == PostThreadState::kPauseRequested) { + ALOGI("HardwareComposer::PostThread: Post thread pause requested."); + post_thread_state_ = PostThreadState::kPaused; + post_thread_state_cond_var_.notify_all(); + post_thread_state_cond_var_.wait( + post_thread_lock, + [this] { return post_thread_state_ == PostThreadState::kRunning; }); + // The layers will need to be updated since they were deleted previously + display_surfaces_updated_ = true; + hardware_layers_need_update_ = true; } - post_thread_running_ = true; - } - - if (!was_running) { - ALOGI("VrHwcPost thread resumed"); - OnPostThreadResumed(); - was_running = true; } int64_t vsync_timestamp = 0; @@ -840,13 +887,22 @@ void HardwareComposer::PostThread() { error < 0, "HardwareComposer::PostThread: Failed to wait for vsync event: %s", strerror(-error)); + // Don't bother processing this frame if a pause was requested - if (error == kPostThreadInterrupted) + std::lock_guard post_thread_lock(post_thread_state_mutex_); + if (post_thread_state_ == PostThreadState::kPauseRequested) { continue; + } } ++vsync_count_; + static double last_print_time = -1; + double current_time = GetSystemClockSec(); + if (last_print_time < 0 || current_time - last_print_time > 3) { + last_print_time = current_time; + } + if (pose_client_) { // Signal the pose service with vsync info. // Display timestamp is in the middle of scanout. @@ -855,24 +911,24 @@ void HardwareComposer::PostThread() { ns_per_frame, right_eye_photon_offset_ns); } - bool layer_config_changed = UpdateLayerConfig(); + bool layer_config_changed = UpdateLayerConfig(&compositor_surfaces); - if (!was_running || layer_config_changed) { - frame_time_history_.ResetWithSeed( - GuessFrameTime(compositor_surfaces_.size())); - frame_time_backlog_.clear(); + if (layer_config_changed) { + frame_time_history.ResetWithSeed( + GuessFrameTime(compositor_surfaces.size())); + frame_time_backlog.clear(); } else { - UpdateFrameTimeHistory(&frame_time_backlog_, kFrameTimeBacklogMax, - &fence_info_buffer, &frame_time_history_); + UpdateFrameTimeHistory(&frame_time_backlog, kFrameTimeBacklogMax, + &fence_info_buffer, &frame_time_history); } // Get our current best estimate at how long the next frame will take to // render, based on how long previous frames took to render. Use this // estimate to decide when to wake up for EDS. int64_t frame_time_estimate = - frame_time_history_.GetSampleCount() == 0 - ? GuessFrameTime(compositor_surfaces_.size()) - : frame_time_history_.GetAverage(); + frame_time_history.GetSampleCount() == 0 + ? GuessFrameTime(compositor_surfaces.size()) + : frame_time_history.GetAverage(); frame_time_estimate = std::max(frame_time_estimate, kFrameTimeEstimateMin); DebugHudData::data.hwc_latency = frame_time_estimate; @@ -902,9 +958,9 @@ void HardwareComposer::PostThread() { // There are several reasons we might skip a frame, but one possibility // is we mispredicted the frame time. Clear out the frame time history. - frame_time_history_.ResetWithSeed( - GuessFrameTime(compositor_surfaces_.size())); - frame_time_backlog_.clear(); + frame_time_history.ResetWithSeed( + GuessFrameTime(compositor_surfaces.size())); + frame_time_backlog.clear(); DebugHudData::data.hwc_frame_stats.SkipFrame(); continue; @@ -918,8 +974,6 @@ void HardwareComposer::PostThread() { error = SleepUntil(display_time_est - frame_time_estimate); ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s", strerror(-error)); - if (error == kPostThreadInterrupted) - continue; } } @@ -938,7 +992,7 @@ void HardwareComposer::PostThread() { // permanently backed up. PostLayers(layer_config_changed); - PostCompositorBuffers(); + PostCompositorBuffers(compositor_surfaces); if (gpu_layer_ != nullptr) { // Note, with scanline racing, this draw is timed along with the post @@ -946,88 +1000,55 @@ void HardwareComposer::PostThread() { LocalHandle frame_fence_fd; compositor_.DrawFrame(vsync_count_ + 1, &frame_fence_fd); if (frame_fence_fd) { - LOG_ALWAYS_FATAL_IF(frame_time_backlog_.size() >= kFrameTimeBacklogMax, + LOG_ALWAYS_FATAL_IF(frame_time_backlog.size() >= kFrameTimeBacklogMax, "Frame time backlog exceeds capacity"); - frame_time_backlog_.push_back( + frame_time_backlog.push_back( {frame_start_time, std::move(frame_fence_fd)}); } } else if (!layer_config_changed) { - frame_time_history_.AddSample(GetSystemClockNs() - frame_start_time); + frame_time_history.AddSample(GetSystemClockNs() - frame_start_time); } HandlePendingScreenshots(); } + + // TODO(skiazyk): Currently the compositor is not fully releasing its EGL + // context, which seems to prevent the thread from exiting properly. + // This shouldn't be too hard to address, I just don't have time right now. + compositor_.Shutdown(); } -bool HardwareComposer::UpdateLayerConfig() { - std::vector> old_display_surfaces; - { - std::lock_guard lock(post_thread_mutex_); - if (!active_surfaces_updated_) - return false; - old_display_surfaces = display_surfaces_; - display_surfaces_ = active_surfaces_; - active_surfaces_updated_ = false; - } +bool HardwareComposer::UpdateLayerConfig( + std::vector>* compositor_surfaces) { + std::lock_guard layer_lock(layer_mutex_); - DebugHudData::data.ResetLayers(); - - // Figure out whether we need to update hardware layers. If this surface - // change does not add or remove hardware layers we can avoid display hiccups - // by gracefully updating only the GPU compositor layers. - int old_gpu_layer_count = 0; - int new_gpu_layer_count = 0; - bool hardware_layers_need_update = false; - // Look for new hardware layers and count new GPU layers. - for (const auto& surface : display_surfaces_) { - if (!(surface->flags() & - DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) - ++new_gpu_layer_count; - else if (std::find(old_display_surfaces.begin(), old_display_surfaces.end(), - surface) == old_display_surfaces.end()) - // This is a new hardware layer, we need to update. - hardware_layers_need_update = true; - } - // Look for deleted hardware layers or compositor layers. - for (const auto& surface : old_display_surfaces) { - if (!(surface->flags() & - DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) - ++old_gpu_layer_count; - else if (std::find(display_surfaces_.begin(), display_surfaces_.end(), - surface) == display_surfaces_.end()) - // This is a deleted hardware layer, we need to update. - hardware_layers_need_update = true; - } - // Check for compositor hardware layer transition. - if ((!old_gpu_layer_count && new_gpu_layer_count) || - (old_gpu_layer_count && !new_gpu_layer_count)) - hardware_layers_need_update = true; + if (!display_surfaces_updated_) + return false; - // Set the chosen layer order for all surfaces. - for (size_t i = 0; i < display_surfaces_.size(); ++i) { - display_surfaces_[i]->SetLayerOrder(static_cast(i)); - } + display_surfaces_updated_ = false; + DebugHudData::data.ResetLayers(); // Update compositor layers. { ATRACE_NAME("UpdateLayerConfig_GpuLayers"); compositor_.UpdateSurfaces(display_surfaces_); - compositor_surfaces_.clear(); + compositor_surfaces->clear(); for (size_t i = 0; i < display_surfaces_.size(); ++i) { const auto& surface = display_surfaces_[i]; if (!(surface->flags() & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) { - compositor_surfaces_.push_back(surface); + compositor_surfaces->push_back(surface); } } } - if (!hardware_layers_need_update) + if (!hardware_layers_need_update_) return true; // Update hardware layers. ATRACE_NAME("UpdateLayerConfig_HwLayers"); + hardware_layers_need_update_ = false; // Update the display layers in a non-destructive fashion. @@ -1158,9 +1179,10 @@ bool HardwareComposer::UpdateLayerConfig() { return true; } -void HardwareComposer::PostCompositorBuffers() { +void HardwareComposer::PostCompositorBuffers( + const std::vector>& compositor_surfaces) { ATRACE_NAME("PostCompositorBuffers"); - for (const auto& surface : compositor_surfaces_) { + for (const auto& surface : compositor_surfaces) { compositor_.PostBuffer(surface); } } diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index 2d3d78b506..e2a8b90adb 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -176,12 +176,6 @@ class Layer { // HardwareComposer encapsulates the hardware composer HAL, exposing a // simplified API to post buffers to the display. -// -// HardwareComposer is accessed by both the vr flinger dispatcher thread and the -// surface flinger main thread, in addition to internally running a separate -// thread for compositing/EDS and posting layers to the HAL. When changing how -// variables are used or adding new state think carefully about which threads -// will access the state and whether it needs to be synchronized. class HardwareComposer { public: // Type for vsync callback. @@ -199,12 +193,8 @@ class HardwareComposer { bool IsInitialized() const { return initialized_; } - // Start the post thread if there's work to do (i.e. visible layers). This - // should only be called from surface flinger's main thread. - void Enable(); - // Pause the post thread, blocking until the post thread has signaled that - // it's paused. This should only be called from surface flinger's main thread. - void Disable(); + bool Suspend(); + bool Resume(); // Get the HMD display metrics for the current display. DisplayMetrics GetHmdDisplayMetrics() const; @@ -229,9 +219,12 @@ class HardwareComposer { return native_display_metrics_; } + std::shared_ptr framebuffer_target() const { + return framebuffer_target_; + } + // Set the display surface stack to compose to the display each frame. - void SetDisplaySurfaces( - std::vector> surfaces); + int SetDisplaySurfaces(std::vector> surfaces); Compositor* GetCompositor() { return &compositor_; } @@ -273,21 +266,8 @@ class HardwareComposer { void PostLayers(bool is_geometry_changed); void PostThread(); - // Check to see if we have a value written to post_thread_interrupt_event_fd_, - // indicating a control thread interrupted the post thread. This clears the - // post_thread_interrupt_event_fd_ state in the process. Returns true if an - // interrupt was requested. - bool CheckPostThreadInterruptEventFd(); - // 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. - int PostThreadPollInterruptible(int event_fd); - - // 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. int ReadWaitPPState(); - int BlockUntilVSync(); + int BlockUntilVSync(/*out*/ bool* suspend_requested); int ReadVSyncTimestamp(int64_t* timestamp); int WaitForVSync(int64_t* timestamp); int SleepUntil(int64_t wakeup_timestamp); @@ -295,18 +275,12 @@ class HardwareComposer { bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; } // Returns true if the layer config changed, false otherwise - bool UpdateLayerConfig(); - void PostCompositorBuffers(); - - // Return true if the post thread has work to do (i.e. there are visible - // surfaces to post to the screen). Must be called with post_thread_mutex_ - // locked. Called only from the post thread. - bool PostThreadHasWork(); + bool UpdateLayerConfig( + std::vector>* compositor_surfaces); + void PostCompositorBuffers( + const std::vector>& compositor_surfaces); - // Called on the post thread when the post thread is resumed. - void OnPostThreadResumed(); - // Called on the post thread when the post thread is paused or quits. - void OnPostThreadPaused(); + void UpdateDisplayState(); struct FrameTimeMeasurementRecord { int64_t start_time; @@ -350,28 +324,14 @@ class HardwareComposer { // Buffer for the background layer required by hardware composer. std::shared_ptr framebuffer_target_; - // Protects access to variables used by the post thread and one of the control - // threads (either the vr flinger dispatcher thread or the surface flinger - // main thread). This includes active_surfaces_, active_surfaces_updated_, - // post_thread_enabled_, post_thread_running_, and - // post_thread_quit_requested_. - std::mutex post_thread_mutex_; - - // Surfaces configured by the display manager. Written by the vr flinger - // dispatcher thread, read by the post thread. - std::vector> active_surfaces_; - // active_surfaces_updated_ is set to true by the vr flinger dispatcher thread - // when the list of active surfaces changes. active_surfaces_updated_ will be - // set back to false by the post thread when it processes the update. - bool active_surfaces_updated_; - - // The surfaces displayed by the post thread. Used exclusively by the post - // thread. - std::vector> display_surfaces_; + // Protects access to the display surfaces and logical layers. + std::mutex layer_mutex_; - // The surfaces rendered by the compositor. Used exclusively by the post - // thread. - std::vector> compositor_surfaces_; + // Active display surfaces configured by the display manager. + std::vector> display_surfaces_; + std::vector> added_display_surfaces_; + bool display_surfaces_updated_; + bool hardware_layers_need_update_; // Layer array for handling buffer flow into hardware composer layers. // Note that the first array is the actual storage for the layer objects, @@ -392,22 +352,31 @@ class HardwareComposer { // hand buffers to post processing and the results to hardware composer. std::thread post_thread_; - // Set to true if the post thread is allowed to run. Surface flinger and vr - // flinger share access to the display, and vr flinger shouldn't use the - // display while surface flinger is using it. While surface flinger owns the - // display, post_thread_enabled_ will be set to false to indicate the post - // thread shouldn't run. - bool post_thread_enabled_; - // Set to true by the post thread if it's currently running. - bool post_thread_running_; - // Set to true if the post thread should quit. Only set when destroying the - // HardwareComposer instance. - bool post_thread_quit_requested_; - // Used to wake the post thread up while it's waiting for vsync or sleeping - // until EDS preemption, for faster transition to the paused state. - pdx::LocalHandle post_thread_interrupt_event_fd_; + enum class PostThreadState { + // post_thread_state_ starts off paused. When suspending, the control thread + // will block until post_thread_state_ == kPaused, indicating the post + // thread has completed the transition to paused (most importantly: no more + // hardware composer calls). + kPaused, + // post_thread_state_ is set to kRunning by the control thread (either + // surface flinger's main thread or the vr flinger dispatcher thread). The + // post thread blocks until post_thread_state_ == kRunning. + kRunning, + // Set by the control thread to indicate the post thread should pause. The + // post thread will change post_thread_state_ from kPauseRequested to + // kPaused when it stops. + kPauseRequested + }; + // Control variables to control the state of the post thread + PostThreadState post_thread_state_; + // Used to wake the post thread up while it's waiting for vsync, for faster + // transition to the paused state. + pdx::LocalHandle terminate_post_thread_event_fd_; + // post_thread_state_mutex_ should be held before checking or modifying + // post_thread_state_. + std::mutex post_thread_state_mutex_; // Used to communicate between the control thread and the post thread. - std::condition_variable post_thread_cond_var_; + std::condition_variable post_thread_state_cond_var_; // Backlight LED brightness sysfs node. pdx::LocalHandle backlight_brightness_fd_; @@ -441,17 +410,6 @@ class HardwareComposer { // out to display frame boundaries, so we need to tell it about vsyncs. DvrPose* pose_client_; - // Our history of frame times. This is used to get a better estimate of how - // long the next frame will take, to set a schedule for EDS. - FrameTimeHistory frame_time_history_; - - // The backlog is used to allow us to start rendering the next frame before - // the previous frame has finished, and still get an accurate measurement of - // frame duration. - std::vector frame_time_backlog_; - - 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); diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index 145852e949..17dce96870 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -4,9 +4,6 @@ #include #include -#include -#include - namespace android { namespace Hwc2 { @@ -19,39 +16,16 @@ class DisplayService; class VrFlinger { public: - using RequestDisplayCallback = std::function; - static std::unique_ptr Create( - Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback); - ~VrFlinger(); - - // These functions are all called on surface flinger's main thread. - void OnBootFinished(); - void GrantDisplayOwnership(); - void SeizeDisplayOwnership(); + VrFlinger(); + int Run(Hwc2::Composer* hidl); - // Called on a binder thread. + void EnterVrMode(); + void ExitVrMode(); void OnHardwareComposerRefresh(); private: - VrFlinger(); - bool Init(Hwc2::Composer* hidl, - RequestDisplayCallback request_display_callback); - - // Needs to be a separate class for binder's ref counting - class PersistentVrStateCallback : public BnPersistentVrStateCallbacks { - public: - PersistentVrStateCallback(RequestDisplayCallback request_display_callback) - : request_display_callback_(request_display_callback) {} - void onPersistentVrStateChanged(bool enabled) override; - private: - RequestDisplayCallback request_display_callback_; - }; - - std::thread dispatcher_thread_; - std::unique_ptr dispatcher_; + std::thread displayd_thread_; std::shared_ptr display_service_; - sp persistent_vr_state_callback_; - RequestDisplayCallback request_display_callback_; }; } // namespace dvr diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 21226dba8b..9163e71f79 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -9,13 +9,11 @@ #include #include -#include #include #include #include #include #include -#include #include #include @@ -31,37 +29,11 @@ namespace android { namespace dvr { -std::unique_ptr VrFlinger::Create( - Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { - std::unique_ptr vr_flinger(new VrFlinger); - if (vr_flinger->Init(hidl, request_display_callback)) - return vr_flinger; - else - return nullptr; -} - VrFlinger::VrFlinger() {} -VrFlinger::~VrFlinger() { - if (persistent_vr_state_callback_.get()) { - sp vr_manager = interface_cast( - defaultServiceManager()->checkService(String16("vrmanager"))); - if (vr_manager.get()) { - vr_manager->unregisterPersistentVrStateListener( - persistent_vr_state_callback_); - } - } - - if (dispatcher_) - dispatcher_->SetCanceled(true); - if (dispatcher_thread_.joinable()) - dispatcher_thread_.join(); -} - -bool VrFlinger::Init(Hwc2::Composer* hidl, - RequestDisplayCallback request_display_callback) { - if (!hidl || !request_display_callback) - return false; +int VrFlinger::Run(Hwc2::Composer* hidl) { + if (!hidl) + return EINVAL; std::shared_ptr service; @@ -75,27 +47,25 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, android::ProcessState::self()->startThreadPool(); - request_display_callback_ = request_display_callback; - - dispatcher_ = + std::shared_ptr dispatcher = android::pdx::default_transport::ServiceDispatcher::Create(); - CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher."); + CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher."); display_service_ = android::dvr::DisplayService::Create(hidl); CHECK_ERROR(!display_service_, error, "Failed to create display service."); - dispatcher_->AddService(display_service_); + dispatcher->AddService(display_service_); service = android::dvr::DisplayManagerService::Create(display_service_); CHECK_ERROR(!service, error, "Failed to create display manager service."); - dispatcher_->AddService(service); + dispatcher->AddService(service); service = android::dvr::ScreenshotService::Create(); CHECK_ERROR(!service, error, "Failed to create screenshot service."); - dispatcher_->AddService(service); + dispatcher->AddService(service); service = android::dvr::VSyncService::Create(); CHECK_ERROR(!service, error, "Failed to create vsync service."); - dispatcher_->AddService(service); + dispatcher->AddService(service); display_service_->SetVSyncCallback( std::bind(&android::dvr::VSyncService::VSyncEvent, @@ -103,51 +73,45 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - dispatcher_thread_ = std::thread([this]() { - prctl(PR_SET_NAME, reinterpret_cast("VrDispatch"), 0, 0, 0); + displayd_thread_ = std::thread([this, dispatcher]() { ALOGI("Entering message loop."); - int ret = dispatcher_->EnterDispatchLoop(); + int ret = dispatcher->EnterDispatchLoop(); if (ret < 0) { ALOGE("Dispatch loop exited because: %s\n", strerror(-ret)); } }); - return true; + return NO_ERROR; error: - return false; + display_service_.reset(); + + return -1; } -void VrFlinger::OnBootFinished() { - sp vr_manager = interface_cast( - defaultServiceManager()->checkService(String16("vrmanager"))); - if (vr_manager.get()) { - persistent_vr_state_callback_ = - new PersistentVrStateCallback(request_display_callback_); - vr_manager->registerPersistentVrStateListener( - persistent_vr_state_callback_); +void VrFlinger::EnterVrMode() { + if (display_service_) { + display_service_->SetActive(true); } else { - ALOGE("Unable to register vr flinger for persistent vr mode changes"); + ALOGE("Failed to enter VR mode : Display service is not started."); } } -void VrFlinger::GrantDisplayOwnership() { - display_service_->GrantDisplayOwnership(); -} - -void VrFlinger::SeizeDisplayOwnership() { - display_service_->SeizeDisplayOwnership(); +void VrFlinger::ExitVrMode() { + if (display_service_) { + display_service_->SetActive(false); + } else { + ALOGE("Failed to exit VR mode : Display service is not started."); + } } void VrFlinger::OnHardwareComposerRefresh() { - display_service_->OnHardwareComposerRefresh(); -} - -void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged( - bool enabled) { - ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off"); - request_display_callback_(enabled); + if (display_service_) { + display_service_->OnHardwareComposerRefresh(); + } else { + ALOGE("OnHardwareComposerRefresh failed : Display service is not started."); + } } } // namespace dvr diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index c87a8d9eaa..a6ea75051e 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -53,6 +53,7 @@ ifeq ($(TARGET_USES_HWC2),true) LOCAL_CFLAGS += -DUSE_HWC2 LOCAL_SRC_FILES += \ SurfaceFlinger.cpp \ + VrStateCallbacks.cpp \ DisplayHardware/HWComposer.cpp ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true) LOCAL_CFLAGS += -DBYPASS_IHWC diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0aaab0c031..06dd9037ff 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -73,6 +73,7 @@ #include "LayerDim.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" +#include "VrStateCallbacks.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" @@ -117,7 +118,6 @@ int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; uint64_t SurfaceFlinger::maxVirtualDisplaySize; bool SurfaceFlinger::hasSyncFramework; -bool SurfaceFlinger::useVrFlinger; SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), @@ -136,6 +136,7 @@ SurfaceFlinger::SurfaceFlinger() mVisibleRegionsDirty(false), mGeometryInvalid(false), mAnimCompositionPending(false), + mVrModeSupported(0), mDebugRegion(0), mDebugDDMS(0), mDebugDisableHWC(0), @@ -155,8 +156,10 @@ SurfaceFlinger::SurfaceFlinger() mFrameBuckets(), mTotalTime(0), mLastSwapTime(0), - mNumLayers(0), - mVrFlingerRequestsDisplay(false) + mNumLayers(0) +#ifdef USE_HWC2 + ,mEnterVrMode(false) +#endif { ALOGI("SurfaceFlinger is starting"); @@ -181,13 +184,13 @@ SurfaceFlinger::SurfaceFlinger() maxVirtualDisplaySize = getUInt64(0); - // Vr flinger is only enabled on Daydream ready devices. - useVrFlinger = getBool< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::useVrFlinger>(false); - // debugging stuff... char value[PROPERTY_VALUE_MAX]; + // TODO (urbanus): remove once b/35319396 is fixed. + property_get("ro.boot.vr", value, "0"); + mVrModeSupported = atoi(value); + property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value); @@ -228,6 +231,14 @@ SurfaceFlinger::~SurfaceFlinger() EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(display); + + if (mVrStateCallbacks.get()) { + sp vrManagerService = interface_cast( + defaultServiceManager()->checkService(String16("vrmanager"))); + if (vrManagerService.get()) { + vrManagerService->unregisterListener(mVrStateCallbacks); + } + } } void SurfaceFlinger::binderDied(const wp& /* who */) @@ -354,10 +365,6 @@ void SurfaceFlinger::bootFinished() window->linkToDeath(static_cast(this)); } - if (mVrFlinger) { - mVrFlinger->OnBootFinished(); - } - // stop boot animation // formerly we would just kill the process, but we now ask it to exit so it // can choose where to stop the animation. @@ -366,6 +373,13 @@ void SurfaceFlinger::bootFinished() const int LOGTAG_SF_STOP_BOOTANIM = 60110; LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); + + sp vrManagerService = interface_cast( + defaultServiceManager()->checkService(String16("vrmanager"))); + if (vrManagerService.get()) { + mVrStateCallbacks = new VrStateCallbacks(*this); + vrManagerService->registerListener(mVrStateCallbacks); + } } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -561,26 +575,13 @@ void SurfaceFlinger::init() { // Drop the state lock while we initialize the hardware composer. We drop // the lock because on creation, it will call back into SurfaceFlinger to // initialize the primary display. - LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, - "Starting with vr flinger active is not currently supported."); + LOG_ALWAYS_FATAL_IF(mEnterVrMode, "Starting in vr mode is not currently supported."); mRealHwc = new HWComposer(false); mHwc = mRealHwc; mHwc->setEventHandler(static_cast(this)); Mutex::Autolock _l(mStateLock); - if (useVrFlinger) { - auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { - mVrFlingerRequestsDisplay = requestDisplay; - signalTransaction(); - }; - mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(), - vrFlingerRequestDisplayCallback); - if (!mVrFlinger) { - ALOGE("Failed to start vrflinger"); - } - } - // retrieve the EGL context that was selected/created mEGLContext = mRenderEngine->getEGLContext(); @@ -1212,17 +1213,14 @@ void SurfaceFlinger::resetHwc() { // transition. mDrawingState.displays.clear(); mDisplays.clear(); - initializeDisplays(); } -void SurfaceFlinger::updateVrFlinger() { - if (!mVrFlinger) - return; - bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay; - if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) { +void SurfaceFlinger::updateVrMode() { + bool enteringVrMode = mEnterVrMode; + if (enteringVrMode == mHwc->isUsingVrComposer()) { return; } - if (vrFlingerRequestsDisplay && !mVrHwc) { + if (enteringVrMode && !mVrHwc) { // Construct new HWComposer without holding any locks. mVrHwc = new HWComposer(true); ALOGV("Vr HWC created"); @@ -1230,13 +1228,25 @@ void SurfaceFlinger::updateVrFlinger() { { Mutex::Autolock _l(mStateLock); - if (vrFlingerRequestsDisplay) { + if (enteringVrMode) { + // Start vrflinger thread, if it hasn't been started already. + if (!mVrFlinger) { + mVrFlinger = std::make_unique(); + int err = mVrFlinger->Run(mHwc->getComposer()); + if (err != NO_ERROR) { + ALOGE("Failed to run vrflinger: %s (%d)", strerror(-err), err); + mVrFlinger.reset(); + mEnterVrMode = false; + return; + } + } + resetHwc(); mHwc = mVrHwc; - mVrFlinger->GrantDisplayOwnership(); + mVrFlinger->EnterVrMode(); } else { - mVrFlinger->SeizeDisplayOwnership(); + mVrFlinger->ExitVrMode(); resetHwc(); @@ -1258,6 +1268,12 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { + // TODO(eieio): Tied to a conditional until SELinux issues + // are resolved. + if (mVrModeSupported) { + updateVrMode(); + } + bool frameMissed = !mHadClientComposition && mPreviousPresentFence != Fence::NO_FENCE && (mPreviousPresentFence->getSignalTime() == @@ -1269,11 +1285,6 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { break; } - // Now that we're going to make it to the handleMessageTransaction() - // call below it's safe to call updateVrFlinger(), which will - // potentially trigger a display handoff. - updateVrFlinger(); - bool refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); refreshNeeded |= mRepaintEverything; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e3637f564f..921ecf6797 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -84,6 +84,7 @@ class RenderEngine; class EventControlThread; class VSyncSource; class InjectVSyncSource; +class VrStateCallbacks; namespace dvr { class VrFlinger; @@ -210,6 +211,7 @@ private: friend class EventThread; friend class Layer; friend class MonitoredProducer; + friend class VrStateCallbacks; // This value is specified in number of frames. Log frame stats at most // every half hour. @@ -530,8 +532,9 @@ private: void clearHwcLayers(const LayerVector& layers); void resetHwc(); - // Check to see if we should handoff to vr flinger. - void updateVrFlinger(); + // Check to see if we should change to or from vr mode, and if so, perform + // the handoff. + void updateVrMode(); #endif /* ------------------------------------------------------------------------ @@ -601,6 +604,7 @@ private: DefaultKeyedVector< wp, sp > mDisplays; // don't use a lock for these, we don't care + int mVrModeSupported; int mDebugRegion; int mDebugDDMS; int mDebugDisableHWC; @@ -697,8 +701,9 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); #ifdef USE_HWC2 - std::atomic mVrFlingerRequestsDisplay; - static bool useVrFlinger; + sp mVrStateCallbacks; + + std::atomic mEnterVrMode; #endif }; }; // namespace android diff --git a/services/surfaceflinger/VrStateCallbacks.cpp b/services/surfaceflinger/VrStateCallbacks.cpp new file mode 100644 index 0000000000..a924def4c8 --- /dev/null +++ b/services/surfaceflinger/VrStateCallbacks.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 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 "VrStateCallbacks.h" +#include "SurfaceFlinger.h" + +namespace android { + +VrStateCallbacks::VrStateCallbacks(SurfaceFlinger& flinger) + : mFlinger(flinger) {} + +void VrStateCallbacks::onVrStateChanged(bool enabled) { + mFlinger.mEnterVrMode = enabled; + mFlinger.signalTransaction(); +} + +} // namespace android diff --git a/services/surfaceflinger/VrStateCallbacks.h b/services/surfaceflinger/VrStateCallbacks.h new file mode 100644 index 0000000000..4e655d3668 --- /dev/null +++ b/services/surfaceflinger/VrStateCallbacks.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 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_VR_STATE_CALLBACKS_H +#define ANDROID_VR_STATE_CALLBACKS_H + +#include + +namespace android { + +class SurfaceFlinger; + +class VrStateCallbacks : public BnVrStateCallbacks { +public: + VrStateCallbacks(SurfaceFlinger& flinger); + void onVrStateChanged(bool enabled) override; + +private: + SurfaceFlinger& mFlinger; +}; + +} // namespace android + +#endif // ANDROID_VR_STATE_CALLBACKS_H diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp index 3dfd9f1a9f..eb9f40755a 100644 --- a/services/vr/vr_window_manager/application.cpp +++ b/services/vr/vr_window_manager/application.cpp @@ -25,7 +25,7 @@ Application::~Application() { sp vrManagerService = interface_cast( defaultServiceManager()->getService(String16("vrmanager"))); if (vrManagerService.get()) { - vrManagerService->unregisterPersistentVrStateListener(vr_mode_listener_); + vrManagerService->unregisterListener(vr_mode_listener_); } } @@ -39,7 +39,7 @@ int Application::Initialize() { sp vrManagerService = interface_cast( defaultServiceManager()->getService(String16("vrmanager"))); if (vrManagerService.get()) { - vrManagerService->registerPersistentVrStateListener(vr_mode_listener_); + vrManagerService->registerListener(vr_mode_listener_); } return 0; } @@ -315,7 +315,7 @@ void Application::QueueTask(MainThreadTask task) { wake_up_init_and_render_.notify_one(); } -void Application::VrModeListener::onPersistentVrStateChanged(bool enabled) { +void Application::VrModeListener::onVrStateChanged(bool enabled) { if (!enabled) app_->QueueTask(MainThreadTask::ExitingVrMode); } diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h index 4b36ecc22b..62155615f1 100644 --- a/services/vr/vr_window_manager/application.h +++ b/services/vr/vr_window_manager/application.h @@ -44,10 +44,10 @@ class Application { Show, }; - class VrModeListener : public BnPersistentVrStateCallbacks { + class VrModeListener : public BnVrStateCallbacks { public: VrModeListener(Application *app) : app_(app) {} - void onPersistentVrStateChanged(bool enabled) override; + void onVrStateChanged(bool enabled) override; private: Application *app_; -- 2.11.0