CanvasContext.cpp revision cd55852fcd840f7f4c4d7a0a7253a2995c77afa2
1/*
2 * Copyright (C) 2014 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 <GpuMemoryTracker.h>
18#include "CanvasContext.h"
19
20#include "AnimationContext.h"
21#include "Caches.h"
22#include "EglManager.h"
23#include "Frame.h"
24#include "LayerUpdateQueue.h"
25#include "Properties.h"
26#include "RenderThread.h"
27#include "hwui/Canvas.h"
28#include "renderstate/RenderState.h"
29#include "renderstate/Stencil.h"
30#include "protos/hwui.pb.h"
31#include "OpenGLPipeline.h"
32#include "pipeline/skia/SkiaOpenGLPipeline.h"
33#include "pipeline/skia/SkiaPipeline.h"
34#include "pipeline/skia/SkiaVulkanPipeline.h"
35#include "utils/GLUtils.h"
36#include "utils/TimeUtils.h"
37
38#include <cutils/properties.h>
39#include <google/protobuf/io/zero_copy_stream_impl.h>
40#include <private/hwui/DrawGlInfo.h>
41#include <strings.h>
42
43#include <algorithm>
44#include <fcntl.h>
45#include <sys/stat.h>
46
47#include <cstdlib>
48
49#define TRIM_MEMORY_COMPLETE 80
50#define TRIM_MEMORY_UI_HIDDEN 20
51
52#define ENABLE_RENDERNODE_SERIALIZATION false
53
54#define LOG_FRAMETIME_MMA 0
55
56#if LOG_FRAMETIME_MMA
57static float sBenchMma = 0;
58static int sFrameCount = 0;
59static const float NANOS_PER_MILLIS_F = 1000000.0f;
60#endif
61
62namespace android {
63namespace uirenderer {
64namespace renderthread {
65
66CanvasContext* CanvasContext::create(RenderThread& thread,
67        bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) {
68
69    auto renderType = Properties::getRenderPipelineType();
70
71    switch (renderType) {
72        case RenderPipelineType::OpenGL:
73            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
74                    std::make_unique<OpenGLPipeline>(thread));
75        case RenderPipelineType::SkiaGL:
76            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
77                    std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
78        case RenderPipelineType::SkiaVulkan:
79            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
80                                std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
81        default:
82            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
83            break;
84    }
85    return nullptr;
86}
87
88void CanvasContext::destroyLayer(RenderNode* node) {
89    auto renderType = Properties::getRenderPipelineType();
90    switch (renderType) {
91        case RenderPipelineType::OpenGL:
92            OpenGLPipeline::destroyLayer(node);
93            break;
94        case RenderPipelineType::SkiaGL:
95        case RenderPipelineType::SkiaVulkan:
96            skiapipeline::SkiaPipeline::destroyLayer(node);
97            break;
98        default:
99            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
100            break;
101    }
102}
103
104void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) {
105    ATRACE_CALL();
106    auto renderType = Properties::getRenderPipelineType();
107    switch (renderType) {
108        case RenderPipelineType::OpenGL:
109            OpenGLPipeline::invokeFunctor(thread, functor);
110            break;
111        case RenderPipelineType::SkiaGL:
112            skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor);
113            break;
114        case RenderPipelineType::SkiaVulkan:
115            skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor);
116            break;
117        default:
118            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
119            break;
120    }
121}
122
123void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
124    auto renderType = Properties::getRenderPipelineType();
125    switch (renderType) {
126        case RenderPipelineType::OpenGL:
127            OpenGLPipeline::prepareToDraw(thread, bitmap);
128            break;
129        case RenderPipelineType::SkiaGL:
130        case RenderPipelineType::SkiaVulkan:
131            skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap);
132            break;
133        default:
134            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
135            break;
136    }
137}
138
139CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
140        RenderNode* rootRenderNode, IContextFactory* contextFactory,
141        std::unique_ptr<IRenderPipeline> renderPipeline)
142        : mRenderThread(thread)
143        , mOpaque(!translucent)
144        , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
145        , mJankTracker(thread.mainDisplayInfo())
146        , mProfiler(mFrames)
147        , mContentDrawBounds(0, 0, 0, 0)
148        , mRenderPipeline(std::move(renderPipeline)) {
149    mRenderNodes.emplace_back(rootRenderNode);
150    mRenderThread.renderState().registerCanvasContext(this);
151    mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
152}
153
154CanvasContext::~CanvasContext() {
155    destroy(nullptr);
156    mRenderThread.renderState().unregisterCanvasContext(this);
157}
158
159void CanvasContext::destroy(TreeObserver* observer) {
160    stopDrawing();
161    setSurface(nullptr);
162    freePrefetchedLayers(observer);
163    destroyHardwareResources(observer);
164    mAnimationContext->destroy();
165}
166
167void CanvasContext::setSurface(Surface* surface) {
168    ATRACE_CALL();
169
170    mNativeSurface = surface;
171
172    bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior);
173
174    mFrameNumber = -1;
175
176    if (hasSurface) {
177         mHaveNewSurface = true;
178         mSwapHistory.clear();
179    } else {
180         mRenderThread.removeFrameCallback(this);
181    }
182}
183
184void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
185    mSwapBehavior = swapBehavior;
186}
187
188void CanvasContext::initialize(Surface* surface) {
189    setSurface(surface);
190}
191
192void CanvasContext::updateSurface(Surface* surface) {
193    setSurface(surface);
194}
195
196bool CanvasContext::pauseSurface(Surface* surface) {
197    return mRenderThread.removeFrameCallback(this);
198}
199
200void CanvasContext::setStopped(bool stopped) {
201    if (mStopped != stopped) {
202        mStopped = stopped;
203        if (mStopped) {
204            mRenderThread.removeFrameCallback(this);
205            mRenderPipeline->onStop();
206        } else if (mIsDirty && hasSurface()) {
207            mRenderThread.postFrameCallback(this);
208        }
209    }
210}
211
212void CanvasContext::setup(float lightRadius,
213        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
214    mLightGeometry.radius = lightRadius;
215    mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
216    mLightInfo.spotShadowAlpha = spotShadowAlpha;
217}
218
219void CanvasContext::setLightCenter(const Vector3& lightCenter) {
220    mLightGeometry.center = lightCenter;
221}
222
223void CanvasContext::setOpaque(bool opaque) {
224    mOpaque = opaque;
225}
226
227bool CanvasContext::makeCurrent() {
228    if (mStopped) return false;
229
230    auto result = mRenderPipeline->makeCurrent();
231    switch (result) {
232        case MakeCurrentResult::AlreadyCurrent:
233            return true;
234        case MakeCurrentResult::Failed:
235            mHaveNewSurface = true;
236            setSurface(nullptr);
237            return false;
238        case MakeCurrentResult::Succeeded:
239            mHaveNewSurface = true;
240            return true;
241        default:
242            LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent",
243                    (int32_t) result);
244    }
245
246    return true;
247}
248
249static bool wasSkipped(FrameInfo* info) {
250    return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
251}
252
253bool CanvasContext::isSwapChainStuffed() {
254    static const auto SLOW_THRESHOLD = 6_ms;
255
256    if (mSwapHistory.size() != mSwapHistory.capacity()) {
257        // We want at least 3 frames of history before attempting to
258        // guess if the queue is stuffed
259        return false;
260    }
261    nsecs_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
262    auto& swapA = mSwapHistory[0];
263
264    // Was there a happy queue & dequeue time? If so, don't
265    // consider it stuffed
266    if (swapA.dequeueDuration < SLOW_THRESHOLD
267            && swapA.queueDuration < SLOW_THRESHOLD) {
268        return false;
269    }
270
271    for (size_t i = 1; i < mSwapHistory.size(); i++) {
272        auto& swapB = mSwapHistory[i];
273
274        // If there's a multi-frameInterval gap we effectively already dropped a frame,
275        // so consider the queue healthy.
276        if (swapA.swapCompletedTime - swapB.swapCompletedTime > frameInterval * 3) {
277            return false;
278        }
279
280        // Was there a happy queue & dequeue time? If so, don't
281        // consider it stuffed
282        if (swapB.dequeueDuration < SLOW_THRESHOLD
283                && swapB.queueDuration < SLOW_THRESHOLD) {
284            return false;
285        }
286
287        swapA = swapB;
288    }
289
290    // All signs point to a stuffed swap chain
291    ATRACE_NAME("swap chain stuffed");
292    return true;
293}
294
295void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
296        int64_t syncQueued, RenderNode* target) {
297    mRenderThread.removeFrameCallback(this);
298
299    // If the previous frame was dropped we don't need to hold onto it, so
300    // just keep using the previous frame's structure instead
301    if (!wasSkipped(mCurrentFrameInfo)) {
302        mCurrentFrameInfo = &mFrames.next();
303    }
304    mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
305    mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
306    mCurrentFrameInfo->markSyncStart();
307
308    info.damageAccumulator = &mDamageAccumulator;
309    info.layerUpdateQueue = &mLayerUpdateQueue;
310
311    mAnimationContext->startFrame(info.mode);
312    for (const sp<RenderNode>& node : mRenderNodes) {
313        // Only the primary target node will be drawn full - all other nodes would get drawn in
314        // real time mode. In case of a window, the primary node is the window content and the other
315        // node(s) are non client / filler nodes.
316        info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
317        node->prepareTree(info);
318        GL_CHECKPOINT(MODERATE);
319    }
320    mAnimationContext->runRemainingAnimations(info);
321    GL_CHECKPOINT(MODERATE);
322
323    freePrefetchedLayers(info.observer);
324    GL_CHECKPOINT(MODERATE);
325
326    mIsDirty = true;
327
328    if (CC_UNLIKELY(!mNativeSurface.get())) {
329        mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
330        info.out.canDrawThisFrame = false;
331        return;
332    }
333
334    if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
335        nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
336        SwapHistory& lastSwap = mSwapHistory.back();
337        nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
338        // The slight fudge-factor is to deal with cases where
339        // the vsync was estimated due to being slow handling the signal.
340        // See the logic in TimeLord#computeFrameTimeNanos or in
341        // Choreographer.java for details on when this happens
342        if (vsyncDelta < 2_ms) {
343            // Already drew for this vsync pulse, UI draw request missed
344            // the deadline for RT animations
345            info.out.canDrawThisFrame = false;
346        } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3
347                || (latestVsync - mLastDropVsync) < 500_ms) {
348            // It's been several frame intervals, assume the buffer queue is fine
349            // or the last drop was too recent
350            info.out.canDrawThisFrame = true;
351        } else {
352            info.out.canDrawThisFrame = !isSwapChainStuffed();
353            if (!info.out.canDrawThisFrame) {
354                // dropping frame
355                mLastDropVsync = mRenderThread.timeLord().latestVsync();
356            }
357        }
358    } else {
359        info.out.canDrawThisFrame = true;
360    }
361
362    if (!info.out.canDrawThisFrame) {
363        mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
364    }
365
366    if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
367        if (!info.out.requiresUiRedraw) {
368            // If animationsNeedsRedraw is set don't bother posting for an RT anim
369            // as we will just end up fighting the UI thread.
370            mRenderThread.postFrameCallback(this);
371        }
372    }
373}
374
375void CanvasContext::stopDrawing() {
376    mRenderThread.removeFrameCallback(this);
377    mAnimationContext->pauseAnimators();
378}
379
380void CanvasContext::notifyFramePending() {
381    ATRACE_CALL();
382    mRenderThread.pushBackFrameCallback(this);
383}
384
385void CanvasContext::draw() {
386    SkRect dirty;
387    mDamageAccumulator.finish(&dirty);
388
389    // TODO: Re-enable after figuring out cause of b/22592975
390//    if (dirty.isEmpty() && Properties::skipEmptyFrames) {
391//        mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
392//        return;
393//    }
394
395    mCurrentFrameInfo->markIssueDrawCommandsStart();
396
397    Frame frame = mRenderPipeline->getFrame();
398
399    SkRect windowDirty = computeDirtyRect(frame, &dirty);
400
401    bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
402            mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler()));
403
404    waitOnFences();
405
406    bool requireSwap = false;
407    bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo,
408            &requireSwap);
409
410    mIsDirty = false;
411
412    if (requireSwap) {
413        if (!didSwap) { //some error happened
414            setSurface(nullptr);
415        }
416        SwapHistory& swap = mSwapHistory.next();
417        swap.damage = windowDirty;
418        swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC);
419        swap.vsyncTime = mRenderThread.timeLord().latestVsync();
420        if (mNativeSurface.get()) {
421            int durationUs;
422            mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
423            swap.dequeueDuration = us2ns(durationUs);
424            mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
425            swap.queueDuration = us2ns(durationUs);
426        } else {
427            swap.dequeueDuration = 0;
428            swap.queueDuration = 0;
429        }
430        mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
431                = swap.dequeueDuration;
432        mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
433                = swap.queueDuration;
434        mHaveNewSurface = false;
435        mFrameNumber = -1;
436    } else {
437        mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0;
438        mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0;
439    }
440
441    // TODO: Use a fence for real completion?
442    mCurrentFrameInfo->markFrameCompleted();
443
444#if LOG_FRAMETIME_MMA
445    float thisFrame = mCurrentFrameInfo->duration(
446            FrameInfoIndex::IssueDrawCommandsStart,
447            FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F;
448    if (sFrameCount) {
449        sBenchMma = ((9 * sBenchMma) + thisFrame) / 10;
450    } else {
451        sBenchMma = thisFrame;
452    }
453    if (++sFrameCount == 10) {
454        sFrameCount = 1;
455        ALOGD("Average frame time: %.4f", sBenchMma);
456    }
457#endif
458
459    mJankTracker.addFrame(*mCurrentFrameInfo);
460    mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
461    if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) {
462        mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data());
463    }
464
465    GpuMemoryTracker::onFrameCompleted();
466#ifdef BUGREPORT_FONT_CACHE_USAGE
467    auto renderType = Properties::getRenderPipelineType();
468    if (RenderPipelineType::OpenGL == renderType) {
469        Caches& caches = Caches::getInstance();
470        caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
471    }
472#endif
473
474}
475
476// Called by choreographer to do an RT-driven animation
477void CanvasContext::doFrame() {
478    if (!mRenderPipeline->isSurfaceReady()) return;
479    prepareAndDraw(nullptr);
480}
481
482void CanvasContext::prepareAndDraw(RenderNode* node) {
483    ATRACE_CALL();
484
485    nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
486    int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
487    UiFrameInfoBuilder(frameInfo)
488        .addFlag(FrameInfoFlags::RTAnimation)
489        .setVsync(vsync, vsync);
490
491    TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
492    prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
493    if (info.out.canDrawThisFrame) {
494        draw();
495    } else {
496        // wait on fences so tasks don't overlap next frame
497        waitOnFences();
498    }
499}
500
501void CanvasContext::markLayerInUse(RenderNode* node) {
502    if (mPrefetchedLayers.erase(node)) {
503        node->decStrong(nullptr);
504    }
505}
506
507void CanvasContext::freePrefetchedLayers(TreeObserver* observer) {
508    if (mPrefetchedLayers.size()) {
509        for (auto& node : mPrefetchedLayers) {
510            ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
511                    node->getName());
512            node->destroyHardwareResources(observer);
513            node->decStrong(observer);
514        }
515        mPrefetchedLayers.clear();
516    }
517}
518
519void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
520    ATRACE_CALL();
521    if (!mRenderPipeline->isContextReady()) return;
522
523    // buildLayer() will leave the tree in an unknown state, so we must stop drawing
524    stopDrawing();
525
526    TreeInfo info(TreeInfo::MODE_FULL, *this);
527    info.damageAccumulator = &mDamageAccumulator;
528    info.observer = observer;
529    info.layerUpdateQueue = &mLayerUpdateQueue;
530    info.runAnimations = false;
531    node->prepareTree(info);
532    SkRect ignore;
533    mDamageAccumulator.finish(&ignore);
534    // Tickle the GENERIC property on node to mark it as dirty for damaging
535    // purposes when the frame is actually drawn
536    node->setPropertyFieldsDirty(RenderNode::GENERIC);
537
538    mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
539
540    node->incStrong(nullptr);
541    mPrefetchedLayers.insert(node);
542}
543
544bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
545    return mRenderPipeline->copyLayerInto(layer, bitmap);
546}
547
548void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
549    stopDrawing();
550    if (mRenderPipeline->isContextReady()) {
551        freePrefetchedLayers(observer);
552        for (const sp<RenderNode>& node : mRenderNodes) {
553            node->destroyHardwareResources(observer);
554        }
555        mRenderPipeline->onDestroyHardwareResources();
556    }
557}
558
559void CanvasContext::trimMemory(RenderThread& thread, int level) {
560    // No context means nothing to free
561    if (!thread.eglManager().hasEglContext()) return;
562
563    ATRACE_CALL();
564    if (level >= TRIM_MEMORY_COMPLETE) {
565        thread.renderState().flush(Caches::FlushMode::Full);
566        thread.eglManager().destroy();
567    } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
568        thread.renderState().flush(Caches::FlushMode::Moderate);
569    }
570}
571
572DeferredLayerUpdater* CanvasContext::createTextureLayer() {
573    return mRenderPipeline->createTextureLayer();
574}
575
576void CanvasContext::dumpFrames(int fd) {
577    FILE* file = fdopen(fd, "a");
578    fprintf(file, "\n\n---PROFILEDATA---\n");
579    for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
580        fprintf(file, "%s", FrameInfoNames[i].c_str());
581        fprintf(file, ",");
582    }
583    for (size_t i = 0; i < mFrames.size(); i++) {
584        FrameInfo& frame = mFrames[i];
585        if (frame[FrameInfoIndex::SyncStart] == 0) {
586            continue;
587        }
588        fprintf(file, "\n");
589        for (int i = 0; i < static_cast<int>(FrameInfoIndex::NumIndexes); i++) {
590            fprintf(file, "%" PRId64 ",", frame[i]);
591        }
592    }
593    fprintf(file, "\n---PROFILEDATA---\n\n");
594    fflush(file);
595}
596
597void CanvasContext::resetFrameStats() {
598    mFrames.clear();
599    mRenderThread.jankTracker().reset();
600}
601
602void CanvasContext::serializeDisplayListTree() {
603#if ENABLE_RENDERNODE_SERIALIZATION
604    using namespace google::protobuf::io;
605    char package[128];
606    // Check whether tracing is enabled for this process.
607    FILE * file = fopen("/proc/self/cmdline", "r");
608    if (file) {
609        if (!fgets(package, 128, file)) {
610            ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
611            fclose(file);
612            return;
613        }
614        fclose(file);
615    } else {
616        ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
617                errno);
618        return;
619    }
620    char path[1024];
621    snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package);
622    int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH);
623    if (fd == -1) {
624        ALOGD("Failed to open '%s'", path);
625        return;
626    }
627    proto::RenderNode tree;
628    // TODO: Streaming writes?
629    mRootRenderNode->copyTo(&tree);
630    std::string data = tree.SerializeAsString();
631    write(fd, data.c_str(), data.length());
632    close(fd);
633#endif
634}
635
636void CanvasContext::waitOnFences() {
637    if (mFrameFences.size()) {
638        ATRACE_CALL();
639        for (auto& fence : mFrameFences) {
640            fence->getResult();
641        }
642        mFrameFences.clear();
643    }
644}
645
646class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
647public:
648    explicit FuncTaskProcessor(TaskManager* taskManager)
649            : TaskProcessor<bool>(taskManager) {}
650
651    virtual void onProcess(const sp<Task<bool> >& task) override {
652        FuncTask* t = static_cast<FuncTask*>(task.get());
653        t->func();
654        task->setResult(true);
655    }
656};
657
658void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
659    if (!mFrameWorkProcessor.get()) {
660        mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager());
661    }
662    sp<FuncTask> task(new FuncTask());
663    task->func = func;
664    mFrameFences.push_back(task);
665    mFrameWorkProcessor->add(task);
666}
667
668int64_t CanvasContext::getFrameNumber() {
669    // mFrameNumber is reset to -1 when the surface changes or we swap buffers
670    if (mFrameNumber == -1 && mNativeSurface.get()) {
671        mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber());
672    }
673    return mFrameNumber;
674}
675
676SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
677    if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
678        // can't rely on prior content of window if viewport size changes
679        dirty->setEmpty();
680        mLastFrameWidth = frame.width();
681        mLastFrameHeight = frame.height();
682    } else if (mHaveNewSurface || frame.bufferAge() == 0) {
683        // New surface needs a full draw
684        dirty->setEmpty();
685    } else {
686        if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) {
687            ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
688                    SK_RECT_ARGS(*dirty), frame.width(), frame.height());
689            dirty->setEmpty();
690        }
691        profiler().unionDirty(dirty);
692    }
693
694    if (dirty->isEmpty()) {
695        dirty->set(0, 0, frame.width(), frame.height());
696    }
697
698    // At this point dirty is the area of the window to update. However,
699    // the area of the frame we need to repaint is potentially different, so
700    // stash the screen area for later
701    SkRect windowDirty(*dirty);
702
703    // If the buffer age is 0 we do a full-screen repaint (handled above)
704    // If the buffer age is 1 the buffer contents are the same as they were
705    // last frame so there's nothing to union() against
706    // Therefore we only care about the > 1 case.
707    if (frame.bufferAge() > 1) {
708        if (frame.bufferAge() > (int) mSwapHistory.size()) {
709            // We don't have enough history to handle this old of a buffer
710            // Just do a full-draw
711            dirty->set(0, 0, frame.width(), frame.height());
712        } else {
713            // At this point we haven't yet added the latest frame
714            // to the damage history (happens below)
715            // So we need to damage
716            for (int i = mSwapHistory.size() - 1;
717                    i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
718                dirty->join(mSwapHistory[i].damage);
719            }
720        }
721    }
722
723    return windowDirty;
724}
725
726} /* namespace renderthread */
727} /* namespace uirenderer */
728} /* namespace android */
729