};
+// 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<IPersistentVrStateCallbacks> {
+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 {
virtual void registerListener(const sp<IVrStateCallbacks>& cb) = 0;
virtual void unregisterListener(const sp<IVrStateCallbacks>& cb) = 0;
+ virtual void registerPersistentVrStateListener(
+ const sp<IPersistentVrStateCallbacks>& cb) = 0;
+ virtual void unregisterPersistentVrStateListener(
+ const sp<IPersistentVrStateCallbacks>& 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,
};
return 0;
}
-int DisplayClient::EnterVrMode() {
- auto status = InvokeRemoteMethod<DisplayRPC::EnterVrMode>();
- if (!status) {
- ALOGE(
- "DisplayClient::EnterVrMode: Failed to set display service to Vr mode");
- return -status.error();
- }
-
- return 0;
-}
-
-int DisplayClient::ExitVrMode() {
- auto status = InvokeRemoteMethod<DisplayRPC::ExitVrMode>();
- if (!status) {
- ALOGE(
- "DisplayClient::ExitVrMode: Failed to revert display service from Vr "
- "mode");
- return -status.error();
- }
-
- return 0;
-}
-
std::unique_ptr<DisplaySurfaceClient> DisplayClient::CreateDisplaySurface(
int width, int height, int format, int usage, int flags) {
return DisplaySurfaceClient::Create(width, height, format, usage, flags);
// Pull the latest eds pose data from the display service renderer
int GetLastFrameEdsTransform(LateLatchOutput* ll_out);
- int EnterVrMode();
- int ExitVrMode();
-
std::unique_ptr<DisplaySurfaceClient> CreateDisplaySurface(
int width, int height, int format, int usage, int flags);
kOpGetMetadataBuffer,
kOpCreateVideoMeshSurface,
kOpVideoMeshSurfaceCreateProducerQueue,
- kOpEnterVrMode,
- kOpExitVrMode,
kOpSetViewerParams,
kOpGetPoseBuffer,
};
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));
PDX_REMOTE_METHOD(GetPoseBuffer, kOpGetPoseBuffer,
return BBinder::onTransact(code, data, reply, flags);
}
+// Must be kept in sync with interface defined in
+// IPersistentVrStateCallbacks.aidl.
+
+class BpPersistentVrStateCallbacks
+ : public BpInterface<IPersistentVrStateCallbacks> {
+ public:
+ explicit BpPersistentVrStateCallbacks(const sp<IBinder>& impl)
+ : BpInterface<IPersistentVrStateCallbacks>(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<IVrManager> {
remote()->transact(UNREGISTER_LISTENER, data, NULL);
}
+ void registerPersistentVrStateListener(
+ const sp<IPersistentVrStateCallbacks>& 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<IPersistentVrStateCallbacks>& 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());
namespace android {
namespace dvr {
-DisplayService::DisplayService() : DisplayService(nullptr) {}
+DisplayService::DisplayService()
+ : DisplayService(nullptr) {}
DisplayService::DisplayService(Hwc2::Composer* hidl)
: BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
*this, &DisplayService::OnCreateSurface, message);
return 0;
- case DisplayRPC::EnterVrMode::Opcode:
- DispatchRemoteMethod<DisplayRPC::EnterVrMode>(
- *this, &DisplayService::OnEnterVrMode, message);
- return 0;
-
- case DisplayRPC::ExitVrMode::Opcode:
- DispatchRemoteMethod<DisplayRPC::ExitVrMode>(
- *this, &DisplayService::OnExitVrMode, message);
- return 0;
-
case DisplayRPC::SetViewerParams::Opcode:
DispatchRemoteMethod<DisplayRPC::SetViewerParams>(
*this, &DisplayService::OnSetViewerParams, 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();
return visible_surfaces;
}
-int DisplayService::UpdateActiveDisplaySurfaces() {
+void DisplayService::UpdateActiveDisplaySurfaces() {
auto visible_surfaces = GetVisibleDisplaySurfaces();
// Sort the surfaces based on manager z order first, then client z order.
if (surface->client_blur_behind())
blur_requested = true;
}
- return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
+
+ hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
pdx::BorrowedChannelHandle DisplayService::SetupPoseBuffer(
// Updates the list of actively displayed surfaces. This must be called after
// any change to client/manager attributes that affect visibility or z order.
- int UpdateActiveDisplaySurfaces();
+ void UpdateActiveDisplaySurfaces();
pdx::BorrowedChannelHandle SetupPoseBuffer(size_t extended_region_size,
int usage);
return hardware_composer_.display_metrics();
}
- void SetActive(bool activated) {
- if (activated) {
- hardware_composer_.Resume();
- } else {
- hardware_composer_.Suspend();
- }
- }
+ void GrantDisplayOwnership() { hardware_composer_.Enable(); }
+ void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
void OnHardwareComposerRefresh();
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);
pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message);
: initialized_(false),
hwc2_hidl_(hwc2_hidl),
display_transform_(HWC_TRANSFORM_NONE),
- display_surfaces_updated_(false),
- hardware_layers_need_update_(false),
+ active_surfaces_updated_(false),
active_layer_count_(0),
gpu_layer_(nullptr),
- post_thread_state_(PostThreadState::kPaused),
- terminate_post_thread_event_fd_(-1),
+ post_thread_enabled_(false),
+ post_thread_running_(false),
+ post_thread_quit_requested_(false),
+ post_thread_interrupt_event_fd_(-1),
backlight_brightness_fd_(-1),
primary_display_vsync_event_fd_(-1),
primary_display_wait_pp_fd_(-1),
}
HardwareComposer::~HardwareComposer(void) {
- Suspend();
+ std::unique_lock<std::mutex> lock(post_thread_mutex_);
+ if (post_thread_.joinable()) {
+ post_thread_quit_requested_ = true;
+ post_thread_cond_var_.notify_all();
+ post_thread_.join();
+ }
}
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_;
}
-bool HardwareComposer::Resume() {
- std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
- if (post_thread_state_ == PostThreadState::kRunning) {
- return false;
- }
-
- std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+void HardwareComposer::Enable() {
+ std::lock_guard<std::mutex> lock(post_thread_mutex_);
+ post_thread_enabled_ = true;
+ post_thread_cond_var_.notify_all();
+}
- int32_t ret = HWC2_ERROR_NONE;
+void HardwareComposer::Disable() {
+ std::unique_lock<std::mutex> 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));
+ }
+}
- // Always turn off vsync when we start.
- EnableVsync(false);
+bool HardwareComposer::PostThreadHasWork() {
+ return !display_surfaces_.empty() ||
+ (active_surfaces_updated_ && !active_surfaces_.empty());
+}
+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;
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");
- 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));
+ EnableVsync(true);
- post_thread_state_ = PostThreadState::kRunning;
- post_thread_state_cond_var_.notify_all();
+ // 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);
- // 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();
- }
+ // Initialize the GPU compositor.
+ LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
+ "Failed to initialize the compositor");
- return true;
+ // Trigger target-specific performance mode change.
+ property_set(kDvrPerformanceProperty, "performance");
}
-bool HardwareComposer::Suspend() {
- std::unique_lock<std::mutex> 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<std::mutex> 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();
+void HardwareComposer::OnPostThreadPaused() {
retire_fence_fds_.clear();
gpu_layer_ = nullptr;
- // We have to destroy the layers before we close the hwc device
+ // We have to destroy the layers to fully clear hwc device state before
+ // handing off back to surface flinger
for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
layers_[i]->Reset();
}
framebuffer_target_.reset();
- //hwc2_hidl_.reset();
+ display_surfaces_.clear();
+ compositor_surfaces_.clear();
+
+ // Since we're clearing display_surfaces_ we'll need an update.
+ active_surfaces_updated_ = true;
- if (pose_client_)
+ if (pose_client_) {
dvrPoseDestroy(pose_client_);
+ pose_client_ = nullptr;
+ }
- return true;
+ EnableVsync(false);
+
+ frame_time_history_.ResetWithSeed(GuessFrameTime(0));
+ frame_time_backlog_.clear();
+
+ compositor_.Shutdown();
+
+ // Trigger target-specific performance mode change.
+ property_set(kDvrPerformanceProperty, "idle");
}
DisplayMetrics HardwareComposer::GetHmdDisplayMetrics() const {
}
}
-// 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(
+void HardwareComposer::SetDisplaySurfaces(
std::vector<std::shared_ptr<DisplaySurface>> surfaces) {
- // The double lock is necessary because we access both the display surfaces
- // and post_thread_state_.
- std::lock_guard<std::mutex> post_thread_state_lock(post_thread_state_mutex_);
- std::lock_guard<std::mutex> layer_lock(layer_mutex_);
-
ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd",
surfaces.size());
+ std::unique_lock<std::mutex> lock(post_thread_mutex_);
+ active_surfaces_ = std::move(surfaces);
+ active_surfaces_updated_ = true;
+ if (post_thread_enabled_)
+ post_thread_cond_var_.notify_all();
+}
- // 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;
-
- 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<int>(i));
- }
+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);
- // TODO(skiazyk): fix this so that it is handled seamlessly with dormant/non-
- // dormant state.
- if (post_thread_state_ == PostThreadState::kRunning) {
- UpdateDisplayState();
+ 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;
}
-
- return 0;
}
// Reads the value of the display driver wait_pingpong state. Returns 0 or 1
// 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(/*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;
+int HardwareComposer::BlockUntilVSync() {
+ return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get());
}
// Waits for the next vsync and returns the timestamp of the vsync event. If
if (error == -EAGAIN) {
// Vsync was turned off, wait for the next vsync event.
- bool suspend_requested = false;
- error = BlockUntilVSync(&suspend_requested);
- if (error < 0 || suspend_requested)
+ error = BlockUntilVSync();
+ if (error < 0 || error == kPostThreadInterrupted)
return error;
// Try again to get the timestamp for this new vsync interval.
if (distance_to_vsync_est > threshold_ns) {
// Wait for vsync event notification.
- bool suspend_requested = false;
- error = BlockUntilVSync(&suspend_requested);
- if (error < 0 || suspend_requested)
+ error = BlockUntilVSync();
+ if (error < 0 || error == kPostThreadInterrupted)
return error;
} else {
- // Sleep for a short time before retrying.
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ // Sleep for a short time (1 millisecond) before retrying.
+ error = SleepUntil(GetSystemClockNs() + 1000000);
+ if (error < 0 || error == kPostThreadInterrupted)
+ return error;
}
}
}
return -error;
}
- // 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;
+ return PostThreadPollInterruptible(timer_fd);
}
void HardwareComposer::PostThread() {
// NOLINTNEXTLINE(runtime/int)
- prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("PostThread"), 0, 0, 0);
+ prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrHwcPost"), 0, 0, 0);
// Set the scheduler to SCHED_FIFO with high priority.
int error = dvrSetSchedulerClass(0, "graphics:high");
"HardwareComposer::PostThread: Failed to set cpu partition: %s",
strerror(-error));
- // Force the layers to be setup at least once.
- display_surfaces_updated_ = true;
+#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
- // Initialize the GPU compositor.
- LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
- "Failed to initialize the compositor");
+ // 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));
+
+ // 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));
const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
right_eye_photon_offset_ns =
property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
- // The list of surfaces the compositor should attempt to render. This is set
- // at the start of each frame.
- std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces;
- compositor_surfaces.reserve(2);
+ 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<FrameTimeMeasurementRecord> 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<std::mutex> 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;
+ std::unique_lock<std::mutex> 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);
}
+ post_thread_running_ = true;
+ }
+
+ if (!was_running) {
+ ALOGI("VrHwcPost thread resumed");
+ OnPostThreadResumed();
+ was_running = true;
}
int64_t vsync_timestamp = 0;
error < 0,
"HardwareComposer::PostThread: Failed to wait for vsync event: %s",
strerror(-error));
-
// Don't bother processing this frame if a pause was requested
- std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
- if (post_thread_state_ == PostThreadState::kPauseRequested) {
+ if (error == kPostThreadInterrupted)
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.
ns_per_frame, right_eye_photon_offset_ns);
}
- bool layer_config_changed = UpdateLayerConfig(&compositor_surfaces);
+ bool layer_config_changed = UpdateLayerConfig();
- if (layer_config_changed) {
- frame_time_history.ResetWithSeed(
- GuessFrameTime(compositor_surfaces.size()));
- frame_time_backlog.clear();
+ if (!was_running || 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;
// 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;
error = SleepUntil(display_time_est - frame_time_estimate);
ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
strerror(-error));
+ if (error == kPostThreadInterrupted)
+ continue;
}
}
// permanently backed up.
PostLayers(layer_config_changed);
- PostCompositorBuffers(compositor_surfaces);
+ PostCompositorBuffers();
if (gpu_layer_ != nullptr) {
// Note, with scanline racing, this draw is timed along with the post
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<std::shared_ptr<DisplaySurface>>* compositor_surfaces) {
- std::lock_guard<std::mutex> layer_lock(layer_mutex_);
-
- if (!display_surfaces_updated_)
- return false;
+bool HardwareComposer::UpdateLayerConfig() {
+ std::vector<std::shared_ptr<DisplaySurface>> old_display_surfaces;
+ {
+ std::lock_guard<std::mutex> lock(post_thread_mutex_);
+ if (!active_surfaces_updated_)
+ return false;
+ old_display_surfaces = display_surfaces_;
+ display_surfaces_ = active_surfaces_;
+ active_surfaces_updated_ = false;
+ }
- display_surfaces_updated_ = false;
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;
+
+ // Set the chosen layer order for all surfaces.
+ for (size_t i = 0; i < display_surfaces_.size(); ++i) {
+ display_surfaces_[i]->SetLayerOrder(static_cast<int>(i));
+ }
+
// 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.
return true;
}
-void HardwareComposer::PostCompositorBuffers(
- const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces) {
+void HardwareComposer::PostCompositorBuffers() {
ATRACE_NAME("PostCompositorBuffers");
- for (const auto& surface : compositor_surfaces) {
+ for (const auto& surface : compositor_surfaces_) {
compositor_.PostBuffer(surface);
}
}
// 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.
bool IsInitialized() const { return initialized_; }
- bool Suspend();
- bool Resume();
+ // 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();
// Get the HMD display metrics for the current display.
DisplayMetrics GetHmdDisplayMetrics() const;
return native_display_metrics_;
}
- std::shared_ptr<IonBuffer> framebuffer_target() const {
- return framebuffer_target_;
- }
-
// Set the display surface stack to compose to the display each frame.
- int SetDisplaySurfaces(std::vector<std::shared_ptr<DisplaySurface>> surfaces);
+ void SetDisplaySurfaces(
+ std::vector<std::shared_ptr<DisplaySurface>> surfaces);
Compositor* GetCompositor() { return &compositor_; }
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(/*out*/ bool* suspend_requested);
+ int BlockUntilVSync();
int ReadVSyncTimestamp(int64_t* timestamp);
int WaitForVSync(int64_t* timestamp);
int SleepUntil(int64_t wakeup_timestamp);
bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
// Returns true if the layer config changed, false otherwise
- bool UpdateLayerConfig(
- std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces);
- void PostCompositorBuffers(
- const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces);
+ 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();
- void UpdateDisplayState();
+ // 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();
struct FrameTimeMeasurementRecord {
int64_t start_time;
// Buffer for the background layer required by hardware composer.
std::shared_ptr<IonBuffer> framebuffer_target_;
- // Protects access to the display surfaces and logical layers.
- std::mutex layer_mutex_;
-
- // Active display surfaces configured by the display manager.
+ // 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<std::shared_ptr<DisplaySurface>> 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<std::shared_ptr<DisplaySurface>> display_surfaces_;
- std::vector<std::shared_ptr<DisplaySurface>> added_display_surfaces_;
- bool display_surfaces_updated_;
- bool hardware_layers_need_update_;
+
+ // The surfaces rendered by the compositor. Used exclusively by the post
+ // thread.
+ std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces_;
// Layer array for handling buffer flow into hardware composer layers.
// Note that the first array is the actual storage for the layer objects,
// hand buffers to post processing and the results to hardware composer.
std::thread post_thread_;
- 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_;
+ // 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_;
// Used to communicate between the control thread and the post thread.
- std::condition_variable post_thread_state_cond_var_;
+ std::condition_variable post_thread_cond_var_;
// Backlight LED brightness sysfs node.
pdx::LocalHandle backlight_brightness_fd_;
// 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<FrameTimeMeasurementRecord> 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);
#include <thread>
#include <memory>
+#include <pdx/default_transport/service_dispatcher.h>
+#include <vr/vr_manager/vr_manager.h>
+
namespace android {
namespace Hwc2 {
class VrFlinger {
public:
- VrFlinger();
- int Run(Hwc2::Composer* hidl);
+ using RequestDisplayCallback = std::function<void(bool)>;
+ static std::unique_ptr<VrFlinger> Create(
+ Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback);
+ ~VrFlinger();
- void EnterVrMode();
- void ExitVrMode();
+ // These functions are all called on surface flinger's main thread.
+ void OnBootFinished();
+ void GrantDisplayOwnership();
+ void SeizeDisplayOwnership();
+
+ // Called on a binder thread.
void OnHardwareComposerRefresh();
private:
- std::thread displayd_thread_;
+ 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<android::pdx::ServiceDispatcher> dispatcher_;
std::shared_ptr<android::dvr::DisplayService> display_service_;
+ sp<PersistentVrStateCallback> persistent_vr_state_callback_;
+ RequestDisplayCallback request_display_callback_;
};
} // namespace dvr
#include <unistd.h>
#include <memory>
+#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <log/log.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <private/dvr/display_client.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <pdx/default_transport/service_dispatcher.h>
namespace android {
namespace dvr {
+std::unique_ptr<VrFlinger> VrFlinger::Create(
+ Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
+ std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger);
+ if (vr_flinger->Init(hidl, request_display_callback))
+ return vr_flinger;
+ else
+ return nullptr;
+}
+
VrFlinger::VrFlinger() {}
-int VrFlinger::Run(Hwc2::Composer* hidl) {
- if (!hidl)
- return EINVAL;
+VrFlinger::~VrFlinger() {
+ if (persistent_vr_state_callback_.get()) {
+ sp<IVrManager> vr_manager = interface_cast<IVrManager>(
+ 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;
std::shared_ptr<android::pdx::Service> service;
android::ProcessState::self()->startThreadPool();
- std::shared_ptr<android::pdx::ServiceDispatcher> dispatcher =
+ request_display_callback_ = request_display_callback;
+
+ 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,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4));
- displayd_thread_ = std::thread([this, dispatcher]() {
+ dispatcher_thread_ = std::thread([this]() {
+ prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
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 NO_ERROR;
+ return true;
error:
- display_service_.reset();
-
- return -1;
+ return false;
}
-void VrFlinger::EnterVrMode() {
- if (display_service_) {
- display_service_->SetActive(true);
+void VrFlinger::OnBootFinished() {
+ sp<IVrManager> vr_manager = interface_cast<IVrManager>(
+ defaultServiceManager()->checkService(String16("vrmanager")));
+ if (vr_manager.get()) {
+ persistent_vr_state_callback_ =
+ new PersistentVrStateCallback(request_display_callback_);
+ vr_manager->registerPersistentVrStateListener(
+ persistent_vr_state_callback_);
} else {
- ALOGE("Failed to enter VR mode : Display service is not started.");
+ ALOGE("Unable to register vr flinger for persistent vr mode changes");
}
}
-void VrFlinger::ExitVrMode() {
- if (display_service_) {
- display_service_->SetActive(false);
- } else {
- ALOGE("Failed to exit VR mode : Display service is not started.");
- }
+void VrFlinger::GrantDisplayOwnership() {
+ display_service_->GrantDisplayOwnership();
+}
+
+void VrFlinger::SeizeDisplayOwnership() {
+ display_service_->SeizeDisplayOwnership();
}
void VrFlinger::OnHardwareComposerRefresh() {
- if (display_service_) {
- display_service_->OnHardwareComposerRefresh();
- } else {
- ALOGE("OnHardwareComposerRefresh failed : Display service is not started.");
- }
+ display_service_->OnHardwareComposerRefresh();
+}
+
+void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
+ bool enabled) {
+ ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
+ request_display_callback_(enabled);
}
} // namespace dvr
LOCAL_CFLAGS += -DUSE_HWC2
LOCAL_SRC_FILES += \
SurfaceFlinger.cpp \
- VrStateCallbacks.cpp \
DisplayHardware/HWComposer.cpp
ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true)
LOCAL_CFLAGS += -DBYPASS_IHWC
#include "LayerDim.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
-#include "VrStateCallbacks.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
bool SurfaceFlinger::hasSyncFramework;
+bool SurfaceFlinger::useVrFlinger;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
- mVrModeSupported(0),
mDebugRegion(0),
mDebugDDMS(0),
mDebugDisableHWC(0),
mFrameBuckets(),
mTotalTime(0),
mLastSwapTime(0),
- mNumLayers(0)
-#ifdef USE_HWC2
- ,mEnterVrMode(false)
-#endif
+ mNumLayers(0),
+ mVrFlingerRequestsDisplay(false)
{
ALOGI("SurfaceFlinger is starting");
maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::maxVirtualDisplaySize>(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);
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(display);
-
- if (mVrStateCallbacks.get()) {
- sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
- defaultServiceManager()->checkService(String16("vrmanager")));
- if (vrManagerService.get()) {
- vrManagerService->unregisterListener(mVrStateCallbacks);
- }
- }
}
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(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.
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-
- sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
- defaultServiceManager()->checkService(String16("vrmanager")));
- if (vrManagerService.get()) {
- mVrStateCallbacks = new VrStateCallbacks(*this);
- vrManagerService->registerListener(mVrStateCallbacks);
- }
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
// 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(mEnterVrMode, "Starting in vr mode is not currently supported.");
+ LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
+ "Starting with vr flinger active is not currently supported.");
mRealHwc = new HWComposer(false);
mHwc = mRealHwc;
mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(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();
// transition.
mDrawingState.displays.clear();
mDisplays.clear();
+ initializeDisplays();
}
-void SurfaceFlinger::updateVrMode() {
- bool enteringVrMode = mEnterVrMode;
- if (enteringVrMode == mHwc->isUsingVrComposer()) {
+void SurfaceFlinger::updateVrFlinger() {
+ if (!mVrFlinger)
+ return;
+ bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
+ if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
return;
}
- if (enteringVrMode && !mVrHwc) {
+ if (vrFlingerRequestsDisplay && !mVrHwc) {
// Construct new HWComposer without holding any locks.
mVrHwc = new HWComposer(true);
ALOGV("Vr HWC created");
{
Mutex::Autolock _l(mStateLock);
- if (enteringVrMode) {
- // Start vrflinger thread, if it hasn't been started already.
- if (!mVrFlinger) {
- mVrFlinger = std::make_unique<dvr::VrFlinger>();
- 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;
- }
- }
-
+ if (vrFlingerRequestsDisplay) {
resetHwc();
mHwc = mVrHwc;
- mVrFlinger->EnterVrMode();
+ mVrFlinger->GrantDisplayOwnership();
} else {
- mVrFlinger->ExitVrMode();
+ mVrFlinger->SeizeDisplayOwnership();
resetHwc();
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() ==
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;
class EventControlThread;
class VSyncSource;
class InjectVSyncSource;
-class VrStateCallbacks;
namespace dvr {
class VrFlinger;
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.
void clearHwcLayers(const LayerVector& layers);
void resetHwc();
- // Check to see if we should change to or from vr mode, and if so, perform
- // the handoff.
- void updateVrMode();
+ // Check to see if we should handoff to vr flinger.
+ void updateVrFlinger();
#endif
/* ------------------------------------------------------------------------
DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
// don't use a lock for these, we don't care
- int mVrModeSupported;
int mDebugRegion;
int mDebugDDMS;
int mDebugDisableHWC;
status_t CheckTransactCodeCredentials(uint32_t code);
#ifdef USE_HWC2
- sp<VrStateCallbacks> mVrStateCallbacks;
-
- std::atomic<bool> mEnterVrMode;
+ std::atomic<bool> mVrFlingerRequestsDisplay;
+ static bool useVrFlinger;
#endif
};
}; // namespace android
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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 <vr/vr_manager/vr_manager.h>
-
-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
sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
defaultServiceManager()->getService(String16("vrmanager")));
if (vrManagerService.get()) {
- vrManagerService->unregisterListener(vr_mode_listener_);
+ vrManagerService->unregisterPersistentVrStateListener(vr_mode_listener_);
}
}
sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
defaultServiceManager()->getService(String16("vrmanager")));
if (vrManagerService.get()) {
- vrManagerService->registerListener(vr_mode_listener_);
+ vrManagerService->registerPersistentVrStateListener(vr_mode_listener_);
}
return 0;
}
wake_up_init_and_render_.notify_one();
}
-void Application::VrModeListener::onVrStateChanged(bool enabled) {
+void Application::VrModeListener::onPersistentVrStateChanged(bool enabled) {
if (!enabled)
app_->QueueTask(MainThreadTask::ExitingVrMode);
}
Show,
};
- class VrModeListener : public BnVrStateCallbacks {
+ class VrModeListener : public BnPersistentVrStateCallbacks {
public:
VrModeListener(Application *app) : app_(app) {}
- void onVrStateChanged(bool enabled) override;
+ void onPersistentVrStateChanged(bool enabled) override;
private:
Application *app_;