Home | History | Annotate | Download | only in renderthread
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "RenderProxy.h"
     18 
     19 #include "DeferredLayerUpdater.h"
     20 #include "DisplayList.h"
     21 #include "Properties.h"
     22 #include "Readback.h"
     23 #include "Rect.h"
     24 #include "WebViewFunctorManager.h"
     25 #include "pipeline/skia/SkiaOpenGLPipeline.h"
     26 #include "pipeline/skia/VectorDrawableAtlas.h"
     27 #include "renderstate/RenderState.h"
     28 #include "renderthread/CanvasContext.h"
     29 #include "renderthread/EglManager.h"
     30 #include "renderthread/RenderTask.h"
     31 #include "renderthread/RenderThread.h"
     32 #include "utils/Macros.h"
     33 #include "utils/TimeUtils.h"
     34 #include "utils/TraceUtils.h"
     35 
     36 #include <ui/GraphicBuffer.h>
     37 
     38 namespace android {
     39 namespace uirenderer {
     40 namespace renderthread {
     41 
     42 RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
     43                          IContextFactory* contextFactory)
     44         : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
     45     mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
     46         return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
     47     });
     48     mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
     49 }
     50 
     51 RenderProxy::~RenderProxy() {
     52     destroyContext();
     53 }
     54 
     55 void RenderProxy::destroyContext() {
     56     if (mContext) {
     57         mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
     58         // This is also a fence as we need to be certain that there are no
     59         // outstanding mDrawFrame tasks posted before it is destroyed
     60         mRenderThread.queue().runSync([this]() { delete mContext; });
     61         mContext = nullptr;
     62     }
     63 }
     64 
     65 void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
     66     mRenderThread.queue().post([this, swapBehavior]() { mContext->setSwapBehavior(swapBehavior); });
     67 }
     68 
     69 bool RenderProxy::loadSystemProperties() {
     70     return mRenderThread.queue().runSync([this]() -> bool {
     71         bool needsRedraw = Properties::load();
     72         if (mContext->profiler().consumeProperties()) {
     73             needsRedraw = true;
     74         }
     75         return needsRedraw;
     76     });
     77 }
     78 
     79 void RenderProxy::setName(const char* name) {
     80     // block since name/value pointers owned by caller
     81     // TODO: Support move arguments
     82     mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
     83 }
     84 
     85 void RenderProxy::setSurface(const sp<Surface>& surface) {
     86     mRenderThread.queue().post(
     87             [this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); });
     88 }
     89 
     90 void RenderProxy::allocateBuffers() {
     91     mRenderThread.queue().post([=]() { mContext->allocateBuffers(); });
     92 }
     93 
     94 bool RenderProxy::pause() {
     95     return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); });
     96 }
     97 
     98 void RenderProxy::setStopped(bool stopped) {
     99     mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); });
    100 }
    101 
    102 void RenderProxy::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
    103     mRenderThread.queue().post(
    104             [=]() { mContext->setLightAlpha(ambientShadowAlpha, spotShadowAlpha); });
    105 }
    106 
    107 void RenderProxy::setLightGeometry(const Vector3& lightCenter, float lightRadius) {
    108     mRenderThread.queue().post([=]() { mContext->setLightGeometry(lightCenter, lightRadius); });
    109 }
    110 
    111 void RenderProxy::setOpaque(bool opaque) {
    112     mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
    113 }
    114 
    115 void RenderProxy::setWideGamut(bool wideGamut) {
    116     mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
    117 }
    118 
    119 int64_t* RenderProxy::frameInfo() {
    120     return mDrawFrameTask.frameInfo();
    121 }
    122 
    123 int RenderProxy::syncAndDrawFrame() {
    124     return mDrawFrameTask.drawFrame();
    125 }
    126 
    127 void RenderProxy::destroy() {
    128     // destroyCanvasAndSurface() needs a fence as when it returns the
    129     // underlying BufferQueue is going to be released from under
    130     // the render thread.
    131     mRenderThread.queue().runSync([=]() { mContext->destroy(); });
    132 }
    133 
    134 void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
    135     ATRACE_CALL();
    136     RenderThread& thread = RenderThread::getInstance();
    137     auto invoke = [&thread, functor]() { CanvasContext::invokeFunctor(thread, functor); };
    138     if (waitForCompletion) {
    139         // waitForCompletion = true is expected to be fairly rare and only
    140         // happen in destruction. Thus it should be fine to temporarily
    141         // create a Mutex
    142         thread.queue().runSync(std::move(invoke));
    143     } else {
    144         thread.queue().post(std::move(invoke));
    145     }
    146 }
    147 
    148 void RenderProxy::destroyFunctor(int functor) {
    149     ATRACE_CALL();
    150     RenderThread& thread = RenderThread::getInstance();
    151     thread.queue().post([=]() { WebViewFunctorManager::instance().destroyFunctor(functor); });
    152 }
    153 
    154 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
    155     return mRenderThread.queue().runSync([this]() -> auto {
    156         return mContext->createTextureLayer();
    157     });
    158 }
    159 
    160 void RenderProxy::buildLayer(RenderNode* node) {
    161     mRenderThread.queue().runSync([&]() { mContext->buildLayer(node); });
    162 }
    163 
    164 bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
    165     ATRACE_NAME("TextureView#getBitmap");
    166     auto& thread = RenderThread::getInstance();
    167     return thread.queue().runSync([&]() -> bool {
    168         return thread.readback().copyLayerInto(layer, &bitmap) == CopyResult::Success;
    169     });
    170 }
    171 
    172 void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
    173     mDrawFrameTask.pushLayerUpdate(layer);
    174 }
    175 
    176 void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
    177     mDrawFrameTask.removeLayerUpdate(layer);
    178 }
    179 
    180 void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
    181     return mRenderThread.queue().runSync([&]() { layer->detachSurfaceTexture(); });
    182 }
    183 
    184 void RenderProxy::destroyHardwareResources() {
    185     return mRenderThread.queue().runSync([&]() { mContext->destroyHardwareResources(); });
    186 }
    187 
    188 void RenderProxy::trimMemory(int level) {
    189     // Avoid creating a RenderThread to do a trimMemory.
    190     if (RenderThread::hasInstance()) {
    191         RenderThread& thread = RenderThread::getInstance();
    192         thread.queue().post([&thread, level]() { CanvasContext::trimMemory(thread, level); });
    193     }
    194 }
    195 
    196 void RenderProxy::overrideProperty(const char* name, const char* value) {
    197     // expensive, but block here since name/value pointers owned by caller
    198     RenderThread::getInstance().queue().runSync(
    199             [&]() { Properties::overrideProperty(name, value); });
    200 }
    201 
    202 void RenderProxy::fence() {
    203     mRenderThread.queue().runSync([]() {});
    204 }
    205 
    206 int RenderProxy::maxTextureSize() {
    207     static int maxTextureSize = RenderThread::getInstance().queue().runSync(
    208             []() { return DeviceInfo::get()->maxTextureSize(); });
    209     return maxTextureSize;
    210 }
    211 
    212 void RenderProxy::stopDrawing() {
    213     mRenderThread.queue().runSync([this]() { mContext->stopDrawing(); });
    214 }
    215 
    216 void RenderProxy::notifyFramePending() {
    217     mRenderThread.queue().post([this]() { mContext->notifyFramePending(); });
    218 }
    219 
    220 void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
    221     mRenderThread.queue().runSync([&]() {
    222         mContext->profiler().dumpData(fd);
    223         if (dumpFlags & DumpFlags::FrameStats) {
    224             mContext->dumpFrames(fd);
    225         }
    226         if (dumpFlags & DumpFlags::JankStats) {
    227             mRenderThread.globalProfileData()->dump(fd);
    228         }
    229         if (dumpFlags & DumpFlags::Reset) {
    230             mContext->resetFrameStats();
    231         }
    232     });
    233 }
    234 
    235 void RenderProxy::resetProfileInfo() {
    236     mRenderThread.queue().runSync([=]() { mContext->resetFrameStats(); });
    237 }
    238 
    239 uint32_t RenderProxy::frameTimePercentile(int percentile) {
    240     return mRenderThread.queue().runSync([&]() -> auto {
    241         return mRenderThread.globalProfileData()->findPercentile(percentile);
    242     });
    243 }
    244 
    245 void RenderProxy::dumpGraphicsMemory(int fd) {
    246     if (RenderThread::hasInstance()) {
    247         auto& thread = RenderThread::getInstance();
    248         thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
    249     }
    250 }
    251 
    252 void RenderProxy::setProcessStatsBuffer(int fd) {
    253     auto& rt = RenderThread::getInstance();
    254     rt.queue().post([&rt, fd = dup(fd)]() {
    255         rt.globalProfileData().switchStorageToAshmem(fd);
    256         close(fd);
    257     });
    258 }
    259 
    260 void RenderProxy::rotateProcessStatsBuffer() {
    261     auto& rt = RenderThread::getInstance();
    262     rt.queue().post([&rt]() { rt.globalProfileData().rotateStorage(); });
    263 }
    264 
    265 int RenderProxy::getRenderThreadTid() {
    266     return mRenderThread.getTid();
    267 }
    268 
    269 void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) {
    270     mRenderThread.queue().post([=]() { mContext->addRenderNode(node, placeFront); });
    271 }
    272 
    273 void RenderProxy::removeRenderNode(RenderNode* node) {
    274     mRenderThread.queue().post([=]() { mContext->removeRenderNode(node); });
    275 }
    276 
    277 void RenderProxy::drawRenderNode(RenderNode* node) {
    278     mRenderThread.queue().runSync([=]() { mContext->prepareAndDraw(node); });
    279 }
    280 
    281 void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) {
    282     mDrawFrameTask.setContentDrawBounds(left, top, right, bottom);
    283 }
    284 
    285 void RenderProxy::setPictureCapturedCallback(
    286         const std::function<void(sk_sp<SkPicture>&&)>& callback) {
    287     mRenderThread.queue().post(
    288             [this, cb = callback]() { mContext->setPictureCapturedCallback(cb); });
    289 }
    290 
    291 void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
    292     mDrawFrameTask.setFrameCallback(std::move(callback));
    293 }
    294 
    295 void RenderProxy::setFrameCompleteCallback(std::function<void(int64_t)>&& callback) {
    296     mDrawFrameTask.setFrameCompleteCallback(std::move(callback));
    297 }
    298 
    299 void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
    300     mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
    301         mContext->addFrameMetricsObserver(observer.get());
    302     });
    303 }
    304 
    305 void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
    306     mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
    307         mContext->removeFrameMetricsObserver(observer.get());
    308     });
    309 }
    310 
    311 void RenderProxy::setForceDark(bool enable) {
    312     mRenderThread.queue().post([this, enable]() { mContext->setForceDark(enable); });
    313 }
    314 
    315 void RenderProxy::setRenderAheadDepth(int renderAhead) {
    316     mRenderThread.queue().post(
    317             [context = mContext, renderAhead] { context->setRenderAheadDepth(renderAhead); });
    318 }
    319 
    320 int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
    321                                  SkBitmap* bitmap) {
    322     auto& thread = RenderThread::getInstance();
    323     return static_cast<int>(thread.queue().runSync([&]() -> auto {
    324         return thread.readback().copySurfaceInto(*surface, Rect(left, top, right, bottom), bitmap);
    325     }));
    326 }
    327 
    328 void RenderProxy::prepareToDraw(Bitmap& bitmap) {
    329     // If we haven't spun up a hardware accelerated window yet, there's no
    330     // point in precaching these bitmaps as it can't impact jank.
    331     // We also don't know if we even will spin up a hardware-accelerated
    332     // window or not.
    333     if (!RenderThread::hasInstance()) return;
    334     RenderThread* renderThread = &RenderThread::getInstance();
    335     bitmap.ref();
    336     auto task = [renderThread, &bitmap]() {
    337         CanvasContext::prepareToDraw(*renderThread, &bitmap);
    338         bitmap.unref();
    339     };
    340     nsecs_t lastVsync = renderThread->timeLord().latestVsync();
    341     nsecs_t estimatedNextVsync = lastVsync + renderThread->timeLord().frameIntervalNanos();
    342     nsecs_t timeToNextVsync = estimatedNextVsync - systemTime(CLOCK_MONOTONIC);
    343     // We expect the UI thread to take 4ms and for RT to be active from VSYNC+4ms to
    344     // VSYNC+12ms or so, so aim for the gap during which RT is expected to
    345     // be idle
    346     // TODO: Make this concept a first-class supported thing? RT could use
    347     // knowledge of pending draws to better schedule this task
    348     if (timeToNextVsync > -6_ms && timeToNextVsync < 1_ms) {
    349         renderThread->queue().postAt(estimatedNextVsync + 8_ms, task);
    350     } else {
    351         renderThread->queue().post(task);
    352     }
    353 }
    354 
    355 int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
    356     ATRACE_NAME("HardwareBitmap readback");
    357     RenderThread& thread = RenderThread::getInstance();
    358     if (gettid() == thread.getTid()) {
    359         // TODO: fix everything that hits this. We should never be triggering a readback ourselves.
    360         return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
    361     } else {
    362         return thread.queue().runSync(
    363                 [&]() -> int { return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap); });
    364     }
    365 }
    366 
    367 void RenderProxy::disableVsync() {
    368     Properties::disableVsync = true;
    369 }
    370 
    371 void RenderProxy::repackVectorDrawableAtlas() {
    372     RenderThread& thread = RenderThread::getInstance();
    373     thread.queue().post([&thread]() {
    374         // The context may be null if trimMemory executed, but then the atlas was deleted too.
    375         if (thread.getGrContext() != nullptr) {
    376             thread.cacheManager().acquireVectorDrawableAtlas()->repackIfNeeded(
    377                     thread.getGrContext());
    378         }
    379     });
    380 }
    381 
    382 void RenderProxy::releaseVDAtlasEntries() {
    383     RenderThread& thread = RenderThread::getInstance();
    384     thread.queue().post([&thread]() {
    385         // The context may be null if trimMemory executed, but then the atlas was deleted too.
    386         if (thread.getGrContext() != nullptr) {
    387             thread.cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries();
    388         }
    389     });
    390 }
    391 
    392 void RenderProxy::preload() {
    393     // Create RenderThread object and start the thread. Then preload Vulkan/EGL driver.
    394     auto& thread = RenderThread::getInstance();
    395     thread.queue().post([&thread]() { thread.preload(); });
    396 }
    397 
    398 } /* namespace renderthread */
    399 } /* namespace uirenderer */
    400 } /* namespace android */
    401