};
-// 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
};
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));
};
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;
}
-void DisplayService::UpdateActiveDisplaySurfaces() {
+int 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;
}
-
- hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
+ return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
void DisplayService::OnHardwareComposerRefresh() {
// 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 <class A>
void ForEachDisplaySurface(A action) const {
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();
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
: 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),
}
HardwareComposer::~HardwareComposer(void) {
- 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();
- }
+ Suspend();
}
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<std::mutex> lock(post_thread_mutex_);
- post_thread_enabled_ = true;
- post_thread_cond_var_.notify_all();
-}
-
-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));
+bool HardwareComposer::Resume() {
+ std::lock_guard<std::mutex> 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<std::mutex> 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;
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<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();
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();
}
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 {
}
}
-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<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();
-}
-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<int>(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
// 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
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.
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));
}
}
}
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<unsigned long>("VrHwcPost"), 0, 0, 0);
+ prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("PostThread"), 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));
-#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);
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<std::shared_ptr<DisplaySurface>> 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<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> 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<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;
}
- 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
- if (error == kPostThreadInterrupted)
+ std::lock_guard<std::mutex> 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.
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;
// 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();
+ PostCompositorBuffers(compositor_surfaces);
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>> 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;
- }
+bool HardwareComposer::UpdateLayerConfig(
+ std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces) {
+ std::lock_guard<std::mutex> 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<int>(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.
return true;
}
-void HardwareComposer::PostCompositorBuffers() {
+void HardwareComposer::PostCompositorBuffers(
+ const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces) {
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_; }
- // 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;
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.
- void SetDisplaySurfaces(
- std::vector<std::shared_ptr<DisplaySurface>> surfaces);
+ int 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();
+ int BlockUntilVSync(/*out*/ bool* suspend_requested);
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();
- 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<std::shared_ptr<DisplaySurface>>* compositor_surfaces);
+ void PostCompositorBuffers(
+ const std::vector<std::shared_ptr<DisplaySurface>>& 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;
// Buffer for the background layer required by hardware composer.
std::shared_ptr<IonBuffer> 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<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_;
+ // 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<std::shared_ptr<DisplaySurface>> compositor_surfaces_;
+ // Active display surfaces configured by the display manager.
+ 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_;
// 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_;
- // 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_;
// 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:
- using RequestDisplayCallback = std::function<void(bool)>;
- static std::unique_ptr<VrFlinger> 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<android::pdx::ServiceDispatcher> dispatcher_;
+ std::thread displayd_thread_;
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() {}
-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;
+int VrFlinger::Run(Hwc2::Composer* hidl) {
+ if (!hidl)
+ return EINVAL;
std::shared_ptr<android::pdx::Service> service;
android::ProcessState::self()->startThreadPool();
- request_display_callback_ = request_display_callback;
-
- dispatcher_ =
+ std::shared_ptr<android::pdx::ServiceDispatcher> 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));
- dispatcher_thread_ = std::thread([this]() {
- prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("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<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_);
+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
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),
- mVrFlingerRequestsDisplay(false)
+ mNumLayers(0)
+#ifdef USE_HWC2
+ ,mEnterVrMode(false)
+#endif
{
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(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<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::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");
{
Mutex::Autolock _l(mStateLock);
- if (vrFlingerRequestsDisplay) {
+ 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;
+ }
+ }
+
resetHwc();
mHwc = mVrHwc;
- mVrFlinger->GrantDisplayOwnership();
+ mVrFlinger->EnterVrMode();
} else {
- mVrFlinger->SeizeDisplayOwnership();
+ mVrFlinger->ExitVrMode();
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 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
/* ------------------------------------------------------------------------
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
- std::atomic<bool> mVrFlingerRequestsDisplay;
- static bool useVrFlinger;
+ sp<VrStateCallbacks> mVrStateCallbacks;
+
+ std::atomic<bool> mEnterVrMode;
#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->unregisterPersistentVrStateListener(vr_mode_listener_);
+ vrManagerService->unregisterListener(vr_mode_listener_);
}
}
sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
defaultServiceManager()->getService(String16("vrmanager")));
if (vrManagerService.get()) {
- vrManagerService->registerPersistentVrStateListener(vr_mode_listener_);
+ vrManagerService->registerListener(vr_mode_listener_);
}
return 0;
}
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);
}
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_;