OSDN Git Service

Dynamically adjust renderahead
authorJohn Reck <jreck@google.com>
Thu, 11 Apr 2019 23:11:24 +0000 (16:11 -0700)
committerJohn Reck <jreck@google.com>
Thu, 18 Apr 2019 21:20:56 +0000 (14:20 -0700)
Tracks refresh rate changes and adjusts renderahead
based off of the active refresh rate.

Default is 60hz = 0 render ahead & > 70hz is render ahead 1

Bug: 127822449
Test: systraced stuff

Change-Id: I9849aa065262f21f7602d44cd1761373279dc28d

libs/hwui/DeviceInfo.cpp
libs/hwui/DeviceInfo.h
libs/hwui/Properties.cpp
libs/hwui/Properties.h
libs/hwui/renderthread/CanvasContext.cpp
libs/hwui/renderthread/CanvasContext.h
libs/hwui/renderthread/RenderThread.cpp
libs/hwui/renderthread/RenderThread.h
libs/hwui/tests/unit/CacheManagerTests.cpp

index cf5d7ce..0a9d965 100644 (file)
@@ -45,12 +45,12 @@ static constexpr android::DisplayInfo sDummyDisplay{
         1920,   // viewportH
 };
 
-const DeviceInfo* DeviceInfo::get() {
+DeviceInfo* DeviceInfo::get() {
         static DeviceInfo sDeviceInfo;
         return &sDeviceInfo;
 }
 
-DisplayInfo QueryDisplayInfo() {
+static DisplayInfo QueryDisplayInfo() {
     if (Properties::isolatedProcess) {
         return sDummyDisplay;
     }
@@ -65,6 +65,27 @@ DisplayInfo QueryDisplayInfo() {
     return displayInfo;
 }
 
+static float QueryMaxRefreshRate() {
+    if (Properties::isolatedProcess) {
+        return sDummyDisplay.fps;
+    }
+
+    const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
+    LOG_ALWAYS_FATAL_IF(token == nullptr,
+                        "Failed to get display info because internal display is disconnected");
+
+    Vector<DisplayInfo> configs;
+    configs.reserve(10);
+    status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to getDisplayConfigs, error %d", status);
+    LOG_ALWAYS_FATAL_IF(configs.size() == 0, "getDisplayConfigs returned 0 configs?");
+    float max = 0.0f;
+    for (auto& info : configs) {
+        max = std::max(max, info.fps);
+    }
+    return max;
+}
+
 static void queryWideColorGamutPreference(sk_sp<SkColorSpace>* colorSpace, SkColorType* colorType) {
     if (Properties::isolatedProcess) {
         *colorSpace = SkColorSpace::MakeSRGB();
@@ -103,7 +124,7 @@ static void queryWideColorGamutPreference(sk_sp<SkColorSpace>* colorSpace, SkCol
     }
 }
 
-DeviceInfo::DeviceInfo() {
+DeviceInfo::DeviceInfo() : mMaxRefreshRate(QueryMaxRefreshRate()) {
 #if HWUI_NULL_GPU
         mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
 #else
@@ -119,7 +140,11 @@ int DeviceInfo::maxTextureSize() const {
 }
 
 void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
-    const_cast<DeviceInfo*>(DeviceInfo::get())->mMaxTextureSize = maxTextureSize;
+    DeviceInfo::get()->mMaxTextureSize = maxTextureSize;
+}
+
+void DeviceInfo::onDisplayConfigChanged() {
+    mDisplayInfo = QueryDisplayInfo();
 }
 
 } /* namespace uirenderer */
index 2bab5d3..0e3f119 100644 (file)
@@ -32,7 +32,7 @@ class DeviceInfo {
     PREVENT_COPY_AND_ASSIGN(DeviceInfo);
 
 public:
-    static const DeviceInfo* get();
+    static DeviceInfo* get();
 
     // this value is only valid after the GPU has been initialized and there is a valid graphics
     // context or if you are using the HWUI_NULL_GPU
@@ -40,6 +40,9 @@ public:
     const DisplayInfo& displayInfo() const { return mDisplayInfo; }
     sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
     SkColorType getWideColorType() const { return mWideColorType; }
+    float getMaxRefreshRate() const { return mMaxRefreshRate; }
+
+    void onDisplayConfigChanged();
 
 private:
     friend class renderthread::RenderThread;
@@ -51,6 +54,7 @@ private:
     DisplayInfo mDisplayInfo;
     sk_sp<SkColorSpace> mWideColorSpace;
     SkColorType mWideColorType;
+    const float mMaxRefreshRate;
 };
 
 } /* namespace uirenderer */
index 9998854..19f509c 100644 (file)
@@ -67,7 +67,7 @@ bool Properties::debuggingEnabled = false;
 bool Properties::isolatedProcess = false;
 
 int Properties::contextPriority = 0;
-uint32_t Properties::defaultRenderAhead = 0;
+int Properties::defaultRenderAhead = -1;
 
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {
@@ -130,9 +130,8 @@ bool Properties::load() {
 
     enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
 
-    defaultRenderAhead =
-            std::max(0u, std::min(2u, static_cast<uint32_t>(property_get_int(
-                                              PROPERTY_RENDERAHEAD, render_ahead().value_or(0)))));
+    defaultRenderAhead = std::max(-1, std::min(2, property_get_int(PROPERTY_RENDERAHEAD,
+            render_ahead().value_or(0))));
 
     return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
 }
index 3105e58..3e91c63 100644 (file)
@@ -253,7 +253,7 @@ public:
 
     ANDROID_API static int contextPriority;
 
-    static uint32_t defaultRenderAhead;
+    static int defaultRenderAhead;
 
 private:
     static ProfileType sProfileType;
index 2957b14..f326ce8 100644 (file)
@@ -105,13 +105,13 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
         , mGenerationID(0)
         , mOpaque(!translucent)
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
-        , mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo())
+        , mJankTracker(&thread.globalProfileData(), DeviceInfo::get()->displayInfo())
         , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
         , mContentDrawBounds(0, 0, 0, 0)
         , mRenderPipeline(std::move(renderPipeline)) {
     rootRenderNode->makeRoot();
     mRenderNodes.emplace_back(rootRenderNode);
-    mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
+    mProfiler.setDensity(DeviceInfo::get()->displayInfo().density);
     setRenderAheadDepth(Properties::defaultRenderAhead);
 }
 
@@ -153,16 +153,23 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
         mNativeSurface = nullptr;
     }
 
+    if (mRenderAheadDepth == 0 && DeviceInfo::get()->getMaxRefreshRate() > 66.6f) {
+        mFixedRenderAhead = false;
+        mRenderAheadCapacity = 1;
+    } else {
+        mFixedRenderAhead = true;
+        mRenderAheadCapacity = mRenderAheadDepth;
+    }
+
     ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
     bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
-                                                  mRenderAheadDepth);
+                                                  mRenderAheadCapacity);
 
     mFrameNumber = -1;
 
     if (hasSurface) {
         mHaveNewSurface = true;
         mSwapHistory.clear();
-        applyRenderAheadSettings();
     } else {
         mRenderThread.removeFrameCallback(this);
         mGenerationID++;
@@ -403,6 +410,23 @@ void CanvasContext::notifyFramePending() {
     mRenderThread.pushBackFrameCallback(this);
 }
 
+void CanvasContext::setPresentTime() {
+    int64_t presentTime = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    int renderAhead = 0;
+    const auto frameIntervalNanos = mRenderThread.timeLord().frameIntervalNanos();
+    if (mFixedRenderAhead) {
+        renderAhead = std::min(mRenderAheadDepth, mRenderAheadCapacity);
+    } else if (frameIntervalNanos < 15_ms) {
+        renderAhead = std::min(1, static_cast<int>(mRenderAheadCapacity));
+    }
+
+    if (renderAhead) {
+        presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
+                (frameIntervalNanos * (renderAhead + 1));
+    }
+    native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+}
+
 void CanvasContext::draw() {
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
@@ -415,14 +439,9 @@ void CanvasContext::draw() {
     mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     Frame frame = mRenderPipeline->getFrame();
+    setPresentTime();
 
     SkRect windowDirty = computeDirtyRect(frame, &dirty);
-    if (mRenderAheadDepth) {
-        auto presentTime =
-                mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
-                (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1));
-        native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
-    }
 
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
                                       mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
@@ -656,18 +675,12 @@ bool CanvasContext::surfaceRequiresRedraw() {
     return width == mLastFrameWidth && height == mLastFrameHeight;
 }
 
-void CanvasContext::applyRenderAheadSettings() {
-    if (mNativeSurface && !mRenderAheadDepth) {
-        native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO);
-    }
-}
-
-void CanvasContext::setRenderAheadDepth(uint32_t renderAhead) {
-    if (renderAhead > 2 || renderAhead == mRenderAheadDepth || mNativeSurface) {
+void CanvasContext::setRenderAheadDepth(int renderAhead) {
+    if (renderAhead > 2 || renderAhead < 0 || mNativeSurface) {
         return;
     }
-    mRenderAheadDepth = renderAhead;
-    applyRenderAheadSettings();
+    mFixedRenderAhead = true;
+    mRenderAheadDepth = static_cast<uint32_t>(renderAhead);
 }
 
 SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
index 912b125..f9de002 100644 (file)
@@ -204,7 +204,7 @@ public:
     }
 
     // Must be called before setSurface
-    void setRenderAheadDepth(uint32_t renderAhead);
+    void setRenderAheadDepth(int renderAhead);
 
     SkISize getNextFrameSize() const;
 
@@ -221,7 +221,7 @@ private:
 
     bool isSwapChainStuffed();
     bool surfaceRequiresRedraw();
-    void applyRenderAheadSettings();
+    void setPresentTime();
 
     SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
 
@@ -240,7 +240,9 @@ private:
     // painted onto its surface.
     bool mIsDirty = false;
     SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default;
+    bool mFixedRenderAhead = false;
     uint32_t mRenderAheadDepth = 0;
+    uint32_t mRenderAheadCapacity = 0;
     struct SwapHistory {
         SkRect damage;
         nsecs_t vsyncTime;
index eca7d88..41cb8fd 100644 (file)
@@ -60,8 +60,10 @@ static JVMAttachHook gOnStartHook = nullptr;
 
 class DisplayEventReceiverWrapper : public VsyncSource {
 public:
-    DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver)
-            : mDisplayEventReceiver(std::move(receiver)) {}
+    DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver,
+            const std::function<void()>& onDisplayConfigChanged)
+            : mDisplayEventReceiver(std::move(receiver))
+            , mOnDisplayConfigChanged(onDisplayConfigChanged) {}
 
     virtual void requestNextVsync() override {
         status_t status = mDisplayEventReceiver->requestNextVsync();
@@ -79,6 +81,9 @@ public:
                     case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
                         latest = ev.header.timestamp;
                         break;
+                    case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+                        mOnDisplayConfigChanged();
+                        break;
                 }
             }
         }
