From 933ed5ceb9d70829333ae438985a1bfeec8e79a8 Mon Sep 17 00:00:00 2001 From: Alex Sakhartchouk Date: Mon, 5 Jun 2017 10:37:57 -0400 Subject: Re-enable default display when switching to VR mode. Previously, in an attempt to minimize the number of changes that got reset during VR mode transitions, the primary display was not turned back on. Bug: 62215749 Test: Switch device into VR mode, observe primary display invalidations. Change-Id: Idd883e1522f519a0db06fdd88b071007487b6e70 --- services/surfaceflinger/SurfaceFlinger.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 78579a51ef..1bc9cec932 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1315,11 +1315,21 @@ void SurfaceFlinger::updateVrFlinger() { // parts of this class rely on the primary display always being available. createDefaultDisplayDevice(); - // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); - const nsecs_t period = activeConfig->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(period); - setCompositorTimingSnapped(0, period, 0); + // Re-enable default display. + sp requestMessage = new LambdaMessage([&]() { + sp hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); + setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL); + + // Reset the timing values to account for the period of the swapped in HWC + const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const nsecs_t period = activeConfig->getVsyncPeriod(); + mAnimFrameTracker.setDisplayRefreshPeriod(period); + + // Use phase of 0 since phase is not known. + // Use latency of 0, which will snap to the ideal latency. + setCompositorTimingSnapped(0, period, 0); + }); + postMessageAsync(requestMessage); android_atomic_or(1, &mRepaintEverything); setTransactionFlags(eDisplayTransactionNeeded); -- cgit v1.2.3-59-g8ed1b From fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 26 May 2017 16:23:54 -0700 Subject: Reduce number of Fence syscalls made. This patch saves 6 or more Fence syscalls per frame. * Timelines are updated just before adding a new fence since the newly added fence is unlikely to have signaled. * Layer::latch uses a FenceTime now, so the signal time is automatically shared with other owners of the FenceTime. * DispSync uses FenceTime now, only using cached values of the signal time that have been populated by a Timeline. Test: SurfaceFlinger boots and dumps still work. Change-Id: Ie0cfc1af2aca143dd8d5f08f08dbe1e597376f2f --- services/surfaceflinger/DispSync.cpp | 72 +++++++++++++------------ services/surfaceflinger/DispSync.h | 20 +++++-- services/surfaceflinger/Layer.cpp | 14 +++-- services/surfaceflinger/SurfaceFlinger.cpp | 8 +-- services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 6 +-- 5 files changed, 71 insertions(+), 49 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp index bd9b8aafcd..ac8aa04e9d 100644 --- a/services/surfaceflinger/DispSync.cpp +++ b/services/surfaceflinger/DispSync.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include "DispSync.h" #include "SurfaceFlinger.h" @@ -419,25 +419,13 @@ void DispSync::reset() { resetErrorLocked(); } -bool DispSync::addPresentFence(const sp& fence) { +bool DispSync::addPresentFence(const std::shared_ptr& fenceTime) { Mutex::Autolock lock(mMutex); - mPresentFences[mPresentSampleOffset] = fence; - mPresentTimes[mPresentSampleOffset] = 0; + mPresentFences[mPresentSampleOffset] = fenceTime; mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES; mNumResyncSamplesSincePresent = 0; - for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - const sp& f(mPresentFences[i]); - if (f != NULL) { - nsecs_t t = f->getSignalTime(); - if (t < INT64_MAX) { - mPresentFences[i].clear(); - mPresentTimes[i] = t + mPresentTimeOffset; - } - } - } - updateErrorLocked(); return !mModelUpdated || mError > kErrorThreshold; @@ -602,21 +590,39 @@ void DispSync::updateErrorLocked() { nsecs_t sqErrSum = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - nsecs_t sample = mPresentTimes[i] - mReferenceTime; - if (sample > mPhase) { - nsecs_t sampleErr = (sample - mPhase) % period; - if (sampleErr > period / 2) { - sampleErr -= period; - } - sqErrSum += sampleErr * sampleErr; - numErrSamples++; + // Only check for the cached value of signal time to avoid unecessary + // syscalls. It is the responsibility of the DispSync owner to + // call getSignalTime() periodically so the cache is updated when the + // fence signals. + nsecs_t time = mPresentFences[i]->getCachedSignalTime(); + if (time == Fence::SIGNAL_TIME_PENDING || + time == Fence::SIGNAL_TIME_INVALID) { + continue; + } + + nsecs_t sample = time - mReferenceTime; + if (sample <= mPhase) { + continue; + } + + nsecs_t sampleErr = (sample - mPhase) % period; + if (sampleErr > period / 2) { + sampleErr -= period; } + sqErrSum += sampleErr * sampleErr; + numErrSamples++; } if (numErrSamples > 0) { mError = sqErrSum / numErrSamples; + mZeroErrSamplesCount = 0; } else { mError = 0; + // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam. + mZeroErrSamplesCount++; + ALOGE_IF( + (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0, + "No present times for model error."); } if (kTraceDetailedInfo) { @@ -627,9 +633,9 @@ void DispSync::updateErrorLocked() { void DispSync::resetErrorLocked() { mPresentSampleOffset = 0; mError = 0; + mZeroErrSamplesCount = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - mPresentFences[i].clear(); - mPresentTimes[i] = 0; + mPresentFences[i] = FenceTime::NO_FENCE; } } @@ -668,19 +674,19 @@ void DispSync::dump(String8& result) const { previous = sampleTime; } - result.appendFormat("mPresentFences / mPresentTimes [%d]:\n", + result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - previous = 0; + previous = Fence::SIGNAL_TIME_INVALID; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES; - bool signaled = mPresentFences[idx] == NULL; - nsecs_t presentTime = mPresentTimes[idx]; - if (!signaled) { + nsecs_t presentTime = mPresentFences[idx]->getSignalTime(); + if (presentTime == Fence::SIGNAL_TIME_PENDING) { result.appendFormat(" [unsignaled fence]\n"); - } else if (presentTime == 0) { - result.appendFormat(" 0\n"); - } else if (previous == 0) { + } else if(presentTime == Fence::SIGNAL_TIME_INVALID) { + result.appendFormat(" [invalid fence]\n"); + } else if (previous == Fence::SIGNAL_TIME_PENDING || + previous == Fence::SIGNAL_TIME_INVALID) { result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime, (now - presentTime) / 1000000.0); } else { diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 82ae79590a..c9f3b0481e 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -23,10 +23,14 @@ #include #include +#include + +#include + namespace android { class String8; -class Fence; +class FenceTime; class DispSyncThread; // DispSync maintains a model of the periodic hardware-based vsync events of a @@ -67,7 +71,7 @@ public: // // This method should be called with the retire fence from each HWComposer // set call that affects the display. - bool addPresentFence(const sp& fence); + bool addPresentFence(const std::shared_ptr& fenceTime); // The beginResync, addResyncSample, and endResync methods are used to re- // synchronize the DispSync's model to the hardware vsync events. The re- @@ -129,6 +133,7 @@ private: enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 }; enum { NUM_PRESENT_SAMPLES = 8 }; enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; + enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 }; const char* const mName; @@ -146,9 +151,14 @@ private: // mError is the computed model error. It is based on the difference // between the estimated vsync event times and those observed in the - // mPresentTimes array. + // mPresentFences array. nsecs_t mError; + // mZeroErrSamplesCount keeps track of how many times in a row there were + // zero timestamps available in the mPresentFences array. + // Used to sanity check that we are able to calculate the model error. + size_t mZeroErrSamplesCount; + // Whether we have updated the vsync event model since the last resync. bool mModelUpdated; @@ -162,8 +172,8 @@ private: // These member variables store information about the present fences used // to validate the currently computed model. - sp mPresentFences[NUM_PRESENT_SAMPLES]; - nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES]; + std::shared_ptr + mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE}; size_t mPresentSampleOffset; int mRefreshSkipCount; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1b9a2303a7..3e9b10d858 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1308,7 +1308,8 @@ bool Layer::headFenceHasSignaled() const { // able to be latched. To avoid this, grab this buffer anyway. return true; } - return mQueueItems[0].mFence->getSignalTime() != INT64_MAX; + return mQueueItems[0].mFenceTime->getSignalTime() != + Fence::SIGNAL_TIME_PENDING; #else return true; #endif @@ -2011,9 +2012,6 @@ bool Layer::onPreComposition(nsecs_t refreshStartTime) { bool Layer::onPostComposition(const std::shared_ptr& glDoneFence, const std::shared_ptr& presentFence, const CompositorTiming& compositorTiming) { - mAcquireTimeline.updateSignalTimes(); - mReleaseTimeline.updateSignalTimes(); - // mFrameLatencyNeeded is true when a new frame was latched for the // composition. if (!mFrameLatencyNeeded) @@ -2064,6 +2062,7 @@ void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { auto releaseFenceTime = std::make_shared( mSurfaceFlingerConsumer->getPrevFinalReleaseFence()); + mReleaseTimeline.updateSignalTimes(); mReleaseTimeline.push(releaseFenceTime); Mutex::Autolock lock(mFrameEventHistoryMutex); @@ -2254,6 +2253,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) #ifndef USE_HWC2 auto releaseFenceTime = std::make_shared( mSurfaceFlingerConsumer->getPrevFinalReleaseFence()); + mReleaseTimeline.updateSignalTimes(); mReleaseTimeline.push(releaseFenceTime); if (mPreviousFrameNumber != 0) { mFrameEventHistory.addRelease(mPreviousFrameNumber, @@ -2509,6 +2509,12 @@ void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta *outDelta) { Mutex::Autolock lock(mFrameEventHistoryMutex); if (newTimestamps) { + // If there are any unsignaled fences in the aquire timeline at this + // point, the previously queued frame hasn't been latched yet. Go ahead + // and try to get the signal time here so the syscall is taken out of + // the main thread's critical path. + mAcquireTimeline.updateSignalTimes(); + // Push the new fence after updating since it's likely still pending. mAcquireTimeline.push(newTimestamps->acquireFence); mFrameEventHistory.addQueue(*newTimestamps); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a6b34c2184..99b39cb1b8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1553,6 +1553,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) // |mStateLock| not needed as we are on the main thread const sp hw(getDefaultDisplayDeviceLocked()); + mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr glCompositionDoneFenceTime; if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) { glCompositionDoneFenceTime = @@ -1561,12 +1562,11 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) } else { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - mGlCompositionDoneTimeline.updateSignalTimes(); + mDisplayTimeline.updateSignalTimes(); sp presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY); auto presentFenceTime = std::make_shared(presentFence); mDisplayTimeline.push(presentFenceTime); - mDisplayTimeline.updateSignalTimes(); nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0); nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod(); @@ -1591,8 +1591,8 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) } }); - if (presentFence->isValid()) { - if (mPrimaryDispSync.addPresentFence(presentFence)) { + if (presentFenceTime->isValid()) { + if (mPrimaryDispSync.addPresentFence(presentFenceTime)) { enableHardwareVsync(); } else { disableHardwareVsync(false); diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 6ea070dc2d..7741681fae 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -1257,6 +1257,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) const HWComposer& hwc = getHwComposer(); const sp hw(getDefaultDisplayDevice()); + mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr glCompositionDoneFenceTime; if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) { glCompositionDoneFenceTime = @@ -1265,12 +1266,11 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) } else { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - mGlCompositionDoneTimeline.updateSignalTimes(); + mDisplayTimeline.updateSignalTimes(); sp retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY); auto retireFenceTime = std::make_shared(retireFence); mDisplayTimeline.push(retireFenceTime); - mDisplayTimeline.updateSignalTimes(); nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0); nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod(); @@ -1298,7 +1298,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) }); if (retireFence->isValid()) { - if (mPrimaryDispSync.addPresentFence(retireFence)) { + if (mPrimaryDispSync.addPresentFence(retireFenceTime)) { enableHardwareVsync(); } else { disableHardwareVsync(false); -- cgit v1.2.3-59-g8ed1b From fda2c6fd94052e19ef327e5a2656ae74d9da0554 Mon Sep 17 00:00:00 2001 From: Fabien Sanglard Date: Tue, 20 Jun 2017 15:38:21 -0700 Subject: Remove backpressure ALOG The backpressure ALOG was needed to troubleshoot fence not signaling while we worked on libhwc2on1adapter. Since these issues have been resolved we don't need the log anymore. Test: Manual Change-Id: I29b2aa36f27f93d93ef14f1746d8c2f03101fc33 --- services/surfaceflinger/SurfaceFlinger.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c6ce82c460..64f97c4e85 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1353,7 +1353,6 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { Fence::SIGNAL_TIME_PENDING); ATRACE_INT("FrameMissed", static_cast(frameMissed)); if (mPropagateBackpressure && frameMissed) { - ALOGD("Backpressure trigger, skipping transaction & refresh!"); signalLayerUpdate(); break; } -- cgit v1.2.3-59-g8ed1b From 64f7b420c4a48cf75bcd8536716d9a515369dc7a Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 12 Jul 2017 10:31:58 -0700 Subject: Update LayerVector's order after modifying relative layer. If the z value for a layer is updated due to a relative layer change, the order of layers in the SortedVector was not updated and could cause lookup failures in the binary search. This updates the vector by removing and then re-adding the layer to ensure it's resorted. Also added the eRelativeLayerChanged condition for SurfaceFlinger_hwc1. Test: Added multiple layers that updated relative layer. The LayerVector's order was updated correctly and the layers remain in the correct order. Change-Id: If5403a0b626f34db41bf7a98fe42830ed272d16e --- services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3fba609a9c..ded6607778 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2952,7 +2952,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eRelativeLayerChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); flags |= eTransactionNeeded|eTraversalNeeded; } } diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 2972485f12..0ea032efb8 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -2577,6 +2577,14 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } } + if (what & layer_state_t::eRelativeLayerChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + flags |= eTransactionNeeded|eTraversalNeeded; + } + } if (what & layer_state_t::eSizeChanged) { if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; -- cgit v1.2.3-59-g8ed1b From f41745301d5ecfa680dcef3a1948a8a321f80509 Mon Sep 17 00:00:00 2001 From: Saurabh Shah Date: Thu, 13 Jul 2017 10:45:07 -0700 Subject: sf: Defer DispSync initialization Some DispSync members are initialized based on uninitialized static members of sf, that are in turn initialized in sf constructor. Fix the sequence by deferring DispSync initialization. Current sequence: sf constructor|-> DispSync constructor -> Access static sf members |-> Initialize sf static members New sequence: sf constructor|-> DispSync constructor |-> Initialize sf static members |-> DispSync init -> Access static sf members Bug: 63671437 Test: "present fences are ignored" not present in SF dumpsys Change-Id: I618d2bbbbd4e39fc382e67f85dd8d637dd82cf38 --- services/surfaceflinger/DispSync.cpp | 14 ++++++++------ services/surfaceflinger/DispSync.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp index ac8aa04e9d..bef12ea50f 100644 --- a/services/surfaceflinger/DispSync.cpp +++ b/services/surfaceflinger/DispSync.cpp @@ -377,11 +377,16 @@ private: DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0), - mThread(new DispSyncThread(name)), - mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){ + mThread(new DispSyncThread(name)) { +} + +DispSync::~DispSync() {} - mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset; +void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) { + mIgnorePresentFences = !hasSyncFramework; + mPresentTimeOffset = dispSyncPresentTimeOffset; mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); + // set DispSync to SCHED_FIFO to minimize jitter struct sched_param param = {0}; param.sched_priority = 2; @@ -389,7 +394,6 @@ DispSync::DispSync(const char* name) : ALOGE("Couldn't set SCHED_FIFO for DispSyncThread"); } - reset(); beginResync(); @@ -405,8 +409,6 @@ DispSync::DispSync(const char* name) : } } -DispSync::~DispSync() {} - void DispSync::reset() { Mutex::Autolock lock(mMutex); diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index c9f3b0481e..880a24d6ad 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -59,6 +59,8 @@ public: explicit DispSync(const char* name); ~DispSync(); + void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset); + // reset clears the resync samples and error value. void reset(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7fb315865f..fe0fa2b0ff 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -195,6 +195,8 @@ SurfaceFlinger::SurfaceFlinger() hasWideColorDisplay = getBool(false); + mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset); + // debugging stuff... char value[PROPERTY_VALUE_MAX]; -- cgit v1.2.3-59-g8ed1b From 79d272442ce13418c3ea81c95d7fea0159b4b481 Mon Sep 17 00:00:00 2001 From: Courtney Goeltzenleuchter Date: Thu, 13 Jul 2017 17:54:01 -0600 Subject: Communicate composition buffer dataspace to HWC Test: adb shell dumpsys SurfaceFlinger look for dataspace info in DisplayDevice section Bug: 63146977 Change-Id: If427171994fbc91faacf5bad9cc736ddfbd35ec3 --- services/surfaceflinger/DisplayDevice.cpp | 5 +++++ services/surfaceflinger/DisplayDevice.h | 1 + .../surfaceflinger/DisplayHardware/FramebufferSurface.cpp | 14 +++++++------- services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ 4 files changed, 16 insertions(+), 7 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index a0abf12f9a..fc60002334 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -442,6 +442,11 @@ void DisplayDevice::setActiveColorMode(android_color_mode_t mode) { android_color_mode_t DisplayDevice::getActiveColorMode() const { return mActiveColorMode; } + +void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) { + ANativeWindow* const window = mNativeWindow.get(); + native_window_set_buffers_data_space(window, dataspace); +} #endif // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e2852a7c69..578f81b690 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -189,6 +189,7 @@ public: #ifdef USE_HWC2 android_color_mode_t getActiveColorMode() const; void setActiveColorMode(android_color_mode_t mode); + void setCompositionDataSpace(android_dataspace dataspace); #endif /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index afb91d4be4..05e9c2dae3 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -108,12 +108,6 @@ status_t FramebufferSurface::advanceFrame() { if (result != NO_ERROR) { ALOGE("error latching next FramebufferSurface buffer: %s (%d)", strerror(-result), result); - return result; - } - result = mHwc.setClientTarget(mDisplayType, slot, - acquireFence, buf, dataspace); - if (result != NO_ERROR) { - ALOGE("error posting framebuffer: %d", result); } return result; #else @@ -184,7 +178,13 @@ status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& #else outBuffer = mCurrentBuffer; #endif - return NO_ERROR; + status_t result = + mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace); + if (result != NO_ERROR) { + ALOGE("error posting framebuffer: %d", result); + } + + return result; } #ifndef USE_HWC2 diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index bcc30f6281..2d05d9c605 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -385,6 +385,7 @@ void SurfaceFlinger::bootFinished() #ifdef USE_HWC2 sp hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); if (hw->getWideColorSupport()) { + hw->setCompositionDataSpace(HAL_DATASPACE_V0_SRGB); setActiveColorModeInternal(hw, HAL_COLOR_MODE_SRGB); } #endif @@ -1224,6 +1225,7 @@ void SurfaceFlinger::createDefaultDisplayDevice() { hasWideColorModes && hasWideColorDisplay); mDisplays.add(token, hw); setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE); + hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); } void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { @@ -1872,6 +1874,7 @@ void SurfaceFlinger::setUpHWComposer() { // To achieve this we suppress color mode changes until after the boot animation if (mBootFinished) { setActiveColorModeInternal(displayDevice, newColorMode); + displayDevice->setCompositionDataSpace(newDataSpace); } } } -- cgit v1.2.3-59-g8ed1b From a099a24c93bfa599fc5c36a647e946c26f68514f Mon Sep 17 00:00:00 2001 From: Kalle Raita Date: Wed, 11 Jan 2017 11:17:29 -0800 Subject: Faked HWC for SurfaceFlinger testing Infrastructure and initial port of transaction tests. Faking the HWC allows exercising the real path through the SurfaceFlinger, not relying on screen captures. Faked HWC also opens up the possibility of faking interactions like display hotplugs. The tests are verifying the composition rectangles instead of a set of select pixels. GLES rendering differences won't affect the results. Also, the test expectations become clearer. The ported transaction tests ran roughly twice as fast when compared with the original transaction test. This is mostly due to the thighter control over the vsyncs. Test: Running the test on Marlin Change-Id: I1c876cda78db94c1965498af957e64fdd23459ce --- libs/gui/Android.bp | 1 + libs/gui/ISurfaceComposer.cpp | 42 + libs/gui/LayerDebugInfo.cpp | 136 ++ libs/gui/include/gui/ISurfaceComposer.h | 8 + libs/gui/include/gui/LayerDebugInfo.h | 73 ++ libs/gui/include/gui/SurfaceControl.h | 10 + libs/gui/tests/Surface_test.cpp | 3 + libs/ui/DebugUtils.cpp | 7 + libs/ui/include/ui/DebugUtils.h | 5 + services/surfaceflinger/Android.bp | 2 + .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 10 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 2 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 4 +- services/surfaceflinger/DisplayHardware/HWC2.h | 7 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 9 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 9 +- services/surfaceflinger/Layer.cpp | 107 +- services/surfaceflinger/Layer.h | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 59 +- services/surfaceflinger/SurfaceFlinger.h | 2 + services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 31 +- services/surfaceflinger/tests/fakehwc/Android.bp | 35 + .../tests/fakehwc/FakeComposerClient.cpp | 613 +++++++++ .../tests/fakehwc/FakeComposerClient.h | 146 +++ .../tests/fakehwc/FakeComposerService.cpp | 54 + .../tests/fakehwc/FakeComposerService.h | 40 + .../tests/fakehwc/FakeComposerUtils.cpp | 183 +++ .../tests/fakehwc/FakeComposerUtils.h | 119 ++ .../surfaceflinger/tests/fakehwc/RenderState.h | 44 + .../tests/fakehwc/SFFakeHwc_test.cpp | 1306 ++++++++++++++++++++ 30 files changed, 2984 insertions(+), 91 deletions(-) create mode 100644 libs/gui/LayerDebugInfo.cpp create mode 100644 libs/gui/include/gui/LayerDebugInfo.h create mode 100644 services/surfaceflinger/tests/fakehwc/Android.bp create mode 100644 services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp create mode 100644 services/surfaceflinger/tests/fakehwc/FakeComposerClient.h create mode 100644 services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp create mode 100644 services/surfaceflinger/tests/fakehwc/FakeComposerService.h create mode 100644 services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp create mode 100644 services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h create mode 100644 services/surfaceflinger/tests/fakehwc/RenderState.h create mode 100644 services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 4558fe87c6..ed2f30aaf5 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -93,6 +93,7 @@ cc_library_shared { "IProducerListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", + "LayerDebugInfo.cpp", "LayerState.cpp", "OccupancyTracker.cpp", "StreamSplitter.cpp", diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0a0d112af6..8e7f814313 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -469,6 +470,36 @@ public: return result; } + virtual status_t getLayerDebugInfo(std::vector* outLayers) const + { + if (!outLayers) { + return UNEXPECTED_NULL; + } + + Parcel data, reply; + + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + return err; + } + + err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply); + if (err != NO_ERROR) { + return err; + } + + int32_t result = 0; + err = reply.readInt32(&result); + if (err != NO_ERROR) { + return err; + } + if (result != NO_ERROR) { + return result; + } + + outLayers->clear(); + return reply.readParcelableVector(outLayers); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -763,6 +794,17 @@ status_t BnSurfaceComposer::onTransact( } return injectVSync(when); } + case GET_LAYER_DEBUG_INFO: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + std::vector outLayers; + status_t result = getLayerDebugInfo(&outLayers); + reply->writeInt32(result); + if (result == NO_ERROR) + { + result = reply->writeParcelableVector(outLayers); + } + return result; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp new file mode 100644 index 0000000000..57ddde075a --- /dev/null +++ b/libs/gui/LayerDebugInfo.cpp @@ -0,0 +1,136 @@ +/* + * 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 + +#include + +#include + +#include + +using namespace android; + +#define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false) + +namespace android { + +status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { + RETURN_ON_ERROR(parcel->writeCString(mName.c_str())); + RETURN_ON_ERROR(parcel->writeCString(mParentName.c_str())); + RETURN_ON_ERROR(parcel->writeCString(mType.c_str())); + RETURN_ON_ERROR(parcel->write(mTransparentRegion)); + RETURN_ON_ERROR(parcel->write(mVisibleRegion)); + RETURN_ON_ERROR(parcel->write(mSurfaceDamageRegion)); + RETURN_ON_ERROR(parcel->writeUint32(mLayerStack)); + RETURN_ON_ERROR(parcel->writeFloat(mX)); + RETURN_ON_ERROR(parcel->writeFloat(mY)); + RETURN_ON_ERROR(parcel->writeUint32(mZ)); + RETURN_ON_ERROR(parcel->writeInt32(mWidth)); + RETURN_ON_ERROR(parcel->writeInt32(mHeight)); + RETURN_ON_ERROR(parcel->write(mCrop)); + RETURN_ON_ERROR(parcel->write(mFinalCrop)); + RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeUint32(mFlags)); + RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); + RETURN_ON_ERROR(parcel->writeUint32(static_cast(mDataSpace))); + for (size_t index = 0; index < 4; index++) { + RETURN_ON_ERROR(parcel->writeFloat(mMatrix[index / 2][index % 2])); + } + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferWidth)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferHeight)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat)); + RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames)); + RETURN_ON_ERROR(parcel->writeBool(mRefreshPending)); + RETURN_ON_ERROR(parcel->writeBool(mIsOpaque)); + RETURN_ON_ERROR(parcel->writeBool(mContentDirty)); + return NO_ERROR; +} + +status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { + mName = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + mParentName = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + mType = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + RETURN_ON_ERROR(parcel->read(mTransparentRegion)); + RETURN_ON_ERROR(parcel->read(mVisibleRegion)); + RETURN_ON_ERROR(parcel->read(mSurfaceDamageRegion)); + RETURN_ON_ERROR(parcel->readUint32(&mLayerStack)); + RETURN_ON_ERROR(parcel->readFloat(&mX)); + RETURN_ON_ERROR(parcel->readFloat(&mY)); + RETURN_ON_ERROR(parcel->readUint32(&mZ)); + RETURN_ON_ERROR(parcel->readInt32(&mWidth)); + RETURN_ON_ERROR(parcel->readInt32(&mHeight)); + RETURN_ON_ERROR(parcel->read(mCrop)); + RETURN_ON_ERROR(parcel->read(mFinalCrop)); + RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + RETURN_ON_ERROR(parcel->readUint32(&mFlags)); + RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); + // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? + mDataSpace = static_cast(parcel->readUint32()); + RETURN_ON_ERROR(parcel->errorCheck()); + for (size_t index = 0; index < 4; index++) { + RETURN_ON_ERROR(parcel->readFloat(&mMatrix[index / 2][index % 2])); + } + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferWidth)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferHeight)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat)); + RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames)); + RETURN_ON_ERROR(parcel->readBool(&mRefreshPending)); + RETURN_ON_ERROR(parcel->readBool(&mIsOpaque)); + RETURN_ON_ERROR(parcel->readBool(&mContentDirty)); + return NO_ERROR; +} + +std::string to_string(const LayerDebugInfo& info) { + String8 result; + + result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str()); + info.mTransparentRegion.dump(result, "TransparentRegion"); + info.mVisibleRegion.dump(result, "VisibleRegion"); + info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion"); + + result.appendFormat(" layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", + info.mLayerStack, info.mZ, static_cast(info.mX), static_cast(info.mY), + info.mWidth, info.mHeight); + + result.appendFormat("crop=%s, finalCrop=%s, ", + to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str()); + result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); + result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); + result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); + result.appendFormat("alpha=%.3f, flags=0x%08x, ", + static_cast(info.mAlpha), info.mFlags); + result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", + static_cast(info.mMatrix[0][0]), static_cast(info.mMatrix[0][1]), + static_cast(info.mMatrix[1][0]), static_cast(info.mMatrix[1][1])); + result.append("\n"); + result.appendFormat(" parent=%s\n", info.mParentName.c_str()); + result.appendFormat(" activeBuffer=[%4ux%4u:%4u,%s],", + info.mActiveBufferWidth, info.mActiveBufferHeight, + info.mActiveBufferStride, + decodePixelFormat(info.mActiveBufferFormat).c_str()); + result.appendFormat(" queued-frames=%d, mRefreshPending=%d", + info.mNumQueuedFrames, info.mRefreshPending); + result.append("\n"); + return std::string(result.c_str()); +} + +} // android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index f80ba000b4..b2267426a8 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -39,6 +39,7 @@ struct ComposerState; struct DisplayState; struct DisplayInfo; struct DisplayStatInfo; +class LayerDebugInfo; class HdrCapabilities; class IDisplayEventConnection; class IGraphicBufferProducer; @@ -195,6 +196,12 @@ public: virtual status_t enableVSyncInjections(bool enable) = 0; virtual status_t injectVSync(nsecs_t when) = 0; + + /* Gets the list of active layers in Z order for debugging purposes + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getLayerDebugInfo(std::vector* outLayers) const = 0; }; // ---------------------------------------------------------------------------- @@ -229,6 +236,7 @@ public: SET_ACTIVE_COLOR_MODE, ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, + GET_LAYER_DEBUG_INFO, CREATE_SCOPED_CONNECTION }; diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h new file mode 100644 index 0000000000..8453e043ef --- /dev/null +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace android { + +/* Class for transporting debug info from SurfaceFlinger to authorized + * recipients. The class is intended to be a data container. There are + * no getters or setters. + */ +class LayerDebugInfo : public Parcelable { +public: + LayerDebugInfo() = default; + LayerDebugInfo(const LayerDebugInfo&) = default; + virtual ~LayerDebugInfo() = default; + + virtual status_t writeToParcel(Parcel* parcel) const; + virtual status_t readFromParcel(const Parcel* parcel); + + std::string mName = std::string("NOT FILLED"); + std::string mParentName = std::string("NOT FILLED"); + std::string mType = std::string("NOT FILLED"); + Region mTransparentRegion = Region::INVALID_REGION; + Region mVisibleRegion = Region::INVALID_REGION; + Region mSurfaceDamageRegion = Region::INVALID_REGION; + uint32_t mLayerStack = 0; + float mX = 0.f; + float mY = 0.f; + uint32_t mZ = 0 ; + int32_t mWidth = -1; + int32_t mHeight = -1; + Rect mCrop = Rect::INVALID_RECT; + Rect mFinalCrop = Rect::INVALID_RECT; + float mAlpha = 0.f; + uint32_t mFlags = 0; + PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; + android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + // Row-major transform matrix (SurfaceControl::setMatrix()) + float mMatrix[2][2] = {{0.f, 0.f}, {0.f, 0.f}}; + int32_t mActiveBufferWidth = -1; + int32_t mActiveBufferHeight = -1; + int32_t mActiveBufferStride = 0; + PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE; + int32_t mNumQueuedFrames = -1; + bool mRefreshPending = false; + bool mIsOpaque = false; + bool mContentDirty = false; +}; + +std::string to_string(const LayerDebugInfo& info); + +} // namespace android diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 8bb705cf77..c15209d32c 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -90,6 +90,16 @@ public: status_t setFlags(uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const Region& transparent); status_t setAlpha(float alpha=1.0f); + + // Experimentarily it appears that the matrix transforms the + // on-screen rectangle and it's contents before the position is + // applied. + // + // TODO: Test with other combinations to find approximate transformation rules. + // + // For example: + // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives + // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); status_t setCrop(const Rect& crop); status_t setFinalCrop(const Rect& crop); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e18af17bde..45e95a593b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -539,6 +539,9 @@ public: return NO_ERROR; } status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } + status_t getLayerDebugInfo(std::vector* /*layers*/) const override { + return NO_ERROR; + } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 6e31d2a2c4..2d72944665 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -16,10 +16,13 @@ #include #include +#include #include #include +using android::base::StringPrintf; + std::string decodeStandard(android_dataspace dataspace) { const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK); switch (dataspaceSelect) { @@ -262,3 +265,7 @@ std::string decodePixelFormat(android::PixelFormat format) { return android::base::StringPrintf("Unknown %#08x", format); } } + +std::string to_string(const android::Rect& rect) { + return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom); +} diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h index 30f4a59fe0..dad9446b3a 100644 --- a/libs/ui/include/ui/DebugUtils.h +++ b/libs/ui/include/ui/DebugUtils.h @@ -21,9 +21,14 @@ #include +namespace android { +class Rect; +} + std::string decodeStandard(android_dataspace dataspace); std::string decodeTransfer(android_dataspace dataspace); std::string decodeRange(android_dataspace dataspace); std::string dataspaceDetails(android_dataspace dataspace); std::string decodeColorMode(android_color_mode colormode); std::string decodePixelFormat(android::PixelFormat format); +std::string to_string(const android::Rect& rect); diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index cc93105543..4775e4ef54 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -2,3 +2,5 @@ cc_library_static { name: "libsurfaceflingerincludes", export_include_dirs: ["."], } + +subdirs = ["tests/fakehwc"] \ No newline at end of file diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index e34fa163c4..704b17ef43 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -157,15 +157,11 @@ void Composer::CommandWriter::writeBufferMetadata( write64(metadata.usage); } -Composer::Composer(bool useVrComposer) +Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize), - mIsUsingVrComposer(useVrComposer) + mIsUsingVrComposer(serviceName == std::string("vr")) { - if (mIsUsingVrComposer) { - mComposer = IComposer::getService("vr"); - } else { - mComposer = IComposer::getService(); // use default name - } + mComposer = IComposer::getService(serviceName); if (mComposer == nullptr) { LOG_ALWAYS_FATAL("failed to get hwcomposer service"); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 96dd833cd5..40d2a4c3aa 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -136,7 +136,7 @@ private: // Composer is a wrapper to IComposer, a proxy to server-side composer. class Composer { public: - Composer(bool useVrComposer); + Composer(const std::string& serviceName); std::vector getCapabilities(); std::string dumpDebugInfo(); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 270a73228b..b749ce630d 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -88,8 +88,8 @@ namespace Hwc2 = android::Hwc2; // Device methods -Device::Device(bool useVrComposer) - : mComposer(std::make_unique(useVrComposer)), +Device::Device(const std::string& serviceName) + : mComposer(std::make_unique(serviceName)), mCapabilities(), mDisplays(), mHotplug(), diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 404bb284c5..9bcda1eb0a 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -63,10 +63,9 @@ typedef std::function, nsecs_t)> VsyncCallback; class Device { public: - // useVrComposer is passed to the composer HAL. When true, the composer HAL - // will use the vr composer service, otherwise it uses the real hardware - // composer. - Device(bool useVrComposer); + // Service name is expected to be 'default' or 'vr' for normal use. + // 'vr' will slightly modify the behavior of the mComposer. + Device(const std::string& serviceName); ~Device(); friend class HWC2::Display; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index ac2dde29d4..abf7dd12d0 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -59,7 +59,7 @@ namespace android { // --------------------------------------------------------------------------- -HWComposer::HWComposer(bool useVrComposer) +HWComposer::HWComposer(const std::string& serviceName) : mHwcDevice(), mDisplayData(2), mFreeDisplaySlots(), @@ -74,7 +74,7 @@ HWComposer::HWComposer(bool useVrComposer) mVSyncCounts[i] = 0; } - loadHwcModule(useVrComposer); + loadHwcModule(serviceName); } HWComposer::~HWComposer() {} @@ -103,10 +103,11 @@ void HWComposer::setEventHandler(EventHandler* handler) } // Load and prepare the hardware composer module. Sets mHwc. -void HWComposer::loadHwcModule(bool useVrComposer) +void HWComposer::loadHwcModule(const std::string& serviceName) { ALOGV("loadHwcModule"); - mHwcDevice = std::make_unique(useVrComposer); + mHwcDevice = std::make_unique(serviceName); + mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 7463362c35..3dfb65b1e3 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -75,10 +75,9 @@ public: virtual ~EventHandler() {} }; - // useVrComposer is passed to the composer HAL. When true, the composer HAL - // will use the vr composer service, otherwise it uses the real hardware - // composer. - HWComposer(bool useVrComposer); + // Uses the named composer service. Valid choices for normal use + // are 'default' and 'vr'. + HWComposer(const std::string& serviceName); ~HWComposer(); @@ -170,7 +169,7 @@ public: private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; - void loadHwcModule(bool useVrComposer); + void loadHwcModule(const std::string& serviceName); bool isValidDisplay(int32_t displayId) const; static void validateChange(HWC2::Composition from, HWC2::Composition to); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8eb406747a..3903a5546f 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include "clz.h" @@ -2363,71 +2364,51 @@ void Layer::updateTransformHint(const sp& hw) const { // debugging // ---------------------------------------------------------------------------- -void Layer::dump(String8& result, Colorizer& colorizer) const -{ - const Layer::State& s(getDrawingState()); - - colorizer.colorize(result, Colorizer::GREEN); - result.appendFormat( - "+ %s %p (%s)\n", - getTypeId(), this, getName().string()); - colorizer.reset(result); - - s.activeTransparentRegion.dump(result, "transparentRegion"); - visibleRegion.dump(result, "visibleRegion"); - surfaceDamageRegion.dump(result, "surfaceDamageRegion"); - sp client(mClientRef.promote()); - PixelFormat pf = PIXEL_FORMAT_UNKNOWN; - const sp& buffer(getActiveBuffer()); - if (buffer != NULL) { - pf = buffer->getPixelFormat(); - } - +LayerDebugInfo Layer::getLayerDebugInfo() const { + LayerDebugInfo info; + const Layer::State& ds = getDrawingState(); + info.mName = getName(); sp parent = getParent(); - - result.appendFormat( " " - "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " - "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " - "isOpaque=%1d, invalidate=%1d, " - "dataspace=%s, pixelformat=%s " -#ifdef USE_HWC2 - "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" -#else - "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" -#endif - " client=%p parent=%s\n", - getLayerStack(), s.z, - s.active.transform.tx(), s.active.transform.ty(), - s.active.w, s.active.h, - s.crop.left, s.crop.top, - s.crop.right, s.crop.bottom, - s.finalCrop.left, s.finalCrop.top, - s.finalCrop.right, s.finalCrop.bottom, - isOpaque(s), contentDirty, - dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(), - s.alpha, s.flags, - s.active.transform[0][0], s.active.transform[0][1], - s.active.transform[1][0], s.active.transform[1][1], - client.get(), parent == nullptr ? "none" : parent->getName().string()); - - sp buf0(mActiveBuffer); - uint32_t w0=0, h0=0, s0=0, f0=0; - if (buf0 != 0) { - w0 = buf0->getWidth(); - h0 = buf0->getHeight(); - s0 = buf0->getStride(); - f0 = buf0->format; - } - result.appendFormat( - " " - "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," - " queued-frames=%d, mRefreshPending=%d\n", - mFormat, w0, h0, s0,f0, - mQueuedFrames, mRefreshPending); - - if (mSurfaceFlingerConsumer != 0) { - mSurfaceFlingerConsumer->dumpState(result, " "); + info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string()); + info.mType = String8(getTypeId()); + info.mTransparentRegion = ds.activeTransparentRegion; + info.mVisibleRegion = visibleRegion; + info.mSurfaceDamageRegion = surfaceDamageRegion; + info.mLayerStack = getLayerStack(); + info.mX = ds.active.transform.tx(); + info.mY = ds.active.transform.ty(); + info.mZ = ds.z; + info.mWidth = ds.active.w; + info.mHeight = ds.active.h; + info.mCrop = ds.crop; + info.mFinalCrop = ds.finalCrop; + info.mAlpha = ds.alpha; + info.mFlags = ds.flags; + info.mPixelFormat = getPixelFormat(); + info.mDataSpace = getDataSpace(); + info.mMatrix[0][0] = ds.active.transform[0][0]; + info.mMatrix[0][1] = ds.active.transform[0][1]; + info.mMatrix[1][0] = ds.active.transform[1][0]; + info.mMatrix[1][1] = ds.active.transform[1][1]; + { + sp activeBuffer = getActiveBuffer(); + if (activeBuffer != 0) { + info.mActiveBufferWidth = activeBuffer->getWidth(); + info.mActiveBufferHeight = activeBuffer->getHeight(); + info.mActiveBufferStride = activeBuffer->getStride(); + info.mActiveBufferFormat = activeBuffer->format; + } else { + info.mActiveBufferWidth = 0; + info.mActiveBufferHeight = 0; + info.mActiveBufferStride = 0; + info.mActiveBufferFormat = 0; + } } + info.mNumQueuedFrames = getQueuedFrameCount(); + info.mRefreshPending = isBufferLatched(); + info.mIsOpaque = isOpaque(ds); + info.mContentDirty = contentDirty; + return info; } #ifdef USE_HWC2 diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2306d1a43a..8df8c49bbe 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -60,6 +60,7 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; +class LayerDebugInfo; // --------------------------------------------------------------------------- @@ -441,6 +442,8 @@ public: bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } + int32_t getQueuedFrameCount() const { return mQueuedFrames; } + #ifdef USE_HWC2 // ----------------------------------------------------------------------- @@ -489,9 +492,9 @@ public: inline const State& getCurrentState() const { return mCurrentState; } inline State& getCurrentState() { return mCurrentState; } + LayerDebugInfo getLayerDebugInfo() const; /* always call base class first */ - void dump(String8& result, Colorizer& colorizer) const; #ifdef USE_HWC2 static void miniDumpHeader(String8& result); void miniDump(String8& result, int32_t hwcId) const; @@ -689,6 +692,9 @@ public: sp getProducer() const; const String8& getName() const; void notifyAvailableFrames(); + + PixelFormat getPixelFormat() const { return mFormat; } + private: // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index aaaafbfa9e..4154d6a87f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -123,6 +124,21 @@ bool SurfaceFlinger::useVrFlinger; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; bool SurfaceFlinger::hasWideColorDisplay; + +std::string getHwcServiceName() { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.hwc_service_name", value, "default"); + ALOGI("Using HWComposer service: '%s'", value); + return std::string(value); +} + +bool useTrebleTestingOverride() { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.treble_testing_override", value, "false"); + ALOGI("Treble testing override: '%s'", value); + return std::string(value) == "true"; +} + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), @@ -134,6 +150,7 @@ SurfaceFlinger::SurfaceFlinger() mHwc(nullptr), mRealHwc(nullptr), mVrHwc(nullptr), + mHwcServiceName(getHwcServiceName()), mRenderEngine(nullptr), mBootTime(systemTime()), mBuiltinDisplays(), @@ -233,6 +250,15 @@ SurfaceFlinger::SurfaceFlinger() // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is // instead read after the boot animation + + if (useTrebleTestingOverride()) { + // Without the override SurfaceFlinger cannot connect to HIDL + // services that are not listed in the manifests. Considered + // deriving the setting from the set service name, but it + // would be brittle if the name that's not 'default' is used + // for production purposes later on. + setenv("TREBLE_TESTING_OVERRIDE", "true", true); + } } void SurfaceFlinger::onFirstRef() @@ -594,7 +620,7 @@ void SurfaceFlinger::init() { // initialize the primary display. LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, "Starting with vr flinger active is not currently supported."); - mRealHwc = new HWComposer(false); + mRealHwc = new HWComposer(mHwcServiceName); mHwc = mRealHwc; mHwc->setEventHandler(static_cast(this)); @@ -1055,6 +1081,33 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return NO_ERROR; } +status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) const { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + + // Try to acquire a lock for 1s, fail gracefully + const status_t err = mStateLock.timedLock(s2ns(1)); + const bool locked = (err == NO_ERROR); + if (!locked) { + ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); + return TIMED_OUT; + } + + outLayers->clear(); + mCurrentState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo()); + }); + + mStateLock.unlock(); + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection( @@ -1312,7 +1365,7 @@ void SurfaceFlinger::updateVrFlinger() { if (vrFlingerRequestsDisplay && !mVrHwc) { // Construct new HWComposer without holding any locks. - mVrHwc = new HWComposer(true); + mVrHwc = new HWComposer("vr"); // Set up the event handlers. This step is neccessary to initialize the internal state of // the hardware composer object properly. Our callbacks are designed such that if they are @@ -3706,7 +3759,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector& args, size_t& index, result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); mCurrentState.traverseInZOrder([&](Layer* layer) { - layer->dump(result, colorizer); + result.append(to_string(layer->getLayerDebugInfo()).c_str()); }); /* diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index acfad46526..5123b58913 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -300,6 +300,7 @@ private: HdrCapabilities* outCapabilities) const; virtual status_t enableVSyncInjections(bool enable); virtual status_t injectVSync(nsecs_t when); + virtual status_t getLayerDebugInfo(std::vector* outLayers) const; /* ------------------------------------------------------------------------ @@ -628,6 +629,7 @@ private: #ifdef USE_HWC2 HWComposer* mRealHwc; HWComposer* mVrHwc; + const std::string mHwcServiceName; // "default" for real use, something else for testing. #endif // constant members (no synchronization needed for access) RenderEngine* mRenderEngine; diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index dae03b3c25..7aaa42aa4b 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -931,6 +932,34 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return NO_ERROR; } +status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) const { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + + // Try to acquire a lock for 1s, fail gracefully + status_t err = mStateLock.timedLock(s2ns(1)); + bool locked = (err == NO_ERROR); + if (!locked) { + ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); + return TIMED_OUT; + } + + outLayers->clear(); + mCurrentState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo()); + }); + + mStateLock.unlock(); + + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection( @@ -3261,7 +3290,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector& args, size_t& index, result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); mCurrentState.traverseInZOrder([&](Layer* layer) { - layer->dump(result, colorizer); + result.append(to_string(layer->getLayerDebugInfo()).c_str()); }); /* diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp new file mode 100644 index 0000000000..94f3f2561a --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -0,0 +1,35 @@ +cc_test { + name: "sffakehwc_test", + srcs: [ + "FakeComposerClient.cpp", + "FakeComposerService.cpp", + "FakeComposerUtils.cpp", + "SFFakeHwc_test.cpp" + ], + shared_libs: [ + "libcutils", + "libutils", + "libbinder", + "libui", + "libgui", + "liblog", + "libnativewindow", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "libhwbinder", + "libhardware", + "libhidlbase", + "libsync", + "libfmq", + "libbase", + "libhidltransport" + ], + static_libs: [ + "libhwcomposer-client", + "libsurfaceflingerincludes", + "libtrace_proto", + "libgmock" + ], + tags: ["tests"], + test_suites: ["device-tests"] +} \ No newline at end of file diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp new file mode 100644 index 0000000000..60916f3ab9 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp @@ -0,0 +1,613 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeComposer" + +#include "FakeComposerClient.h" + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr Config NULL_DISPLAY_CONFIG = static_cast(0); +constexpr Display DEFAULT_DISPLAY = static_cast(1); + +using namespace sftest; + +using android::Condition; +using android::Mutex; + +using Clock = std::chrono::steady_clock; +using TimePoint = std::chrono::time_point; + +namespace { + +// Internal state of a layer in the HWC API. +class LayerImpl { +public: + LayerImpl() = default; + + bool mValid = true; + RenderState mRenderState; + uint32_t mZ = 0; +}; + +// Struct for storing per frame rectangle state. Contains the render +// state shared to the test case. Basically a snapshot and a subset of +// LayerImpl sufficient to re-create the pixels of a layer for the +// frame. +struct FrameRect { +public: + FrameRect(Layer layer_, const RenderState& state, uint32_t z_) + : layer(layer_), renderState(state), z(z_) {} + + const Layer layer; + const RenderState renderState; + const uint32_t z; +}; + +// Collection of FrameRects forming one rendered frame. Could store +// related fences and other data in the future. +class Frame { +public: + Frame() = default; + std::vector> rectangles; +}; + +class DelayedEventGenerator { +public: + DelayedEventGenerator(std::function onTimerExpired) + : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {} + + ~DelayedEventGenerator() { + ALOGI("DelayedEventGenerator exiting."); + { + std::unique_lock lock(mMutex); + mRunning = false; + mWakeups.clear(); + mCondition.notify_one(); + } + mThread.join(); + ALOGI("DelayedEventGenerator exited."); + } + + void wakeAfter(std::chrono::nanoseconds waitTime) { + std::unique_lock lock(mMutex); + mWakeups.insert(Clock::now() + waitTime); + mCondition.notify_one(); + } + +private: + void loop() { + while (true) { + // Lock scope + { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); }); + if (!mRunning && mWakeups.empty()) { + // This thread should only exit once the destructor has been called and all + // wakeups have been processed + return; + } + + // At this point, mWakeups will not be empty + + TimePoint target = *(mWakeups.begin()); + auto status = mCondition.wait_until(lock, target); + while (status == std::cv_status::no_timeout) { + // This was either a spurious wakeup or another wakeup was added, so grab the + // oldest point and wait again + target = *(mWakeups.begin()); + status = mCondition.wait_until(lock, target); + } + + // status must have been timeout, so we can finally clear this point + mWakeups.erase(target); + } + // Callback *without* locks! + mOnTimerExpired(); + } + } + + std::function mOnTimerExpired; + std::thread mThread; + std::mutex mMutex; + std::condition_variable mCondition; + bool mRunning = true; + std::set mWakeups; +}; + +} // namespace + +FakeComposerClient::FakeComposerClient() + : mCallbacksOn(false), + mClient(nullptr), + mCurrentConfig(NULL_DISPLAY_CONFIG), + mVsyncEnabled(false), + mLayers(), + mDelayedEventGenerator( + std::make_unique([this]() { this->requestVSync(); })), + mSurfaceComposer(nullptr) {} + +FakeComposerClient::~FakeComposerClient() {} + +void FakeComposerClient::removeClient() { + ALOGV("removeClient"); + // TODO: Ahooga! Only thing current lifetime management choices in + // APIs make possible. Sad. + delete this; +} + +void FakeComposerClient::enableCallback(bool enable) { + ALOGV("enableCallback"); + mCallbacksOn = enable; + if (mCallbacksOn) { + mClient->onHotplug(DEFAULT_DISPLAY, IComposerCallback::Connection::CONNECTED); + } +} + +void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) { + if (mCallbacksOn) { + mClient->onHotplug(display, state); + } +} + +uint32_t FakeComposerClient::getMaxVirtualDisplayCount() { + ALOGV("getMaxVirtualDisplayCount"); + return 1; +} + +Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/, + PixelFormat* /*format*/, Display* /*outDisplay*/) { + ALOGV("createVirtualDisplay"); + return Error::NONE; +} + +Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) { + ALOGV("destroyVirtualDisplay"); + return Error::NONE; +} + +Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) { + ALOGV("createLayer"); + *outLayer = mLayers.size(); + auto newLayer = std::make_unique(); + mLayers.push_back(std::move(newLayer)); + return Error::NONE; +} + +Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) { + ALOGV("destroyLayer"); + mLayers[layer]->mValid = false; + return Error::NONE; +} + +Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) { + ALOGV("getActiveConfig"); + + // TODO Assert outConfig != nullptr + + // TODO This is my reading of the + // IComposerClient::getActiveConfig, but returning BAD_CONFIG + // seems to not fit SurfaceFlinger plans. See version 2 below. + // if (mCurrentConfig == NULL_DISPLAY_CONFIG) { + // return Error::BAD_CONFIG; + // } + //*outConfig = mCurrentConfig; + *outConfig = 1; // Very special config for you my friend + return Error::NONE; +} + +Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/, + uint32_t /*height*/, PixelFormat /*format*/, + Dataspace /*dataspace*/) { + ALOGV("getClientTargetSupport"); + return Error::NONE; +} + +Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec* /*outModes*/) { + ALOGV("getColorModes"); + return Error::NONE; +} + +Error FakeComposerClient::getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute, + int32_t* outValue) { + ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast(display), + static_cast(config), static_cast(attribute), outValue); + + // TODO: SOOO much fun to be had with these alone + switch (attribute) { + case IComposerClient::Attribute::WIDTH: + *outValue = 1920; + break; + case IComposerClient::Attribute::HEIGHT: + *outValue = 1080; + break; + case IComposerClient::Attribute::VSYNC_PERIOD: + *outValue = 1666666666; + break; // TOOD: Tests break down if lowered to 16ms? + case IComposerClient::Attribute::DPI_X: + *outValue = 240; + break; + case IComposerClient::Attribute::DPI_Y: + *outValue = 240; + break; + default: + LOG_ALWAYS_FATAL("Say what!?! New attribute"); + } + + return Error::NONE; +} + +Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec* outConfigs) { + ALOGV("getDisplayConfigs"); + // TODO assert display == 1, outConfigs != nullptr + + outConfigs->resize(1); + (*outConfigs)[0] = 1; + + return Error::NONE; +} + +Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) { + ALOGV("getDisplayName"); + return Error::NONE; +} + +Error FakeComposerClient::getDisplayType(Display /*display*/, + IComposerClient::DisplayType* outType) { + ALOGV("getDisplayType"); + // TODO: This setting nothing on the output had no effect on initial trials. Is first display + // assumed to be physical? + *outType = static_cast(HWC2_DISPLAY_TYPE_PHYSICAL); + return Error::NONE; +} + +Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) { + ALOGV("getDozeSupport"); + return Error::NONE; +} + +Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec* /*outTypes*/, + float* /*outMaxLuminance*/, + float* /*outMaxAverageLuminance*/, + float* /*outMinLuminance*/) { + ALOGV("getHdrCapabilities"); + return Error::NONE; +} + +Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) { + ALOGV("setActiveConfig"); + mCurrentConfig = config; + return Error::NONE; +} + +Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) { + ALOGV("setColorMode"); + return Error::NONE; +} + +Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) { + ALOGV("setPowerMode"); + return Error::NONE; +} + +Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) { + mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE); + ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE"); + return Error::NONE; +} + +Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/, + int32_t /*hint*/) { + ALOGV("setColorTransform"); + return Error::NONE; +} + +Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/, + int32_t /*acquireFence*/, int32_t /*dataspace*/, + const std::vector& /*damage*/) { + ALOGV("setClientTarget"); + return Error::NONE; +} + +Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/, + int32_t /*releaseFence*/) { + ALOGV("setOutputBuffer"); + return Error::NONE; +} + +Error FakeComposerClient::validateDisplay( + Display /*display*/, std::vector* /*outChangedLayers*/, + std::vector* /*outCompositionTypes*/, + uint32_t* /*outDisplayRequestMask*/, std::vector* /*outRequestedLayers*/, + std::vector* /*outRequestMasks*/) { + ALOGV("validateDisplay"); + // TODO: Assume touching nothing means All Korrekt! + return Error::NONE; +} + +Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) { + ALOGV("acceptDisplayChanges"); + // Didn't ask for changes because software is omnipotent. + return Error::NONE; +} + +bool layerZOrdering(const std::unique_ptr& a, const std::unique_ptr& b) { + return a->z <= b->z; +} + +Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/, + std::vector* /*outLayers*/, + std::vector* /*outReleaseFences*/) { + ALOGV("presentDisplay"); + // TODO Leaving layers and their fences out for now. Doing so + // means that we've already processed everything. Important to + // test that the fences are respected, though. (How?) + + std::unique_ptr newFrame(new Frame); + for (uint64_t layer = 0; layer < mLayers.size(); layer++) { + const LayerImpl& layerImpl = *mLayers[layer]; + + if (!layerImpl.mValid) continue; + + auto rect = std::make_unique(layer, layerImpl.mRenderState, layerImpl.mZ); + newFrame->rectangles.push_back(std::move(rect)); + } + std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering); + { + Mutex::Autolock _l(mStateMutex); + mFrames.push_back(std::move(newFrame)); + mFramesAvailable.broadcast(); + } + return Error::NONE; +} + +Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/, + int32_t /*x*/, int32_t /*y*/) { + ALOGV("setLayerCursorPosition"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) { + ALOGV("setLayerBuffer"); + LayerImpl& l = getLayerImpl(layer); + if (buffer != l.mRenderState.mBuffer) { + l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not? + } + l.mRenderState.mBuffer = buffer; + l.mRenderState.mAcquireFence = acquireFence; + + return Error::NONE; +} + +Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/, + const std::vector& /*damage*/) { + ALOGV("setLayerSurfaceDamage"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) { + ALOGV("setLayerBlendMode"); + getLayerImpl(layer).mRenderState.mBlendMode = static_cast(mode); + return Error::NONE; +} + +Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer, + IComposerClient::Color color) { + ALOGV("setLayerColor"); + getLayerImpl(layer).mRenderState.mLayerColor.r = color.r; + getLayerImpl(layer).mRenderState.mLayerColor.g = color.g; + getLayerImpl(layer).mRenderState.mLayerColor.b = color.b; + getLayerImpl(layer).mRenderState.mLayerColor.a = color.a; + return Error::NONE; +} + +Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/, + int32_t /*type*/) { + ALOGV("setLayerCompositionType"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/, + int32_t /*dataspace*/) { + ALOGV("setLayerDataspace"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer, + const hwc_rect_t& frame) { + ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right, + frame.bottom); + getLayerImpl(layer).mRenderState.mDisplayFrame = frame; + return Error::NONE; +} + +Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) { + ALOGV("setLayerPlaneAlpha"); + getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha; + return Error::NONE; +} + +Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/, + buffer_handle_t /*stream*/) { + ALOGV("setLayerSidebandStream"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer, + const hwc_frect_t& crop) { + ALOGV("setLayerSourceCrop"); + getLayerImpl(layer).mRenderState.mSourceCrop = crop; + return Error::NONE; +} + +Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) { + ALOGV("setLayerTransform"); + getLayerImpl(layer).mRenderState.mTransform = static_cast(transform); + return Error::NONE; +} + +Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer, + const std::vector& visible) { + ALOGV("setLayerVisibleRegion"); + getLayerImpl(layer).mRenderState.mVisibleRegion = visible; + return Error::NONE; +} + +Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) { + ALOGV("setLayerZOrder"); + getLayerImpl(layer).mZ = z; + return Error::NONE; +} + +////////////////////////////////////////////////////////////////// + +void FakeComposerClient::setClient(ComposerClient* client) { + mClient = client; +} + +void FakeComposerClient::requestVSync(uint64_t vsyncTime) { + if (mCallbacksOn) { + uint64_t timestamp = vsyncTime; + ALOGV("Vsync"); + if (timestamp == 0) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + } + if (mSurfaceComposer != nullptr) { + mSurfaceComposer->injectVSync(timestamp); + } else { + mClient->onVsync(DEFAULT_DISPLAY, timestamp); + } + } +} + +void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) { + mDelayedEventGenerator->wakeAfter(wait); +} + +LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) { + // TODO Change these to an internal state check that can be + // invoked from the gtest? GTest macros do not seem all that safe + // when used outside the test class + EXPECT_GE(handle, static_cast(0)); + EXPECT_LT(handle, mLayers.size()); + return *(mLayers[handle]); +} + +int FakeComposerClient::getFrameCount() const { + return mFrames.size(); +} + +static std::vector extractRenderState( + const std::vector>& internalRects) { + std::vector result; + result.reserve(internalRects.size()); + for (const std::unique_ptr& rect : internalRects) { + result.push_back(rect->renderState); + } + return result; +} + +std::vector FakeComposerClient::getFrameRects(int frame) const { + Mutex::Autolock _l(mStateMutex); + return extractRenderState(mFrames[frame]->rectangles); +} + +std::vector FakeComposerClient::getLatestFrame() const { + Mutex::Autolock _l(mStateMutex); + return extractRenderState(mFrames[mFrames.size() - 1]->rectangles); +} + +void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) { + int currentFrame = 0; + { + Mutex::Autolock _l(mStateMutex); // I hope this is ok... + currentFrame = static_cast(mFrames.size()); + requestVSync(); + } + waitUntilFrame(currentFrame + 1, maxWait); +} + +void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const { + Mutex::Autolock _l(mStateMutex); + while (mFrames.size() < static_cast(targetFrame)) { + android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count()); + if (result == android::TIMED_OUT) { + ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame, + mFrames.size(), maxWait.count()); + return; + } + } +} + +void FakeComposerClient::clearFrames() { + Mutex::Autolock _l(mStateMutex); + mFrames.clear(); + for (const std::unique_ptr& layer : mLayers) { + if (layer->mValid) { + layer->mRenderState.mSwapCount = 0; + } + } +} + +void FakeComposerClient::onSurfaceFlingerStart() { + mSurfaceComposer == nullptr; + do { + mSurfaceComposer = new android::SurfaceComposerClient; + android::status_t initResult = mSurfaceComposer->initCheck(); + if (initResult != android::NO_ERROR) { + ALOGD("Init result: %d", initResult); + mSurfaceComposer = nullptr; + std::this_thread::sleep_for(10ms); + } + } while (mSurfaceComposer == nullptr); + ALOGD("SurfaceComposerClient created"); + mSurfaceComposer->enableVSyncInjections(true); +} + +void FakeComposerClient::onSurfaceFlingerStop() { + mSurfaceComposer->dispose(); + mSurfaceComposer.clear(); +} + +// Includes destroyed layers, stored in order of creation. +int FakeComposerClient::getLayerCount() const { + return mLayers.size(); +} + +Layer FakeComposerClient::getLayer(size_t index) const { + // NOTE: If/when passing calls through to actual implementation, + // this might get more involving. + return static_cast(index); +} diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h new file mode 100644 index 0000000000..294abb2c59 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h @@ -0,0 +1,146 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include "ComposerClient.h" +#include "RenderState.h" + +#include + +#include + +using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_1::implementation; +using namespace android::hardware; +using namespace std::chrono_literals; + +namespace { +class LayerImpl; +class Frame; +class DelayedEventGenerator; +} // namespace + +namespace android { +class SurfaceComposerClient; +} // namespace android + +namespace sftest { + +class FakeComposerClient : public ComposerBase { +public: + FakeComposerClient(); + virtual ~FakeComposerClient(); + + void removeClient() override; + void enableCallback(bool enable) override; + uint32_t getMaxVirtualDisplayCount() override; + Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, + Display* outDisplay) override; + Error destroyVirtualDisplay(Display display) override; + Error createLayer(Display display, Layer* outLayer) override; + Error destroyLayer(Display display, Layer layer) override; + + Error getActiveConfig(Display display, Config* outConfig) override; + Error getClientTargetSupport(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override; + Error getColorModes(Display display, hidl_vec* outModes) override; + Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, + int32_t* outValue) override; + Error getDisplayConfigs(Display display, hidl_vec* outConfigs) override; + Error getDisplayName(Display display, hidl_string* outName) override; + Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override; + Error getDozeSupport(Display display, bool* outSupport) override; + Error getHdrCapabilities(Display display, hidl_vec* outTypes, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance) override; + + Error setActiveConfig(Display display, Config config) override; + Error setColorMode(Display display, ColorMode mode) override; + Error setPowerMode(Display display, IComposerClient::PowerMode mode) override; + Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override; + + Error setColorTransform(Display display, const float* matrix, int32_t hint) override; + Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence, + int32_t dataspace, const std::vector& damage) override; + Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override; + Error validateDisplay(Display display, std::vector* outChangedLayers, + std::vector* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, + std::vector* outRequestMasks) override; + Error acceptDisplayChanges(Display display) override; + Error presentDisplay(Display display, int32_t* outPresentFence, std::vector* outLayers, + std::vector* outReleaseFences) override; + + Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override; + Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) override; + Error setLayerSurfaceDamage(Display display, Layer layer, + const std::vector& damage) override; + Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override; + Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override; + Error setLayerCompositionType(Display display, Layer layer, int32_t type) override; + Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override; + Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override; + Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override; + Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override; + Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override; + Error setLayerTransform(Display display, Layer layer, int32_t transform) override; + Error setLayerVisibleRegion(Display display, Layer layer, + const std::vector& visible) override; + Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; + + void setClient(ComposerClient* client); + + void requestVSync(uint64_t vsyncTime = 0); + // We don't want tests hanging, so always use a timeout. Remember + // to always check the number of frames with test ASSERT_! + // Wait until next frame is rendered after requesting vsync. + void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms); + void runVSyncAfter(std::chrono::nanoseconds wait); + + int getFrameCount() const; + // We don't want tests hanging, so always use a timeout. Remember + // to always check the number of frames with test ASSERT_! + void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const; + std::vector getFrameRects(int frame) const; + std::vector getLatestFrame() const; + void clearFrames(); + + void onSurfaceFlingerStart(); + void onSurfaceFlingerStop(); + + int getLayerCount() const; + Layer getLayer(size_t index) const; + + void hotplugDisplay(Display display, IComposerCallback::Connection state); + +private: + LayerImpl& getLayerImpl(Layer handle); + + bool mCallbacksOn; + ComposerClient* mClient; + Config mCurrentConfig; + bool mVsyncEnabled; + std::vector> mLayers; + std::vector> mFrames; + // Using a pointer to hide the implementation into the CPP file. + std::unique_ptr mDelayedEventGenerator; + android::sp mSurfaceComposer; // For VSync injections + mutable android::Mutex mStateMutex; + mutable android::Condition mFramesAvailable; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp new file mode 100644 index 0000000000..c411604587 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcService" +#include + +#include "FakeComposerService.h" + +using namespace android::hardware; + +namespace sftest { + +FakeComposerService::FakeComposerService(android::sp& client) : mClient(client) {} + +FakeComposerService::~FakeComposerService() { + ALOGI("Maybe killing client %p", mClient.get()); + // Rely on sp to kill the client. +} + +Return FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) { + ALOGI("FakeComposerService::getCapabilities"); + hidl_cb(hidl_vec()); + return Void(); +} + +Return FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) { + ALOGI("FakeComposerService::dumpDebugInfo"); + hidl_cb(hidl_string()); + return Void(); +} + +Return FakeComposerService::createClient(createClient_cb hidl_cb) { + ALOGI("FakeComposerService::createClient %p", mClient.get()); + mClient->initialize(); + hidl_cb(Error::NONE, mClient); + return Void(); +} + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h new file mode 100644 index 0000000000..520408496f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#pragma once + +#include "ComposerClient.h" + +using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_1::implementation; +using android::hardware::Return; + +namespace sftest { + +class FakeComposerService : public IComposer { +public: + FakeComposerService(android::sp& client); + virtual ~FakeComposerService(); + + Return getCapabilities(getCapabilities_cb hidl_cb) override; + Return dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return createClient(createClient_cb hidl_cb) override; + +private: + android::sp mClient; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp new file mode 100644 index 0000000000..51956ec970 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 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. + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcUtil" +#include + +#include "FakeComposerUtils.h" +#include "RenderState.h" + +#include "SurfaceFlinger.h" // Get the name of the service... + +#include + +#include + +#include +#include + +using android::String16; +using android::sp; +using namespace std::chrono_literals; +using namespace sftest; +using std::setw; + +namespace sftest { + +// clang-format off +inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) { + os << std::fixed << std::setprecision(1) << "(" + << setw(align) << sourceRect.left << setw(0) << "," + << setw(align) << sourceRect.top << setw(0) << "," + << setw(align) << sourceRect.right << setw(0) << "," + << setw(align) << sourceRect.bottom << setw(0) << ")"; +} + +inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) { + os << "(" + << setw(align) << displayRect.left << setw(0) << "," + << setw(align) << displayRect.top << setw(0) << "," + << setw(align) << displayRect.right << setw(0) << "," + << setw(align) << displayRect.bottom << setw(0) << ")"; +} +// clang-format on + +inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) { + printSourceRectAligned(os, state.mSourceCrop, 7); + os << "->"; + printDisplayRectAligned(os, state.mDisplayFrame, 5); + return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3) + << state.mPlaneAlpha << " Xform:" << state.mTransform; +} + +// Helper for verifying the parts of the RenderState +template +bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val, + const char* name) { + if (ref != val) { + message = message << "Expected " << name << ":" << ref << ", got:" << val << "."; + return false; + } + return true; +} + +::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) { + // TODO: Message could start as success and be assigned as failure. + // Only problem is that utility assumes it to be failure and just adds stuff. Would + // need still special case the initial failure in the utility? + // TODO: ... or would it be possible to break this back to gtest primitives? + ::testing::AssertionResult message = ::testing::AssertionFailure(); + bool passes = true; + + // The work here is mostly about providing good log strings for differences + passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame"); + passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha"); + passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count"); + passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop"); + // ... add more + if (passes) { + return ::testing::AssertionSuccess(); + } + return message; +} + +::testing::AssertionResult framesAreSame(const std::vector& ref, + const std::vector& val) { + ::testing::AssertionResult message = ::testing::AssertionFailure(); + bool passed = true; + if (ref.size() != val.size()) { + message << "Expected " << ref.size() << " rects, got " << val.size() << "."; + passed = false; + } + for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) { + ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]); + if (rectResult == false) { + message << "First different rect at " << rectIndex << ": " << rectResult.message(); + passed = false; + break; + } + } + + if (passed) { + return ::testing::AssertionSuccess(); + } else { + message << "\nReference:"; + for (auto state = ref.begin(); state != ref.end(); ++state) { + message << "\n" << *state; + } + message << "\nActual:"; + for (auto state = val.begin(); state != val.end(); ++state) { + message << "\n" << *state; + } + } + return message; +} + +void startSurfaceFlinger() { + ALOGI("Start SurfaceFlinger"); + system("start surfaceflinger"); + + sp sm(android::defaultServiceManager()); + sp sf; + while (sf == nullptr) { + std::this_thread::sleep_for(10ms); + sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName())); + } + ALOGV("SurfaceFlinger running"); +} + +void stopSurfaceFlinger() { + ALOGI("Stop SurfaceFlinger"); + system("stop surfaceflinger"); + sp sm(android::defaultServiceManager()); + sp sf; + while (sf != nullptr) { + std::this_thread::sleep_for(10ms); + sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName())); + } + ALOGV("SurfaceFlinger stopped"); +} + +//////////////////////////////////////////////// + +void FakeHwcEnvironment::SetUp() { + ALOGI("Test env setup"); + system("setenforce 0"); + system("stop"); + property_set("debug.sf.nobootanimation", "1"); + { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.nobootanimation", value, "0"); + LOG_FATAL_IF(atoi(value) != 1, "boot skip not set"); + } + // TODO: Try registering the mock as the default service instead. + property_set("debug.sf.hwc_service_name", "mock"); + // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files. + property_set("debug.sf.treble_testing_override", "true"); +} + +void FakeHwcEnvironment::TearDown() { + ALOGI("Test env tear down"); + system("stop"); + // Wait for mock call signaling teardown? + property_set("debug.sf.nobootanimation", "0"); + property_set("debug.sf.hwc_service_name", "default"); + ALOGI("Test env tear down - done"); +} + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h new file mode 100644 index 0000000000..74dc0e51bb --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h @@ -0,0 +1,119 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include "FakeComposerClient.h" + +#include + +#include + +#include + +#include + +// clang-format off +// Note: This needs to reside in the global namespace for the GTest to use it +inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) { + return os << "(" << rect.left << "," + << rect.top << "," + << rect.right << "," + << rect.bottom << ")"; +} + +inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) { + return os << "(" << rect.left << "," + << rect.top << "," + << rect.right << "," + << rect.bottom << ")"; +} +// clang-format on + +namespace sftest { + +class RenderState; + +// clang-format off +inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) { + return a.top == b.top && + a.left == b.left && + a.bottom == b.bottom && + a.right == b.right; +} + +inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) { + return a.top == b.top && + a.left == b.left && + a.bottom == b.bottom && + a.right == b.right; +} +// clang-format on + +inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) { + return !(a == b); +} + +inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) { + return !(a == b); +} + +::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val); +::testing::AssertionResult framesAreSame(const std::vector& ref, + const std::vector& val); + +void startSurfaceFlinger(); +void stopSurfaceFlinger(); + +class FakeHwcEnvironment : public ::testing::Environment { +public: + virtual ~FakeHwcEnvironment() {} + void SetUp() override; + void TearDown() override; +}; + +/* + * All surface state changes are supposed to happen inside a global + * transaction. GlobalTransactionScope object at the beginning of + * scope automates the process. The resulting scope gives a visual cue + * on the span of the transaction as well. + * + * Closing the transaction is synchronous, i.e., it waits for + * SurfaceFlinger to composite one frame. Now, the FakeComposerClient + * is built to explicitly request vsyncs one at the time. A delayed + * request must be made before closing the transaction or the test + * thread stalls until SurfaceFlinger does an emergency vsync by + * itself. GlobalTransactionScope encapsulates this vsync magic. + */ +class GlobalTransactionScope { +public: + GlobalTransactionScope(FakeComposerClient& composer) : mComposer(composer) { + android::SurfaceComposerClient::openGlobalTransaction(); + } + ~GlobalTransactionScope() { + int frameCount = mComposer.getFrameCount(); + mComposer.runVSyncAfter(1ms); + android::SurfaceComposerClient::closeGlobalTransaction(true); + // Make sure that exactly one frame has been rendered. + mComposer.waitUntilFrame(frameCount + 1); + LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(), + "Unexpected frame advance. Delta: %d", + mComposer.getFrameCount() - frameCount); + } + FakeComposerClient& mComposer; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h new file mode 100644 index 0000000000..0059289d4f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/RenderState.h @@ -0,0 +1,44 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include + +#include + +namespace sftest { +// Description of a rendered rectangle. Should only contain +// instructions necessary to rasterize the rectangle. The full scene +// is given as a sorted list of rectangles, bottom layer at index 0. +class RenderState { +public: + RenderState() = default; + // Default copy-ctor + + hwc_rect_t mDisplayFrame = {0, 0, 0, 0}; + hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f}; + std::vector mVisibleRegion; + hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE; + buffer_handle_t mBuffer = 0; + uint32_t mSwapCount = 0; // How many set buffer calls to the layer. + int32_t mAcquireFence = 0; // Probably should not be here. + float mPlaneAlpha = 0.f; + hwc_color_t mLayerColor = {0, 0, 0, 0}; + hwc_transform_t mTransform = static_cast(0); +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp new file mode 100644 index 0000000000..8902ede301 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -0,0 +1,1306 @@ +/* + * 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. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcTest" + +#include "FakeComposerClient.h" +#include "FakeComposerService.h" +#include "FakeComposerUtils.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include +#include + +#include + +using namespace std::chrono_literals; + +using namespace android; +using namespace android::hardware; + +using namespace sftest; + +namespace { + +// Mock test helpers +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::_; + +/////////////////////////////////////////////// + +struct TestColor { +public: + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +constexpr static TestColor RED = {195, 63, 63, 255}; +constexpr static TestColor LIGHT_RED = {255, 177, 177, 255}; +constexpr static TestColor GREEN = {63, 195, 63, 255}; +constexpr static TestColor BLUE = {63, 63, 195, 255}; +constexpr static TestColor DARK_GRAY = {63, 63, 63, 255}; +constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255}; + +// Fill an RGBA_8888 formatted surface with a single color. +static void fillSurfaceRGBA8(const sp& sc, const TestColor& color, + bool unlock = true) { + ANativeWindow_Buffer outBuffer; + sp s = sc->getSurface(); + ASSERT_TRUE(s != nullptr); + ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); + uint8_t* img = reinterpret_cast(outBuffer.bits); + for (int y = 0; y < outBuffer.height; y++) { + for (int x = 0; x < outBuffer.width; x++) { + uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); + pixel[0] = color.r; + pixel[1] = color.g; + pixel[2] = color.b; + pixel[3] = color.a; + } + } + if (unlock) { + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + } +} + +inline RenderState makeSimpleRect(int left, int top, int right, int bottom) { + RenderState res; + res.mDisplayFrame = hwc_rect_t{left, top, right, bottom}; + res.mPlaneAlpha = 1.0f; + res.mSwapCount = 0; + res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast(right - left), + static_cast(bottom - top)}; + return res; +} + +inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right, + unsigned int bottom) { + EXPECT_LE(left, static_cast(INT_MAX)); + EXPECT_LE(top, static_cast(INT_MAX)); + EXPECT_LE(right, static_cast(INT_MAX)); + EXPECT_LE(bottom, static_cast(INT_MAX)); + return makeSimpleRect(static_cast(left), static_cast(top), static_cast(right), + static_cast(bottom)); +} + +//////////////////////////////////////////////// + +class DisplayTest : public ::testing::Test { +public: + class MockComposerClient : public FakeComposerClient { + public: + MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType)); + MOCK_METHOD4(getDisplayAttribute, + Error(Display display, Config config, IComposerClient::Attribute attribute, + int32_t* outValue)); + + // Re-routing to basic fake implementation + Error getDisplayAttributeFake(Display display, Config config, + IComposerClient::Attribute attribute, int32_t* outValue) { + return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue); + } + }; + +protected: + void SetUp() override; + void TearDown() override; + + sp mFakeService; + sp mComposerClient; + + MockComposerClient* mMockComposer; +}; + +void DisplayTest::SetUp() { + // TODO: The mMockComposer should be a unique_ptr, but it needs to + // outlive the test class. Currently ComposerClient only dies + // when the service is replaced. The Mock deletes itself when + // removeClient is called on it, which is ugly. This can be + // changed if HIDL ServiceManager allows removing services or + // ComposerClient starts taking the ownership of the contained + // implementation class. Moving the fake class to the HWC2 + // interface instead of the current Composer interface might also + // change the situation. + mMockComposer = new MockComposerClient; + sp client = new ComposerClient(*mMockComposer); + mMockComposer->setClient(client.get()); + mFakeService = new FakeComposerService(client); + mFakeService->registerAsService("mock"); + + android::hardware::ProcessState::self()->startThreadPool(); + android::ProcessState::self()->startThreadPool(); + + EXPECT_CALL(*mMockComposer, getDisplayType(1, _)) + .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + // Seems to be doubled right now, once for display ID 1 and once for 0. This sounds fishy + // but encoding that here exactly. + EXPECT_CALL(*mMockComposer, getDisplayAttribute(1, 1, _, _)) + .Times(5) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + // TODO: Find out what code is generating the ID 0. + EXPECT_CALL(*mMockComposer, getDisplayAttribute(0, 1, _, _)) + .Times(5) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + + startSurfaceFlinger(); + + // Fake composer wants to enable VSync injection + mMockComposer->onSurfaceFlingerStart(); + + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); +} + +void DisplayTest::TearDown() { + mComposerClient->dispose(); + mComposerClient = nullptr; + + // Fake composer needs to release SurfaceComposerClient before the stop. + mMockComposer->onSurfaceFlingerStop(); + stopSurfaceFlinger(); + + mFakeService = nullptr; + // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime + // management. + mMockComposer = nullptr; +} + +TEST_F(DisplayTest, Hotplug) { + ALOGD("DisplayTest::Hotplug"); + + EXPECT_CALL(*mMockComposer, getDisplayType(2, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + // The attribute queries will get done twice. This is for defaults + EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, _, _)) + .Times(2 * 3) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + // ... and then special handling for dimensions. Specifying this + // rules later means that gmock will try them first, i.e., + // ordering of width/height vs. the default implementation for + // other queries is significant. + EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::WIDTH, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE))); + + EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::HEIGHT, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE))); + + // TODO: Width and height queries are not actually called. Display + // info returns dimensions 0x0 in display info. Why? + + mMockComposer->hotplugDisplay(static_cast(2), + IComposerCallback::Connection::CONNECTED); + + { + sp display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(400u, info.w); + ASSERT_EQ(200u, info.h); + + auto surfaceControl = + mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(surfaceControl != nullptr); + ASSERT_TRUE(surfaceControl->isValid()); + fillSurfaceRGBA8(surfaceControl, BLUE); + + { + GlobalTransactionScope gts(*mMockComposer); + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, surfaceControl->show()); + } + } + + mMockComposer->hotplugDisplay(static_cast(2), + IComposerCallback::Connection::DISCONNECTED); + + mMockComposer->clearFrames(); + + mMockComposer->hotplugDisplay(static_cast(2), + IComposerCallback::Connection::CONNECTED); + + { + sp display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(400u, info.w); + ASSERT_EQ(200u, info.h); + + auto surfaceControl = + mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(surfaceControl != nullptr); + ASSERT_TRUE(surfaceControl->isValid()); + fillSurfaceRGBA8(surfaceControl, BLUE); + + { + GlobalTransactionScope gts(*mMockComposer); + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, surfaceControl->show()); + } + } + mMockComposer->hotplugDisplay(static_cast(2), + IComposerCallback::Connection::DISCONNECTED); +} + +//////////////////////////////////////////////// + +class TransactionTest : public ::testing::Test { +protected: + // Layer array indexing constants. + constexpr static int BG_LAYER = 0; + constexpr static int FG_LAYER = 1; + + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; + + sp mComposerClient; + sp mBGSurfaceControl; + sp mFGSurfaceControl; + std::vector mBaseFrame; + uint32_t mDisplayWidth; + uint32_t mDisplayHeight; + + static FakeComposerClient* sFakeComposer; +}; + +FakeComposerClient* TransactionTest::sFakeComposer; + +void TransactionTest::SetUpTestCase() { + // TODO: See TODO comment at DisplayTest::SetUp for background on + // the lifetime of the FakeComposerClient. + sFakeComposer = new FakeComposerClient; + sp client = new ComposerClient(*sFakeComposer); + sFakeComposer->setClient(client.get()); + sp fakeService = new FakeComposerService(client); + fakeService->registerAsService("mock"); + + android::hardware::ProcessState::self()->startThreadPool(); + android::ProcessState::self()->startThreadPool(); + + startSurfaceFlinger(); + + // Fake composer wants to enable VSync injection + sFakeComposer->onSurfaceFlingerStart(); +} + +void TransactionTest::TearDownTestCase() { + // Fake composer needs to release SurfaceComposerClient before the stop. + sFakeComposer->onSurfaceFlingerStop(); + stopSurfaceFlinger(); + // TODO: This is deleted when the ComposerClient calls + // removeClient. Devise better lifetime control. + sFakeComposer = nullptr; +} + +void TransactionTest::SetUp() { + ALOGI("TransactionTest::SetUp"); + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + ALOGI("TransactionTest::SetUp - display"); + sp display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + + mDisplayWidth = info.w; + mDisplayHeight = info.h; + + // Background surface + mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth, + mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mBGSurfaceControl != nullptr); + ASSERT_TRUE(mBGSurfaceControl->isValid()); + fillSurfaceRGBA8(mBGSurfaceControl, BLUE); + + // Foreground surface + mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mFGSurfaceControl != nullptr); + ASSERT_TRUE(mFGSurfaceControl->isValid()); + + fillSurfaceRGBA8(mFGSurfaceControl, RED); + + SurfaceComposerClient::openGlobalTransaction(); + + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); + + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX - 1)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + + // Synchronous transaction will stop this thread, so we set up a + // delayed, off-thread vsync request before closing the + // transaction. In the test code this is usually done with + // GlobalTransactionScope. Leaving here in the 'vanilla' form for + // reference. + ASSERT_EQ(0, sFakeComposer->getFrameCount()); + sFakeComposer->runVSyncAfter(1ms); + SurfaceComposerClient::closeGlobalTransaction(true); + sFakeComposer->waitUntilFrame(1); + + // Reference data. This is what the HWC should see. + static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing"); + mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight)); + mBaseFrame[BG_LAYER].mSwapCount = 1; + mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64)); + mBaseFrame[FG_LAYER].mSwapCount = 1; + + auto frame = sFakeComposer->getFrameRects(0); + ASSERT_TRUE(framesAreSame(mBaseFrame, frame)); +} + +void TransactionTest::TearDown() { + ALOGD("TransactionTest::TearDown"); + + mComposerClient->dispose(); + mBGSurfaceControl = 0; + mFGSurfaceControl = 0; + mComposerClient = 0; + + sFakeComposer->runVSyncAndWait(); + mBaseFrame.clear(); + sFakeComposer->clearFrames(); + ASSERT_EQ(0, sFakeComposer->getFrameCount()); + + sp sf(ComposerService::getComposerService()); + std::vector layers; + status_t result = sf->getLayerDebugInfo(&layers); + if (result != NO_ERROR) { + ALOGE("Failed to get layers %s %d", strerror(-result), result); + } else { + // If this fails, the test being torn down leaked layers. + EXPECT_EQ(0u, layers.size()); + if (layers.size() > 0) { + for (auto layer = layers.begin(); layer != layers.end(); ++layer) { + std::cout << to_string(*layer).c_str(); + } + // To ensure the next test has clean slate, will run the class + // tear down and setup here. + TearDownTestCase(); + SetUpTestCase(); + } + } + ALOGD("TransactionTest::TearDown - complete"); +} + +TEST_F(TransactionTest, LayerMove) { + ALOGD("TransactionTest::LayerMove"); + + // The scope opens and closes a global transaction and, at the + // same time, makes sure the SurfaceFlinger progresses one frame + // after the transaction closes. The results of the transaction + // should be available in the latest frame stored by the fake + // composer. + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls. + // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?) + // + // sFakeComposer->runVSyncAndWait(); + } + + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + + ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's + // no extra frames. + + // NOTE: Frame 0 is produced in the SetUp. + auto frame1Ref = mBaseFrame; + frame1Ref[FG_LAYER].mDisplayFrame = + hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves. + EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); + + auto frame2Ref = frame1Ref; + frame2Ref[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); +} + +TEST_F(TransactionTest, LayerResize) { + ALOGD("TransactionTest::LayerResize"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); + } + + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + + ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's + // no extra frames. + + auto frame1Ref = mBaseFrame; + // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted. + EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); + + auto frame2Ref = frame1Ref; + frame2Ref[FG_LAYER].mSwapCount++; + frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128}; + frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f}; + EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); +} + +TEST_F(TransactionTest, LayerCrop) { + // TODO: Add scaling to confirm that crop happens in buffer space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f}; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerFinalCrop) { + // TODO: Add scaling to confirm that crop happens in display space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(32, 32, 32 + 64, 32 + 64); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // In display space we are cropping with [32, 32, 96, 96] against display rect + // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96] + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32}; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerFinalCropEmpty) { + // TODO: Add scaling to confirm that crop happens in display space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // In display space we are cropping with [16, 16, 32, 32] against display rect + // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited. + std::vector referenceFrame(1); + referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetLayer) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // The layers will switch order, but both are rendered because the background layer is + // transparent (RGBA8888). + std::vector referenceFrame(2); + referenceFrame[0] = mBaseFrame[FG_LAYER]; + referenceFrame[1] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetLayerOpaque) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + ASSERT_EQ(NO_ERROR, + mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, + layer_state_t::eLayerOpaque)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // The former foreground layer is now covered with opaque layer - it should have disappeared + std::vector referenceFrame(1); + referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, SetLayerStack) { + ALOGD("TransactionTest::SetLayerStack"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerShowHide) { + ALOGD("TransactionTest::LayerShowHide"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + } + + // Foreground layer should be back + ASSERT_EQ(3, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetAlpha) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); + } + + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetFlags) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, + mFGSurfaceControl->setFlags(layer_state_t::eLayerHidden, + layer_state_t::eLayerHidden)); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetMatrix) { + struct matrixTestData { + float matrix[4]; + hwc_transform_t expectedTransform; + hwc_rect_t expectedDisplayFrame; + }; + + // The matrix operates on the display frame and is applied before + // the position is added. So, the foreground layer rect is (0, 0, + // 64, 64) is first transformed, potentially yielding negative + // coordinates and then the position (64, 64) is added yielding + // the final on-screen rectangles given. + + const matrixTestData MATRIX_TESTS[7] = // clang-format off + {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}}, + {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}}, + {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}}, + {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}}, + {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}}, + {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}}, + {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}}; + // clang-format on + constexpr int TEST_COUNT = sizeof(MATRIX_TESTS)/sizeof(matrixTestData); + + for (int i = 0; i < TEST_COUNT; i++) { + // TODO: How to leverage the HWC2 stringifiers? + const matrixTestData& xform = MATRIX_TESTS[i]; + SCOPED_TRACE(i); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, + mFGSurfaceControl->setMatrix(xform.matrix[0], xform.matrix[1], + xform.matrix[2], xform.matrix[3])); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mTransform = xform.expectedTransform; + referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + } +} + +#if 0 +TEST_F(TransactionTest, LayerSetMatrix2) { + { + GlobalTransactionScope gts(*sFakeComposer); + // TODO: PLEASE SPEC THE FUNCTION! + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(0.11f, 0.123f, + -2.33f, 0.22f)); + } + auto referenceFrame = mBaseFrame; + // TODO: Is this correct for sure? + //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} +#endif + +TEST_F(TransactionTest, DeferredTransaction) { + // Synchronization surface + constexpr static int SYNC_LAYER = 2; + auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(syncSurfaceControl != nullptr); + ASSERT_TRUE(syncSurfaceControl->isValid()); + + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->setLayer(INT32_MAX - 1)); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->setPosition(mDisplayWidth - 2, mDisplayHeight - 2)); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->show()); + } + auto referenceFrame = mBaseFrame; + referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2, + mDisplayWidth - 1, mDisplayHeight - 1)); + referenceFrame[SYNC_LAYER].mSwapCount = 1; + EXPECT_EQ(2, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // set up two deferred transactions on different frames - these should not yield composited + // frames + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75)); + mFGSurfaceControl + ->deferTransactionUntil(syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber()); + } + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + mFGSurfaceControl + ->deferTransactionUntil(syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber() + 1); + } + EXPECT_EQ(4, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // should trigger the first deferred transaction, but not the second one + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + sFakeComposer->runVSyncAndWait(); + EXPECT_EQ(5, sFakeComposer->getFrameCount()); + + referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; + referenceFrame[SYNC_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // should show up immediately since it's not deferred + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0)); + } + referenceFrame[FG_LAYER].mPlaneAlpha = 1.f; + EXPECT_EQ(6, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // trigger the second deferred transaction + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + sFakeComposer->runVSyncAndWait(); + // TODO: Compute from layer size? + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64}; + referenceFrame[SYNC_LAYER].mSwapCount++; + EXPECT_EQ(7, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, SetRelativeLayer) { + constexpr int RELATIVE_LAYER = 2; + auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED); + + // Now we stack the surface above the foreground surface and make sure it is visible. + { + GlobalTransactionScope gts(*sFakeComposer); + relativeSurfaceControl->setPosition(64, 64); + relativeSurfaceControl->show(); + relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1); + } + auto referenceFrame = mBaseFrame; + // NOTE: All three layers will be visible as the surfaces are + // transparent because of the RGBA format. + referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64)); + referenceFrame[RELATIVE_LAYER].mSwapCount = 1; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // A call to setLayer will override a call to setRelativeLayer + { + GlobalTransactionScope gts(*sFakeComposer); + relativeSurfaceControl->setLayer(0); + } + + // Previous top layer will now appear at the bottom. + auto referenceFrame2 = mBaseFrame; + referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]); + EXPECT_EQ(3, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +class ChildLayerTest : public TransactionTest { +protected: + constexpr static int CHILD_LAYER = 2; + + void SetUp() override { + TransactionTest::SetUp(); + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(mChild, LIGHT_GRAY); + + sFakeComposer->runVSyncAndWait(); + mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10)); + mBaseFrame[CHILD_LAYER].mSwapCount = 1; + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + } + void TearDown() override { + mChild = 0; + TransactionTest::TearDown(); + } + + sp mChild; +}; + +TEST_F(ChildLayerTest, Positioning) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + // Move to the same position as in the original setup. + mFGSurfaceControl->setPosition(64, 64); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0)); + } + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Cropping) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5)); + } + // NOTE: The foreground surface would be occluded by the child + // now, but is included in the stack because the child is + // transparent. + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, FinalCropping) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5)); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Constraints) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mFGSurfaceControl->setPosition(0, 0); + mChild->setPosition(63, 63); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Scaling) { + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setPosition(0, 0); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0); + } + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, LayerAlpha) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5)); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5)); + } + + auto referenceFrame2 = referenceFrame; + referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f; + referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, ReparentChildren) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle()); + } + + auto referenceFrame2 = referenceFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, DetachChildren) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->detachChildren(); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->hide(); + } + + // Nothing should have changed. The child control becomes a no-op + // zombie on detach. See comments for detachChildren in the + // SurfaceControl.h file. + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // We cause scaling by 2. + mFGSurfaceControl->setSize(128, 128); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +// Regression test for b/37673612 +TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + } + + // We set things up as in b/37673612 so that there is a mismatch between the buffer size and + // the WM specified state size. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 64); + } + + sp s = mFGSurfaceControl->getSurface(); + auto anw = static_cast(s.get()); + native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); + native_window_set_buffers_dimensions(anw, 64, 128); + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + + // The child should still be in the same place and not have any strange scaling as in + // b/37673612. + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f}; + referenceFrame[FG_LAYER].mSwapCount++; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Bug36858924) { + // Destroy the child layer + mChild.clear(); + + // Now recreate it as hidden + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden, + mFGSurfaceControl.get()); + + // Show the child layer in a deferred transaction + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(), + mFGSurfaceControl->getSurface()->getNextFrameNumber()); + mChild->show(); + } + + // Render the foreground surface a few times + // + // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third + // frame because SurfaceFlinger would never process the deferred transaction and would therefore + // never acquire/release the first buffer + ALOGI("Filling 1"); + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 2"); + fillSurfaceRGBA8(mFGSurfaceControl, BLUE); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 3"); + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 4"); + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); +} + +class LatchingTest : public TransactionTest { +protected: + void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); } + + void unlockFGBuffer() { + sp s = mFGSurfaceControl->getSurface(); + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + sFakeComposer->runVSyncAndWait(); + } + + void completeFGResize() { + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + } + void restoreInitialState() { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(64, 64); + mFGSurfaceControl->setPosition(64, 64); + mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64)); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + } +}; + +TEST_F(LatchingTest, SurfacePositionLatching) { + // By default position can be updated even while + // a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(32, 32); + mFGSurfaceControl->setPosition(100, 100); + } + + // The size should not have updated as we have not provided a new buffer. + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + // Now we repeat with setGeometryAppliesWithResize + // and verify the position DOESN'T latch. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setSize(32, 32); + mFGSurfaceControl->setPosition(100, 100); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32}; + referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, CropLatching) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; + referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; + referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, FinalCropLatching) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame1[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast(127 - 64), static_cast(127 - 64)}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame2[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast(127 - 64), static_cast(127 - 64)}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +// In this test we ensure that setGeometryAppliesWithResize actually demands +// a buffer of the new size, and not just any size. +TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame1[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast(127 - 64), static_cast(127 - 64)}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + // In order to prepare to submit a buffer at the wrong size, we acquire it prior to + // initiating the resize. + lockAndFillFGBuffer(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + // We now submit our old buffer, at the old size, and ensure it doesn't + // trigger geometry latching. + unlockFGBuffer(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); + + completeFGResize(); + auto referenceFrame3 = referenceFrame2; + referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame3[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast(127 - 64), static_cast(127 - 64)}; + referenceFrame3[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) { + // In this scenario, we attempt to set the final crop a second time while the resize + // is still pending, and ensure we are successful. Success meaning the second crop + // is the one which eventually latches and not the first. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment; + ::testing::AddGlobalTestEnvironment(fakeEnvironment); + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} -- cgit v1.2.3-59-g8ed1b From d7f49c5e93a554c2f0e85e279a765f92fb1e66f1 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Wed, 26 Jul 2017 18:48:28 -0700 Subject: Use a separate hwcomposer hidl instance for vr flinger Improve robustness of vr flinger <--> surface flinger switching by having vr flinger use a separate hardware composer hidl instance instead of sharing the instance with surface flinger. Sharing the hardware composer instance has proven to be error prone, with situations where both the vr flinger thread and surface flinger main thread would write to the composer at the same time, causing hard to diagnose crashes (b/62925812). Instead of sharing the hardware composer instance, when switching to vr flinger we now delete the existing instance, create a new instance directed to the vr hardware composer shim, and vr flinger creates its own composer instance connected to the real hardware composer. By creating a separate composer instance for vr flinger, crashes like the ones found in b/62925812 are no longer impossible. Most of the changes in this commit are related to enabling surface flinger to delete HWComposer instances cleanly. In particular: - Previously the hardware composer callbacks (which come in on a hwbinder thread) would land in HWC2::Device and bubble up to the SurfaceFlinger object. But with the new behavior the HWC2::Device might be dead or in the process of being destroyed, so instead we have SurfaceFlinger receive the composer callbacks directly, and forward them to HWComposer and HWC2::Device. We include a composer id field in the callbacks so surface flinger can ignore stale callbacks from dead composer instances. - Object ownership for HWC2::Display and HWC2::Layer was shared by passing around shared_ptrs to these objects. This was problematic because they referenced and used the HWC2::Device, which can now be destroyed when switching to vr flinger. Simplify the ownership model by having HWC2::Device own (via unique_ptr<>) instances of HWC2::Display, which owns (again via unique_ptr<>) instances of HWC2::Layer. In cases where we previously passed std::shared_ptr<> to HWC2::Display or HWC2::Layer, instead pass non-owning HWC2::Display* and HWC2::Layer* pointers. This ensures clean composer instance teardown with no stale references to the deleted HWC2::Device. - When the hardware composer instance is destroyed and the HWC2::Layers are removed, notify the android::Layer via a callback, so it can remove the HWC2::Layer from its internal table of hardware composer layers. This removes the burden to explicitly clear out all hardware composer layers when switching to vr flinger, which has been a source of bugs. - We were missing an mStateLock lock in SurfaceFlinger::setVsyncEnabled(), which was necessary to ensure we were setting vsync on the correct hardware composer instance. Once that lock was added, surface flinger would sometimes deadlock when transitioning to vr flinger, because the surface flinger main thread would acquire mStateLock and then EventControlThread::mMutex, whereas the event control thread would acquire the locks in the opposite order. The changes in EventControlThread.cpp are to ensure it doesn't hold a lock on EventControlThread::mMutex while calling setVsyncEnabled(), to avoid the deadlock. I found that without a composer callback registered in vr flinger the vsync_event file wasn't getting vsync timestamps written, so vr flinger would get stuck in an infinite loop trying to parse a vsync timestamp. Since we need to have a callback anyway I changed the code in hardware_composer.cpp to get the vsync timestamp from the callback, as surface flinger does. I confirmed the timestamps are the same with either method, and this lets us remove some extra code for extracting the vsync timestamp that (probably) wasn't compatible with all devices we want to run on anyway. I also added a timeout to the vysnc wait so we'll see an error message in the log if we fail to wait for vsync, instead of looping forever. Bug: 62925812 Test: - Confirmed surface flinger <--> vr flinger switching is robust by switching devices on and off hundreds of times and observing no hardware composer related issues, surface flinger crashes, or hardware composer service crashes. - Confirmed 2d in vr works as before by going through the OOBE flow on a standalone. This also exercises virtual display creation and usage through surface flinger. - Added logs to confirm perfect layer/display cleanup when destroying hardware composer instances. - Tested normal 2d phone usage to confirm basic layer create/destroy functionality works as before. - Monitored surface flinger file descriptor usage across dozens of surface flinger <--> vr flinger transitions and observed no file descriptor leaks. - Confirmed the HWC1 code path still compiles. - Ran the surface flinger tests and confirmed there are no new test failures. - Ran the hardware composer hidl in passthrough mode on a Marlin and confirmed it works. - Ran CTS tests for virtual displays and confirmed they all pass. - Tested Android Auto and confirmed basic graphics functionality still works. Change-Id: I17dc0e060bfb5cb447ffbaa573b279fc6d2d8bd1 Merged-In: I17dc0e060bfb5cb447ffbaa573b279fc6d2d8bd1 --- libs/vr/libvrflinger/display_service.cpp | 10 +- libs/vr/libvrflinger/display_service.h | 3 - libs/vr/libvrflinger/hardware_composer.cpp | 352 +++++-------- libs/vr/libvrflinger/hardware_composer.h | 110 ++--- libs/vr/libvrflinger/include/dvr/vr_flinger.h | 3 - libs/vr/libvrflinger/vr_flinger.cpp | 4 - services/surfaceflinger/DisplayDevice.cpp | 6 +- .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 4 + .../surfaceflinger/DisplayHardware/ComposerHal.h | 5 + services/surfaceflinger/DisplayHardware/HWC2.cpp | 549 +++++++++------------ services/surfaceflinger/DisplayHardware/HWC2.h | 124 +++-- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 130 +++-- .../surfaceflinger/DisplayHardware/HWComposer.h | 39 +- services/surfaceflinger/EventControlThread.cpp | 43 +- services/surfaceflinger/Layer.cpp | 50 +- services/surfaceflinger/Layer.h | 34 +- .../surfaceflinger/RenderEngine/RenderEngine.cpp | 33 +- .../surfaceflinger/RenderEngine/RenderEngine.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 293 +++++------ services/surfaceflinger/SurfaceFlinger.h | 61 ++- services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 4 +- 21 files changed, 842 insertions(+), 1017 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 733edc659c..f350762e79 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -40,10 +40,8 @@ namespace dvr { DisplayService::DisplayService(Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) : BASE("DisplayService", - Endpoint::Create(display::DisplayProtocol::kClientPath)), - hardware_composer_(hidl, request_display_callback), - request_display_callback_(request_display_callback) { - hardware_composer_.Initialize(); + Endpoint::Create(display::DisplayProtocol::kClientPath)) { + hardware_composer_.Initialize(hidl, request_display_callback); } bool DisplayService::IsInitialized() const { @@ -398,10 +396,6 @@ pdx::Status DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) { return {0}; } -void DisplayService::OnHardwareComposerRefresh() { - hardware_composer_.OnHardwareComposerRefresh(); -} - void DisplayService::SetDisplayConfigurationUpdateNotifier( DisplayConfigurationUpdateNotifier update_notifier) { update_notifier_ = update_notifier; diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 6efe264b09..55e33ab852 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -72,8 +72,6 @@ class DisplayService : public pdx::ServiceBase { void GrantDisplayOwnership() { hardware_composer_.Enable(); } void SeizeDisplayOwnership() { hardware_composer_.Disable(); } - void OnHardwareComposerRefresh(); - private: friend BASE; friend DisplaySurface; @@ -119,7 +117,6 @@ class DisplayService : public pdx::ServiceBase { pdx::Status HandleSurfaceMessage(pdx::Message& message); HardwareComposer hardware_composer_; - RequestDisplayCallback request_display_callback_; EpollEventDispatcher dispatcher_; DisplayConfigurationUpdateNotifier update_notifier_; diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 11c137063e..3418d65671 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -28,6 +28,8 @@ #include #include +using android::hardware::Return; +using android::hardware::Void; using android::pdx::LocalHandle; using android::pdx::rpc::EmptyVariant; using android::pdx::rpc::IfAnyOf; @@ -42,9 +44,6 @@ namespace { const char kBacklightBrightnessSysFile[] = "/sys/class/leds/lcd-backlight/brightness"; -const char kPrimaryDisplayVSyncEventFile[] = - "/sys/class/graphics/fb0/vsync_event"; - const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp"; const char kDvrPerformanceProperty[] = "sys.dvr.performance"; @@ -86,22 +85,11 @@ bool SetThreadPolicy(const std::string& scheduler_class, } // anonymous namespace -// Layer static data. -Hwc2::Composer* Layer::hwc2_hidl_; -const HWCDisplayMetrics* Layer::display_metrics_; - // HardwareComposer static data; constexpr size_t HardwareComposer::kMaxHardwareLayers; HardwareComposer::HardwareComposer() - : HardwareComposer(nullptr, RequestDisplayCallback()) {} - -HardwareComposer::HardwareComposer( - Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback) - : initialized_(false), - hwc2_hidl_(hwc2_hidl), - request_display_callback_(request_display_callback), - callbacks_(new ComposerCallback) {} + : initialized_(false), request_display_callback_(nullptr) {} HardwareComposer::~HardwareComposer(void) { UpdatePostThreadState(PostThreadState::Quit, true); @@ -109,16 +97,19 @@ HardwareComposer::~HardwareComposer(void) { post_thread_.join(); } -bool HardwareComposer::Initialize() { +bool HardwareComposer::Initialize( + Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { if (initialized_) { ALOGE("HardwareComposer::Initialize: already initialized."); return false; } + request_display_callback_ = request_display_callback; + HWC::Error error = HWC::Error::None; Hwc2::Config config; - error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); + error = hidl->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); if (error != HWC::Error::None) { ALOGE("HardwareComposer: Failed to get current display config : %d", @@ -126,8 +117,8 @@ bool HardwareComposer::Initialize() { return false; } - error = - GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_); + error = GetDisplayMetrics(hidl, HWC_DISPLAY_PRIMARY, config, + &native_display_metrics_); if (error != HWC::Error::None) { ALOGE( @@ -149,9 +140,6 @@ bool HardwareComposer::Initialize() { display_transform_ = HWC_TRANSFORM_NONE; display_metrics_ = native_display_metrics_; - // Pass hwc instance and metrics to setup globals for Layer. - Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_); - post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF( !post_thread_event_fd_, @@ -210,15 +198,11 @@ void HardwareComposer::UpdatePostThreadState(PostThreadStateType state, } void HardwareComposer::OnPostThreadResumed() { - hwc2_hidl_->resetCommands(); + hidl_.reset(new Hwc2::Composer(false)); + hidl_callback_ = new ComposerCallback; + hidl_->registerCallback(hidl_callback_); - // HIDL HWC seems to have an internal race condition. If we submit a frame too - // soon after turning on VSync we don't get any VSync signals. Give poor HWC - // implementations a chance to enable VSync before we continue. - EnableVsync(false); - std::this_thread::sleep_for(100ms); EnableVsync(true); - std::this_thread::sleep_for(100ms); // TODO(skiazyk): We need to do something about accessing this directly, // supposedly there is a backlight service on the way. @@ -240,9 +224,12 @@ void HardwareComposer::OnPostThreadPaused() { } active_layer_count_ = 0; - EnableVsync(false); + if (hidl_) { + EnableVsync(false); + } - hwc2_hidl_->resetCommands(); + hidl_callback_ = nullptr; + hidl_.reset(nullptr); // Trigger target-specific performance mode change. property_set(kDvrPerformanceProperty, "idle"); @@ -252,21 +239,21 @@ HWC::Error HardwareComposer::Validate(hwc2_display_t display) { uint32_t num_types; uint32_t num_requests; HWC::Error error = - hwc2_hidl_->validateDisplay(display, &num_types, &num_requests); + hidl_->validateDisplay(display, &num_types, &num_requests); if (error == HWC2_ERROR_HAS_CHANGES) { // TODO(skiazyk): We might need to inspect the requested changes first, but // so far it seems like we shouldn't ever hit a bad state. // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_, // display); - error = hwc2_hidl_->acceptDisplayChanges(display); + error = hidl_->acceptDisplayChanges(display); } return error; } -int32_t HardwareComposer::EnableVsync(bool enabled) { - return (int32_t)hwc2_hidl_->setVsyncEnabled( +HWC::Error HardwareComposer::EnableVsync(bool enabled) { + return hidl_->setVsyncEnabled( HWC_DISPLAY_PRIMARY, (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE : HWC2_VSYNC_DISABLE)); @@ -274,7 +261,7 @@ int32_t HardwareComposer::EnableVsync(bool enabled) { HWC::Error HardwareComposer::Present(hwc2_display_t display) { int32_t present_fence; - HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence); + HWC::Error error = hidl_->presentDisplay(display, &present_fence); // According to the documentation, this fence is signaled at the time of // vsync/DMA for physical displays. @@ -288,20 +275,21 @@ HWC::Error HardwareComposer::Present(hwc2_display_t display) { return error; } -HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display, +HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* hidl, + hwc2_display_t display, hwc2_config_t config, hwc2_attribute_t attribute, int32_t* out_value) const { - return hwc2_hidl_->getDisplayAttribute( + return hidl->getDisplayAttribute( display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value); } HWC::Error HardwareComposer::GetDisplayMetrics( - hwc2_display_t display, hwc2_config_t config, + Hwc2::Composer* hidl, hwc2_display_t display, hwc2_config_t config, HWCDisplayMetrics* out_metrics) const { HWC::Error error; - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_WIDTH, &out_metrics->width); if (error != HWC::Error::None) { ALOGE( @@ -310,7 +298,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_HEIGHT, &out_metrics->height); if (error != HWC::Error::None) { ALOGE( @@ -319,7 +307,8 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD, + error = GetDisplayAttribute(hidl, display, config, + HWC2_ATTRIBUTE_VSYNC_PERIOD, &out_metrics->vsync_period_ns); if (error != HWC::Error::None) { ALOGE( @@ -328,7 +317,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_X, &out_metrics->dpi.x); if (error != HWC::Error::None) { ALOGE( @@ -337,7 +326,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_Y, &out_metrics->dpi.y); if (error != HWC::Error::None) { ALOGE( @@ -374,7 +363,7 @@ std::string HardwareComposer::Dump() { if (post_thread_resumed_) { stream << "Hardware Composer Debug Info:" << std::endl; - stream << hwc2_hidl_->dumpDebugInfo(); + stream << hidl_->dumpDebugInfo(); } return stream.str(); @@ -446,8 +435,8 @@ void HardwareComposer::PostLayers() { std::vector out_layers; std::vector out_fences; - error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, - &out_fences); + error = hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, + &out_fences); ALOGE_IF(error != HWC::Error::None, "HardwareComposer::PostLayers: Failed to get release fences: %s", error.to_string().c_str()); @@ -546,7 +535,7 @@ void HardwareComposer::UpdateConfigBuffer() { } int HardwareComposer::PostThreadPollInterruptible( - const pdx::LocalHandle& event_fd, int requested_events) { + const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) { pollfd pfd[2] = { { .fd = event_fd.Get(), @@ -561,7 +550,7 @@ int HardwareComposer::PostThreadPollInterruptible( }; int ret, error; do { - ret = poll(pfd, 2, -1); + ret = poll(pfd, 2, timeout_ms); error = errno; ALOGW_IF(ret < 0, "HardwareComposer::PostThreadPollInterruptible: Error during " @@ -571,6 +560,8 @@ int HardwareComposer::PostThreadPollInterruptible( if (ret < 0) { return -error; + } else if (ret == 0) { + return -ETIMEDOUT; } else if (pfd[0].revents != 0) { return 0; } else if (pfd[1].revents != 0) { @@ -623,114 +614,17 @@ int HardwareComposer::ReadWaitPPState() { } } -// Reads the timestamp of the last vsync from the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) { - const int event_fd = primary_display_vsync_event_fd_.Get(); - int ret, error; - - // The driver returns data in the form "VSYNC=". - std::array data; - data.fill('\0'); - - // Seek back to the beginning of the event file. - ret = lseek(event_fd, 0, SEEK_SET); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: " - "%s", - strerror(error)); - return -error; - } - - // Read the vsync event timestamp. - ret = read(event_fd, data.data(), data.size()); - if (ret < 0) { - error = errno; - ALOGE_IF( - error != EAGAIN, - "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: " - "%s", - strerror(error)); - return -error; - } - - ret = sscanf(data.data(), "VSYNC=%" PRIu64, - reinterpret_cast(timestamp)); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: " - "%s", - strerror(error)); - return -error; - } - - return 0; -} - -// Blocks until the next vsync event is signaled by the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::BlockUntilVSync() { - // Vsync is signaled by POLLPRI on the fb vsync node. - return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI); -} - // Waits for the next vsync and returns the timestamp of the vsync event. If // vsync already passed since the last call, returns the latest vsync timestamp -// instead of blocking. This method updates the last_vsync_timeout_ in the -// process. -// -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. +// instead of blocking. int HardwareComposer::WaitForVSync(int64_t* timestamp) { - int error; - - // Get the current timestamp and decide what to do. - while (true) { - int64_t current_vsync_timestamp; - error = ReadVSyncTimestamp(¤t_vsync_timestamp); - if (error < 0 && error != -EAGAIN) - return error; - - if (error == -EAGAIN) { - // Vsync was turned off, wait for the next vsync event. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - - // Try again to get the timestamp for this new vsync interval. - continue; - } - - // Check that we advanced to a later vsync interval. - if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) { - *timestamp = last_vsync_timestamp_ = current_vsync_timestamp; - return 0; - } - - // See how close we are to the next expected vsync. If we're within 1ms, - // sleep for 1ms and try again. - const int64_t ns_per_frame = display_metrics_.vsync_period_ns; - const int64_t threshold_ns = 1000000; // 1ms - - const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame; - const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs(); - - if (distance_to_vsync_est > threshold_ns) { - // Wait for vsync event notification. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } else { - // Sleep for a short time (1 millisecond) before retrying. - error = SleepUntil(GetSystemClockNs() + threshold_ns); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } + int error = PostThreadPollInterruptible( + hidl_callback_->GetVsyncEventFd(), POLLIN, /*timeout_ms*/ 1000); + if (error == kPostThreadInterrupted || error < 0) { + return error; + } else { + *timestamp = hidl_callback_->GetVsyncTime(); + return 0; } } @@ -749,7 +643,8 @@ int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { return -error; } - return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN); + return PostThreadPollInterruptible( + vsync_sleep_timer_fd_, POLLIN, /*timeout_ms*/ -1); } void HardwareComposer::PostThread() { @@ -772,15 +667,6 @@ void HardwareComposer::PostThread() { strerror(errno)); #endif // ENABLE_BACKLIGHT_BRIGHTNESS - // Open the vsync event node for the primary display. - // TODO(eieio): Move this into a platform-specific class. - primary_display_vsync_event_fd_ = - LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY); - ALOGE_IF(!primary_display_vsync_event_fd_, - "HardwareComposer: Failed to open vsync event node for primary " - "display: %s", - strerror(errno)); - // Open the wait pingpong status node for the primary display. // TODO(eieio): Move this into a platform-specific class. primary_display_wait_pp_fd_ = @@ -951,7 +837,8 @@ bool HardwareComposer::UpdateLayerConfig() { // The bottom layer is opaque, other layers blend. HWC::BlendMode blending = layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage; - layers_[layer_index].Setup(surfaces[layer_index], blending, + layers_[layer_index].Setup(surfaces[layer_index], native_display_metrics_, + hidl_.get(), blending, display_transform_, HWC::Composition::Device, layer_index); display_surfaces_.push_back(surfaces[layer_index]); @@ -979,50 +866,67 @@ void HardwareComposer::SetVSyncCallback(VSyncCallback callback) { vsync_callback_ = callback; } -void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/) { - // TODO(eieio): implement invalidate callbacks. +void HardwareComposer::SetBacklightBrightness(int brightness) { + if (backlight_brightness_fd_) { + std::array text; + const int length = snprintf(text.data(), text.size(), "%d", brightness); + write(backlight_brightness_fd_.Get(), text.data(), length); + } } -void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/, - int64_t /*timestamp*/) { - ATRACE_NAME(__PRETTY_FUNCTION__); - // Intentionally empty. HWC may require a callback to be set to enable vsync - // signals. We bypass this callback thread by monitoring the vsync event - // directly, but signals still need to be enabled. +HardwareComposer::ComposerCallback::ComposerCallback() { + vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF( + !vsync_event_fd_, + "Failed to create vsync event fd : %s", + strerror(errno)); } -void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/, - hwc2_display_t /*display*/, - hwc2_connection_t /*connected*/) { - // TODO(eieio): implement display hotplug callbacks. +Return HardwareComposer::ComposerCallback::onHotplug( + Hwc2::Display /*display*/, + IComposerCallback::Connection /*conn*/) { + return Void(); } -void HardwareComposer::OnHardwareComposerRefresh() { - // TODO(steventhomas): Handle refresh. +Return HardwareComposer::ComposerCallback::onRefresh( + Hwc2::Display /*display*/) { + return hardware::Void(); } -void HardwareComposer::SetBacklightBrightness(int brightness) { - if (backlight_brightness_fd_) { - std::array text; - const int length = snprintf(text.data(), text.size(), "%d", brightness); - write(backlight_brightness_fd_.Get(), text.data(), length); +Return HardwareComposer::ComposerCallback::onVsync( + Hwc2::Display display, int64_t timestamp) { + if (display == HWC_DISPLAY_PRIMARY) { + std::lock_guard lock(vsync_mutex_); + vsync_time_ = timestamp; + int error = eventfd_write(vsync_event_fd_.Get(), 1); + LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd"); } + return Void(); +} + +const pdx::LocalHandle& +HardwareComposer::ComposerCallback::GetVsyncEventFd() const { + return vsync_event_fd_; } -void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics) { - hwc2_hidl_ = hwc2_hidl; - display_metrics_ = metrics; +int64_t HardwareComposer::ComposerCallback::GetVsyncTime() { + std::lock_guard lock(vsync_mutex_); + eventfd_t event; + eventfd_read(vsync_event_fd_.Get(), &event); + LOG_ALWAYS_FATAL_IF(vsync_time_ < 0, + "Attempt to read vsync time before vsync event"); + int64_t return_val = vsync_time_; + vsync_time_ = -1; + return return_val; } void Layer::Reset() { - if (hwc2_hidl_ != nullptr && hardware_composer_layer_) { - hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); + if (hidl_ != nullptr && hardware_composer_layer_) { + hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); hardware_composer_layer_ = 0; } + hidl_ = nullptr; z_order_ = 0; blending_ = HWC::BlendMode::None; transform_ = HWC::Transform::None; @@ -1034,29 +938,35 @@ void Layer::Reset() { } void Layer::Setup(const std::shared_ptr& surface, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceSurface{surface}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::Setup(const std::shared_ptr& buffer, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceBuffer{buffer}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::UpdateBuffer(const std::shared_ptr& buffer) { @@ -1076,7 +986,7 @@ IonBuffer* Layer::GetBuffer() { return source_.Visit(Visitor{}); } -void Layer::UpdateLayerSettings() { +void Layer::UpdateLayerSettings(const HWCDisplayMetrics& display_metrics) { if (!IsLayerSetup()) { ALOGE( "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update " @@ -1087,7 +997,7 @@ void Layer::UpdateLayerSettings() { HWC::Error error; hwc2_display_t display = HWC_DISPLAY_PRIMARY; - error = hwc2_hidl_->setLayerCompositionType( + error = hidl_->setLayerCompositionType( display, hardware_composer_layer_, composition_type_.cast()); ALOGE_IF( @@ -1095,7 +1005,7 @@ void Layer::UpdateLayerSettings() { "Layer::UpdateLayerSettings: Error setting layer composition type: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerBlendMode( + error = hidl_->setLayerBlendMode( display, hardware_composer_layer_, blending_.cast()); ALOGE_IF(error != HWC::Error::None, @@ -1104,41 +1014,39 @@ void Layer::UpdateLayerSettings() { // TODO(eieio): Use surface attributes or some other mechanism to control // the layer display frame. - error = hwc2_hidl_->setLayerDisplayFrame( + error = hidl_->setLayerDisplayFrame( display, hardware_composer_layer_, - {0, 0, display_metrics_->width, display_metrics_->height}); + {0, 0, display_metrics.width, display_metrics.height}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer display frame: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerVisibleRegion( + error = hidl_->setLayerVisibleRegion( display, hardware_composer_layer_, - {{0, 0, display_metrics_->width, display_metrics_->height}}); + {{0, 0, display_metrics.width, display_metrics.height}}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer visible region: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); + error = hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); + error = hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting z_ order: %s", error.to_string().c_str()); } -void Layer::CommonLayerSetup() { +void Layer::CommonLayerSetup(const HWCDisplayMetrics& display_metrics) { HWC::Error error = - hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); + hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); ALOGE_IF( error != HWC::Error::None, "Layer::CommonLayerSetup: Failed to create layer on primary display: %s", error.to_string().c_str()); - UpdateLayerSettings(); + UpdateLayerSettings(display_metrics); } void Layer::Prepare() { @@ -1157,12 +1065,12 @@ void Layer::Prepare() { if (!handle.get()) { if (composition_type_ == HWC::Composition::Invalid) { composition_type_ = HWC::Composition::SolidColor; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast()); Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0}; - hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, - layer_color); + hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + layer_color); } else { // The composition type is already set. Nothing else to do until a // buffer arrives. @@ -1170,15 +1078,15 @@ void Layer::Prepare() { } else { if (composition_type_ != target_composition_type_) { composition_type_ = target_composition_type_; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast()); } HWC::Error error{HWC::Error::None}; - error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, 0, handle, - acquire_fence_.Get()); + error = hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, 0, handle, + acquire_fence_.Get()); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer buffer: %s", @@ -1187,9 +1095,9 @@ void Layer::Prepare() { if (!surface_rect_functions_applied_) { const float float_right = right; const float float_bottom = bottom; - error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, - {0, 0, float_right, float_bottom}); + error = hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, + {0, 0, float_right, float_bottom}); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer source crop: %s", diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index a0c50e14d8..fc0efeeeb4 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -54,11 +54,6 @@ class Layer { public: Layer() {} - // Sets up the global state used by all Layer instances. This must be called - // before using any Layer methods. - static void InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics); - // Releases any shared pointers and fence handles held by this instance. void Reset(); @@ -72,6 +67,7 @@ class Layer { // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). // |index| is the index of this surface in the DirectDisplaySurface array. void Setup(const std::shared_ptr& surface, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, HWC::BlendMode blending, HWC::Transform transform, HWC::Composition composition_type, size_t z_roder); @@ -83,9 +79,10 @@ class Layer { // |transform| receives HWC_TRANSFORM_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). - void Setup(const std::shared_ptr& buffer, HWC::BlendMode blending, - HWC::Transform transform, HWC::Composition composition_type, - size_t z_order); + void Setup(const std::shared_ptr& buffer, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, + HWC::BlendMode blending, HWC::Transform transform, + HWC::Composition composition_type, size_t z_order); // Layers that use a direct IonBuffer should call this each frame to update // which buffer will be used for the next PostLayers. @@ -121,7 +118,7 @@ class Layer { bool IsLayerSetup() const { return !source_.empty(); } // Applies all of the settings to this layer using the hwc functions - void UpdateLayerSettings(); + void UpdateLayerSettings(const HWCDisplayMetrics& display_metrics); int GetSurfaceId() const { int surface_id = -1; @@ -142,10 +139,9 @@ class Layer { } private: - void CommonLayerSetup(); + void CommonLayerSetup(const HWCDisplayMetrics& display_metrics); - static Hwc2::Composer* hwc2_hidl_; - static const HWCDisplayMetrics* display_metrics_; + Hwc2::Composer* hidl_ = nullptr; // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; @@ -263,11 +259,10 @@ class HardwareComposer { static constexpr size_t kMaxHardwareLayers = 4; HardwareComposer(); - HardwareComposer(Hwc2::Composer* hidl, - RequestDisplayCallback request_display_callback); ~HardwareComposer(); - bool Initialize(); + bool Initialize(Hwc2::Composer* hidl, + RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } @@ -281,11 +276,6 @@ class HardwareComposer { // Get the HMD display metrics for the current display. display::Metrics GetHmdDisplayMetrics() const; - HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config, - hwc2_attribute_t attributes, - int32_t* out_value) const; - HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config, - HWCDisplayMetrics* out_metrics) const; std::string Dump(); void SetVSyncCallback(VSyncCallback callback); @@ -308,34 +298,31 @@ class HardwareComposer { int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); - void OnHardwareComposerRefresh(); - private: - int32_t EnableVsync(bool enabled); + HWC::Error GetDisplayAttribute(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + hwc2_attribute_t attributes, + int32_t* out_value) const; + HWC::Error GetDisplayMetrics(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + HWCDisplayMetrics* out_metrics) const; + + HWC::Error EnableVsync(bool enabled); class ComposerCallback : public Hwc2::IComposerCallback { public: - ComposerCallback() {} - - hardware::Return onHotplug(Hwc2::Display /*display*/, - Connection /*connected*/) override { - // TODO(skiazyk): depending on how the server is implemented, we might - // have to set it up to synchronize with receiving this event, as it can - // potentially be a critical event for setting up state within the - // hwc2 module. That is, we (technically) should not call any other hwc - // methods until this method has been called after registering the - // callbacks. - return hardware::Void(); - } - - hardware::Return onRefresh(Hwc2::Display /*display*/) override { - return hardware::Void(); - } - - hardware::Return onVsync(Hwc2::Display /*display*/, - int64_t /*timestamp*/) override { - return hardware::Void(); - } + ComposerCallback(); + hardware::Return onHotplug(Hwc2::Display display, + Connection conn) override; + hardware::Return onRefresh(Hwc2::Display display) override; + hardware::Return onVsync(Hwc2::Display display, + int64_t timestamp) override; + const pdx::LocalHandle& GetVsyncEventFd() const; + int64_t GetVsyncTime(); + private: + std::mutex vsync_mutex_; + pdx::LocalHandle vsync_event_fd_; + int64_t vsync_time_ = -1; }; HWC::Error Validate(hwc2_display_t display); @@ -364,17 +351,18 @@ class HardwareComposer { void UpdatePostThreadState(uint32_t state, bool suspend); // Blocks until either event_fd becomes readable, or we're interrupted by a - // control thread. Any errors are returned as negative errno values. If we're - // interrupted, kPostThreadInterrupted will be returned. + // control thread, or timeout_ms is reached before any events occur. Any + // errors are returned as negative errno values, with -ETIMEDOUT returned in + // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be + // returned. int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd, - int requested_events); + int requested_events, + int timeout_ms); - // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made - // on the post thread that can be interrupted by a control thread. If - // interrupted, these calls return kPostThreadInterrupted. + // WaitForVSync and SleepUntil are blocking calls made on the post thread that + // can be interrupted by a control thread. If interrupted, these calls return + // kPostThreadInterrupted. int ReadWaitPPState(); - int BlockUntilVSync(); - int ReadVSyncTimestamp(int64_t* timestamp); int WaitForVSync(int64_t* timestamp); int SleepUntil(int64_t wakeup_timestamp); @@ -398,11 +386,9 @@ class HardwareComposer { bool initialized_; - // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own - // this pointer. - Hwc2::Composer* hwc2_hidl_; + std::unique_ptr hidl_; + sp hidl_callback_; RequestDisplayCallback request_display_callback_; - sp callbacks_; // Display metrics of the physical display. HWCDisplayMetrics native_display_metrics_; @@ -433,7 +419,8 @@ class HardwareComposer { std::thread post_thread_; // Post thread state machine and synchronization primitives. - PostThreadStateType post_thread_state_{PostThreadState::Idle}; + PostThreadStateType post_thread_state_{ + PostThreadState::Idle | PostThreadState::Suspended}; std::atomic post_thread_quiescent_{true}; bool post_thread_resumed_{false}; pdx::LocalHandle post_thread_event_fd_; @@ -444,9 +431,6 @@ class HardwareComposer { // Backlight LED brightness sysfs node. pdx::LocalHandle backlight_brightness_fd_; - // Primary display vsync event sysfs node. - pdx::LocalHandle primary_display_vsync_event_fd_; - // Primary display wait_pingpong state sysfs node. pdx::LocalHandle primary_display_wait_pp_fd_; @@ -478,12 +462,6 @@ class HardwareComposer { static constexpr int kPostThreadInterrupted = 1; - static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display); - static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display, - int64_t timestamp); - static void HwcHotplug(hwc2_callback_data_t callbackData, - hwc2_display_t display, hwc2_connection_t connected); - HardwareComposer(const HardwareComposer&) = delete; void operator=(const HardwareComposer&) = delete; }; diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index e7f41a7379..33cbc84d7d 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -29,9 +29,6 @@ class VrFlinger { void GrantDisplayOwnership(); void SeizeDisplayOwnership(); - // Called on a binder thread. - void OnHardwareComposerRefresh(); - // dump all vr flinger state. std::string Dump(); diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 56405deeaa..fcf94f0865 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -133,10 +133,6 @@ void VrFlinger::SeizeDisplayOwnership() { display_service_->SeizeDisplayOwnership(); } -void VrFlinger::OnHardwareComposerRefresh() { - display_service_->OnHardwareComposerRefresh(); -} - std::string VrFlinger::Dump() { // TODO(karthikrs): Add more state information here. return display_service_->DumpState(0/*unused*/); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fc60002334..b28c9ba4cc 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -134,9 +134,11 @@ DisplayDevice::DisplayDevice( EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { #ifdef USE_HWC2 - config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888); + config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888, + /*logConfig*/ false); #else - config = RenderEngine::chooseEglConfig(display, format); + config = RenderEngine::chooseEglConfig(display, format, + /*logConfig*/ false); #endif } eglSurface = eglCreateWindowSurface(display, config, window, NULL); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index e34fa163c4..ac739a2a05 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -219,6 +219,10 @@ void Composer::registerCallback(const sp& callback) } } +bool Composer::isRemote() { + return mClient->isRemote(); +} + void Composer::resetCommands() { mWriter.reset(); } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 96dd833cd5..533509be35 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -143,6 +143,11 @@ public: void registerCallback(const sp& callback); + // Returns true if the connected composer service is running in a remote + // process, false otherwise. This will return false if the service is + // configured in passthrough mode, for example. + bool isRemote(); + // Reset all pending commands in the command buffer. Useful if you want to // skip a frame but have already queued some commands. void resetCommands(); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 270a73228b..ae44ae0e83 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -33,45 +33,6 @@ #include #include -extern "C" { - static void hotplug_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int32_t intConnected) { - auto device = static_cast(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - auto connected = static_cast(intConnected); - device->callHotplug(std::move(display), connected); - } else { - ALOGE("Hotplug callback called with unknown display %" PRIu64, - displayId); - } - } - - static void refresh_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId) { - auto device = static_cast(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callRefresh(std::move(display)); - } else { - ALOGE("Refresh callback called with unknown display %" PRIu64, - displayId); - } - } - - static void vsync_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int64_t timestamp) { - auto device = static_cast(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callVsync(std::move(display), timestamp); - } else { - ALOGE("Vsync callback called with unknown display %" PRIu64, - displayId); - } - } -} - using android::Fence; using android::FloatRect; using android::GraphicBuffer; @@ -86,51 +47,78 @@ namespace HWC2 { namespace Hwc2 = android::Hwc2; +namespace { + +class ComposerCallbackBridge : public Hwc2::IComposerCallback { +public: + ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId) + : mCallback(callback), mSequenceId(sequenceId), + mHasPrimaryDisplay(false) {} + + Return onHotplug(Hwc2::Display display, + IComposerCallback::Connection conn) override + { + HWC2::Connection connection = static_cast(conn); + if (!mHasPrimaryDisplay) { + LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected, + "Initial onHotplug callback should be " + "primary display connected"); + mHasPrimaryDisplay = true; + mCallback->onHotplugReceived(mSequenceId, display, + connection, true); + } else { + mCallback->onHotplugReceived(mSequenceId, display, + connection, false); + } + return Void(); + } + + Return onRefresh(Hwc2::Display display) override + { + mCallback->onRefreshReceived(mSequenceId, display); + return Void(); + } + + Return onVsync(Hwc2::Display display, int64_t timestamp) override + { + mCallback->onVsyncReceived(mSequenceId, display, timestamp); + return Void(); + } + + bool HasPrimaryDisplay() { return mHasPrimaryDisplay; } + +private: + ComposerCallback* mCallback; + int32_t mSequenceId; + bool mHasPrimaryDisplay; +}; + +} // namespace anonymous + + // Device methods Device::Device(bool useVrComposer) : mComposer(std::make_unique(useVrComposer)), mCapabilities(), mDisplays(), - mHotplug(), - mPendingHotplugs(), - mRefresh(), - mPendingRefreshes(), - mVsync(), - mPendingVsyncs() + mRegisteredCallback(false) { loadCapabilities(); - registerCallbacks(); } -Device::~Device() -{ - for (auto element : mDisplays) { - auto display = element.second.lock(); - if (!display) { - ALOGE("~Device: Found a display (%" PRId64 " that has already been" - " destroyed", element.first); - continue; - } - - DisplayType displayType = HWC2::DisplayType::Invalid; - auto error = display->getType(&displayType); - if (error != Error::None) { - ALOGE("~Device: Failed to determine type of display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast(error)); - continue; - } - - if (displayType == HWC2::DisplayType::Physical) { - error = display->setVsyncEnabled(HWC2::Vsync::Disable); - if (error != Error::None) { - ALOGE("~Device: Failed to disable vsync for display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast(error)); - } - } +void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) { + if (mRegisteredCallback) { + ALOGW("Callback already registered. Ignored extra registration " + "attempt."); + return; } + mRegisteredCallback = true; + sp callbackBridge( + new ComposerCallbackBridge(callback, sequenceId)); + mComposer->registerCallback(callbackBridge); + LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(), + "Registered composer callback but didn't get primary display"); } // Required by HWC2 device @@ -146,7 +134,7 @@ uint32_t Device::getMaxVirtualDisplayCount() const } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, std::shared_ptr* outDisplay) + android_pixel_format_t* format, Display** outDisplay) { ALOGI("Creating virtual display"); @@ -159,104 +147,66 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, return error; } - ALOGI("Created virtual display"); + auto display = std::make_unique( + *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual); + *outDisplay = display.get(); *format = static_cast(intFormat); - *outDisplay = getDisplayById(displayId); - if (!*outDisplay) { - ALOGE("Failed to get display by id"); - return Error::BadDisplay; - } - (*outDisplay)->setConnected(true); + mDisplays.emplace(displayId, std::move(display)); + ALOGI("Created virtual display"); return Error::None; } -void Device::registerHotplugCallback(HotplugCallback hotplug) +void Device::destroyDisplay(hwc2_display_t displayId) { - ALOGV("registerHotplugCallback"); - mHotplug = hotplug; - for (auto& pending : mPendingHotplugs) { - auto& display = pending.first; - auto connected = pending.second; - ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(), - to_string(connected).c_str()); - mHotplug(std::move(display), connected); - } + ALOGI("Destroying display %" PRIu64, displayId); + mDisplays.erase(displayId); } -void Device::registerRefreshCallback(RefreshCallback refresh) -{ - mRefresh = refresh; - for (auto& pending : mPendingRefreshes) { - mRefresh(std::move(pending)); - } -} - -void Device::registerVsyncCallback(VsyncCallback vsync) -{ - mVsync = vsync; - for (auto& pending : mPendingVsyncs) { - auto& display = pending.first; - auto timestamp = pending.second; - mVsync(std::move(display), timestamp); - } -} - -// For use by Device callbacks +void Device::onHotplug(hwc2_display_t displayId, Connection connection) { + if (connection == Connection::Connected) { + auto display = getDisplayById(displayId); + if (display) { + if (display->isConnected()) { + ALOGW("Attempt to hotplug connect display %" PRIu64 + " , which is already connected.", displayId); + } else { + display->setConnected(true); + } + } else { + DisplayType displayType; + auto intError = mComposer->getDisplayType(displayId, + reinterpret_cast( + &displayType)); + auto error = static_cast(intError); + if (error != Error::None) { + ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). " + "Aborting hotplug attempt.", + displayId, to_string(error).c_str(), intError); + return; + } -void Device::callHotplug(std::shared_ptr display, Connection connected) -{ - if (connected == Connection::Connected) { - if (!display->isConnected()) { - mComposer->setClientTargetSlotCount(display->getId()); - display->loadConfigs(); - display->setConnected(true); + auto newDisplay = std::make_unique( + *mComposer.get(), mCapabilities, displayId, displayType); + mDisplays.emplace(displayId, std::move(newDisplay)); + } + } else if (connection == Connection::Disconnected) { + // The display will later be destroyed by a call to + // destroyDisplay(). For now we just mark it disconnected. + auto display = getDisplayById(displayId); + if (display) { + display->setConnected(false); + } else { + ALOGW("Attempted to disconnect unknown display %" PRIu64, + displayId); } - } else { - display->setConnected(false); - mDisplays.erase(display->getId()); - } - - if (mHotplug) { - mHotplug(std::move(display), connected); - } else { - ALOGV("callHotplug called, but no valid callback registered, storing"); - mPendingHotplugs.emplace_back(std::move(display), connected); - } -} - -void Device::callRefresh(std::shared_ptr display) -{ - if (mRefresh) { - mRefresh(std::move(display)); - } else { - ALOGV("callRefresh called, but no valid callback registered, storing"); - mPendingRefreshes.emplace_back(std::move(display)); - } -} - -void Device::callVsync(std::shared_ptr display, nsecs_t timestamp) -{ - if (mVsync) { - mVsync(std::move(display), timestamp); - } else { - ALOGV("callVsync called, but no valid callback registered, storing"); - mPendingVsyncs.emplace_back(std::move(display), timestamp); } } // Other Device methods -std::shared_ptr Device::getDisplayById(hwc2_display_t id) { - if (mDisplays.count(id) != 0) { - auto strongDisplay = mDisplays[id].lock(); - ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no" - " longer alive", id); - return strongDisplay; - } - - auto display = std::make_shared(*this, id); - mDisplays.emplace(id, display); - return display; +Display* Device::getDisplayById(hwc2_display_t id) { + auto iter = mDisplays.find(id); + return iter == mDisplays.end() ? nullptr : iter->second.get(); } // Device initialization methods @@ -271,84 +221,37 @@ void Device::loadCapabilities() } } -bool Device::hasCapability(HWC2::Capability capability) const -{ - return std::find(mCapabilities.cbegin(), mCapabilities.cend(), - capability) != mCapabilities.cend(); -} - -namespace { -class ComposerCallback : public Hwc2::IComposerCallback { -public: - ComposerCallback(Device* device) : mDevice(device) {} - - Return onHotplug(Hwc2::Display display, - Connection connected) override - { - hotplug_hook(mDevice, display, static_cast(connected)); - return Void(); - } - - Return onRefresh(Hwc2::Display display) override - { - refresh_hook(mDevice, display); - return Void(); - } - - Return onVsync(Hwc2::Display display, int64_t timestamp) override - { - vsync_hook(mDevice, display, timestamp); - return Void(); - } - -private: - Device* mDevice; -}; -} // namespace anonymous - -void Device::registerCallbacks() -{ - sp callback = new ComposerCallback(this); - mComposer->registerCallback(callback); -} - - -// For use by Display - -void Device::destroyVirtualDisplay(hwc2_display_t display) -{ - ALOGI("Destroying virtual display"); - auto intError = mComposer->destroyVirtualDisplay(display); - auto error = static_cast(intError); - ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:" - " %s (%d)", display, to_string(error).c_str(), intError); - mDisplays.erase(display); -} - // Display methods -Display::Display(Device& device, hwc2_display_t id) - : mDevice(device), +Display::Display(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t id, DisplayType type) + : mComposer(composer), + mCapabilities(capabilities), mId(id), mIsConnected(false), - mType(DisplayType::Invalid) + mType(type) { ALOGV("Created display %" PRIu64, id); - - auto intError = mDevice.mComposer->getDisplayType(mId, - reinterpret_cast(&mType)); - auto error = static_cast(intError); - if (error != Error::None) { - ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)", - id, to_string(error).c_str(), intError); - } + setConnected(true); } -Display::~Display() -{ - ALOGV("Destroyed display %" PRIu64, mId); +Display::~Display() { + mLayers.clear(); + if (mType == DisplayType::Virtual) { - mDevice.destroyVirtualDisplay(mId); + ALOGV("Destroying virtual display"); + auto intError = mComposer.destroyVirtualDisplay(mId); + auto error = static_cast(intError); + ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 + ") failed: %s (%d)", mId, to_string(error).c_str(), intError); + } else if (mType == DisplayType::Physical) { + auto error = setVsyncEnabled(HWC2::Vsync::Disable); + if (error != Error::None) { + ALOGE("~Display: Failed to disable vsync for display %" PRIu64 + ": %s (%d)", mId, to_string(error).c_str(), + static_cast(error)); + } } } @@ -383,22 +286,35 @@ float Display::Config::Builder::getDefaultDensity() { Error Display::acceptChanges() { - auto intError = mDevice.mComposer->acceptDisplayChanges(mId); + auto intError = mComposer.acceptDisplayChanges(mId); return static_cast(intError); } -Error Display::createLayer(std::shared_ptr* outLayer) +Error Display::createLayer(Layer** outLayer) { + if (!outLayer) { + return Error::BadParameter; + } hwc2_layer_t layerId = 0; - auto intError = mDevice.mComposer->createLayer(mId, &layerId); + auto intError = mComposer.createLayer(mId, &layerId); auto error = static_cast(intError); if (error != Error::None) { return error; } - auto layer = std::make_shared(shared_from_this(), layerId); - mLayers.emplace(layerId, layer); - *outLayer = std::move(layer); + auto layer = std::make_unique( + mComposer, mCapabilities, mId, layerId); + *outLayer = layer.get(); + mLayers.emplace(layerId, std::move(layer)); + return Error::None; +} + +Error Display::destroyLayer(Layer* layer) +{ + if (!layer) { + return Error::BadParameter; + } + mLayers.erase(layer->getId()); return Error::None; } @@ -407,7 +323,7 @@ Error Display::getActiveConfig( { ALOGV("[%" PRIu64 "] getActiveConfig", mId); hwc2_config_t configId = 0; - auto intError = mDevice.mComposer->getActiveConfig(mId, &configId); + auto intError = mComposer.getActiveConfig(mId, &configId); auto error = static_cast(intError); if (error != Error::None) { @@ -430,12 +346,12 @@ Error Display::getActiveConfig( } Error Display::getChangedCompositionTypes( - std::unordered_map, Composition>* outTypes) + std::unordered_map* outTypes) { std::vector layerIds; std::vector types; - auto intError = mDevice.mComposer->getChangedCompositionTypes(mId, - &layerIds, &types); + auto intError = mComposer.getChangedCompositionTypes( + mId, &layerIds, &types); uint32_t numElements = layerIds.size(); auto error = static_cast(intError); error = static_cast(intError); @@ -464,7 +380,7 @@ Error Display::getChangedCompositionTypes( Error Display::getColorModes(std::vector* outModes) const { std::vector modes; - auto intError = mDevice.mComposer->getColorModes(mId, &modes); + auto intError = mComposer.getColorModes(mId, &modes); uint32_t numModes = modes.size(); auto error = static_cast(intError); if (error != Error::None) { @@ -489,19 +405,18 @@ std::vector> Display::getConfigs() const Error Display::getName(std::string* outName) const { - auto intError = mDevice.mComposer->getDisplayName(mId, outName); + auto intError = mComposer.getDisplayName(mId, outName); return static_cast(intError); } Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, - std::unordered_map, LayerRequest>* - outLayerRequests) + std::unordered_map* outLayerRequests) { uint32_t intDisplayRequests; std::vector layerIds; std::vector layerRequests; - auto intError = mDevice.mComposer->getDisplayRequests(mId, - &intDisplayRequests, &layerIds, &layerRequests); + auto intError = mComposer.getDisplayRequests( + mId, &intDisplayRequests, &layerIds, &layerRequests); uint32_t numElements = layerIds.size(); auto error = static_cast(intError); if (error != Error::None) { @@ -535,7 +450,7 @@ Error Display::getType(DisplayType* outType) const Error Display::supportsDoze(bool* outSupport) const { bool intSupport = false; - auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport); + auto intError = mComposer.getDozeSupport(mId, &intSupport); auto error = static_cast(intError); if (error != Error::None) { return error; @@ -552,7 +467,7 @@ Error Display::getHdrCapabilities( float maxAverageLuminance = -1.0f; float minLuminance = -1.0f; std::vector intTypes; - auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes, + auto intError = mComposer.getHdrCapabilities(mId, &intTypes, &maxLuminance, &maxAverageLuminance, &minLuminance); auto error = static_cast(intError); @@ -571,25 +486,24 @@ Error Display::getHdrCapabilities( } Error Display::getReleaseFences( - std::unordered_map, sp>* outFences) const + std::unordered_map>* outFences) const { std::vector layerIds; std::vector fenceFds; - auto intError = mDevice.mComposer->getReleaseFences(mId, - &layerIds, &fenceFds); + auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds); auto error = static_cast(intError); uint32_t numElements = layerIds.size(); if (error != Error::None) { return error; } - std::unordered_map, sp> releaseFences; + std::unordered_map> releaseFences; releaseFences.reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { sp fence(new Fence(fenceFds[element])); - releaseFences.emplace(std::move(layer), fence); + releaseFences.emplace(layer, fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); @@ -607,7 +521,7 @@ Error Display::getReleaseFences( Error Display::present(sp* outPresentFence) { int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd); + auto intError = mComposer.presentDisplay(mId, &presentFenceFd); auto error = static_cast(intError); if (error != Error::None) { return error; @@ -625,7 +539,7 @@ Error Display::setActiveConfig(const std::shared_ptr& config) config->getDisplayId(), mId); return Error::BadConfig; } - auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId()); + auto intError = mComposer.setActiveConfig(mId, config->getId()); return static_cast(intError); } @@ -634,7 +548,7 @@ Error Display::setClientTarget(uint32_t slot, const sp& target, { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setClientTarget(mId, slot, target, + auto intError = mComposer.setClientTarget(mId, slot, target, fenceFd, static_cast(dataspace), std::vector()); return static_cast(intError); @@ -642,15 +556,15 @@ Error Display::setClientTarget(uint32_t slot, const sp& target, Error Display::setColorMode(android_color_mode_t mode) { - auto intError = mDevice.mComposer->setColorMode(mId, - static_cast(mode)); + auto intError = mComposer.setColorMode( + mId, static_cast(mode)); return static_cast(intError); } Error Display::setColorTransform(const android::mat4& matrix, android_color_transform_t hint) { - auto intError = mDevice.mComposer->setColorTransform(mId, + auto intError = mComposer.setColorTransform(mId, matrix.asArray(), static_cast(hint)); return static_cast(intError); } @@ -660,7 +574,7 @@ Error Display::setOutputBuffer(const sp& buffer, { int32_t fenceFd = releaseFence->dup(); auto handle = buffer->getNativeBuffer()->handle; - auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd); + auto intError = mComposer.setOutputBuffer(mId, handle, fenceFd); close(fenceFd); return static_cast(intError); } @@ -668,14 +582,14 @@ Error Display::setOutputBuffer(const sp& buffer, Error Display::setPowerMode(PowerMode mode) { auto intMode = static_cast(mode); - auto intError = mDevice.mComposer->setPowerMode(mId, intMode); + auto intError = mComposer.setPowerMode(mId, intMode); return static_cast(intError); } Error Display::setVsyncEnabled(Vsync enabled) { auto intEnabled = static_cast(enabled); - auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled); + auto intError = mComposer.setVsyncEnabled(mId, intEnabled); return static_cast(intError); } @@ -683,8 +597,7 @@ Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { uint32_t numTypes = 0; uint32_t numRequests = 0; - auto intError = mDevice.mComposer->validateDisplay(mId, - &numTypes, &numRequests); + auto intError = mComposer.validateDisplay(mId, &numTypes, &numRequests); auto error = static_cast(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -701,7 +614,8 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests uint32_t numTypes = 0; uint32_t numRequests = 0; int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentOrValidateDisplay(mId, &numTypes, &numRequests, &presentFenceFd, state); + auto intError = mComposer.presentOrValidateDisplay( + mId, &numTypes, &numRequests, &presentFenceFd, state); auto error = static_cast(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -720,15 +634,23 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests void Display::discardCommands() { - mDevice.mComposer->resetCommands(); + mComposer.resetCommands(); } // For use by Device +void Display::setConnected(bool connected) { + if (!mIsConnected && connected && mType == DisplayType::Physical) { + mComposer.setClientTargetSlotCount(mId); + loadConfigs(); + } + mIsConnected = connected; +} + int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute) { int32_t value = 0; - auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId, + auto intError = mComposer.getDisplayAttribute(mId, configId, static_cast(attribute), &value); auto error = static_cast(intError); @@ -760,7 +682,7 @@ void Display::loadConfigs() ALOGV("[%" PRIu64 "] loadConfigs", mId); std::vector configIds; - auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds); + auto intError = mComposer.getDisplayConfigs(mId, &configIds); auto error = static_cast(intError); if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId, @@ -773,54 +695,51 @@ void Display::loadConfigs() } } -// For use by Layer - -void Display::destroyLayer(hwc2_layer_t layerId) -{ - auto intError =mDevice.mComposer->destroyLayer(mId, layerId); - auto error = static_cast(intError); - ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" - " failed: %s (%d)", mId, layerId, to_string(error).c_str(), - intError); - mLayers.erase(layerId); -} - // Other Display methods -std::shared_ptr Display::getLayerById(hwc2_layer_t id) const +Layer* Display::getLayerById(hwc2_layer_t id) const { if (mLayers.count(id) == 0) { return nullptr; } - auto layer = mLayers.at(id).lock(); - return layer; + return mLayers.at(id).get(); } // Layer methods -Layer::Layer(const std::shared_ptr& display, hwc2_layer_t id) - : mDisplay(display), - mDisplayId(display->getId()), - mDevice(display->getDevice()), - mId(id) +Layer::Layer(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId) + : mComposer(composer), + mCapabilities(capabilities), + mDisplayId(displayId), + mId(layerId) { - ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id, - display->getId()); + ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId); } Layer::~Layer() { - auto display = mDisplay.lock(); - if (display) { - display->destroyLayer(mId); + auto intError = mComposer.destroyLayer(mDisplayId, mId); + auto error = static_cast(intError); + ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" + " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(), + intError); + if (mLayerDestroyedListener) { + mLayerDestroyedListener(this); } } +void Layer::setLayerDestroyedListener(std::function listener) { + LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener, + "Attempt to set layer destroyed listener multiple times"); + mLayerDestroyedListener = listener; +} + Error Layer::setCursorPosition(int32_t x, int32_t y) { - auto intError = mDevice.mComposer->setCursorPosition(mDisplayId, - mId, x, y); + auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y); return static_cast(intError); } @@ -828,8 +747,8 @@ Error Layer::setBuffer(uint32_t slot, const sp& buffer, const sp& acquireFence) { int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId, - mId, slot, buffer, fenceFd); + auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer, + fenceFd); return static_cast(intError); } @@ -839,7 +758,7 @@ Error Layer::setSurfaceDamage(const Region& damage) // rects for HWC Hwc2::Error intError = Hwc2::Error::NONE; if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, std::vector()); } else { size_t rectCount = 0; @@ -851,8 +770,7 @@ Error Layer::setSurfaceDamage(const Region& damage) rectArray[rect].right, rectArray[rect].bottom}); } - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, - mId, hwcRects); + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects); } return static_cast(intError); @@ -861,24 +779,22 @@ Error Layer::setSurfaceDamage(const Region& damage) Error Layer::setBlendMode(BlendMode mode) { auto intMode = static_cast(mode); - auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId, - mId, intMode); + auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, intMode); return static_cast(intError); } Error Layer::setColor(hwc_color_t color) { Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a}; - auto intError = mDevice.mComposer->setLayerColor(mDisplayId, - mId, hwcColor); + auto intError = mComposer.setLayerColor(mDisplayId, mId, hwcColor); return static_cast(intError); } Error Layer::setCompositionType(Composition type) { auto intType = static_cast(type); - auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId, - mId, intType); + auto intError = mComposer.setLayerCompositionType( + mDisplayId, mId, intType); return static_cast(intError); } @@ -889,8 +805,7 @@ Error Layer::setDataspace(android_dataspace_t dataspace) } mDataSpace = dataspace; auto intDataspace = static_cast(dataspace); - auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId, - mId, intDataspace); + auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace); return static_cast(intError); } @@ -898,27 +813,24 @@ Error Layer::setDisplayFrame(const Rect& frame) { Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top, frame.right, frame.bottom}; - auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect); return static_cast(intError); } Error Layer::setPlaneAlpha(float alpha) { - auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId, - mId, alpha); + auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha); return static_cast(intError); } Error Layer::setSidebandStream(const native_handle_t* stream) { - if (!mDevice.hasCapability(Capability::SidebandStream)) { + if (mCapabilities.count(Capability::SidebandStream) == 0) { ALOGE("Attempted to call setSidebandStream without checking that the " "device supports sideband streams"); return Error::Unsupported; } - auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId, - mId, stream); + auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream); return static_cast(intError); } @@ -926,16 +838,14 @@ Error Layer::setSourceCrop(const FloatRect& crop) { Hwc2::IComposerClient::FRect hwcRect{ crop.left, crop.top, crop.right, crop.bottom}; - auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect); return static_cast(intError); } Error Layer::setTransform(Transform transform) { auto intTransform = static_cast(transform); - auto intError = mDevice.mComposer->setLayerTransform(mDisplayId, - mId, intTransform); + auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform); return static_cast(intError); } @@ -950,20 +860,19 @@ Error Layer::setVisibleRegion(const Region& region) rectArray[rect].right, rectArray[rect].bottom}); } - auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId, - mId, hwcRects); + auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects); return static_cast(intError); } Error Layer::setZOrder(uint32_t z) { - auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z); + auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z); return static_cast(intError); } Error Layer::setInfo(uint32_t type, uint32_t appId) { - auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId); + auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId); return static_cast(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 404bb284c5..949f0e3f82 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -53,10 +53,26 @@ namespace HWC2 { class Display; class Layer; -typedef std::function, Connection)> - HotplugCallback; -typedef std::function)> RefreshCallback; -typedef std::function, nsecs_t)> VsyncCallback; +// Implement this interface to receive hardware composer events. +// +// These callback functions will generally be called on a hwbinder thread, but +// when first registering the callback the onHotplugReceived() function will +// immediately be called on the thread calling registerCallback(). +// +// All calls receive a sequenceId, which will be the value that was supplied to +// HWC2::Device::registerCallback(). It's used to help differentiate callbacks +// from different hardware composer instances. +class ComposerCallback { + public: + virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + Connection connection, + bool primaryDisplay) = 0; + virtual void onRefreshReceived(int32_t sequenceId, + hwc2_display_t display) = 0; + virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) = 0; + virtual ~ComposerCallback() = default; +}; // C++ Wrapper around hwc2_device_t. Load all functions pointers // and handle callback registration. @@ -67,10 +83,8 @@ public: // will use the vr composer service, otherwise it uses the real hardware // composer. Device(bool useVrComposer); - ~Device(); - friend class HWC2::Display; - friend class HWC2::Layer; + void registerCallback(ComposerCallback* callback, int32_t sequenceId); // Required by HWC2 @@ -82,27 +96,14 @@ public: uint32_t getMaxVirtualDisplayCount() const; Error createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, - std::shared_ptr* outDisplay); - - void registerHotplugCallback(HotplugCallback hotplug); - void registerRefreshCallback(RefreshCallback refresh); - void registerVsyncCallback(VsyncCallback vsync); + android_pixel_format_t* format, Display** outDisplay); + void destroyDisplay(hwc2_display_t displayId); - // For use by callbacks - - void callHotplug(std::shared_ptr display, Connection connected); - void callRefresh(std::shared_ptr display); - void callVsync(std::shared_ptr display, nsecs_t timestamp); + void onHotplug(hwc2_display_t displayId, Connection connection); // Other Device methods - // This will create a Display if one is not found, but it will not be marked - // as connected. This Display may be null if the display has been torn down - // but has not been removed from the map yet. - std::shared_ptr getDisplayById(hwc2_display_t id); - - bool hasCapability(HWC2::Capability capability) const; + Display* getDisplayById(hwc2_display_t id); android::Hwc2::Composer* getComposer() { return mComposer.get(); } @@ -110,37 +111,23 @@ private: // Initialization methods void loadCapabilities(); - void registerCallbacks(); - - // For use by Display - - void destroyVirtualDisplay(hwc2_display_t display); // Member variables std::unique_ptr mComposer; - std::unordered_set mCapabilities; - std::unordered_map> mDisplays; - - HotplugCallback mHotplug; - std::vector, Connection>> - mPendingHotplugs; - RefreshCallback mRefresh; - std::vector> mPendingRefreshes; - VsyncCallback mVsync; - std::vector, nsecs_t>> mPendingVsyncs; + std::unordered_map> mDisplays; + bool mRegisteredCallback; }; // Convenience C++ class to access hwc2_device_t Display functions directly. -class Display : public std::enable_shared_from_this +class Display { public: - Display(Device& device, hwc2_display_t id); + Display(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t id, DisplayType type); ~Display(); - friend class HWC2::Device; - friend class HWC2::Layer; - class Config { public: @@ -213,12 +200,12 @@ public: // Required by HWC2 [[clang::warn_unused_result]] Error acceptChanges(); - [[clang::warn_unused_result]] Error createLayer( - std::shared_ptr* outLayer); + [[clang::warn_unused_result]] Error createLayer(Layer** outLayer); + [[clang::warn_unused_result]] Error destroyLayer(Layer* layer); [[clang::warn_unused_result]] Error getActiveConfig( std::shared_ptr* outConfig) const; [[clang::warn_unused_result]] Error getChangedCompositionTypes( - std::unordered_map, Composition>* outTypes); + std::unordered_map* outTypes); [[clang::warn_unused_result]] Error getColorModes( std::vector* outModes) const; @@ -228,14 +215,13 @@ public: [[clang::warn_unused_result]] Error getName(std::string* outName) const; [[clang::warn_unused_result]] Error getRequests( DisplayRequest* outDisplayRequests, - std::unordered_map, LayerRequest>* - outLayerRequests); + std::unordered_map* outLayerRequests); [[clang::warn_unused_result]] Error getType(DisplayType* outType) const; [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const; [[clang::warn_unused_result]] Error getHdrCapabilities( std::unique_ptr* outCapabilities) const; [[clang::warn_unused_result]] Error getReleaseFences( - std::unordered_map, + std::unordered_map>* outFences) const; [[clang::warn_unused_result]] Error present( android::sp* outPresentFence); @@ -267,32 +253,31 @@ public: // Other Display methods - Device& getDevice() const { return mDevice; } hwc2_display_t getId() const { return mId; } bool isConnected() const { return mIsConnected; } + void setConnected(bool connected); // For use by Device only private: - // For use by Device - - void setConnected(bool connected) { mIsConnected = connected; } int32_t getAttribute(hwc2_config_t configId, Attribute attribute); void loadConfig(hwc2_config_t configId); void loadConfigs(); - // For use by Layer - void destroyLayer(hwc2_layer_t layerId); - // This may fail (and return a null pointer) if no layer with this ID exists // on this display - std::shared_ptr getLayerById(hwc2_layer_t id) const; + Layer* getLayerById(hwc2_layer_t id) const; // Member variables - Device& mDevice; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Display, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set& mCapabilities; + hwc2_display_t mId; bool mIsConnected; DisplayType mType; - std::unordered_map> mLayers; + std::unordered_map> mLayers; // The ordering in this map matters, for getConfigs(), when it is // converted to a vector std::map> mConfigs; @@ -302,12 +287,18 @@ private: class Layer { public: - Layer(const std::shared_ptr& display, hwc2_layer_t id); + Layer(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId); ~Layer(); - bool isAbandoned() const { return mDisplay.expired(); } hwc2_layer_t getId() const { return mId; } + // Register a listener to be notified when the layer is destroyed. When the + // listener function is called, the Layer will be in the process of being + // destroyed, so it's not safe to call methods on it. + void setLayerDestroyedListener(std::function listener); + [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y); [[clang::warn_unused_result]] Error setBuffer(uint32_t slot, const android::sp& buffer, @@ -334,11 +325,16 @@ public: [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId); private: - std::weak_ptr mDisplay; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Layer, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set& mCapabilities; + hwc2_display_t mDisplayId; - Device& mDevice; hwc2_layer_t mId; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + std::function mLayerDestroyedListener; }; } // namespace HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index ac2dde29d4..3f3c67b1e6 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -65,7 +65,6 @@ HWComposer::HWComposer(bool useVrComposer) mFreeDisplaySlots(), mHwcDisplaySlots(), mCBContext(), - mEventHandler(nullptr), mVSyncCounts(), mRemainingHwcVirtualDisplays(0) { @@ -74,40 +73,15 @@ HWComposer::HWComposer(bool useVrComposer) mVSyncCounts[i] = 0; } - loadHwcModule(useVrComposer); + mHwcDevice = std::make_unique(useVrComposer); + mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } HWComposer::~HWComposer() {} -void HWComposer::setEventHandler(EventHandler* handler) -{ - if (handler == nullptr) { - ALOGE("setEventHandler: Rejected attempt to clear handler"); - return; - } - - bool wasNull = (mEventHandler == nullptr); - mEventHandler = handler; - - if (wasNull) { - auto hotplugHook = std::bind(&HWComposer::hotplug, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerHotplugCallback(hotplugHook); - auto invalidateHook = std::bind(&HWComposer::invalidate, this, - std::placeholders::_1); - mHwcDevice->registerRefreshCallback(invalidateHook); - auto vsyncHook = std::bind(&HWComposer::vsync, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerVsyncCallback(vsyncHook); - } -} - -// Load and prepare the hardware composer module. Sets mHwc. -void HWComposer::loadHwcModule(bool useVrComposer) -{ - ALOGV("loadHwcModule"); - mHwcDevice = std::make_unique(useVrComposer); - mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); +void HWComposer::registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId) { + mHwcDevice->registerCallback(callback, sequenceId); } bool HWComposer::hasCapability(HWC2::Capability capability) const @@ -145,54 +119,51 @@ void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { } } -void HWComposer::hotplug(const std::shared_ptr& display, - HWC2::Connection connected) { - ALOGV("hotplug: %" PRIu64 ", %s", display->getId(), - to_string(connected).c_str()); - int32_t disp = 0; +void HWComposer::onHotplug(hwc2_display_t displayId, + HWC2::Connection connection) { + ALOGV("hotplug: %" PRIu64 ", %s", displayId, + to_string(connection).c_str()); + mHwcDevice->onHotplug(displayId, connection); if (!mDisplayData[0].hwcDisplay) { - ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary" + ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary" " display would be connected"); - mDisplayData[0].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 0; - disp = DisplayDevice::DISPLAY_PRIMARY; + mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 0; } else { // Disconnect is handled through HWComposer::disconnectDisplay via // SurfaceFlinger's onHotplugReceived callback handling - if (connected == HWC2::Connection::Connected) { - mDisplayData[1].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 1; + if (connection == HWC2::Connection::Connected) { + mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 1; } - disp = DisplayDevice::DISPLAY_EXTERNAL; } - mEventHandler->onHotplugReceived(this, disp, - connected == HWC2::Connection::Connected); } -void HWComposer::invalidate(const std::shared_ptr& /*display*/) { - mEventHandler->onInvalidateReceived(this); -} - -void HWComposer::vsync(const std::shared_ptr& display, - int64_t timestamp) { +bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay) { + auto display = mHwcDevice->getDisplayById(displayId); + if (!display) { + ALOGE("onVsync Failed to find display %" PRIu64, displayId); + return false; + } auto displayType = HWC2::DisplayType::Invalid; auto error = display->getType(&displayType); if (error != HWC2::Error::None) { - ALOGE("vsync: Failed to determine type of display %" PRIu64, + ALOGE("onVsync: Failed to determine type of display %" PRIu64, display->getId()); - return; + return false; } if (displayType == HWC2::DisplayType::Virtual) { ALOGE("Virtual display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } if (mHwcDisplaySlots.count(display->getId()) == 0) { ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } int32_t disp = mHwcDisplaySlots[display->getId()]; @@ -206,17 +177,21 @@ void HWComposer::vsync(const std::shared_ptr& display, if (timestamp == mLastHwVSync[disp]) { ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", timestamp); - return; + return false; } mLastHwVSync[disp] = timestamp; } + if (outDisplay) { + *outDisplay = disp; + } + char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); - mEventHandler->onVSyncReceived(this, disp, timestamp); + return true; } status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, @@ -235,7 +210,7 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return INVALID_OPERATION; } - std::shared_ptr display; + HWC2::Display* display; auto error = mHwcDevice->createVirtualDisplay(width, height, format, &display); if (error != HWC2::Error::None) { @@ -264,13 +239,13 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return NO_ERROR; } -std::shared_ptr HWComposer::createLayer(int32_t displayId) { +HWC2::Layer* HWComposer::createLayer(int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("Failed to create layer on invalid display %d", displayId); return nullptr; } auto display = mDisplayData[displayId].hwcDisplay; - std::shared_ptr layer; + HWC2::Layer* layer; auto error = display->createLayer(&layer); if (error != HWC2::Error::None) { ALOGE("Failed to create layer on display %d: %s (%d)", displayId, @@ -280,6 +255,19 @@ std::shared_ptr HWComposer::createLayer(int32_t displayId) { return layer; } +void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) { + if (!isValidDisplay(displayId)) { + ALOGE("Failed to destroy layer on invalid display %d", displayId); + return; + } + auto display = mDisplayData[displayId].hwcDisplay; + auto error = display->destroyLayer(layer); + if (error != HWC2::Error::None) { + ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId, + to_string(error).c_str(), static_cast(error)); + } +} + nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const { // this returns the last refresh timestamp. // if the last one is not available, we estimate it based on @@ -347,10 +335,8 @@ std::vector HWComposer::getColorModes(int32_t displayId) c displayId); return modes; } - const std::shared_ptr& hwcDisplay = - mDisplayData[displayId].hwcDisplay; - auto error = hwcDisplay->getColorModes(&modes); + auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes); if (error != HWC2::Error::None) { ALOGE("getColorModes failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); @@ -470,7 +456,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return UNKNOWN_ERROR; } if (state == 1) { //Present Succeeded. - std::unordered_map, sp> releaseFences; + std::unordered_map> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); displayData.releaseFences = std::move(releaseFences); displayData.lastPresentFence = outPresentFence; @@ -489,8 +475,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return BAD_INDEX; } - std::unordered_map, HWC2::Composition> - changedTypes; + std::unordered_map changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); if (error != HWC2::Error::None) { @@ -502,8 +487,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { displayData.displayRequests = static_cast(0); - std::unordered_map, HWC2::LayerRequest> - layerRequests; + std::unordered_map layerRequests; layerRequests.reserve(numRequests); error = hwcDisplay->getRequests(&displayData.displayRequests, &layerRequests); @@ -597,7 +581,7 @@ sp HWComposer::getPresentFence(int32_t displayId) const { } sp HWComposer::getLayerReleaseFence(int32_t displayId, - const std::shared_ptr& layer) const { + HWC2::Layer* layer) const { if (!isValidDisplay(displayId)) { ALOGE("getLayerReleaseFence: Invalid display"); return Fence::NO_FENCE; @@ -638,7 +622,7 @@ status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) { return UNKNOWN_ERROR; } - std::unordered_map, sp> releaseFences; + std::unordered_map> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); if (error != HWC2::Error::None) { ALOGE("presentAndGetReleaseFences: Failed to get release fences " @@ -786,6 +770,8 @@ void HWComposer::disconnectDisplay(int displayId) { auto hwcId = displayData.hwcDisplay->getId(); mHwcDisplaySlots.erase(hwcId); displayData.reset(); + + mHwcDevice->destroyDisplay(hwcId); } status_t HWComposer::setOutputBuffer(int32_t displayId, @@ -884,7 +870,7 @@ void HWComposer::dump(String8& result) const { HWComposer::DisplayData::DisplayData() : hasClientComposition(false), hasDeviceComposition(false), - hwcDisplay(), + hwcDisplay(nullptr), lastPresentFence(Fence::NO_FENCE), outbufHandle(nullptr), outbufAcquireFence(Fence::NO_FENCE), diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 7463362c35..e25dee1de3 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -65,16 +65,6 @@ class String8; class HWComposer { public: - class EventHandler { - friend class HWComposer; - virtual void onVSyncReceived( - HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0; - virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0; - virtual void onInvalidateReceived(HWComposer* composer) = 0; - protected: - virtual ~EventHandler() {} - }; - // useVrComposer is passed to the composer HAL. When true, the composer HAL // will use the vr composer service, otherwise it uses the real hardware // composer. @@ -82,7 +72,8 @@ public: ~HWComposer(); - void setEventHandler(EventHandler* handler); + void registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId); bool hasCapability(HWC2::Capability capability) const; @@ -92,7 +83,9 @@ public: android_pixel_format_t* format, int32_t* outId); // Attempts to create a new layer on this display - std::shared_ptr createLayer(int32_t displayId); + HWC2::Layer* createLayer(int32_t displayId); + // Destroy a previously created layer + void destroyLayer(int32_t displayId, HWC2::Layer* layer); // Asks the HAL what it can do status_t prepare(DisplayDevice& displayDevice); @@ -127,7 +120,7 @@ public: // Get last release fence for the given layer sp getLayerReleaseFence(int32_t displayId, - const std::shared_ptr& layer) const; + HWC2::Layer* layer) const; // Set the output buffer and acquire fence for a virtual display. // Returns INVALID_OPERATION if displayId is not a virtual display. @@ -143,6 +136,12 @@ public: // Events handling --------------------------------------------------------- + // Returns true if successful, false otherwise. The + // DisplayDevice::DisplayType of the display is returned as an output param. + bool onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay); + void onHotplug(hwc2_display_t displayId, HWC2::Connection connection); + void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled); // Query display parameters. Pass in a display index (e.g. @@ -170,19 +169,11 @@ public: private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; - void loadHwcModule(bool useVrComposer); - bool isValidDisplay(int32_t displayId) const; static void validateChange(HWC2::Composition from, HWC2::Composition to); struct cb_context; - void invalidate(const std::shared_ptr& display); - void vsync(const std::shared_ptr& display, - int64_t timestamp); - void hotplug(const std::shared_ptr& display, - HWC2::Connection connected); - struct DisplayData { DisplayData(); ~DisplayData(); @@ -190,11 +181,10 @@ private: bool hasClientComposition; bool hasDeviceComposition; - std::shared_ptr hwcDisplay; + HWC2::Display* hwcDisplay; HWC2::DisplayRequest displayRequests; sp lastPresentFence; // signals when the last set op retires - std::unordered_map, sp> - releaseFences; + std::unordered_map> releaseFences; buffer_handle_t outbufHandle; sp outbufAcquireFence; mutable std::unordered_mapsetVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); -#else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, - mVsyncEnabled); -#endif + enum class VsyncState {Unset, On, Off}; + auto currentVsyncState = VsyncState::Unset; while (true) { - status_t err = mCond.wait(mMutex); - if (err != NO_ERROR) { - ALOGE("error waiting for new events: %s (%d)", - strerror(-err), err); - return false; + auto requestedVsyncState = VsyncState::On; + { + Mutex::Autolock lock(mMutex); + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + while (currentVsyncState == requestedVsyncState) { + status_t err = mCond.wait(mMutex); + if (err != NO_ERROR) { + ALOGE("error waiting for new events: %s (%d)", + strerror(-err), err); + return false; + } + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + } } - if (vsyncEnabled != mVsyncEnabled) { + bool enable = requestedVsyncState == VsyncState::On; #ifdef USE_HWC2 - mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); + mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable); #else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, - SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, + SurfaceFlinger::EVENT_VSYNC, enable); #endif - vsyncEnabled = mVsyncEnabled; - } + currentVsyncState = requestedVsyncState; } return false; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b14fd7bb87..4edde14069 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -200,6 +200,12 @@ Layer::~Layer() { } mFlinger->deleteTextureAsync(mTextureName); mFrameTracker.logAndResetStats(mName); + +#ifdef USE_HWC2 + ALOGE_IF(!mHwcLayers.empty(), + "Found stale hardware composer layers when destroying " + "surface flinger layer"); +#endif } // --------------------------------------------------------------------------- @@ -302,7 +308,7 @@ void Layer::onRemoved() { mSurfaceFlingerConsumer->abandon(); #ifdef USE_HWC2 - clearHwcLayers(); + destroyAllHwcLayers(); #endif for (const auto& child : mCurrentChildren) { @@ -363,6 +369,48 @@ sp Layer::getProducer() const { // h/w composer set-up // --------------------------------------------------------------------------- +#ifdef USE_HWC2 +bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Already have a layer for hwcId %d", hwcId); + HWC2::Layer* layer = hwc->createLayer(hwcId); + if (!layer) { + return false; + } + HWCInfo& hwcInfo = mHwcLayers[hwcId]; + hwcInfo.hwc = hwc; + hwcInfo.layer = layer; + layer->setLayerDestroyedListener( + [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);}); + return true; +} + +void Layer::destroyHwcLayer(int32_t hwcId) { + if (mHwcLayers.count(hwcId) == 0) { + return; + } + auto& hwcInfo = mHwcLayers[hwcId]; + LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, + "Attempt to destroy null layer"); + LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer"); + hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer); + // The layer destroyed listener should have cleared the entry from + // mHwcLayers. Verify that. + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Stale layer entry in mHwcLayers"); +} + +void Layer::destroyAllHwcLayers() { + size_t numLayers = mHwcLayers.size(); + for (size_t i = 0; i < numLayers; ++i) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed"); + destroyHwcLayer(mHwcLayers.begin()->first); + } + LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(), + "All hardware composer layers should have been destroyed"); +} +#endif + Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2306d1a43a..222718bcda 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -444,37 +444,21 @@ public: #ifdef USE_HWC2 // ----------------------------------------------------------------------- + bool createHwcLayer(HWComposer* hwc, int32_t hwcId); + void destroyHwcLayer(int32_t hwcId); + void destroyAllHwcLayers(); + bool hasHwcLayer(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { - return false; - } - if (mHwcLayers[hwcId].layer->isAbandoned()) { - ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId); - mHwcLayers.erase(hwcId); - return false; - } - return true; + return mHwcLayers.count(hwcId) > 0; } - std::shared_ptr getHwcLayer(int32_t hwcId) { + HWC2::Layer* getHwcLayer(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { return nullptr; } return mHwcLayers[hwcId].layer; } - void setHwcLayer(int32_t hwcId, std::shared_ptr&& layer) { - if (layer) { - mHwcLayers[hwcId].layer = layer; - } else { - mHwcLayers.erase(hwcId); - } - } - - void clearHwcLayers() { - mHwcLayers.clear(); - } - #endif // ----------------------------------------------------------------------- @@ -760,12 +744,14 @@ private: // HWC items, accessed from the main thread struct HWCInfo { HWCInfo() - : layer(), + : hwc(nullptr), + layer(nullptr), forceClientComposition(false), compositionType(HWC2::Composition::Invalid), clearClientTarget(false) {} - std::shared_ptr layer; + HWComposer* hwc; + HWC2::Layer* layer; bool forceClientComposition; HWC2::Composition compositionType; bool clearClientTarget; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index ac2d8b2aba..57f468d2fa 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -64,7 +64,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f "EGL_ANDROIDX_no_config_context") && !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), "EGL_KHR_no_config_context")) { - config = chooseEglConfig(display, hwcFormat); + config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint renderableType = 0; @@ -108,7 +108,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f EGLConfig dummyConfig = config; if (dummyConfig == EGL_NO_CONFIG) { - dummyConfig = chooseEglConfig(display, hwcFormat); + dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); @@ -406,7 +406,8 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, return err; } -EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { +EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, + bool logConfig) { status_t err; EGLConfig config; @@ -427,18 +428,20 @@ EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { } } - // print some debugging info - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - ALOGI("EGL information:"); - ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); - ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); - ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + if (logConfig) { + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + } return config; } diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 56f582755e..954457946e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -64,7 +64,7 @@ public: }; static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags); - static EGLConfig chooseEglConfig(EGLDisplay display, int format); + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); void primeCache() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6ae217f3c1..ba0af5f876 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -76,6 +76,7 @@ #include "MonitoredProducer.h" #include "SurfaceFlinger.h" +#include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" @@ -100,10 +101,24 @@ EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint na namespace android { - using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +namespace { +class ConditionalLock { +public: + ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) { + if (lock) { + mMutex.lock(); + } + } + ~ConditionalLock() { if (mLocked) mMutex.unlock(); } +private: + Mutex& mMutex; + bool mLocked; +}; +} // namespace anonymous + // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); @@ -131,9 +146,6 @@ SurfaceFlinger::SurfaceFlinger() mLayersRemoved(false), mLayersAdded(false), mRepaintEverything(0), - mHwc(nullptr), - mRealHwc(nullptr), - mVrHwc(nullptr), mRenderEngine(nullptr), mBootTime(systemTime()), mBuiltinDisplays(), @@ -160,7 +172,9 @@ SurfaceFlinger::SurfaceFlinger() mTotalTime(0), mLastSwapTime(0), mNumLayers(0), - mVrFlingerRequestsDisplay(false) + mVrFlingerRequestsDisplay(false), + mMainThreadId(std::this_thread::get_id()), + mComposerSequenceId(0) { ALOGI("SurfaceFlinger is starting"); @@ -557,48 +571,46 @@ void SurfaceFlinger::init() { ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs); - { // Autolock scope - Mutex::Autolock _l(mStateLock); + Mutex::Autolock _l(mStateLock); - // initialize EGL for the default display - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mEGLDisplay, NULL, NULL); - - // start the EventThread - sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); - mEventThread = new EventThread(vsyncSrc, *this, false); - sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); - mSFEventThread = new EventThread(sfVsyncSrc, *this, true); - mEventQueue.setEventThread(mSFEventThread); + // initialize EGL for the default display + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); - // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); - } - if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for EventThread"); - } + // start the EventThread + sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "app"); + mEventThread = new EventThread(vsyncSrc, *this, false); + sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, + sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = new EventThread(sfVsyncSrc, *this, true); + mEventQueue.setEventThread(mSFEventThread); - // Get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, - HAL_PIXEL_FORMAT_RGBA_8888, - hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); + // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); + } + if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for EventThread"); } - // 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."); - mRealHwc = new HWComposer(false); - mHwc = mRealHwc; - mHwc->setEventHandler(static_cast(this)); + // Get a RenderEngine for the given display / config (can't fail) + mRenderEngine = RenderEngine::create(mEGLDisplay, + HAL_PIXEL_FORMAT_RGBA_8888, + hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); - Mutex::Autolock _l(mStateLock); + // retrieve the EGL context that was selected/created + mEGLContext = mRenderEngine->getEGLContext(); + + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, + "couldn't create EGLContext"); + + LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, + "Starting with vr flinger active is not currently supported."); + mHwc.reset(new HWComposer(false)); + mHwc->registerCallback(this, mComposerSequenceId); if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { @@ -613,16 +625,6 @@ void SurfaceFlinger::init() { } } - // retrieve the EGL context that was selected/created - mEGLContext = mRenderEngine->getEGLContext(); - - LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, - "couldn't create EGLContext"); - - // make the GLContext current so that we can create textures when creating - // Layers (which may happens before we render something) - getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); - mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); @@ -1165,11 +1167,16 @@ void SurfaceFlinger::resyncWithRateLimit() { sLastResyncAttempted = now; } -void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, - nsecs_t timestamp) { +void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, + hwc2_display_t displayId, int64_t timestamp) { Mutex::Autolock lock(mStateLock); - // Ignore any vsyncs from the non-active hardware composer. - if (composer != mHwc) { + // Ignore any vsyncs from a previous hardware composer. + if (sequenceId != mComposerSequenceId) { + return; + } + + int32_t type; + if (!mHwc->onVsync(displayId, timestamp, &type)) { return; } @@ -1177,7 +1184,7 @@ void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, { // Scope for the lock Mutex::Autolock _l(mHWVsyncLock); - if (type == 0 && mPrimaryHWVsyncEnabled) { + if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) { needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } @@ -1195,7 +1202,7 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { } void SurfaceFlinger::createDefaultDisplayDevice() { - const int32_t type = DisplayDevice::DISPLAY_PRIMARY; + const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY; wp token = mBuiltinDisplays[type]; // All non-virtual displays are currently considered secure. @@ -1226,28 +1233,49 @@ void SurfaceFlinger::createDefaultDisplayDevice() { mDisplays.add(token, hw); setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE); hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); -} -void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { - ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); + // Add the primary display token to mDrawingState so we don't try to + // recreate the DisplayDevice for the primary display. + mDrawingState.displays.add(token, DisplayDeviceState(type, true)); - if (composer->isUsingVrComposer()) { - // We handle initializing the primary display device for the VR - // window manager hwc explicitly at the time of transition. - if (disp != DisplayDevice::DISPLAY_PRIMARY) { - ALOGE("External displays are not supported by the vr hardware composer."); - } - return; - } + // make the GLContext current so that we can create textures when creating + // Layers (which may happens before we render something) + hw->makeCurrent(mEGLDisplay, mEGLContext); +} - if (disp == DisplayDevice::DISPLAY_PRIMARY) { - Mutex::Autolock lock(mStateLock); - createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); +void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, + hwc2_display_t display, HWC2::Connection connection, + bool primaryDisplay) { + ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)", + sequenceId, display, + connection == HWC2::Connection::Connected ? + "connected" : "disconnected", + primaryDisplay ? "primary" : "external"); + + // Only lock if we're not on the main thread. This function is normally + // called on a hwbinder thread, but for the primary display it's called on + // the main thread with the state lock already held, so don't attempt to + // acquire it here. + ConditionalLock lock(mStateLock, + std::this_thread::get_id() != mMainThreadId); + + if (primaryDisplay) { + mHwc->onHotplug(display, connection); + if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) { + createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); + } createDefaultDisplayDevice(); } else { + if (sequenceId != mComposerSequenceId) { + return; + } + if (mHwc->isUsingVrComposer()) { + ALOGE("External displays are not supported by the vr hardware composer."); + return; + } + mHwc->onHotplug(display, connection); auto type = DisplayDevice::DISPLAY_EXTERNAL; - Mutex::Autolock _l(mStateLock); - if (connected) { + if (connection == HWC2::Connection::Connected) { createBuiltinDisplayLocked(type); } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); @@ -1259,46 +1287,31 @@ void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool } } -void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) { +void SurfaceFlinger::onRefreshReceived(int sequenceId, + hwc2_display_t /*display*/) { Mutex::Autolock lock(mStateLock); - if (composer == mHwc) { - repaintEverything(); - } else { - // This isn't from our current hardware composer. If it's a callback - // from the real composer, forward the refresh request to vr - // flinger. Otherwise ignore it. - if (!composer->isUsingVrComposer()) { - mVrFlinger->OnHardwareComposerRefresh(); - } + if (sequenceId != mComposerSequenceId) { + return; } + repaintEverything(); } void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { ATRACE_CALL(); + Mutex::Autolock lock(mStateLock); getHwComposer().setVsyncEnabled(disp, enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } // Note: it is assumed the caller holds |mStateLock| when this is called -void SurfaceFlinger::resetHwcLocked() { +void SurfaceFlinger::resetDisplayState() { disableHardwareVsync(true); - clearHwcLayers(mDrawingState.layersSortedByZ); - clearHwcLayers(mCurrentState.layersSortedByZ); - for (size_t disp = 0; disp < mDisplays.size(); ++disp) { - clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ()); - } // Clear the drawing state so that the logic inside of // handleTransactionLocked will fire. It will determine the delta between // mCurrentState and mDrawingState and re-apply all changes when we make the // transition. mDrawingState.displays.clear(); - // Release virtual display hwcId during vr mode transition. - for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { - const sp& displayDevice = mDisplays[displayId]; - if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) { - displayDevice->disconnect(getHwComposer()); - } - } + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); mDisplays.clear(); } @@ -1310,57 +1323,53 @@ void SurfaceFlinger::updateVrFlinger() { return; } - if (vrFlingerRequestsDisplay && !mVrHwc) { - // Construct new HWComposer without holding any locks. - mVrHwc = new HWComposer(true); - - // Set up the event handlers. This step is neccessary to initialize the internal state of - // the hardware composer object properly. Our callbacks are designed such that if they are - // triggered between now and the point where the display is properly re-initialized, they - // will not have any effect, so this is safe to do here, before the lock is aquired. - mVrHwc->setEventHandler(static_cast(this)); - ALOGV("Vr HWC created"); + if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) { + ALOGE("Vr flinger is only supported for remote hardware composer" + " service connections. Ignoring request to transition to vr" + " flinger."); + mVrFlingerRequestsDisplay = false; + return; } Mutex::Autolock _l(mStateLock); - if (vrFlingerRequestsDisplay) { - resetHwcLocked(); - - mHwc = mVrHwc; - mVrFlinger->GrantDisplayOwnership(); + int currentDisplayPowerMode = getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode(); - } else { + if (!vrFlingerRequestsDisplay) { mVrFlinger->SeizeDisplayOwnership(); + } - resetHwcLocked(); + resetDisplayState(); + mHwc.reset(); // Delete the current instance before creating the new one + mHwc.reset(new HWComposer(vrFlingerRequestsDisplay)); + mHwc->registerCallback(this, ++mComposerSequenceId); - mHwc = mRealHwc; + LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(), + "Switched to non-remote hardware composer"); + + if (vrFlingerRequestsDisplay) { + mVrFlinger->GrantDisplayOwnership(); + } else { enableHardwareVsync(); } mVisibleRegionsDirty = true; invalidateHwcGeometry(); - // Explicitly re-initialize the primary display. This is because some other - // parts of this class rely on the primary display always being available. - createDefaultDisplayDevice(); - // Re-enable default display. - sp requestMessage = new LambdaMessage([&]() { - sp hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); - setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL); + sp hw(getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); + setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true); - // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); - const nsecs_t period = activeConfig->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(period); + // Reset the timing values to account for the period of the swapped in HWC + const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const nsecs_t period = activeConfig->getVsyncPeriod(); + mAnimFrameTracker.setDisplayRefreshPeriod(period); - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - setCompositorTimingSnapped(0, period, 0); - }); - postMessageAsync(requestMessage); + // Use phase of 0 since phase is not known. + // Use latency of 0, which will snap to the ideal latency. + setCompositorTimingSnapped(0, period, 0); android_atomic_or(1, &mRepaintEverything); setTransactionFlags(eDisplayTransactionNeeded); @@ -1696,15 +1705,14 @@ void SurfaceFlinger::rebuildLayerStacks() { } else { // Clear out the HWC layer if this layer was // previously visible, but no longer is - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer( + displayDevice->getHwcDisplayId()); } } else { // WM changes displayDevice->layerStack upon sleep/awake. // Here we make sure we delete the HWC layers even if // WM changed their layer stack. - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer(displayDevice->getHwcDisplayId()); } }); } @@ -1819,10 +1827,7 @@ void SurfaceFlinger::setUpHWComposer() { for (size_t i = 0; i < currentLayers.size(); i++) { const auto& layer = currentLayers[i]; if (!layer->hasHwcLayer(hwcId)) { - auto hwcLayer = mHwc->createLayer(hwcId); - if (hwcLayer) { - layer->setHwcLayer(hwcId, std::move(hwcLayer)); - } else { + if (!layer->createHwcLayer(mHwc.get(), hwcId)) { layer->forceClientComposition(hwcId); continue; } @@ -2108,7 +2113,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface != NULL) { // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || mHwc == mVrHwc) { + if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); @@ -3229,7 +3234,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.height = 0; displays.add(d); setTransactionState(state, displays, 0); - setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); + setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL, + /*stateLockHeld*/ false); const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); @@ -3255,7 +3261,7 @@ void SurfaceFlinger::initializeDisplays() { } void SurfaceFlinger::setPowerModeInternal(const sp& hw, - int mode) { + int mode, bool stateLockHeld) { ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); @@ -3272,7 +3278,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& hw, } if (mInterceptor.isEnabled()) { - Mutex::Autolock _l(mStateLock); + ConditionalLock lock(mStateLock, !stateLockHeld); ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); if (idx < 0) { ALOGW("Surface Interceptor SavePowerMode: invalid display token"); @@ -3358,7 +3364,8 @@ void SurfaceFlinger::setPowerMode(const sp& display, int mode) { ALOGW("Attempt to set power mode = %d for virtual display", mMode); } else { - mFlinger.setPowerModeInternal(hw, mMode); + mFlinger.setPowerModeInternal( + hw, mMode, /*stateLockHeld*/ false); } return true; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index acfad46526..025da0e827 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -60,13 +60,20 @@ #include "SurfaceInterceptor.h" #include "StartPropertySetThread.h" +#ifdef USE_HWC2 +#include "DisplayHardware/HWC2.h" #include "DisplayHardware/HWComposer.h" +#else +#include "DisplayHardware/HWComposer_hwc1.h" +#endif + #include "Effects/Daltonizer.h" #include #include #include #include +#include #include namespace android { @@ -99,7 +106,11 @@ enum { class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, +#ifdef USE_HWC2 + private HWC2::ComposerCallback +#else private HWComposer::EventHandler +#endif { public: @@ -313,11 +324,20 @@ private: virtual void onFirstRef(); /* ------------------------------------------------------------------------ - * HWComposer::EventHandler interface + * HWC2::ComposerCallback / HWComposer::EventHandler interface */ - virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp); - virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected); - virtual void onInvalidateReceived(HWComposer* composer); +#ifdef USE_HWC2 + void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) override; + void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + HWC2::Connection connection, + bool primaryDisplay) override; + void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override; +#else + void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override; + void onHotplugReceived(HWComposer* composer, int disp, bool connected) override; + void onInvalidateReceived(HWComposer* composer) override; +#endif /* ------------------------------------------------------------------------ * Message handling @@ -332,7 +352,12 @@ private: // called on the main thread in response to setActiveConfig() void setActiveConfigInternal(const sp& hw, int mode); // called on the main thread in response to setPowerMode() +#ifdef USE_HWC2 + void setPowerModeInternal(const sp& hw, int mode, + bool stateLockHeld); +#else void setPowerModeInternal(const sp& hw, int mode); +#endif // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp& hw, android_color_mode_t colorMode); @@ -590,13 +615,7 @@ private: /* ------------------------------------------------------------------------ * VrFlinger */ - template - void clearHwcLayers(const T& layers) { - for (size_t i = 0; i < layers.size(); ++i) { - layers[i]->clearHwcLayers(); - } - } - void resetHwcLocked(); + void resetDisplayState(); // Check to see if we should handoff to vr flinger. void updateVrFlinger(); @@ -623,12 +642,10 @@ private: // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; - // current, real and vr hardware composers. - HWComposer* mHwc; -#ifdef USE_HWC2 - HWComposer* mRealHwc; - HWComposer* mVrHwc; -#endif + // The current hardware composer interface. When switching into and out of + // vr, our HWComposer instance will be recreated. + std::unique_ptr mHwc; + // constant members (no synchronization needed for access) RenderEngine* mRenderEngine; nsecs_t mBootTime; @@ -642,10 +659,6 @@ private: EGLDisplay mEGLDisplay; sp mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; -#ifdef USE_HWC2 - std::unique_ptr mVrFlinger; -#endif - // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; @@ -767,8 +780,14 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); #ifdef USE_HWC2 + std::unique_ptr mVrFlinger; std::atomic mVrFlingerRequestsDisplay; static bool useVrFlinger; + std::thread::id mMainThreadId; + // The composer sequence id is a monotonically increasing integer that we + // use to differentiate callbacks from different hardware composer + // instances. Each hardware composer instance gets a different sequence id. + int32_t mComposerSequenceId; #endif float mSaturation = 1.0f; diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 186031a238..a41d35f19d 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -534,8 +534,8 @@ void SurfaceFlinger::init() { // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. - mHwc = new HWComposer(this, - *static_cast(this)); + mHwc.reset(new HWComposer(this, + *static_cast(this))); // get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, -- cgit v1.2.3-59-g8ed1b From b02664ddc146893e6bbe7939ee2b948d54e7166a Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Wed, 26 Jul 2017 18:48:28 -0700 Subject: Use a separate hwcomposer hidl instance for vr flinger Improve robustness of vr flinger <--> surface flinger switching by having vr flinger use a separate hardware composer hidl instance instead of sharing the instance with surface flinger. Sharing the hardware composer instance has proven to be error prone, with situations where both the vr flinger thread and surface flinger main thread would write to the composer at the same time, causing hard to diagnose crashes (b/62925812). Instead of sharing the hardware composer instance, when switching to vr flinger we now delete the existing instance, create a new instance directed to the vr hardware composer shim, and vr flinger creates its own composer instance connected to the real hardware composer. By creating a separate composer instance for vr flinger, crashes like the ones found in b/62925812 are no longer impossible. Most of the changes in this commit are related to enabling surface flinger to delete HWComposer instances cleanly. In particular: - Previously the hardware composer callbacks (which come in on a hwbinder thread) would land in HWC2::Device and bubble up to the SurfaceFlinger object. But with the new behavior the HWC2::Device might be dead or in the process of being destroyed, so instead we have SurfaceFlinger receive the composer callbacks directly, and forward them to HWComposer and HWC2::Device. We include a composer id field in the callbacks so surface flinger can ignore stale callbacks from dead composer instances. - Object ownership for HWC2::Display and HWC2::Layer was shared by passing around shared_ptrs to these objects. This was problematic because they referenced and used the HWC2::Device, which can now be destroyed when switching to vr flinger. Simplify the ownership model by having HWC2::Device own (via unique_ptr<>) instances of HWC2::Display, which owns (again via unique_ptr<>) instances of HWC2::Layer. In cases where we previously passed std::shared_ptr<> to HWC2::Display or HWC2::Layer, instead pass non-owning HWC2::Display* and HWC2::Layer* pointers. This ensures clean composer instance teardown with no stale references to the deleted HWC2::Device. - When the hardware composer instance is destroyed and the HWC2::Layers are removed, notify the android::Layer via a callback, so it can remove the HWC2::Layer from its internal table of hardware composer layers. This removes the burden to explicitly clear out all hardware composer layers when switching to vr flinger, which has been a source of bugs. - We were missing an mStateLock lock in SurfaceFlinger::setVsyncEnabled(), which was necessary to ensure we were setting vsync on the correct hardware composer instance. Once that lock was added, surface flinger would sometimes deadlock when transitioning to vr flinger, because the surface flinger main thread would acquire mStateLock and then EventControlThread::mMutex, whereas the event control thread would acquire the locks in the opposite order. The changes in EventControlThread.cpp are to ensure it doesn't hold a lock on EventControlThread::mMutex while calling setVsyncEnabled(), to avoid the deadlock. I found that without a composer callback registered in vr flinger the vsync_event file wasn't getting vsync timestamps written, so vr flinger would get stuck in an infinite loop trying to parse a vsync timestamp. Since we need to have a callback anyway I changed the code in hardware_composer.cpp to get the vsync timestamp from the callback, as surface flinger does. I confirmed the timestamps are the same with either method, and this lets us remove some extra code for extracting the vsync timestamp that (probably) wasn't compatible with all devices we want to run on anyway. I also added a timeout to the vysnc wait so we'll see an error message in the log if we fail to wait for vsync, instead of looping forever. Bug: 62925812 Test: - Confirmed surface flinger <--> vr flinger switching is robust by switching devices on and off hundreds of times and observing no hardware composer related issues, surface flinger crashes, or hardware composer service crashes. - Confirmed 2d in vr works as before by going through the OOBE flow on a standalone. This also exercises virtual display creation and usage through surface flinger. - Added logs to confirm perfect layer/display cleanup when destroying hardware composer instances. - Tested normal 2d phone usage to confirm basic layer create/destroy functionality works as before. - Monitored surface flinger file descriptor usage across dozens of surface flinger <--> vr flinger transitions and observed no file descriptor leaks. - Confirmed the HWC1 code path still compiles. - Ran the surface flinger tests and confirmed there are no new test failures. - Ran the hardware composer hidl in passthrough mode on a Marlin and confirmed it works. - Ran CTS tests for virtual displays and confirmed they all pass. - Tested Android Auto and confirmed basic graphics functionality still works. Change-Id: Ibf1dbdf3ec15ca66467697d711f8109dc9e46a47 Merged-In: I17dc0e060bfb5cb447ffbaa573b279fc6d2d8bd1 --- libs/vr/libvrflinger/display_service.cpp | 10 +- libs/vr/libvrflinger/display_service.h | 3 - libs/vr/libvrflinger/hardware_composer.cpp | 352 +++++-------- libs/vr/libvrflinger/hardware_composer.h | 110 ++--- libs/vr/libvrflinger/include/dvr/vr_flinger.h | 3 - libs/vr/libvrflinger/vr_flinger.cpp | 4 - services/surfaceflinger/DisplayDevice.cpp | 6 +- .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 4 + .../surfaceflinger/DisplayHardware/ComposerHal.h | 5 + services/surfaceflinger/DisplayHardware/HWC2.cpp | 549 +++++++++------------ services/surfaceflinger/DisplayHardware/HWC2.h | 124 +++-- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 131 +++-- .../surfaceflinger/DisplayHardware/HWComposer.h | 39 +- services/surfaceflinger/EventControlThread.cpp | 43 +- services/surfaceflinger/Layer.cpp | 50 +- services/surfaceflinger/Layer.h | 34 +- .../surfaceflinger/RenderEngine/RenderEngine.cpp | 33 +- .../surfaceflinger/RenderEngine/RenderEngine.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 294 +++++------ services/surfaceflinger/SurfaceFlinger.h | 60 ++- services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 4 +- 21 files changed, 844 insertions(+), 1016 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 733edc659c..f350762e79 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -40,10 +40,8 @@ namespace dvr { DisplayService::DisplayService(Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) : BASE("DisplayService", - Endpoint::Create(display::DisplayProtocol::kClientPath)), - hardware_composer_(hidl, request_display_callback), - request_display_callback_(request_display_callback) { - hardware_composer_.Initialize(); + Endpoint::Create(display::DisplayProtocol::kClientPath)) { + hardware_composer_.Initialize(hidl, request_display_callback); } bool DisplayService::IsInitialized() const { @@ -398,10 +396,6 @@ pdx::Status DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) { return {0}; } -void DisplayService::OnHardwareComposerRefresh() { - hardware_composer_.OnHardwareComposerRefresh(); -} - void DisplayService::SetDisplayConfigurationUpdateNotifier( DisplayConfigurationUpdateNotifier update_notifier) { update_notifier_ = update_notifier; diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 6efe264b09..55e33ab852 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -72,8 +72,6 @@ class DisplayService : public pdx::ServiceBase { void GrantDisplayOwnership() { hardware_composer_.Enable(); } void SeizeDisplayOwnership() { hardware_composer_.Disable(); } - void OnHardwareComposerRefresh(); - private: friend BASE; friend DisplaySurface; @@ -119,7 +117,6 @@ class DisplayService : public pdx::ServiceBase { pdx::Status HandleSurfaceMessage(pdx::Message& message); HardwareComposer hardware_composer_; - RequestDisplayCallback request_display_callback_; EpollEventDispatcher dispatcher_; DisplayConfigurationUpdateNotifier update_notifier_; diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 11c137063e..f9a5dcd987 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -28,6 +28,8 @@ #include #include +using android::hardware::Return; +using android::hardware::Void; using android::pdx::LocalHandle; using android::pdx::rpc::EmptyVariant; using android::pdx::rpc::IfAnyOf; @@ -42,9 +44,6 @@ namespace { const char kBacklightBrightnessSysFile[] = "/sys/class/leds/lcd-backlight/brightness"; -const char kPrimaryDisplayVSyncEventFile[] = - "/sys/class/graphics/fb0/vsync_event"; - const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp"; const char kDvrPerformanceProperty[] = "sys.dvr.performance"; @@ -86,22 +85,11 @@ bool SetThreadPolicy(const std::string& scheduler_class, } // anonymous namespace -// Layer static data. -Hwc2::Composer* Layer::hwc2_hidl_; -const HWCDisplayMetrics* Layer::display_metrics_; - // HardwareComposer static data; constexpr size_t HardwareComposer::kMaxHardwareLayers; HardwareComposer::HardwareComposer() - : HardwareComposer(nullptr, RequestDisplayCallback()) {} - -HardwareComposer::HardwareComposer( - Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback) - : initialized_(false), - hwc2_hidl_(hwc2_hidl), - request_display_callback_(request_display_callback), - callbacks_(new ComposerCallback) {} + : initialized_(false), request_display_callback_(nullptr) {} HardwareComposer::~HardwareComposer(void) { UpdatePostThreadState(PostThreadState::Quit, true); @@ -109,16 +97,19 @@ HardwareComposer::~HardwareComposer(void) { post_thread_.join(); } -bool HardwareComposer::Initialize() { +bool HardwareComposer::Initialize( + Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { if (initialized_) { ALOGE("HardwareComposer::Initialize: already initialized."); return false; } + request_display_callback_ = request_display_callback; + HWC::Error error = HWC::Error::None; Hwc2::Config config; - error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); + error = hidl->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); if (error != HWC::Error::None) { ALOGE("HardwareComposer: Failed to get current display config : %d", @@ -126,8 +117,8 @@ bool HardwareComposer::Initialize() { return false; } - error = - GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_); + error = GetDisplayMetrics(hidl, HWC_DISPLAY_PRIMARY, config, + &native_display_metrics_); if (error != HWC::Error::None) { ALOGE( @@ -149,9 +140,6 @@ bool HardwareComposer::Initialize() { display_transform_ = HWC_TRANSFORM_NONE; display_metrics_ = native_display_metrics_; - // Pass hwc instance and metrics to setup globals for Layer. - Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_); - post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF( !post_thread_event_fd_, @@ -210,15 +198,11 @@ void HardwareComposer::UpdatePostThreadState(PostThreadStateType state, } void HardwareComposer::OnPostThreadResumed() { - hwc2_hidl_->resetCommands(); + hidl_.reset(new Hwc2::Composer("default")); + hidl_callback_ = new ComposerCallback; + hidl_->registerCallback(hidl_callback_); - // HIDL HWC seems to have an internal race condition. If we submit a frame too - // soon after turning on VSync we don't get any VSync signals. Give poor HWC - // implementations a chance to enable VSync before we continue. - EnableVsync(false); - std::this_thread::sleep_for(100ms); EnableVsync(true); - std::this_thread::sleep_for(100ms); // TODO(skiazyk): We need to do something about accessing this directly, // supposedly there is a backlight service on the way. @@ -240,9 +224,12 @@ void HardwareComposer::OnPostThreadPaused() { } active_layer_count_ = 0; - EnableVsync(false); + if (hidl_) { + EnableVsync(false); + } - hwc2_hidl_->resetCommands(); + hidl_callback_ = nullptr; + hidl_.reset(nullptr); // Trigger target-specific performance mode change. property_set(kDvrPerformanceProperty, "idle"); @@ -252,21 +239,21 @@ HWC::Error HardwareComposer::Validate(hwc2_display_t display) { uint32_t num_types; uint32_t num_requests; HWC::Error error = - hwc2_hidl_->validateDisplay(display, &num_types, &num_requests); + hidl_->validateDisplay(display, &num_types, &num_requests); if (error == HWC2_ERROR_HAS_CHANGES) { // TODO(skiazyk): We might need to inspect the requested changes first, but // so far it seems like we shouldn't ever hit a bad state. // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_, // display); - error = hwc2_hidl_->acceptDisplayChanges(display); + error = hidl_->acceptDisplayChanges(display); } return error; } -int32_t HardwareComposer::EnableVsync(bool enabled) { - return (int32_t)hwc2_hidl_->setVsyncEnabled( +HWC::Error HardwareComposer::EnableVsync(bool enabled) { + return hidl_->setVsyncEnabled( HWC_DISPLAY_PRIMARY, (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE : HWC2_VSYNC_DISABLE)); @@ -274,7 +261,7 @@ int32_t HardwareComposer::EnableVsync(bool enabled) { HWC::Error HardwareComposer::Present(hwc2_display_t display) { int32_t present_fence; - HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence); + HWC::Error error = hidl_->presentDisplay(display, &present_fence); // According to the documentation, this fence is signaled at the time of // vsync/DMA for physical displays. @@ -288,20 +275,21 @@ HWC::Error HardwareComposer::Present(hwc2_display_t display) { return error; } -HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display, +HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* hidl, + hwc2_display_t display, hwc2_config_t config, hwc2_attribute_t attribute, int32_t* out_value) const { - return hwc2_hidl_->getDisplayAttribute( + return hidl->getDisplayAttribute( display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value); } HWC::Error HardwareComposer::GetDisplayMetrics( - hwc2_display_t display, hwc2_config_t config, + Hwc2::Composer* hidl, hwc2_display_t display, hwc2_config_t config, HWCDisplayMetrics* out_metrics) const { HWC::Error error; - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_WIDTH, &out_metrics->width); if (error != HWC::Error::None) { ALOGE( @@ -310,7 +298,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_HEIGHT, &out_metrics->height); if (error != HWC::Error::None) { ALOGE( @@ -319,7 +307,8 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD, + error = GetDisplayAttribute(hidl, display, config, + HWC2_ATTRIBUTE_VSYNC_PERIOD, &out_metrics->vsync_period_ns); if (error != HWC::Error::None) { ALOGE( @@ -328,7 +317,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_X, &out_metrics->dpi.x); if (error != HWC::Error::None) { ALOGE( @@ -337,7 +326,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_Y, &out_metrics->dpi.y); if (error != HWC::Error::None) { ALOGE( @@ -374,7 +363,7 @@ std::string HardwareComposer::Dump() { if (post_thread_resumed_) { stream << "Hardware Composer Debug Info:" << std::endl; - stream << hwc2_hidl_->dumpDebugInfo(); + stream << hidl_->dumpDebugInfo(); } return stream.str(); @@ -446,8 +435,8 @@ void HardwareComposer::PostLayers() { std::vector out_layers; std::vector out_fences; - error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, - &out_fences); + error = hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, + &out_fences); ALOGE_IF(error != HWC::Error::None, "HardwareComposer::PostLayers: Failed to get release fences: %s", error.to_string().c_str()); @@ -546,7 +535,7 @@ void HardwareComposer::UpdateConfigBuffer() { } int HardwareComposer::PostThreadPollInterruptible( - const pdx::LocalHandle& event_fd, int requested_events) { + const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) { pollfd pfd[2] = { { .fd = event_fd.Get(), @@ -561,7 +550,7 @@ int HardwareComposer::PostThreadPollInterruptible( }; int ret, error; do { - ret = poll(pfd, 2, -1); + ret = poll(pfd, 2, timeout_ms); error = errno; ALOGW_IF(ret < 0, "HardwareComposer::PostThreadPollInterruptible: Error during " @@ -571,6 +560,8 @@ int HardwareComposer::PostThreadPollInterruptible( if (ret < 0) { return -error; + } else if (ret == 0) { + return -ETIMEDOUT; } else if (pfd[0].revents != 0) { return 0; } else if (pfd[1].revents != 0) { @@ -623,114 +614,17 @@ int HardwareComposer::ReadWaitPPState() { } } -// Reads the timestamp of the last vsync from the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) { - const int event_fd = primary_display_vsync_event_fd_.Get(); - int ret, error; - - // The driver returns data in the form "VSYNC=". - std::array data; - data.fill('\0'); - - // Seek back to the beginning of the event file. - ret = lseek(event_fd, 0, SEEK_SET); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: " - "%s", - strerror(error)); - return -error; - } - - // Read the vsync event timestamp. - ret = read(event_fd, data.data(), data.size()); - if (ret < 0) { - error = errno; - ALOGE_IF( - error != EAGAIN, - "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: " - "%s", - strerror(error)); - return -error; - } - - ret = sscanf(data.data(), "VSYNC=%" PRIu64, - reinterpret_cast(timestamp)); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: " - "%s", - strerror(error)); - return -error; - } - - return 0; -} - -// Blocks until the next vsync event is signaled by the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::BlockUntilVSync() { - // Vsync is signaled by POLLPRI on the fb vsync node. - return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI); -} - // Waits for the next vsync and returns the timestamp of the vsync event. If // vsync already passed since the last call, returns the latest vsync timestamp -// instead of blocking. This method updates the last_vsync_timeout_ in the -// process. -// -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. +// instead of blocking. int HardwareComposer::WaitForVSync(int64_t* timestamp) { - int error; - - // Get the current timestamp and decide what to do. - while (true) { - int64_t current_vsync_timestamp; - error = ReadVSyncTimestamp(¤t_vsync_timestamp); - if (error < 0 && error != -EAGAIN) - return error; - - if (error == -EAGAIN) { - // Vsync was turned off, wait for the next vsync event. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - - // Try again to get the timestamp for this new vsync interval. - continue; - } - - // Check that we advanced to a later vsync interval. - if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) { - *timestamp = last_vsync_timestamp_ = current_vsync_timestamp; - return 0; - } - - // See how close we are to the next expected vsync. If we're within 1ms, - // sleep for 1ms and try again. - const int64_t ns_per_frame = display_metrics_.vsync_period_ns; - const int64_t threshold_ns = 1000000; // 1ms - - const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame; - const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs(); - - if (distance_to_vsync_est > threshold_ns) { - // Wait for vsync event notification. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } else { - // Sleep for a short time (1 millisecond) before retrying. - error = SleepUntil(GetSystemClockNs() + threshold_ns); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } + int error = PostThreadPollInterruptible( + hidl_callback_->GetVsyncEventFd(), POLLIN, /*timeout_ms*/ 1000); + if (error == kPostThreadInterrupted || error < 0) { + return error; + } else { + *timestamp = hidl_callback_->GetVsyncTime(); + return 0; } } @@ -749,7 +643,8 @@ int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { return -error; } - return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN); + return PostThreadPollInterruptible( + vsync_sleep_timer_fd_, POLLIN, /*timeout_ms*/ -1); } void HardwareComposer::PostThread() { @@ -772,15 +667,6 @@ void HardwareComposer::PostThread() { strerror(errno)); #endif // ENABLE_BACKLIGHT_BRIGHTNESS - // Open the vsync event node for the primary display. - // TODO(eieio): Move this into a platform-specific class. - primary_display_vsync_event_fd_ = - LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY); - ALOGE_IF(!primary_display_vsync_event_fd_, - "HardwareComposer: Failed to open vsync event node for primary " - "display: %s", - strerror(errno)); - // Open the wait pingpong status node for the primary display. // TODO(eieio): Move this into a platform-specific class. primary_display_wait_pp_fd_ = @@ -951,7 +837,8 @@ bool HardwareComposer::UpdateLayerConfig() { // The bottom layer is opaque, other layers blend. HWC::BlendMode blending = layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage; - layers_[layer_index].Setup(surfaces[layer_index], blending, + layers_[layer_index].Setup(surfaces[layer_index], native_display_metrics_, + hidl_.get(), blending, display_transform_, HWC::Composition::Device, layer_index); display_surfaces_.push_back(surfaces[layer_index]); @@ -979,50 +866,67 @@ void HardwareComposer::SetVSyncCallback(VSyncCallback callback) { vsync_callback_ = callback; } -void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/) { - // TODO(eieio): implement invalidate callbacks. +void HardwareComposer::SetBacklightBrightness(int brightness) { + if (backlight_brightness_fd_) { + std::array text; + const int length = snprintf(text.data(), text.size(), "%d", brightness); + write(backlight_brightness_fd_.Get(), text.data(), length); + } } -void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/, - int64_t /*timestamp*/) { - ATRACE_NAME(__PRETTY_FUNCTION__); - // Intentionally empty. HWC may require a callback to be set to enable vsync - // signals. We bypass this callback thread by monitoring the vsync event - // directly, but signals still need to be enabled. +HardwareComposer::ComposerCallback::ComposerCallback() { + vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF( + !vsync_event_fd_, + "Failed to create vsync event fd : %s", + strerror(errno)); } -void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/, - hwc2_display_t /*display*/, - hwc2_connection_t /*connected*/) { - // TODO(eieio): implement display hotplug callbacks. +Return HardwareComposer::ComposerCallback::onHotplug( + Hwc2::Display /*display*/, + IComposerCallback::Connection /*conn*/) { + return Void(); } -void HardwareComposer::OnHardwareComposerRefresh() { - // TODO(steventhomas): Handle refresh. +Return HardwareComposer::ComposerCallback::onRefresh( + Hwc2::Display /*display*/) { + return hardware::Void(); } -void HardwareComposer::SetBacklightBrightness(int brightness) { - if (backlight_brightness_fd_) { - std::array text; - const int length = snprintf(text.data(), text.size(), "%d", brightness); - write(backlight_brightness_fd_.Get(), text.data(), length); +Return HardwareComposer::ComposerCallback::onVsync( + Hwc2::Display display, int64_t timestamp) { + if (display == HWC_DISPLAY_PRIMARY) { + std::lock_guard lock(vsync_mutex_); + vsync_time_ = timestamp; + int error = eventfd_write(vsync_event_fd_.Get(), 1); + LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd"); } + return Void(); +} + +const pdx::LocalHandle& +HardwareComposer::ComposerCallback::GetVsyncEventFd() const { + return vsync_event_fd_; } -void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics) { - hwc2_hidl_ = hwc2_hidl; - display_metrics_ = metrics; +int64_t HardwareComposer::ComposerCallback::GetVsyncTime() { + std::lock_guard lock(vsync_mutex_); + eventfd_t event; + eventfd_read(vsync_event_fd_.Get(), &event); + LOG_ALWAYS_FATAL_IF(vsync_time_ < 0, + "Attempt to read vsync time before vsync event"); + int64_t return_val = vsync_time_; + vsync_time_ = -1; + return return_val; } void Layer::Reset() { - if (hwc2_hidl_ != nullptr && hardware_composer_layer_) { - hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); + if (hidl_ != nullptr && hardware_composer_layer_) { + hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); hardware_composer_layer_ = 0; } + hidl_ = nullptr; z_order_ = 0; blending_ = HWC::BlendMode::None; transform_ = HWC::Transform::None; @@ -1034,29 +938,35 @@ void Layer::Reset() { } void Layer::Setup(const std::shared_ptr& surface, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceSurface{surface}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::Setup(const std::shared_ptr& buffer, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceBuffer{buffer}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::UpdateBuffer(const std::shared_ptr& buffer) { @@ -1076,7 +986,7 @@ IonBuffer* Layer::GetBuffer() { return source_.Visit(Visitor{}); } -void Layer::UpdateLayerSettings() { +void Layer::UpdateLayerSettings(const HWCDisplayMetrics& display_metrics) { if (!IsLayerSetup()) { ALOGE( "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update " @@ -1087,7 +997,7 @@ void Layer::UpdateLayerSettings() { HWC::Error error; hwc2_display_t display = HWC_DISPLAY_PRIMARY; - error = hwc2_hidl_->setLayerCompositionType( + error = hidl_->setLayerCompositionType( display, hardware_composer_layer_, composition_type_.cast()); ALOGE_IF( @@ -1095,7 +1005,7 @@ void Layer::UpdateLayerSettings() { "Layer::UpdateLayerSettings: Error setting layer composition type: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerBlendMode( + error = hidl_->setLayerBlendMode( display, hardware_composer_layer_, blending_.cast()); ALOGE_IF(error != HWC::Error::None, @@ -1104,41 +1014,39 @@ void Layer::UpdateLayerSettings() { // TODO(eieio): Use surface attributes or some other mechanism to control // the layer display frame. - error = hwc2_hidl_->setLayerDisplayFrame( + error = hidl_->setLayerDisplayFrame( display, hardware_composer_layer_, - {0, 0, display_metrics_->width, display_metrics_->height}); + {0, 0, display_metrics.width, display_metrics.height}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer display frame: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerVisibleRegion( + error = hidl_->setLayerVisibleRegion( display, hardware_composer_layer_, - {{0, 0, display_metrics_->width, display_metrics_->height}}); + {{0, 0, display_metrics.width, display_metrics.height}}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer visible region: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); + error = hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); + error = hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting z_ order: %s", error.to_string().c_str()); } -void Layer::CommonLayerSetup() { +void Layer::CommonLayerSetup(const HWCDisplayMetrics& display_metrics) { HWC::Error error = - hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); + hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); ALOGE_IF( error != HWC::Error::None, "Layer::CommonLayerSetup: Failed to create layer on primary display: %s", error.to_string().c_str()); - UpdateLayerSettings(); + UpdateLayerSettings(display_metrics); } void Layer::Prepare() { @@ -1157,12 +1065,12 @@ void Layer::Prepare() { if (!handle.get()) { if (composition_type_ == HWC::Composition::Invalid) { composition_type_ = HWC::Composition::SolidColor; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast()); Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0}; - hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, - layer_color); + hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + layer_color); } else { // The composition type is already set. Nothing else to do until a // buffer arrives. @@ -1170,15 +1078,15 @@ void Layer::Prepare() { } else { if (composition_type_ != target_composition_type_) { composition_type_ = target_composition_type_; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast()); } HWC::Error error{HWC::Error::None}; - error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, 0, handle, - acquire_fence_.Get()); + error = hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, 0, handle, + acquire_fence_.Get()); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer buffer: %s", @@ -1187,9 +1095,9 @@ void Layer::Prepare() { if (!surface_rect_functions_applied_) { const float float_right = right; const float float_bottom = bottom; - error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, - {0, 0, float_right, float_bottom}); + error = hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, + {0, 0, float_right, float_bottom}); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer source crop: %s", diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index a0c50e14d8..fc0efeeeb4 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -54,11 +54,6 @@ class Layer { public: Layer() {} - // Sets up the global state used by all Layer instances. This must be called - // before using any Layer methods. - static void InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics); - // Releases any shared pointers and fence handles held by this instance. void Reset(); @@ -72,6 +67,7 @@ class Layer { // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). // |index| is the index of this surface in the DirectDisplaySurface array. void Setup(const std::shared_ptr& surface, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, HWC::BlendMode blending, HWC::Transform transform, HWC::Composition composition_type, size_t z_roder); @@ -83,9 +79,10 @@ class Layer { // |transform| receives HWC_TRANSFORM_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). - void Setup(const std::shared_ptr& buffer, HWC::BlendMode blending, - HWC::Transform transform, HWC::Composition composition_type, - size_t z_order); + void Setup(const std::shared_ptr& buffer, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, + HWC::BlendMode blending, HWC::Transform transform, + HWC::Composition composition_type, size_t z_order); // Layers that use a direct IonBuffer should call this each frame to update // which buffer will be used for the next PostLayers. @@ -121,7 +118,7 @@ class Layer { bool IsLayerSetup() const { return !source_.empty(); } // Applies all of the settings to this layer using the hwc functions - void UpdateLayerSettings(); + void UpdateLayerSettings(const HWCDisplayMetrics& display_metrics); int GetSurfaceId() const { int surface_id = -1; @@ -142,10 +139,9 @@ class Layer { } private: - void CommonLayerSetup(); + void CommonLayerSetup(const HWCDisplayMetrics& display_metrics); - static Hwc2::Composer* hwc2_hidl_; - static const HWCDisplayMetrics* display_metrics_; + Hwc2::Composer* hidl_ = nullptr; // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; @@ -263,11 +259,10 @@ class HardwareComposer { static constexpr size_t kMaxHardwareLayers = 4; HardwareComposer(); - HardwareComposer(Hwc2::Composer* hidl, - RequestDisplayCallback request_display_callback); ~HardwareComposer(); - bool Initialize(); + bool Initialize(Hwc2::Composer* hidl, + RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } @@ -281,11 +276,6 @@ class HardwareComposer { // Get the HMD display metrics for the current display. display::Metrics GetHmdDisplayMetrics() const; - HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config, - hwc2_attribute_t attributes, - int32_t* out_value) const; - HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config, - HWCDisplayMetrics* out_metrics) const; std::string Dump(); void SetVSyncCallback(VSyncCallback callback); @@ -308,34 +298,31 @@ class HardwareComposer { int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); - void OnHardwareComposerRefresh(); - private: - int32_t EnableVsync(bool enabled); + HWC::Error GetDisplayAttribute(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + hwc2_attribute_t attributes, + int32_t* out_value) const; + HWC::Error GetDisplayMetrics(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + HWCDisplayMetrics* out_metrics) const; + + HWC::Error EnableVsync(bool enabled); class ComposerCallback : public Hwc2::IComposerCallback { public: - ComposerCallback() {} - - hardware::Return onHotplug(Hwc2::Display /*display*/, - Connection /*connected*/) override { - // TODO(skiazyk): depending on how the server is implemented, we might - // have to set it up to synchronize with receiving this event, as it can - // potentially be a critical event for setting up state within the - // hwc2 module. That is, we (technically) should not call any other hwc - // methods until this method has been called after registering the - // callbacks. - return hardware::Void(); - } - - hardware::Return onRefresh(Hwc2::Display /*display*/) override { - return hardware::Void(); - } - - hardware::Return onVsync(Hwc2::Display /*display*/, - int64_t /*timestamp*/) override { - return hardware::Void(); - } + ComposerCallback(); + hardware::Return onHotplug(Hwc2::Display display, + Connection conn) override; + hardware::Return onRefresh(Hwc2::Display display) override; + hardware::Return onVsync(Hwc2::Display display, + int64_t timestamp) override; + const pdx::LocalHandle& GetVsyncEventFd() const; + int64_t GetVsyncTime(); + private: + std::mutex vsync_mutex_; + pdx::LocalHandle vsync_event_fd_; + int64_t vsync_time_ = -1; }; HWC::Error Validate(hwc2_display_t display); @@ -364,17 +351,18 @@ class HardwareComposer { void UpdatePostThreadState(uint32_t state, bool suspend); // Blocks until either event_fd becomes readable, or we're interrupted by a - // control thread. Any errors are returned as negative errno values. If we're - // interrupted, kPostThreadInterrupted will be returned. + // control thread, or timeout_ms is reached before any events occur. Any + // errors are returned as negative errno values, with -ETIMEDOUT returned in + // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be + // returned. int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd, - int requested_events); + int requested_events, + int timeout_ms); - // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made - // on the post thread that can be interrupted by a control thread. If - // interrupted, these calls return kPostThreadInterrupted. + // WaitForVSync and SleepUntil are blocking calls made on the post thread that + // can be interrupted by a control thread. If interrupted, these calls return + // kPostThreadInterrupted. int ReadWaitPPState(); - int BlockUntilVSync(); - int ReadVSyncTimestamp(int64_t* timestamp); int WaitForVSync(int64_t* timestamp); int SleepUntil(int64_t wakeup_timestamp); @@ -398,11 +386,9 @@ class HardwareComposer { bool initialized_; - // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own - // this pointer. - Hwc2::Composer* hwc2_hidl_; + std::unique_ptr hidl_; + sp hidl_callback_; RequestDisplayCallback request_display_callback_; - sp callbacks_; // Display metrics of the physical display. HWCDisplayMetrics native_display_metrics_; @@ -433,7 +419,8 @@ class HardwareComposer { std::thread post_thread_; // Post thread state machine and synchronization primitives. - PostThreadStateType post_thread_state_{PostThreadState::Idle}; + PostThreadStateType post_thread_state_{ + PostThreadState::Idle | PostThreadState::Suspended}; std::atomic post_thread_quiescent_{true}; bool post_thread_resumed_{false}; pdx::LocalHandle post_thread_event_fd_; @@ -444,9 +431,6 @@ class HardwareComposer { // Backlight LED brightness sysfs node. pdx::LocalHandle backlight_brightness_fd_; - // Primary display vsync event sysfs node. - pdx::LocalHandle primary_display_vsync_event_fd_; - // Primary display wait_pingpong state sysfs node. pdx::LocalHandle primary_display_wait_pp_fd_; @@ -478,12 +462,6 @@ class HardwareComposer { static constexpr int kPostThreadInterrupted = 1; - static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display); - static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display, - int64_t timestamp); - static void HwcHotplug(hwc2_callback_data_t callbackData, - hwc2_display_t display, hwc2_connection_t connected); - HardwareComposer(const HardwareComposer&) = delete; void operator=(const HardwareComposer&) = delete; }; diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index e7f41a7379..33cbc84d7d 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -29,9 +29,6 @@ class VrFlinger { void GrantDisplayOwnership(); void SeizeDisplayOwnership(); - // Called on a binder thread. - void OnHardwareComposerRefresh(); - // dump all vr flinger state. std::string Dump(); diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 56405deeaa..fcf94f0865 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -133,10 +133,6 @@ void VrFlinger::SeizeDisplayOwnership() { display_service_->SeizeDisplayOwnership(); } -void VrFlinger::OnHardwareComposerRefresh() { - display_service_->OnHardwareComposerRefresh(); -} - std::string VrFlinger::Dump() { // TODO(karthikrs): Add more state information here. return display_service_->DumpState(0/*unused*/); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 744dd50df5..248ef53f55 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -134,9 +134,11 @@ DisplayDevice::DisplayDevice( EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { #ifdef USE_HWC2 - config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888); + config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888, + /*logConfig*/ false); #else - config = RenderEngine::chooseEglConfig(display, format); + config = RenderEngine::chooseEglConfig(display, format, + /*logConfig*/ false); #endif } eglSurface = eglCreateWindowSurface(display, config, window, NULL); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 704b17ef43..433a224e25 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -215,6 +215,10 @@ void Composer::registerCallback(const sp& callback) } } +bool Composer::isRemote() { + return mClient->isRemote(); +} + void Composer::resetCommands() { mWriter.reset(); } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 40d2a4c3aa..31a3c1d785 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -143,6 +143,11 @@ public: void registerCallback(const sp& callback); + // Returns true if the connected composer service is running in a remote + // process, false otherwise. This will return false if the service is + // configured in passthrough mode, for example. + bool isRemote(); + // Reset all pending commands in the command buffer. Useful if you want to // skip a frame but have already queued some commands. void resetCommands(); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index b749ce630d..78c0c8567a 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -33,45 +33,6 @@ #include #include -extern "C" { - static void hotplug_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int32_t intConnected) { - auto device = static_cast(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - auto connected = static_cast(intConnected); - device->callHotplug(std::move(display), connected); - } else { - ALOGE("Hotplug callback called with unknown display %" PRIu64, - displayId); - } - } - - static void refresh_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId) { - auto device = static_cast(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callRefresh(std::move(display)); - } else { - ALOGE("Refresh callback called with unknown display %" PRIu64, - displayId); - } - } - - static void vsync_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int64_t timestamp) { - auto device = static_cast(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callVsync(std::move(display), timestamp); - } else { - ALOGE("Vsync callback called with unknown display %" PRIu64, - displayId); - } - } -} - using android::Fence; using android::FloatRect; using android::GraphicBuffer; @@ -86,51 +47,78 @@ namespace HWC2 { namespace Hwc2 = android::Hwc2; +namespace { + +class ComposerCallbackBridge : public Hwc2::IComposerCallback { +public: + ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId) + : mCallback(callback), mSequenceId(sequenceId), + mHasPrimaryDisplay(false) {} + + Return onHotplug(Hwc2::Display display, + IComposerCallback::Connection conn) override + { + HWC2::Connection connection = static_cast(conn); + if (!mHasPrimaryDisplay) { + LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected, + "Initial onHotplug callback should be " + "primary display connected"); + mHasPrimaryDisplay = true; + mCallback->onHotplugReceived(mSequenceId, display, + connection, true); + } else { + mCallback->onHotplugReceived(mSequenceId, display, + connection, false); + } + return Void(); + } + + Return onRefresh(Hwc2::Display display) override + { + mCallback->onRefreshReceived(mSequenceId, display); + return Void(); + } + + Return onVsync(Hwc2::Display display, int64_t timestamp) override + { + mCallback->onVsyncReceived(mSequenceId, display, timestamp); + return Void(); + } + + bool HasPrimaryDisplay() { return mHasPrimaryDisplay; } + +private: + ComposerCallback* mCallback; + int32_t mSequenceId; + bool mHasPrimaryDisplay; +}; + +} // namespace anonymous + + // Device methods Device::Device(const std::string& serviceName) : mComposer(std::make_unique(serviceName)), mCapabilities(), mDisplays(), - mHotplug(), - mPendingHotplugs(), - mRefresh(), - mPendingRefreshes(), - mVsync(), - mPendingVsyncs() + mRegisteredCallback(false) { loadCapabilities(); - registerCallbacks(); } -Device::~Device() -{ - for (auto element : mDisplays) { - auto display = element.second.lock(); - if (!display) { - ALOGE("~Device: Found a display (%" PRId64 " that has already been" - " destroyed", element.first); - continue; - } - - DisplayType displayType = HWC2::DisplayType::Invalid; - auto error = display->getType(&displayType); - if (error != Error::None) { - ALOGE("~Device: Failed to determine type of display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast(error)); - continue; - } - - if (displayType == HWC2::DisplayType::Physical) { - error = display->setVsyncEnabled(HWC2::Vsync::Disable); - if (error != Error::None) { - ALOGE("~Device: Failed to disable vsync for display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast(error)); - } - } +void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) { + if (mRegisteredCallback) { + ALOGW("Callback already registered. Ignored extra registration " + "attempt."); + return; } + mRegisteredCallback = true; + sp callbackBridge( + new ComposerCallbackBridge(callback, sequenceId)); + mComposer->registerCallback(callbackBridge); + LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(), + "Registered composer callback but didn't get primary display"); } // Required by HWC2 device @@ -146,7 +134,7 @@ uint32_t Device::getMaxVirtualDisplayCount() const } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, std::shared_ptr* outDisplay) + android_pixel_format_t* format, Display** outDisplay) { ALOGI("Creating virtual display"); @@ -159,104 +147,66 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, return error; } - ALOGI("Created virtual display"); + auto display = std::make_unique( + *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual); + *outDisplay = display.get(); *format = static_cast(intFormat); - *outDisplay = getDisplayById(displayId); - if (!*outDisplay) { - ALOGE("Failed to get display by id"); - return Error::BadDisplay; - } - (*outDisplay)->setConnected(true); + mDisplays.emplace(displayId, std::move(display)); + ALOGI("Created virtual display"); return Error::None; } -void Device::registerHotplugCallback(HotplugCallback hotplug) +void Device::destroyDisplay(hwc2_display_t displayId) { - ALOGV("registerHotplugCallback"); - mHotplug = hotplug; - for (auto& pending : mPendingHotplugs) { - auto& display = pending.first; - auto connected = pending.second; - ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(), - to_string(connected).c_str()); - mHotplug(std::move(display), connected); - } + ALOGI("Destroying display %" PRIu64, displayId); + mDisplays.erase(displayId); } -void Device::registerRefreshCallback(RefreshCallback refresh) -{ - mRefresh = refresh; - for (auto& pending : mPendingRefreshes) { - mRefresh(std::move(pending)); - } -} - -void Device::registerVsyncCallback(VsyncCallback vsync) -{ - mVsync = vsync; - for (auto& pending : mPendingVsyncs) { - auto& display = pending.first; - auto timestamp = pending.second; - mVsync(std::move(display), timestamp); - } -} - -// For use by Device callbacks +void Device::onHotplug(hwc2_display_t displayId, Connection connection) { + if (connection == Connection::Connected) { + auto display = getDisplayById(displayId); + if (display) { + if (display->isConnected()) { + ALOGW("Attempt to hotplug connect display %" PRIu64 + " , which is already connected.", displayId); + } else { + display->setConnected(true); + } + } else { + DisplayType displayType; + auto intError = mComposer->getDisplayType(displayId, + reinterpret_cast( + &displayType)); + auto error = static_cast(intError); + if (error != Error::None) { + ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). " + "Aborting hotplug attempt.", + displayId, to_string(error).c_str(), intError); + return; + } -void Device::callHotplug(std::shared_ptr display, Connection connected) -{ - if (connected == Connection::Connected) { - if (!display->isConnected()) { - mComposer->setClientTargetSlotCount(display->getId()); - display->loadConfigs(); - display->setConnected(true); + auto newDisplay = std::make_unique( + *mComposer.get(), mCapabilities, displayId, displayType); + mDisplays.emplace(displayId, std::move(newDisplay)); + } + } else if (connection == Connection::Disconnected) { + // The display will later be destroyed by a call to + // destroyDisplay(). For now we just mark it disconnected. + auto display = getDisplayById(displayId); + if (display) { + display->setConnected(false); + } else { + ALOGW("Attempted to disconnect unknown display %" PRIu64, + displayId); } - } else { - display->setConnected(false); - mDisplays.erase(display->getId()); - } - - if (mHotplug) { - mHotplug(std::move(display), connected); - } else { - ALOGV("callHotplug called, but no valid callback registered, storing"); - mPendingHotplugs.emplace_back(std::move(display), connected); - } -} - -void Device::callRefresh(std::shared_ptr display) -{ - if (mRefresh) { - mRefresh(std::move(display)); - } else { - ALOGV("callRefresh called, but no valid callback registered, storing"); - mPendingRefreshes.emplace_back(std::move(display)); - } -} - -void Device::callVsync(std::shared_ptr display, nsecs_t timestamp) -{ - if (mVsync) { - mVsync(std::move(display), timestamp); - } else { - ALOGV("callVsync called, but no valid callback registered, storing"); - mPendingVsyncs.emplace_back(std::move(display), timestamp); } } // Other Device methods -std::shared_ptr Device::getDisplayById(hwc2_display_t id) { - if (mDisplays.count(id) != 0) { - auto strongDisplay = mDisplays[id].lock(); - ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no" - " longer alive", id); - return strongDisplay; - } - - auto display = std::make_shared(*this, id); - mDisplays.emplace(id, display); - return display; +Display* Device::getDisplayById(hwc2_display_t id) { + auto iter = mDisplays.find(id); + return iter == mDisplays.end() ? nullptr : iter->second.get(); } // Device initialization methods @@ -271,84 +221,37 @@ void Device::loadCapabilities() } } -bool Device::hasCapability(HWC2::Capability capability) const -{ - return std::find(mCapabilities.cbegin(), mCapabilities.cend(), - capability) != mCapabilities.cend(); -} - -namespace { -class ComposerCallback : public Hwc2::IComposerCallback { -public: - ComposerCallback(Device* device) : mDevice(device) {} - - Return onHotplug(Hwc2::Display display, - Connection connected) override - { - hotplug_hook(mDevice, display, static_cast(connected)); - return Void(); - } - - Return onRefresh(Hwc2::Display display) override - { - refresh_hook(mDevice, display); - return Void(); - } - - Return onVsync(Hwc2::Display display, int64_t timestamp) override - { - vsync_hook(mDevice, display, timestamp); - return Void(); - } - -private: - Device* mDevice; -}; -} // namespace anonymous - -void Device::registerCallbacks() -{ - sp callback = new ComposerCallback(this); - mComposer->registerCallback(callback); -} - - -// For use by Display - -void Device::destroyVirtualDisplay(hwc2_display_t display) -{ - ALOGI("Destroying virtual display"); - auto intError = mComposer->destroyVirtualDisplay(display); - auto error = static_cast(intError); - ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:" - " %s (%d)", display, to_string(error).c_str(), intError); - mDisplays.erase(display); -} - // Display methods -Display::Display(Device& device, hwc2_display_t id) - : mDevice(device), +Display::Display(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t id, DisplayType type) + : mComposer(composer), + mCapabilities(capabilities), mId(id), mIsConnected(false), - mType(DisplayType::Invalid) + mType(type) { ALOGV("Created display %" PRIu64, id); - - auto intError = mDevice.mComposer->getDisplayType(mId, - reinterpret_cast(&mType)); - auto error = static_cast(intError); - if (error != Error::None) { - ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)", - id, to_string(error).c_str(), intError); - } + setConnected(true); } -Display::~Display() -{ - ALOGV("Destroyed display %" PRIu64, mId); +Display::~Display() { + mLayers.clear(); + if (mType == DisplayType::Virtual) { - mDevice.destroyVirtualDisplay(mId); + ALOGV("Destroying virtual display"); + auto intError = mComposer.destroyVirtualDisplay(mId); + auto error = static_cast(intError); + ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 + ") failed: %s (%d)", mId, to_string(error).c_str(), intError); + } else if (mType == DisplayType::Physical) { + auto error = setVsyncEnabled(HWC2::Vsync::Disable); + if (error != Error::None) { + ALOGE("~Display: Failed to disable vsync for display %" PRIu64 + ": %s (%d)", mId, to_string(error).c_str(), + static_cast(error)); + } } } @@ -383,22 +286,35 @@ float Display::Config::Builder::getDefaultDensity() { Error Display::acceptChanges() { - auto intError = mDevice.mComposer->acceptDisplayChanges(mId); + auto intError = mComposer.acceptDisplayChanges(mId); return static_cast(intError); } -Error Display::createLayer(std::shared_ptr* outLayer) +Error Display::createLayer(Layer** outLayer) { + if (!outLayer) { + return Error::BadParameter; + } hwc2_layer_t layerId = 0; - auto intError = mDevice.mComposer->createLayer(mId, &layerId); + auto intError = mComposer.createLayer(mId, &layerId); auto error = static_cast(intError); if (error != Error::None) { return error; } - auto layer = std::make_shared(shared_from_this(), layerId); - mLayers.emplace(layerId, layer); - *outLayer = std::move(layer); + auto layer = std::make_unique( + mComposer, mCapabilities, mId, layerId); + *outLayer = layer.get(); + mLayers.emplace(layerId, std::move(layer)); + return Error::None; +} + +Error Display::destroyLayer(Layer* layer) +{ + if (!layer) { + return Error::BadParameter; + } + mLayers.erase(layer->getId()); return Error::None; } @@ -407,7 +323,7 @@ Error Display::getActiveConfig( { ALOGV("[%" PRIu64 "] getActiveConfig", mId); hwc2_config_t configId = 0; - auto intError = mDevice.mComposer->getActiveConfig(mId, &configId); + auto intError = mComposer.getActiveConfig(mId, &configId); auto error = static_cast(intError); if (error != Error::None) { @@ -430,12 +346,12 @@ Error Display::getActiveConfig( } Error Display::getChangedCompositionTypes( - std::unordered_map, Composition>* outTypes) + std::unordered_map* outTypes) { std::vector layerIds; std::vector types; - auto intError = mDevice.mComposer->getChangedCompositionTypes(mId, - &layerIds, &types); + auto intError = mComposer.getChangedCompositionTypes( + mId, &layerIds, &types); uint32_t numElements = layerIds.size(); auto error = static_cast(intError); error = static_cast(intError); @@ -464,7 +380,7 @@ Error Display::getChangedCompositionTypes( Error Display::getColorModes(std::vector* outModes) const { std::vector modes; - auto intError = mDevice.mComposer->getColorModes(mId, &modes); + auto intError = mComposer.getColorModes(mId, &modes); uint32_t numModes = modes.size(); auto error = static_cast(intError); if (error != Error::None) { @@ -489,19 +405,18 @@ std::vector> Display::getConfigs() const Error Display::getName(std::string* outName) const { - auto intError = mDevice.mComposer->getDisplayName(mId, outName); + auto intError = mComposer.getDisplayName(mId, outName); return static_cast(intError); } Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, - std::unordered_map, LayerRequest>* - outLayerRequests) + std::unordered_map* outLayerRequests) { uint32_t intDisplayRequests; std::vector layerIds; std::vector layerRequests; - auto intError = mDevice.mComposer->getDisplayRequests(mId, - &intDisplayRequests, &layerIds, &layerRequests); + auto intError = mComposer.getDisplayRequests( + mId, &intDisplayRequests, &layerIds, &layerRequests); uint32_t numElements = layerIds.size(); auto error = static_cast(intError); if (error != Error::None) { @@ -535,7 +450,7 @@ Error Display::getType(DisplayType* outType) const Error Display::supportsDoze(bool* outSupport) const { bool intSupport = false; - auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport); + auto intError = mComposer.getDozeSupport(mId, &intSupport); auto error = static_cast(intError); if (error != Error::None) { return error; @@ -552,7 +467,7 @@ Error Display::getHdrCapabilities( float maxAverageLuminance = -1.0f; float minLuminance = -1.0f; std::vector intTypes; - auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes, + auto intError = mComposer.getHdrCapabilities(mId, &intTypes, &maxLuminance, &maxAverageLuminance, &minLuminance); auto error = static_cast(intError); @@ -571,25 +486,24 @@ Error Display::getHdrCapabilities( } Error Display::getReleaseFences( - std::unordered_map, sp>* outFences) const + std::unordered_map>* outFences) const { std::vector layerIds; std::vector fenceFds; - auto intError = mDevice.mComposer->getReleaseFences(mId, - &layerIds, &fenceFds); + auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds); auto error = static_cast(intError); uint32_t numElements = layerIds.size(); if (error != Error::None) { return error; } - std::unordered_map, sp> releaseFences; + std::unordered_map> releaseFences; releaseFences.reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { sp fence(new Fence(fenceFds[element])); - releaseFences.emplace(std::move(layer), fence); + releaseFences.emplace(layer, fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); @@ -607,7 +521,7 @@ Error Display::getReleaseFences( Error Display::present(sp* outPresentFence) { int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd); + auto intError = mComposer.presentDisplay(mId, &presentFenceFd); auto error = static_cast(intError); if (error != Error::None) { return error; @@ -625,7 +539,7 @@ Error Display::setActiveConfig(const std::shared_ptr& config) config->getDisplayId(), mId); return Error::BadConfig; } - auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId()); + auto intError = mComposer.setActiveConfig(mId, config->getId()); return static_cast(intError); } @@ -634,7 +548,7 @@ Error Display::setClientTarget(uint32_t slot, const sp& target, { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setClientTarget(mId, slot, target, + auto intError = mComposer.setClientTarget(mId, slot, target, fenceFd, static_cast(dataspace), std::vector()); return static_cast(intError); @@ -642,15 +556,15 @@ Error Display::setClientTarget(uint32_t slot, const sp& target, Error Display::setColorMode(android_color_mode_t mode) { - auto intError = mDevice.mComposer->setColorMode(mId, - static_cast(mode)); + auto intError = mComposer.setColorMode( + mId, static_cast(mode)); return static_cast(intError); } Error Display::setColorTransform(const android::mat4& matrix, android_color_transform_t hint) { - auto intError = mDevice.mComposer->setColorTransform(mId, + auto intError = mComposer.setColorTransform(mId, matrix.asArray(), static_cast(hint)); return static_cast(intError); } @@ -660,7 +574,7 @@ Error Display::setOutputBuffer(const sp& buffer, { int32_t fenceFd = releaseFence->dup(); auto handle = buffer->getNativeBuffer()->handle; - auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd); + auto intError = mComposer.setOutputBuffer(mId, handle, fenceFd); close(fenceFd); return static_cast(intError); } @@ -668,14 +582,14 @@ Error Display::setOutputBuffer(const sp& buffer, Error Display::setPowerMode(PowerMode mode) { auto intMode = static_cast(mode); - auto intError = mDevice.mComposer->setPowerMode(mId, intMode); + auto intError = mComposer.setPowerMode(mId, intMode); return static_cast(intError); } Error Display::setVsyncEnabled(Vsync enabled) { auto intEnabled = static_cast(enabled); - auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled); + auto intError = mComposer.setVsyncEnabled(mId, intEnabled); return static_cast(intError); } @@ -683,8 +597,7 @@ Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { uint32_t numTypes = 0; uint32_t numRequests = 0; - auto intError = mDevice.mComposer->validateDisplay(mId, - &numTypes, &numRequests); + auto intError = mComposer.validateDisplay(mId, &numTypes, &numRequests); auto error = static_cast(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -701,7 +614,8 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests uint32_t numTypes = 0; uint32_t numRequests = 0; int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentOrValidateDisplay(mId, &numTypes, &numRequests, &presentFenceFd, state); + auto intError = mComposer.presentOrValidateDisplay( + mId, &numTypes, &numRequests, &presentFenceFd, state); auto error = static_cast(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -720,15 +634,23 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests void Display::discardCommands() { - mDevice.mComposer->resetCommands(); + mComposer.resetCommands(); } // For use by Device +void Display::setConnected(bool connected) { + if (!mIsConnected && connected && mType == DisplayType::Physical) { + mComposer.setClientTargetSlotCount(mId); + loadConfigs(); + } + mIsConnected = connected; +} + int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute) { int32_t value = 0; - auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId, + auto intError = mComposer.getDisplayAttribute(mId, configId, static_cast(attribute), &value); auto error = static_cast(intError); @@ -760,7 +682,7 @@ void Display::loadConfigs() ALOGV("[%" PRIu64 "] loadConfigs", mId); std::vector configIds; - auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds); + auto intError = mComposer.getDisplayConfigs(mId, &configIds); auto error = static_cast(intError); if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId, @@ -773,54 +695,51 @@ void Display::loadConfigs() } } -// For use by Layer - -void Display::destroyLayer(hwc2_layer_t layerId) -{ - auto intError =mDevice.mComposer->destroyLayer(mId, layerId); - auto error = static_cast(intError); - ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" - " failed: %s (%d)", mId, layerId, to_string(error).c_str(), - intError); - mLayers.erase(layerId); -} - // Other Display methods -std::shared_ptr Display::getLayerById(hwc2_layer_t id) const +Layer* Display::getLayerById(hwc2_layer_t id) const { if (mLayers.count(id) == 0) { return nullptr; } - auto layer = mLayers.at(id).lock(); - return layer; + return mLayers.at(id).get(); } // Layer methods -Layer::Layer(const std::shared_ptr& display, hwc2_layer_t id) - : mDisplay(display), - mDisplayId(display->getId()), - mDevice(display->getDevice()), - mId(id) +Layer::Layer(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId) + : mComposer(composer), + mCapabilities(capabilities), + mDisplayId(displayId), + mId(layerId) { - ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id, - display->getId()); + ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId); } Layer::~Layer() { - auto display = mDisplay.lock(); - if (display) { - display->destroyLayer(mId); + auto intError = mComposer.destroyLayer(mDisplayId, mId); + auto error = static_cast(intError); + ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" + " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(), + intError); + if (mLayerDestroyedListener) { + mLayerDestroyedListener(this); } } +void Layer::setLayerDestroyedListener(std::function listener) { + LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener, + "Attempt to set layer destroyed listener multiple times"); + mLayerDestroyedListener = listener; +} + Error Layer::setCursorPosition(int32_t x, int32_t y) { - auto intError = mDevice.mComposer->setCursorPosition(mDisplayId, - mId, x, y); + auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y); return static_cast(intError); } @@ -828,8 +747,8 @@ Error Layer::setBuffer(uint32_t slot, const sp& buffer, const sp& acquireFence) { int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId, - mId, slot, buffer, fenceFd); + auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer, + fenceFd); return static_cast(intError); } @@ -839,7 +758,7 @@ Error Layer::setSurfaceDamage(const Region& damage) // rects for HWC Hwc2::Error intError = Hwc2::Error::NONE; if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, std::vector()); } else { size_t rectCount = 0; @@ -851,8 +770,7 @@ Error Layer::setSurfaceDamage(const Region& damage) rectArray[rect].right, rectArray[rect].bottom}); } - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, - mId, hwcRects); + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects); } return static_cast(intError); @@ -861,24 +779,22 @@ Error Layer::setSurfaceDamage(const Region& damage) Error Layer::setBlendMode(BlendMode mode) { auto intMode = static_cast(mode); - auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId, - mId, intMode); + auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, intMode); return static_cast(intError); } Error Layer::setColor(hwc_color_t color) { Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a}; - auto intError = mDevice.mComposer->setLayerColor(mDisplayId, - mId, hwcColor); + auto intError = mComposer.setLayerColor(mDisplayId, mId, hwcColor); return static_cast(intError); } Error Layer::setCompositionType(Composition type) { auto intType = static_cast(type); - auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId, - mId, intType); + auto intError = mComposer.setLayerCompositionType( + mDisplayId, mId, intType); return static_cast(intError); } @@ -889,8 +805,7 @@ Error Layer::setDataspace(android_dataspace_t dataspace) } mDataSpace = dataspace; auto intDataspace = static_cast(dataspace); - auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId, - mId, intDataspace); + auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace); return static_cast(intError); } @@ -898,27 +813,24 @@ Error Layer::setDisplayFrame(const Rect& frame) { Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top, frame.right, frame.bottom}; - auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect); return static_cast(intError); } Error Layer::setPlaneAlpha(float alpha) { - auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId, - mId, alpha); + auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha); return static_cast(intError); } Error Layer::setSidebandStream(const native_handle_t* stream) { - if (!mDevice.hasCapability(Capability::SidebandStream)) { + if (mCapabilities.count(Capability::SidebandStream) == 0) { ALOGE("Attempted to call setSidebandStream without checking that the " "device supports sideband streams"); return Error::Unsupported; } - auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId, - mId, stream); + auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream); return static_cast(intError); } @@ -926,16 +838,14 @@ Error Layer::setSourceCrop(const FloatRect& crop) { Hwc2::IComposerClient::FRect hwcRect{ crop.left, crop.top, crop.right, crop.bottom}; - auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect); return static_cast(intError); } Error Layer::setTransform(Transform transform) { auto intTransform = static_cast(transform); - auto intError = mDevice.mComposer->setLayerTransform(mDisplayId, - mId, intTransform); + auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform); return static_cast(intError); } @@ -950,20 +860,19 @@ Error Layer::setVisibleRegion(const Region& region) rectArray[rect].right, rectArray[rect].bottom}); } - auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId, - mId, hwcRects); + auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects); return static_cast(intError); } Error Layer::setZOrder(uint32_t z) { - auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z); + auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z); return static_cast(intError); } Error Layer::setInfo(uint32_t type, uint32_t appId) { - auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId); + auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId); return static_cast(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 9bcda1eb0a..fbe4c7ebed 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -53,10 +53,26 @@ namespace HWC2 { class Display; class Layer; -typedef std::function, Connection)> - HotplugCallback; -typedef std::function)> RefreshCallback; -typedef std::function, nsecs_t)> VsyncCallback; +// Implement this interface to receive hardware composer events. +// +// These callback functions will generally be called on a hwbinder thread, but +// when first registering the callback the onHotplugReceived() function will +// immediately be called on the thread calling registerCallback(). +// +// All calls receive a sequenceId, which will be the value that was supplied to +// HWC2::Device::registerCallback(). It's used to help differentiate callbacks +// from different hardware composer instances. +class ComposerCallback { + public: + virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + Connection connection, + bool primaryDisplay) = 0; + virtual void onRefreshReceived(int32_t sequenceId, + hwc2_display_t display) = 0; + virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) = 0; + virtual ~ComposerCallback() = default; +}; // C++ Wrapper around hwc2_device_t. Load all functions pointers // and handle callback registration. @@ -66,10 +82,8 @@ public: // Service name is expected to be 'default' or 'vr' for normal use. // 'vr' will slightly modify the behavior of the mComposer. Device(const std::string& serviceName); - ~Device(); - friend class HWC2::Display; - friend class HWC2::Layer; + void registerCallback(ComposerCallback* callback, int32_t sequenceId); // Required by HWC2 @@ -81,27 +95,14 @@ public: uint32_t getMaxVirtualDisplayCount() const; Error createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, - std::shared_ptr* outDisplay); - - void registerHotplugCallback(HotplugCallback hotplug); - void registerRefreshCallback(RefreshCallback refresh); - void registerVsyncCallback(VsyncCallback vsync); + android_pixel_format_t* format, Display** outDisplay); + void destroyDisplay(hwc2_display_t displayId); - // For use by callbacks - - void callHotplug(std::shared_ptr display, Connection connected); - void callRefresh(std::shared_ptr display); - void callVsync(std::shared_ptr display, nsecs_t timestamp); + void onHotplug(hwc2_display_t displayId, Connection connection); // Other Device methods - // This will create a Display if one is not found, but it will not be marked - // as connected. This Display may be null if the display has been torn down - // but has not been removed from the map yet. - std::shared_ptr getDisplayById(hwc2_display_t id); - - bool hasCapability(HWC2::Capability capability) const; + Display* getDisplayById(hwc2_display_t id); android::Hwc2::Composer* getComposer() { return mComposer.get(); } @@ -109,37 +110,23 @@ private: // Initialization methods void loadCapabilities(); - void registerCallbacks(); - - // For use by Display - - void destroyVirtualDisplay(hwc2_display_t display); // Member variables std::unique_ptr mComposer; - std::unordered_set mCapabilities; - std::unordered_map> mDisplays; - - HotplugCallback mHotplug; - std::vector, Connection>> - mPendingHotplugs; - RefreshCallback mRefresh; - std::vector> mPendingRefreshes; - VsyncCallback mVsync; - std::vector, nsecs_t>> mPendingVsyncs; + std::unordered_map> mDisplays; + bool mRegisteredCallback; }; // Convenience C++ class to access hwc2_device_t Display functions directly. -class Display : public std::enable_shared_from_this +class Display { public: - Display(Device& device, hwc2_display_t id); + Display(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t id, DisplayType type); ~Display(); - friend class HWC2::Device; - friend class HWC2::Layer; - class Config { public: @@ -212,12 +199,12 @@ public: // Required by HWC2 [[clang::warn_unused_result]] Error acceptChanges(); - [[clang::warn_unused_result]] Error createLayer( - std::shared_ptr* outLayer); + [[clang::warn_unused_result]] Error createLayer(Layer** outLayer); + [[clang::warn_unused_result]] Error destroyLayer(Layer* layer); [[clang::warn_unused_result]] Error getActiveConfig( std::shared_ptr* outConfig) const; [[clang::warn_unused_result]] Error getChangedCompositionTypes( - std::unordered_map, Composition>* outTypes); + std::unordered_map* outTypes); [[clang::warn_unused_result]] Error getColorModes( std::vector* outModes) const; @@ -227,14 +214,13 @@ public: [[clang::warn_unused_result]] Error getName(std::string* outName) const; [[clang::warn_unused_result]] Error getRequests( DisplayRequest* outDisplayRequests, - std::unordered_map, LayerRequest>* - outLayerRequests); + std::unordered_map* outLayerRequests); [[clang::warn_unused_result]] Error getType(DisplayType* outType) const; [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const; [[clang::warn_unused_result]] Error getHdrCapabilities( std::unique_ptr* outCapabilities) const; [[clang::warn_unused_result]] Error getReleaseFences( - std::unordered_map, + std::unordered_map>* outFences) const; [[clang::warn_unused_result]] Error present( android::sp* outPresentFence); @@ -266,32 +252,31 @@ public: // Other Display methods - Device& getDevice() const { return mDevice; } hwc2_display_t getId() const { return mId; } bool isConnected() const { return mIsConnected; } + void setConnected(bool connected); // For use by Device only private: - // For use by Device - - void setConnected(bool connected) { mIsConnected = connected; } int32_t getAttribute(hwc2_config_t configId, Attribute attribute); void loadConfig(hwc2_config_t configId); void loadConfigs(); - // For use by Layer - void destroyLayer(hwc2_layer_t layerId); - // This may fail (and return a null pointer) if no layer with this ID exists // on this display - std::shared_ptr getLayerById(hwc2_layer_t id) const; + Layer* getLayerById(hwc2_layer_t id) const; // Member variables - Device& mDevice; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Display, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set& mCapabilities; + hwc2_display_t mId; bool mIsConnected; DisplayType mType; - std::unordered_map> mLayers; + std::unordered_map> mLayers; // The ordering in this map matters, for getConfigs(), when it is // converted to a vector std::map> mConfigs; @@ -301,12 +286,18 @@ private: class Layer { public: - Layer(const std::shared_ptr& display, hwc2_layer_t id); + Layer(android::Hwc2::Composer& composer, + const std::unordered_set& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId); ~Layer(); - bool isAbandoned() const { return mDisplay.expired(); } hwc2_layer_t getId() const { return mId; } + // Register a listener to be notified when the layer is destroyed. When the + // listener function is called, the Layer will be in the process of being + // destroyed, so it's not safe to call methods on it. + void setLayerDestroyedListener(std::function listener); + [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y); [[clang::warn_unused_result]] Error setBuffer(uint32_t slot, const android::sp& buffer, @@ -333,11 +324,16 @@ public: [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId); private: - std::weak_ptr mDisplay; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Layer, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set& mCapabilities; + hwc2_display_t mDisplayId; - Device& mDevice; hwc2_layer_t mId; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + std::function mLayerDestroyedListener; }; } // namespace HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index abf7dd12d0..b096a3ae57 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -65,7 +65,6 @@ HWComposer::HWComposer(const std::string& serviceName) mFreeDisplaySlots(), mHwcDisplaySlots(), mCBContext(), - mEventHandler(nullptr), mVSyncCounts(), mRemainingHwcVirtualDisplays(0) { @@ -74,41 +73,15 @@ HWComposer::HWComposer(const std::string& serviceName) mVSyncCounts[i] = 0; } - loadHwcModule(serviceName); + mHwcDevice = std::make_unique(serviceName); + mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } HWComposer::~HWComposer() {} -void HWComposer::setEventHandler(EventHandler* handler) -{ - if (handler == nullptr) { - ALOGE("setEventHandler: Rejected attempt to clear handler"); - return; - } - - bool wasNull = (mEventHandler == nullptr); - mEventHandler = handler; - - if (wasNull) { - auto hotplugHook = std::bind(&HWComposer::hotplug, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerHotplugCallback(hotplugHook); - auto invalidateHook = std::bind(&HWComposer::invalidate, this, - std::placeholders::_1); - mHwcDevice->registerRefreshCallback(invalidateHook); - auto vsyncHook = std::bind(&HWComposer::vsync, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerVsyncCallback(vsyncHook); - } -} - -// Load and prepare the hardware composer module. Sets mHwc. -void HWComposer::loadHwcModule(const std::string& serviceName) -{ - ALOGV("loadHwcModule"); - mHwcDevice = std::make_unique(serviceName); - - mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); +void HWComposer::registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId) { + mHwcDevice->registerCallback(callback, sequenceId); } bool HWComposer::hasCapability(HWC2::Capability capability) const @@ -146,54 +119,51 @@ void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { } } -void HWComposer::hotplug(const std::shared_ptr& display, - HWC2::Connection connected) { - ALOGV("hotplug: %" PRIu64 ", %s", display->getId(), - to_string(connected).c_str()); - int32_t disp = 0; +void HWComposer::onHotplug(hwc2_display_t displayId, + HWC2::Connection connection) { + ALOGV("hotplug: %" PRIu64 ", %s", displayId, + to_string(connection).c_str()); + mHwcDevice->onHotplug(displayId, connection); if (!mDisplayData[0].hwcDisplay) { - ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary" + ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary" " display would be connected"); - mDisplayData[0].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 0; - disp = DisplayDevice::DISPLAY_PRIMARY; + mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 0; } else { // Disconnect is handled through HWComposer::disconnectDisplay via // SurfaceFlinger's onHotplugReceived callback handling - if (connected == HWC2::Connection::Connected) { - mDisplayData[1].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 1; + if (connection == HWC2::Connection::Connected) { + mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 1; } - disp = DisplayDevice::DISPLAY_EXTERNAL; } - mEventHandler->onHotplugReceived(this, disp, - connected == HWC2::Connection::Connected); } -void HWComposer::invalidate(const std::shared_ptr& /*display*/) { - mEventHandler->onInvalidateReceived(this); -} - -void HWComposer::vsync(const std::shared_ptr& display, - int64_t timestamp) { +bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay) { + auto display = mHwcDevice->getDisplayById(displayId); + if (!display) { + ALOGE("onVsync Failed to find display %" PRIu64, displayId); + return false; + } auto displayType = HWC2::DisplayType::Invalid; auto error = display->getType(&displayType); if (error != HWC2::Error::None) { - ALOGE("vsync: Failed to determine type of display %" PRIu64, + ALOGE("onVsync: Failed to determine type of display %" PRIu64, display->getId()); - return; + return false; } if (displayType == HWC2::DisplayType::Virtual) { ALOGE("Virtual display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } if (mHwcDisplaySlots.count(display->getId()) == 0) { ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } int32_t disp = mHwcDisplaySlots[display->getId()]; @@ -207,17 +177,21 @@ void HWComposer::vsync(const std::shared_ptr& display, if (timestamp == mLastHwVSync[disp]) { ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", timestamp); - return; + return false; } mLastHwVSync[disp] = timestamp; } + if (outDisplay) { + *outDisplay = disp; + } + char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); - mEventHandler->onVSyncReceived(this, disp, timestamp); + return true; } status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, @@ -236,7 +210,7 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return INVALID_OPERATION; } - std::shared_ptr display; + HWC2::Display* display; auto error = mHwcDevice->createVirtualDisplay(width, height, format, &display); if (error != HWC2::Error::None) { @@ -265,13 +239,13 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return NO_ERROR; } -std::shared_ptr HWComposer::createLayer(int32_t displayId) { +HWC2::Layer* HWComposer::createLayer(int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("Failed to create layer on invalid display %d", displayId); return nullptr; } auto display = mDisplayData[displayId].hwcDisplay; - std::shared_ptr layer; + HWC2::Layer* layer; auto error = display->createLayer(&layer); if (error != HWC2::Error::None) { ALOGE("Failed to create layer on display %d: %s (%d)", displayId, @@ -281,6 +255,19 @@ std::shared_ptr HWComposer::createLayer(int32_t displayId) { return layer; } +void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) { + if (!isValidDisplay(displayId)) { + ALOGE("Failed to destroy layer on invalid display %d", displayId); + return; + } + auto display = mDisplayData[displayId].hwcDisplay; + auto error = display->destroyLayer(layer); + if (error != HWC2::Error::None) { + ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId, + to_string(error).c_str(), static_cast(error)); + } +} + nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const { // this returns the last refresh timestamp. // if the last one is not available, we estimate it based on @@ -348,10 +335,8 @@ std::vector HWComposer::getColorModes(int32_t displayId) c displayId); return modes; } - const std::shared_ptr& hwcDisplay = - mDisplayData[displayId].hwcDisplay; - auto error = hwcDisplay->getColorModes(&modes); + auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes); if (error != HWC2::Error::None) { ALOGE("getColorModes failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); @@ -471,7 +456,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return UNKNOWN_ERROR; } if (state == 1) { //Present Succeeded. - std::unordered_map, sp> releaseFences; + std::unordered_map> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); displayData.releaseFences = std::move(releaseFences); displayData.lastPresentFence = outPresentFence; @@ -490,8 +475,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return BAD_INDEX; } - std::unordered_map, HWC2::Composition> - changedTypes; + std::unordered_map changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); if (error != HWC2::Error::None) { @@ -503,8 +487,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { displayData.displayRequests = static_cast(0); - std::unordered_map, HWC2::LayerRequest> - layerRequests; + std::unordered_map layerRequests; layerRequests.reserve(numRequests); error = hwcDisplay->getRequests(&displayData.displayRequests, &layerRequests); @@ -598,7 +581,7 @@ sp HWComposer::getPresentFence(int32_t displayId) const { } sp HWComposer::getLayerReleaseFence(int32_t displayId, - const std::shared_ptr& layer) const { + HWC2::Layer* layer) const { if (!isValidDisplay(displayId)) { ALOGE("getLayerReleaseFence: Invalid display"); return Fence::NO_FENCE; @@ -639,7 +622,7 @@ status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) { return UNKNOWN_ERROR; } - std::unordered_map, sp> releaseFences; + std::unordered_map> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); if (error != HWC2::Error::None) { ALOGE("presentAndGetReleaseFences: Failed to get release fences " @@ -787,6 +770,8 @@ void HWComposer::disconnectDisplay(int displayId) { auto hwcId = displayData.hwcDisplay->getId(); mHwcDisplaySlots.erase(hwcId); displayData.reset(); + + mHwcDevice->destroyDisplay(hwcId); } status_t HWComposer::setOutputBuffer(int32_t displayId, @@ -885,7 +870,7 @@ void HWComposer::dump(String8& result) const { HWComposer::DisplayData::DisplayData() : hasClientComposition(false), hasDeviceComposition(false), - hwcDisplay(), + hwcDisplay(nullptr), lastPresentFence(Fence::NO_FENCE), outbufHandle(nullptr), outbufAcquireFence(Fence::NO_FENCE), diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 3dfb65b1e3..3640bb5a98 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -65,23 +65,14 @@ class String8; class HWComposer { public: - class EventHandler { - friend class HWComposer; - virtual void onVSyncReceived( - HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0; - virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0; - virtual void onInvalidateReceived(HWComposer* composer) = 0; - protected: - virtual ~EventHandler() {} - }; - // Uses the named composer service. Valid choices for normal use // are 'default' and 'vr'. HWComposer(const std::string& serviceName); ~HWComposer(); - void setEventHandler(EventHandler* handler); + void registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId); bool hasCapability(HWC2::Capability capability) const; @@ -91,7 +82,9 @@ public: android_pixel_format_t* format, int32_t* outId); // Attempts to create a new layer on this display - std::shared_ptr createLayer(int32_t displayId); + HWC2::Layer* createLayer(int32_t displayId); + // Destroy a previously created layer + void destroyLayer(int32_t displayId, HWC2::Layer* layer); // Asks the HAL what it can do status_t prepare(DisplayDevice& displayDevice); @@ -126,7 +119,7 @@ public: // Get last release fence for the given layer sp getLayerReleaseFence(int32_t displayId, - const std::shared_ptr& layer) const; + HWC2::Layer* layer) const; // Set the output buffer and acquire fence for a virtual display. // Returns INVALID_OPERATION if displayId is not a virtual display. @@ -142,6 +135,12 @@ public: // Events handling --------------------------------------------------------- + // Returns true if successful, false otherwise. The + // DisplayDevice::DisplayType of the display is returned as an output param. + bool onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay); + void onHotplug(hwc2_display_t displayId, HWC2::Connection connection); + void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled); // Query display parameters. Pass in a display index (e.g. @@ -169,19 +168,11 @@ public: private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; - void loadHwcModule(const std::string& serviceName); - bool isValidDisplay(int32_t displayId) const; static void validateChange(HWC2::Composition from, HWC2::Composition to); struct cb_context; - void invalidate(const std::shared_ptr& display); - void vsync(const std::shared_ptr& display, - int64_t timestamp); - void hotplug(const std::shared_ptr& display, - HWC2::Connection connected); - struct DisplayData { DisplayData(); ~DisplayData(); @@ -189,11 +180,10 @@ private: bool hasClientComposition; bool hasDeviceComposition; - std::shared_ptr hwcDisplay; + HWC2::Display* hwcDisplay; HWC2::DisplayRequest displayRequests; sp lastPresentFence; // signals when the last set op retires - std::unordered_map, sp> - releaseFences; + std::unordered_map> releaseFences; buffer_handle_t outbufHandle; sp outbufAcquireFence; mutable std::unordered_mapsetVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); -#else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, - mVsyncEnabled); -#endif + enum class VsyncState {Unset, On, Off}; + auto currentVsyncState = VsyncState::Unset; while (true) { - status_t err = mCond.wait(mMutex); - if (err != NO_ERROR) { - ALOGE("error waiting for new events: %s (%d)", - strerror(-err), err); - return false; + auto requestedVsyncState = VsyncState::On; + { + Mutex::Autolock lock(mMutex); + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + while (currentVsyncState == requestedVsyncState) { + status_t err = mCond.wait(mMutex); + if (err != NO_ERROR) { + ALOGE("error waiting for new events: %s (%d)", + strerror(-err), err); + return false; + } + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + } } - if (vsyncEnabled != mVsyncEnabled) { + bool enable = requestedVsyncState == VsyncState::On; #ifdef USE_HWC2 - mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); + mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable); #else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, - SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, + SurfaceFlinger::EVENT_VSYNC, enable); #endif - vsyncEnabled = mVsyncEnabled; - } + currentVsyncState = requestedVsyncState; } return false; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3903a5546f..54d4cbd613 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -201,6 +201,12 @@ Layer::~Layer() { } mFlinger->deleteTextureAsync(mTextureName); mFrameTracker.logAndResetStats(mName); + +#ifdef USE_HWC2 + ALOGE_IF(!mHwcLayers.empty(), + "Found stale hardware composer layers when destroying " + "surface flinger layer"); +#endif } // --------------------------------------------------------------------------- @@ -303,7 +309,7 @@ void Layer::onRemoved() { mSurfaceFlingerConsumer->abandon(); #ifdef USE_HWC2 - clearHwcLayers(); + destroyAllHwcLayers(); #endif for (const auto& child : mCurrentChildren) { @@ -364,6 +370,48 @@ sp Layer::getProducer() const { // h/w composer set-up // --------------------------------------------------------------------------- +#ifdef USE_HWC2 +bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Already have a layer for hwcId %d", hwcId); + HWC2::Layer* layer = hwc->createLayer(hwcId); + if (!layer) { + return false; + } + HWCInfo& hwcInfo = mHwcLayers[hwcId]; + hwcInfo.hwc = hwc; + hwcInfo.layer = layer; + layer->setLayerDestroyedListener( + [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);}); + return true; +} + +void Layer::destroyHwcLayer(int32_t hwcId) { + if (mHwcLayers.count(hwcId) == 0) { + return; + } + auto& hwcInfo = mHwcLayers[hwcId]; + LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, + "Attempt to destroy null layer"); + LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer"); + hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer); + // The layer destroyed listener should have cleared the entry from + // mHwcLayers. Verify that. + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Stale layer entry in mHwcLayers"); +} + +void Layer::destroyAllHwcLayers() { + size_t numLayers = mHwcLayers.size(); + for (size_t i = 0; i < numLayers; ++i) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed"); + destroyHwcLayer(mHwcLayers.begin()->first); + } + LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(), + "All hardware composer layers should have been destroyed"); +} +#endif + Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 8df8c49bbe..1b7d0759d5 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -447,37 +447,21 @@ public: #ifdef USE_HWC2 // ----------------------------------------------------------------------- + bool createHwcLayer(HWComposer* hwc, int32_t hwcId); + void destroyHwcLayer(int32_t hwcId); + void destroyAllHwcLayers(); + bool hasHwcLayer(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { - return false; - } - if (mHwcLayers[hwcId].layer->isAbandoned()) { - ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId); - mHwcLayers.erase(hwcId); - return false; - } - return true; + return mHwcLayers.count(hwcId) > 0; } - std::shared_ptr getHwcLayer(int32_t hwcId) { + HWC2::Layer* getHwcLayer(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { return nullptr; } return mHwcLayers[hwcId].layer; } - void setHwcLayer(int32_t hwcId, std::shared_ptr&& layer) { - if (layer) { - mHwcLayers[hwcId].layer = layer; - } else { - mHwcLayers.erase(hwcId); - } - } - - void clearHwcLayers() { - mHwcLayers.clear(); - } - #endif // ----------------------------------------------------------------------- @@ -766,12 +750,14 @@ private: // HWC items, accessed from the main thread struct HWCInfo { HWCInfo() - : layer(), + : hwc(nullptr), + layer(nullptr), forceClientComposition(false), compositionType(HWC2::Composition::Invalid), clearClientTarget(false) {} - std::shared_ptr layer; + HWComposer* hwc; + HWC2::Layer* layer; bool forceClientComposition; HWC2::Composition compositionType; bool clearClientTarget; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index ac2d8b2aba..57f468d2fa 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -64,7 +64,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f "EGL_ANDROIDX_no_config_context") && !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), "EGL_KHR_no_config_context")) { - config = chooseEglConfig(display, hwcFormat); + config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint renderableType = 0; @@ -108,7 +108,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f EGLConfig dummyConfig = config; if (dummyConfig == EGL_NO_CONFIG) { - dummyConfig = chooseEglConfig(display, hwcFormat); + dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); @@ -406,7 +406,8 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, return err; } -EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { +EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, + bool logConfig) { status_t err; EGLConfig config; @@ -427,18 +428,20 @@ EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { } } - // print some debugging info - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - ALOGI("EGL information:"); - ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); - ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); - ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + if (logConfig) { + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + } return config; } diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 56f582755e..954457946e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -64,7 +64,7 @@ public: }; static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags); - static EGLConfig chooseEglConfig(EGLDisplay display, int format); + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); void primeCache() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 609b15b382..0d93467125 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -77,6 +77,7 @@ #include "MonitoredProducer.h" #include "SurfaceFlinger.h" +#include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" @@ -101,10 +102,24 @@ EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint na namespace android { - using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +namespace { +class ConditionalLock { +public: + ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) { + if (lock) { + mMutex.lock(); + } + } + ~ConditionalLock() { if (mLocked) mMutex.unlock(); } +private: + Mutex& mMutex; + bool mLocked; +}; +} // namespace anonymous + // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); @@ -147,9 +162,6 @@ SurfaceFlinger::SurfaceFlinger() mLayersRemoved(false), mLayersAdded(false), mRepaintEverything(0), - mHwc(nullptr), - mRealHwc(nullptr), - mVrHwc(nullptr), mHwcServiceName(getHwcServiceName()), mRenderEngine(nullptr), mBootTime(systemTime()), @@ -177,7 +189,9 @@ SurfaceFlinger::SurfaceFlinger() mTotalTime(0), mLastSwapTime(0), mNumLayers(0), - mVrFlingerRequestsDisplay(false) + mVrFlingerRequestsDisplay(false), + mMainThreadId(std::this_thread::get_id()), + mComposerSequenceId(0) { ALOGI("SurfaceFlinger is starting"); @@ -583,48 +597,46 @@ void SurfaceFlinger::init() { ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs); - { // Autolock scope - Mutex::Autolock _l(mStateLock); + Mutex::Autolock _l(mStateLock); - // initialize EGL for the default display - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mEGLDisplay, NULL, NULL); - - // start the EventThread - sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); - mEventThread = new EventThread(vsyncSrc, *this, false); - sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); - mSFEventThread = new EventThread(sfVsyncSrc, *this, true); - mEventQueue.setEventThread(mSFEventThread); + // initialize EGL for the default display + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); - // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); - } - if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for EventThread"); - } + // start the EventThread + sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "app"); + mEventThread = new EventThread(vsyncSrc, *this, false); + sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, + sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = new EventThread(sfVsyncSrc, *this, true); + mEventQueue.setEventThread(mSFEventThread); - // Get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, - HAL_PIXEL_FORMAT_RGBA_8888, - hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); + // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); + } + if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for EventThread"); } - // 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."); - mRealHwc = new HWComposer(mHwcServiceName); - mHwc = mRealHwc; - mHwc->setEventHandler(static_cast(this)); + // Get a RenderEngine for the given display / config (can't fail) + mRenderEngine = RenderEngine::create(mEGLDisplay, + HAL_PIXEL_FORMAT_RGBA_8888, + hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); - Mutex::Autolock _l(mStateLock); + // retrieve the EGL context that was selected/created + mEGLContext = mRenderEngine->getEGLContext(); + + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, + "couldn't create EGLContext"); + + LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, + "Starting with vr flinger active is not currently supported."); + mHwc.reset(new HWComposer(mHwcServiceName)); + mHwc->registerCallback(this, mComposerSequenceId); if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { @@ -639,16 +651,6 @@ void SurfaceFlinger::init() { } } - // retrieve the EGL context that was selected/created - mEGLContext = mRenderEngine->getEGLContext(); - - LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, - "couldn't create EGLContext"); - - // make the GLContext current so that we can create textures when creating - // Layers (which may happens before we render something) - getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); - mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); @@ -1218,11 +1220,16 @@ void SurfaceFlinger::resyncWithRateLimit() { sLastResyncAttempted = now; } -void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, - nsecs_t timestamp) { +void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, + hwc2_display_t displayId, int64_t timestamp) { Mutex::Autolock lock(mStateLock); - // Ignore any vsyncs from the non-active hardware composer. - if (composer != mHwc) { + // Ignore any vsyncs from a previous hardware composer. + if (sequenceId != mComposerSequenceId) { + return; + } + + int32_t type; + if (!mHwc->onVsync(displayId, timestamp, &type)) { return; } @@ -1230,7 +1237,7 @@ void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, { // Scope for the lock Mutex::Autolock _l(mHWVsyncLock); - if (type == 0 && mPrimaryHWVsyncEnabled) { + if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) { needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } @@ -1248,7 +1255,7 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { } void SurfaceFlinger::createDefaultDisplayDevice() { - const int32_t type = DisplayDevice::DISPLAY_PRIMARY; + const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY; wp token = mBuiltinDisplays[type]; // All non-virtual displays are currently considered secure. @@ -1279,28 +1286,49 @@ void SurfaceFlinger::createDefaultDisplayDevice() { mDisplays.add(token, hw); setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE); hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); -} -void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { - ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); + // Add the primary display token to mDrawingState so we don't try to + // recreate the DisplayDevice for the primary display. + mDrawingState.displays.add(token, DisplayDeviceState(type, true)); - if (composer->isUsingVrComposer()) { - // We handle initializing the primary display device for the VR - // window manager hwc explicitly at the time of transition. - if (disp != DisplayDevice::DISPLAY_PRIMARY) { - ALOGE("External displays are not supported by the vr hardware composer."); + // make the GLContext current so that we can create textures when creating + // Layers (which may happens before we render something) + hw->makeCurrent(mEGLDisplay, mEGLContext); +} + +void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, + hwc2_display_t display, HWC2::Connection connection, + bool primaryDisplay) { + ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)", + sequenceId, display, + connection == HWC2::Connection::Connected ? + "connected" : "disconnected", + primaryDisplay ? "primary" : "external"); + + // Only lock if we're not on the main thread. This function is normally + // called on a hwbinder thread, but for the primary display it's called on + // the main thread with the state lock already held, so don't attempt to + // acquire it here. + ConditionalLock lock(mStateLock, + std::this_thread::get_id() != mMainThreadId); + + if (primaryDisplay) { + mHwc->onHotplug(display, connection); + if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) { + createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); } - return; - } - - if (disp == DisplayDevice::DISPLAY_PRIMARY) { - Mutex::Autolock lock(mStateLock); - createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); createDefaultDisplayDevice(); } else { + if (sequenceId != mComposerSequenceId) { + return; + } + if (mHwc->isUsingVrComposer()) { + ALOGE("External displays are not supported by the vr hardware composer."); + return; + } + mHwc->onHotplug(display, connection); auto type = DisplayDevice::DISPLAY_EXTERNAL; - Mutex::Autolock _l(mStateLock); - if (connected) { + if (connection == HWC2::Connection::Connected) { createBuiltinDisplayLocked(type); } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); @@ -1312,46 +1340,31 @@ void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool } } -void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) { +void SurfaceFlinger::onRefreshReceived(int sequenceId, + hwc2_display_t /*display*/) { Mutex::Autolock lock(mStateLock); - if (composer == mHwc) { - repaintEverything(); - } else { - // This isn't from our current hardware composer. If it's a callback - // from the real composer, forward the refresh request to vr - // flinger. Otherwise ignore it. - if (!composer->isUsingVrComposer()) { - mVrFlinger->OnHardwareComposerRefresh(); - } + if (sequenceId != mComposerSequenceId) { + return; } + repaintEverything(); } void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { ATRACE_CALL(); + Mutex::Autolock lock(mStateLock); getHwComposer().setVsyncEnabled(disp, enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } // Note: it is assumed the caller holds |mStateLock| when this is called -void SurfaceFlinger::resetHwcLocked() { +void SurfaceFlinger::resetDisplayState() { disableHardwareVsync(true); - clearHwcLayers(mDrawingState.layersSortedByZ); - clearHwcLayers(mCurrentState.layersSortedByZ); - for (size_t disp = 0; disp < mDisplays.size(); ++disp) { - clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ()); - } // Clear the drawing state so that the logic inside of // handleTransactionLocked will fire. It will determine the delta between // mCurrentState and mDrawingState and re-apply all changes when we make the // transition. mDrawingState.displays.clear(); - // Release virtual display hwcId during vr mode transition. - for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { - const sp& displayDevice = mDisplays[displayId]; - if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) { - displayDevice->disconnect(getHwComposer()); - } - } + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); mDisplays.clear(); } @@ -1363,57 +1376,54 @@ void SurfaceFlinger::updateVrFlinger() { return; } - if (vrFlingerRequestsDisplay && !mVrHwc) { - // Construct new HWComposer without holding any locks. - mVrHwc = new HWComposer("vr"); - - // Set up the event handlers. This step is neccessary to initialize the internal state of - // the hardware composer object properly. Our callbacks are designed such that if they are - // triggered between now and the point where the display is properly re-initialized, they - // will not have any effect, so this is safe to do here, before the lock is aquired. - mVrHwc->setEventHandler(static_cast(this)); - ALOGV("Vr HWC created"); + if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) { + ALOGE("Vr flinger is only supported for remote hardware composer" + " service connections. Ignoring request to transition to vr" + " flinger."); + mVrFlingerRequestsDisplay = false; + return; } Mutex::Autolock _l(mStateLock); - if (vrFlingerRequestsDisplay) { - resetHwcLocked(); - - mHwc = mVrHwc; - mVrFlinger->GrantDisplayOwnership(); + int currentDisplayPowerMode = getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode(); - } else { + if (!vrFlingerRequestsDisplay) { mVrFlinger->SeizeDisplayOwnership(); + } - resetHwcLocked(); + resetDisplayState(); + mHwc.reset(); // Delete the current instance before creating the new one + mHwc.reset(new HWComposer( + vrFlingerRequestsDisplay ? "vr" : mHwcServiceName)); + mHwc->registerCallback(this, ++mComposerSequenceId); - mHwc = mRealHwc; + LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(), + "Switched to non-remote hardware composer"); + + if (vrFlingerRequestsDisplay) { + mVrFlinger->GrantDisplayOwnership(); + } else { enableHardwareVsync(); } mVisibleRegionsDirty = true; invalidateHwcGeometry(); - // Explicitly re-initialize the primary display. This is because some other - // parts of this class rely on the primary display always being available. - createDefaultDisplayDevice(); - // Re-enable default display. - sp requestMessage = new LambdaMessage([&]() { - sp hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); - setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL); + sp hw(getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); + setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true); - // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); - const nsecs_t period = activeConfig->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(period); + // Reset the timing values to account for the period of the swapped in HWC + const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const nsecs_t period = activeConfig->getVsyncPeriod(); + mAnimFrameTracker.setDisplayRefreshPeriod(period); - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - setCompositorTimingSnapped(0, period, 0); - }); - postMessageAsync(requestMessage); + // Use phase of 0 since phase is not known. + // Use latency of 0, which will snap to the ideal latency. + setCompositorTimingSnapped(0, period, 0); android_atomic_or(1, &mRepaintEverything); setTransactionFlags(eDisplayTransactionNeeded); @@ -1749,15 +1759,14 @@ void SurfaceFlinger::rebuildLayerStacks() { } else { // Clear out the HWC layer if this layer was // previously visible, but no longer is - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer( + displayDevice->getHwcDisplayId()); } } else { // WM changes displayDevice->layerStack upon sleep/awake. // Here we make sure we delete the HWC layers even if // WM changed their layer stack. - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer(displayDevice->getHwcDisplayId()); } }); } @@ -1872,10 +1881,7 @@ void SurfaceFlinger::setUpHWComposer() { for (size_t i = 0; i < currentLayers.size(); i++) { const auto& layer = currentLayers[i]; if (!layer->hasHwcLayer(hwcId)) { - auto hwcLayer = mHwc->createLayer(hwcId); - if (hwcLayer) { - layer->setHwcLayer(hwcId, std::move(hwcLayer)); - } else { + if (!layer->createHwcLayer(mHwc.get(), hwcId)) { layer->forceClientComposition(hwcId); continue; } @@ -2161,7 +2167,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface != NULL) { // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || mHwc == mVrHwc) { + if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); @@ -3285,7 +3291,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.height = 0; displays.add(d); setTransactionState(state, displays, 0); - setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); + setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL, + /*stateLockHeld*/ false); const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); @@ -3311,7 +3318,7 @@ void SurfaceFlinger::initializeDisplays() { } void SurfaceFlinger::setPowerModeInternal(const sp& hw, - int mode) { + int mode, bool stateLockHeld) { ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); @@ -3328,7 +3335,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& hw, } if (mInterceptor.isEnabled()) { - Mutex::Autolock _l(mStateLock); + ConditionalLock lock(mStateLock, !stateLockHeld); ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); if (idx < 0) { ALOGW("Surface Interceptor SavePowerMode: invalid display token"); @@ -3414,7 +3421,8 @@ void SurfaceFlinger::setPowerMode(const sp& display, int mode) { ALOGW("Attempt to set power mode = %d for virtual display", mMode); } else { - mFlinger.setPowerModeInternal(hw, mMode); + mFlinger.setPowerModeInternal( + hw, mMode, /*stateLockHeld*/ false); } return true; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5123b58913..058f4a1d3b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -60,13 +60,20 @@ #include "SurfaceInterceptor.h" #include "StartPropertySetThread.h" +#ifdef USE_HWC2 +#include "DisplayHardware/HWC2.h" #include "DisplayHardware/HWComposer.h" +#else +#include "DisplayHardware/HWComposer_hwc1.h" +#endif + #include "Effects/Daltonizer.h" #include #include #include #include +#include #include namespace android { @@ -99,7 +106,11 @@ enum { class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, +#ifdef USE_HWC2 + private HWC2::ComposerCallback +#else private HWComposer::EventHandler +#endif { public: @@ -314,11 +325,20 @@ private: virtual void onFirstRef(); /* ------------------------------------------------------------------------ - * HWComposer::EventHandler interface + * HWC2::ComposerCallback / HWComposer::EventHandler interface */ - virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp); - virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected); - virtual void onInvalidateReceived(HWComposer* composer); +#ifdef USE_HWC2 + void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) override; + void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + HWC2::Connection connection, + bool primaryDisplay) override; + void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override; +#else + void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override; + void onHotplugReceived(HWComposer* composer, int disp, bool connected) override; + void onInvalidateReceived(HWComposer* composer) override; +#endif /* ------------------------------------------------------------------------ * Message handling @@ -333,7 +353,12 @@ private: // called on the main thread in response to setActiveConfig() void setActiveConfigInternal(const sp& hw, int mode); // called on the main thread in response to setPowerMode() +#ifdef USE_HWC2 + void setPowerModeInternal(const sp& hw, int mode, + bool stateLockHeld); +#else void setPowerModeInternal(const sp& hw, int mode); +#endif // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp& hw, android_color_mode_t colorMode); @@ -591,13 +616,7 @@ private: /* ------------------------------------------------------------------------ * VrFlinger */ - template - void clearHwcLayers(const T& layers) { - for (size_t i = 0; i < layers.size(); ++i) { - layers[i]->clearHwcLayers(); - } - } - void resetHwcLocked(); + void resetDisplayState(); // Check to see if we should handoff to vr flinger. void updateVrFlinger(); @@ -624,13 +643,14 @@ private: // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; - // current, real and vr hardware composers. - HWComposer* mHwc; + // The current hardware composer interface. When switching into and out of + // vr, our HWComposer instance will be recreated. + std::unique_ptr mHwc; + #ifdef USE_HWC2 - HWComposer* mRealHwc; - HWComposer* mVrHwc; const std::string mHwcServiceName; // "default" for real use, something else for testing. #endif + // constant members (no synchronization needed for access) RenderEngine* mRenderEngine; nsecs_t mBootTime; @@ -644,10 +664,6 @@ private: EGLDisplay mEGLDisplay; sp mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; -#ifdef USE_HWC2 - std::unique_ptr mVrFlinger; -#endif - // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; @@ -769,8 +785,14 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); #ifdef USE_HWC2 + std::unique_ptr mVrFlinger; std::atomic mVrFlingerRequestsDisplay; static bool useVrFlinger; + std::thread::id mMainThreadId; + // The composer sequence id is a monotonically increasing integer that we + // use to differentiate callbacks from different hardware composer + // instances. Each hardware composer instance gets a different sequence id. + int32_t mComposerSequenceId; #endif float mSaturation = 1.0f; diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 7aaa42aa4b..78a04e08e1 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -535,8 +535,8 @@ void SurfaceFlinger::init() { // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. - mHwc = new HWComposer(this, - *static_cast(this)); + mHwc.reset(new HWComposer(this, + *static_cast(this))); // get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, -- cgit v1.2.3-59-g8ed1b From 00b15b8f223976d016e16536e4720771ef634695 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 10 Aug 2017 20:30:56 +0900 Subject: Mark libEGL, GLESv1_CM, GLESv2, and GLESv3 as LLNDK They are used by libRSDriver and libRS_internal which are VNDK-SP libraries. Therefore, the EGL/GLES libs must be LLNDK or VNDK-SP. We choose to make them as LLNDK since they already have stable ABIs (as they are NDK). In addition, two more functions of libEGL are exposed to vendors eglQueryStringImplementationANDROID and eglDupNativeFenceFDANDROID are non-NDK symbols but are being used by libgui, which is a library marked with vendor_available:true. In order to provide the symbols to the library, they are added to the map.txt file and tagged as "# vndk" so that they are exposed only when built for vendor libs (and hidden when built for NDK). Furthermore, eglQueryStringImplementationANDROID is changed to C-symbol in order to be mentioned in the map.txt file, where C++ mangled symbol name can't be used. Bug: 64425518 Test: BOARD_VNDK_VERSION=current m -j libRSDriver.vendor Test: BOARD_VNDK_VERSION=current m -j libRS_internal.vendor Change-Id: I4d5bcd5f72fb05a7908887f5192de70fd1d8c8f1 --- libs/gui/GLConsumer.cpp | 2 +- libs/gui/SyncFeatures.cpp | 2 +- libs/gui/tests/SurfaceTextureClient_test.cpp | 2 +- opengl/Android.bp | 24 ++++++++++++++++++++++ opengl/libs/Android.bp | 8 -------- opengl/libs/EGL/eglApi.cpp | 2 +- opengl/libs/libEGL.map.txt | 2 ++ opengl/tests/gl2_basic/gl2_basic.cpp | 2 +- opengl/tests/lib/include/EGLUtils.h | 2 +- .../surfaceflinger/RenderEngine/RenderEngine.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 2 +- 12 files changed, 35 insertions(+), 17 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 34c9d7805a..679c70af4c 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -43,7 +43,7 @@ #include #include -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index 187b211be8..afa15c5cda 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -27,7 +27,7 @@ #include -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index bd598e419e..d5b2f004ed 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -28,7 +28,7 @@ #include #include -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" namespace android { diff --git a/opengl/Android.bp b/opengl/Android.bp index aec5a95628..9ca8b0b0fd 100644 --- a/opengl/Android.bp +++ b/opengl/Android.bp @@ -52,6 +52,30 @@ ndk_headers { license: "include/KHR/NOTICE", } +llndk_library { + name: "libEGL", + symbol_file: "libs/libEGL.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv1_CM", + symbol_file: "libs/libGLESv1_CM.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv2", + symbol_file: "libs/libGLESv2.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv3", + symbol_file: "libs/libGLESv3.map.txt", + export_include_dirs: ["include"], +} + cc_library_headers { name: "gl_headers", vendor_available: true, diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 1cfc5133c1..802b3b46e0 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -85,7 +85,6 @@ cc_defaults { cc_defaults { name: "egl_libs_defaults", defaults: ["gl_libs_defaults"], - vendor_available: true, cflags: [ "-DLOG_TAG=\"libEGL\"", ], @@ -117,9 +116,6 @@ cc_library_static { cc_library_shared { name: "libEGL", defaults: ["egl_libs_defaults"], - vndk: { - enabled: true, - }, srcs: [ "EGL/egl_tls.cpp", "EGL/egl_cache.cpp", @@ -155,7 +151,6 @@ cc_test { cc_defaults { name: "gles_libs_defaults", defaults: ["gl_libs_defaults"], - vendor_available: true, arch: { arm: { instruction_set: "arm", @@ -183,9 +178,6 @@ cc_library_shared { cc_library_shared { name: "libGLESv2", defaults: ["gles_libs_defaults"], - vndk: { - enabled: true, - }, srcs: ["GLES2/gl2.cpp"], cflags: ["-DLOG_TAG=\"libGLESv2\""], } diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 0214b0eb56..94dfe6a9de 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -1447,7 +1447,7 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)0); } -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) { clearError(); diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt index 89269a0231..fa26e33f39 100644 --- a/opengl/libs/libEGL.map.txt +++ b/opengl/libs/libEGL.map.txt @@ -21,6 +21,7 @@ LIBEGL { eglDestroyStreamKHR; # introduced=23 eglDestroySurface; eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglDupNativeFenceFDANDROID; # vndk eglGetConfigAttrib; eglGetConfigs; eglGetCurrentContext; @@ -44,6 +45,7 @@ LIBEGL { eglQueryStreamTimeKHR; # introduced=23 eglQueryStreamu64KHR; # introduced=23 eglQueryString; + eglQueryStringImplementationANDROID; # vndk eglQuerySurface; eglReleaseTexImage; eglReleaseThread; diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index ee88667328..67c0969e21 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -30,7 +30,7 @@ #include using namespace android; -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h index 29f4fe442d..9dc6bcf56a 100644 --- a/opengl/tests/lib/include/EGLUtils.h +++ b/opengl/tests/lib/include/EGLUtils.h @@ -29,7 +29,7 @@ #include #include -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // ---------------------------------------------------------------------------- namespace android { diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 57f468d2fa..56e9ac07ad 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -26,7 +26,7 @@ #include #include -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // --------------------------------------------------------------------------- namespace android { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 06e2a7fd35..4aaa8c0b23 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -97,7 +97,7 @@ */ #define DEBUG_SCREENSHOTS false -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index a41d35f19d..e5bb228df1 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -94,7 +94,7 @@ */ #define DEBUG_SCREENSHOTS false -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { // --------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From c665702cea06c5c42360b7f66fed1693127e6680 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Tue, 15 Aug 2017 11:18:17 -0700 Subject: surfaceflinger: fix z-relative layer destruction Layer::commitTransaction is called before Layer::onRemoved. The removal of a layer from another layer's zOrderRelatives is not reflected in Layer::mDrawingState until Layer::commitTransaction is called again. As a result, we may draw a removed layer, which is not supposed to own any HWC or GL resource. Add Layer::onRemovedFromCurrentState that is called when a layer is removed from mCurrentState to mLayersPendingRemoval. Move zOrderRelative* updates from onRemoved to the new onRemovedFromCurrentState, and set eTraversalNeeded as needed. Also fix Layer::~Layer to restore the old behavior and destroy all stale HWC layers just in case. Bug: 64572777 Test: manual and AUPT Change-Id: I546c5b4b7ecac0937fead655733402fae664331c --- services/surfaceflinger/Layer.cpp | 25 +++++++++++++++++-------- services/surfaceflinger/Layer.h | 10 ++++++++-- services/surfaceflinger/SurfaceFlinger.cpp | 1 + services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 1 + 4 files changed, 27 insertions(+), 10 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4edde14069..038ece2e05 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -202,9 +202,11 @@ Layer::~Layer() { mFrameTracker.logAndResetStats(mName); #ifdef USE_HWC2 - ALOGE_IF(!mHwcLayers.empty(), - "Found stale hardware composer layers when destroying " - "surface flinger layer"); + if (!mHwcLayers.empty()) { + ALOGE("Found stale hardware composer layers when destroying " + "surface flinger layer %s", mName.string()); + destroyAllHwcLayers(); + } #endif } @@ -293,20 +295,27 @@ void Layer::onSidebandStreamChanged() { } } -// called with SurfaceFlinger::mStateLock from the drawing thread after -// the layer has been remove from the current state list (and just before -// it's removed from the drawing state list) -void Layer::onRemoved() { +void Layer::onRemovedFromCurrentState() { + // the layer is removed from SF mCurrentState to mLayersPendingRemoval + if (mCurrentState.zOrderRelativeOf != nullptr) { sp strongRelative = mCurrentState.zOrderRelativeOf.promote(); if (strongRelative != nullptr) { strongRelative->removeZOrderRelative(this); + mFlinger->setTransactionFlags(eTraversalNeeded); } mCurrentState.zOrderRelativeOf = nullptr; } - mSurfaceFlingerConsumer->abandon(); + for (const auto& child : mCurrentChildren) { + child->onRemovedFromCurrentState(); + } +} +void Layer::onRemoved() { + // the layer is removed from SF mLayersPendingRemoval + + mSurfaceFlingerConsumer->abandon(); #ifdef USE_HWC2 destroyAllHwcLayers(); #endif diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 222718bcda..c34d8a0930 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -419,8 +419,14 @@ public: bool isPotentialCursor() const { return mPotentialCursor;} /* - * called with the state lock when the surface is removed from the - * current list + * called with the state lock from a binder thread when the layer is + * removed from the current list to the pending removal list + */ + void onRemovedFromCurrentState(); + + /* + * called with the state lock from the main thread when the layer is + * removed from the pending removal list */ void onRemoved(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4aaa8c0b23..769ff9c574 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2790,6 +2790,7 @@ status_t SurfaceFlinger::removeLayer(const sp& layer, bool topLevelOnly) return NO_ERROR; } + layer->onRemovedFromCurrentState(); mLayersPendingRemoval.add(layer); mLayersRemoved = true; mNumLayers -= 1 + layer->getChildrenCount(); diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index e5bb228df1..b28fe68224 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -2382,6 +2382,7 @@ status_t SurfaceFlinger::removeLayer(const sp& layer, bool topLevelOnly) return NO_ERROR; } + layer->onRemovedFromCurrentState(); mLayersPendingRemoval.add(layer); mLayersRemoved = true; mNumLayers -= 1 + layer->getChildrenCount(); -- cgit v1.2.3-59-g8ed1b From 6d8110b1708171da278782d18886fa1a21971cd9 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Thu, 31 Aug 2017 18:24:21 -0700 Subject: Fix race conditions when using mHwc off the main thread In a few cases we were accessing mHwc off the main thread without acquiring mStateLock, resulting in crashes and other incorrect behavior. This CL adds the missing locks. Since the locking semantics are somewhat hard to understand, also add a clarifying comment to the mHwc member declaration in SurfaceFlinger.h. Bug: 64586546 Test: I manually tested normal surface flinger operation and vr behavior on different devices, and confirmed everything looks fine. The crashes we saw that were caused by these mHwc race conditions are hard to reproduce, so I couldn't empirically verify this fixes the crash. I'm relying on manual code inspection to confirm the issue is in fact fixed. Regarding performance, I added profiling code (not part of this CL) to check for lock contention and hold times with the newly added locks. I confirmed that contention is low, so these calls shouldn't be significantly slower as a result of adding the locks. The time spent holding these new locks is also low, except for getDisplayColorModes(), which makes a call to hardware composer service and can in some cases take over a millisecond. That function is called so rarely though, only once at boot, or twice at boot after a fresh flash, that it's not worth optimizing. Change-Id: I3854779c12a61983aaaecddb9f6316f218e519e3 --- services/surfaceflinger/SurfaceFlinger.cpp | 28 +++++++++++++++++++++++----- services/surfaceflinger/SurfaceFlinger.h | 27 +++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 7 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 736346497d..12205af919 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -606,6 +606,8 @@ void SurfaceFlinger::init() { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { ALOGI("VR request display mode: requestDisplay=%d", requestDisplay); mVrFlingerRequestsDisplay = requestDisplay; + ConditionalLock _l(mStateLock, + std::this_thread::get_id() != mMainThreadId); signalTransaction(); }; mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(), @@ -693,6 +695,8 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps( FrameEvent::DEQUEUE_READY, FrameEvent::RELEASE, }; + ConditionalLock _l(mStateLock, + std::this_thread::get_id() != mMainThreadId); if (!getHwComposer().hasCapability( HWC2::Capability::PresentFenceIsNotReliable)) { outSupported->push_back(FrameEvent::DISPLAY_PRESENT); @@ -740,6 +744,8 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& display, configs->clear(); + ConditionalLock _l(mStateLock, + std::this_thread::get_id() != mMainThreadId); for (const auto& hwConfig : getHwComposer().getConfigs(type)) { DisplayInfo info = DisplayInfo(); @@ -763,7 +769,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& display, info.density = density; // TODO: this needs to go away (currently needed only by webkit) - sp hw(getDefaultDisplayDevice()); + sp hw(getDefaultDisplayDeviceLocked()); info.orientation = hw->getOrientation(); } else { // TODO: where should this value come from? @@ -906,7 +912,12 @@ status_t SurfaceFlinger::getDisplayColorModes(const sp& display, return type; } - std::vector modes = getHwComposer().getColorModes(type); + std::vector modes; + { + ConditionalLock _l(mStateLock, + std::this_thread::get_id() != mMainThreadId); + modes = getHwComposer().getColorModes(type); + } outColorModes->clear(); std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes)); @@ -1287,7 +1298,7 @@ void SurfaceFlinger::onRefreshReceived(int sequenceId, if (sequenceId != mComposerSequenceId) { return; } - repaintEverything(); + repaintEverythingLocked(); } void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { @@ -3291,7 +3302,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& hw, mVisibleRegionsDirty = true; mHasPoweredOff = true; - repaintEverything(); + repaintEverythingLocked(); struct sched_param param = {0}; param.sched_priority = 1; @@ -3935,6 +3946,7 @@ status_t SurfaceFlinger::onTransact( return NO_ERROR; } case 1005:{ // force transaction + Mutex::Autolock _l(mStateLock); setTransactionFlags( eTransactionNeeded| eDisplayTransactionNeeded| @@ -4071,11 +4083,17 @@ status_t SurfaceFlinger::onTransact( return err; } -void SurfaceFlinger::repaintEverything() { +void SurfaceFlinger::repaintEverythingLocked() { android_atomic_or(1, &mRepaintEverything); signalTransaction(); } +void SurfaceFlinger::repaintEverything() { + ConditionalLock _l(mStateLock, + std::this_thread::get_id() != mMainThreadId); + repaintEverythingLocked(); +} + // Checks that the requested width and height are valid and updates them to the display dimensions // if they are set to 0 static status_t updateDimensionsLocked(const sp& displayDevice, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 025da0e827..13a057f2b6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -192,6 +192,8 @@ public: // force full composition on all displays void repaintEverything(); + // Can only be called from the main thread or with mStateLock held + void repaintEverythingLocked(); // returns the default Display sp getDefaultDisplayDevice() const { @@ -343,7 +345,9 @@ private: * Message handling */ void waitForEvent(); + // Can only be called from the main thread or with mStateLock held void signalTransaction(); + // Can only be called from the main thread or with mStateLock held void signalLayerUpdate(); void signalRefresh(); @@ -386,6 +390,7 @@ private: */ uint32_t getTransactionFlags(uint32_t flags); uint32_t peekTransactionFlags(); + // Can only be called from the main thread or with mStateLock held uint32_t setTransactionFlags(uint32_t flags); void commitTransaction(); uint32_t setClientStateLocked(const sp& client, const layer_state_t& s); @@ -642,8 +647,26 @@ private: // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; - // The current hardware composer interface. When switching into and out of - // vr, our HWComposer instance will be recreated. + // The current hardware composer interface. + // + // The following thread safety rules apply when accessing mHwc, either + // directly or via getHwComposer(): + // + // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc + // only when switching into and out of vr. Recreating mHwc must only be + // done on the main thread. + // + // 2. When accessing mHwc on the main thread, it's not necessary to acquire + // mStateLock. + // + // 3. When accessing mHwc on a thread other than the main thread, we always + // need to acquire mStateLock. This is because the main thread could be + // in the process of destroying the current mHwc instance. + // + // The above thread safety rules only apply to SurfaceFlinger.cpp. In + // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never + // destroy it, so it's always safe to access mHwc from any thread without + // acquiring mStateLock. std::unique_ptr mHwc; // constant members (no synchronization needed for access) -- cgit v1.2.3-59-g8ed1b From be6cbae3b61a55ab87c131e79dba03d159961aa3 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Thu, 28 Sep 2017 15:30:23 -0700 Subject: Fix deadlock when transitioning to vr flinger If we were unlucky with the timing when switching to vr flinger we would sometimes deadlock. The vr dispatch thread would request the display from surface flinger, locking mStateLock in the process. mStateLock was being held by the surface flinger main thread, which was processing a previous request to switch to vr flinger. The main thread was trying to connect to the vr hardware composer service, which sent a request to the vr dispatch thread as part of its initialization, leading to the deadlock. The deadlock is easily fixed by posting a message to request the vr flinger switch to the surface flinger main thread, instead of doing it on the vr dispatch thread. Bug: 66916578 Test: Confirmed I can still get into/out of vr flinger on Marlin. There's no longer code to acquire mStateLock in the vr dispatch thread, so the deadlock is no longer possible. Change-Id: I3de5476f698ed798f6b9afe927cc733f0f38c56e --- services/surfaceflinger/SurfaceFlinger.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'services/surfaceflinger/SurfaceFlinger.cpp') diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 12205af919..c05ac8aaac 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -604,11 +604,18 @@ void SurfaceFlinger::init() { if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { - ALOGI("VR request display mode: requestDisplay=%d", requestDisplay); - mVrFlingerRequestsDisplay = requestDisplay; - ConditionalLock _l(mStateLock, - std::this_thread::get_id() != mMainThreadId); - signalTransaction(); + // This callback is called from the vr flinger dispatch thread. We + // need to call signalTransaction(), which requires holding + // mStateLock when we're not on the main thread. Acquiring + // mStateLock from the vr flinger dispatch thread might trigger a + // deadlock in surface flinger (see b/66916578), so post a message + // to be handled on the main thread instead. + sp message = new LambdaMessage([=]() { + ALOGI("VR request display mode: requestDisplay=%d", requestDisplay); + mVrFlingerRequestsDisplay = requestDisplay; + signalTransaction(); + }); + postMessageAsync(message); }; mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(), vrFlingerRequestDisplayCallback); -- cgit v1.2.3-59-g8ed1b