@@ -90,6 +95,7 @@ public:
 
 private:
     std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
+    std::function<void()> mOnDisplayConfigChanged;
 };
 
 class DummyVsyncSource : public VsyncSource {
@@ -160,22 +166,29 @@ void RenderThread::initializeDisplayEventReceiver() {
         // Register the FD
         mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
                        RenderThread::displayEventReceiverCallback, this);
-        mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver));
+        mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver), [this] {
+            DeviceInfo::get()->onDisplayConfigChanged();
+            setupFrameInterval();
+        });
     } else {
         mVsyncSource = new DummyVsyncSource(this);
     }
 }
 
 void RenderThread::initThreadLocals() {
-    mDisplayInfo = DeviceInfo::get()->displayInfo();
-    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
-    mTimeLord.setFrameInterval(frameIntervalNanos);
-    mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
+    setupFrameInterval();
     initializeDisplayEventReceiver();
     mEglManager = new EglManager();
     mRenderState = new RenderState(*this);
     mVkManager = new VulkanManager();
-    mCacheManager = new CacheManager(mDisplayInfo);
+    mCacheManager = new CacheManager(DeviceInfo::get()->displayInfo());
+}
+
+void RenderThread::setupFrameInterval() {
+    auto& displayInfo = DeviceInfo::get()->displayInfo();
+    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / displayInfo.fps);
+    mTimeLord.setFrameInterval(frameIntervalNanos);
+    mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
 }
 
 void RenderThread::requireGlContext() {
index 6bb26fd..c96e284 100644 (file)
@@ -102,8 +102,6 @@ public:
     ProfileDataContainer& globalProfileData() { return mGlobalProfileData; }
     Readback& readback();
 
-    const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
-
     GrContext* getGrContext() const { return mGrContext.get(); }
     void setGrContext(sk_sp<GrContext> cxt);
 
@@ -149,13 +147,12 @@ private:
 
     void initThreadLocals();
     void initializeDisplayEventReceiver();
+    void setupFrameInterval();
     static int displayEventReceiverCallback(int fd, int events, void* data);
     void drainDisplayEventQueue();
     void dispatchFrameCallbacks();
     void requestVsync();
 
-    DisplayInfo mDisplayInfo;
-
     VsyncSource* mVsyncSource;
     bool mVsyncRequested;
     std::set<IFrameCallback*> mFrameCallbacks;
index 210fced..3f1ef93 100644 (file)
@@ -33,7 +33,7 @@ static size_t getCacheUsage(GrContext* grContext) {
 }
 
 RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
-    DisplayInfo displayInfo = renderThread.mainDisplayInfo();
+    DisplayInfo displayInfo = DeviceInfo::get()->displayInfo();
     GrContext* grContext = renderThread.getGrContext();
     ASSERT_TRUE(grContext != nullptr);