1/*
2 * Copyright 2016 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#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
19#include <inttypes.h>
20#include "FenceTracker.h"
21#include "Layer.h"
22#include <utils/Trace.h>
23
24namespace android {
25
26FenceTracker::FenceTracker() :
27        mFrameCounter(0),
28        mOffset(0),
29        mFrames() {}
30
31void FenceTracker::dump(String8* outString) {
32    Mutex::Autolock lock(mMutex);
33    checkFencesForCompletion();
34
35    for (size_t i = 0; i < MAX_FRAME_HISTORY; i++) {
36        int index = (mOffset + i) % MAX_FRAME_HISTORY;
37        const FrameRecord& frame = mFrames[index];
38
39        outString->appendFormat("Frame %" PRIu64 "\n", frame.frameId);
40        outString->appendFormat("- Refresh start\t%" PRId64 "\n",
41                frame.refreshStartTime);
42
43        if (frame.glesCompositionDoneTime) {
44            outString->appendFormat("- GLES done\t%" PRId64 "\n",
45                    frame.glesCompositionDoneTime);
46        } else if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
47            outString->append("- GLES done\tNot signaled\n");
48        }
49        if (frame.retireTime) {
50            outString->appendFormat("- Retire\t%" PRId64 "\n",
51                    frame.retireTime);
52        } else {
53            outString->append("- Retire\tNot signaled\n");
54        }
55        for (const auto& kv : frame.layers) {
56            const LayerRecord& layer = kv.second;
57            outString->appendFormat("-- %s\n", layer.name.string());
58            outString->appendFormat("---- Frame # %" PRIu64 " (%s)\n",
59                    layer.frameNumber,
60                    layer.isGlesComposition ? "GLES" : "HWC");
61            outString->appendFormat("---- Posted\t%" PRId64 "\n",
62                    layer.postedTime);
63            if (layer.acquireTime) {
64                outString->appendFormat("---- Acquire\t%" PRId64 "\n",
65                        layer.acquireTime);
66            } else {
67                outString->append("---- Acquire\tNot signaled\n");
68            }
69            if (layer.releaseTime) {
70                outString->appendFormat("---- Release\t%" PRId64 "\n",
71                        layer.releaseTime);
72            } else {
73                outString->append("---- Release\tNot signaled\n");
74            }
75        }
76    }
77}
78
79static inline bool isValidTimestamp(nsecs_t time) {
80    return time > 0 && time < INT64_MAX;
81}
82
83void FenceTracker::checkFencesForCompletion() {
84    ATRACE_CALL();
85    for (auto& frame : mFrames) {
86        if (frame.retireFence != Fence::NO_FENCE) {
87            nsecs_t time = frame.retireFence->getSignalTime();
88            if (isValidTimestamp(time)) {
89                frame.retireTime = time;
90                frame.retireFence = Fence::NO_FENCE;
91            }
92        }
93        if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
94            nsecs_t time = frame.glesCompositionDoneFence->getSignalTime();
95            if (isValidTimestamp(time)) {
96                frame.glesCompositionDoneTime = time;
97                frame.glesCompositionDoneFence = Fence::NO_FENCE;
98            }
99        }
100        for (auto& kv : frame.layers) {
101            LayerRecord& layer = kv.second;
102            if (layer.acquireFence != Fence::NO_FENCE) {
103                nsecs_t time = layer.acquireFence->getSignalTime();
104                if (isValidTimestamp(time)) {
105                    layer.acquireTime = time;
106                    layer.acquireFence = Fence::NO_FENCE;
107                }
108            }
109            if (layer.releaseFence != Fence::NO_FENCE) {
110                nsecs_t time = layer.releaseFence->getSignalTime();
111                if (isValidTimestamp(time)) {
112                    layer.releaseTime = time;
113                    layer.releaseFence = Fence::NO_FENCE;
114                }
115            }
116        }
117    }
118}
119
120void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
121        const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence) {
122    ATRACE_CALL();
123    Mutex::Autolock lock(mMutex);
124    FrameRecord& frame = mFrames[mOffset];
125    FrameRecord& prevFrame = mFrames[(mOffset + MAX_FRAME_HISTORY - 1) %
126                                     MAX_FRAME_HISTORY];
127    frame.layers.clear();
128
129    bool wasGlesCompositionDone = false;
130    const size_t count = layers.size();
131    for (size_t i = 0; i < count; i++) {
132        String8 name;
133        uint64_t frameNumber;
134        bool glesComposition;
135        nsecs_t postedTime;
136        sp<Fence> acquireFence;
137        sp<Fence> prevReleaseFence;
138        int32_t key = layers[i]->getSequence();
139
140        layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
141                &postedTime, &acquireFence, &prevReleaseFence);
142#ifdef USE_HWC2
143        if (glesComposition) {
144            frame.layers.emplace(std::piecewise_construct,
145                    std::forward_as_tuple(key),
146                    std::forward_as_tuple(name, frameNumber, glesComposition,
147                    postedTime, 0, 0, acquireFence, prevReleaseFence));
148            wasGlesCompositionDone = true;
149        } else {
150            frame.layers.emplace(std::piecewise_construct,
151                    std::forward_as_tuple(key),
152                    std::forward_as_tuple(name, frameNumber, glesComposition,
153                    postedTime, 0, 0, acquireFence, Fence::NO_FENCE));
154
155            auto prevLayer = prevFrame.layers.find(key);
156            if (prevLayer != prevFrame.layers.end()) {
157                prevLayer->second.releaseFence = prevReleaseFence;
158            }
159        }
160#else
161        frame.layers.emplace(std::piecewise_construct,
162                std::forward_as_tuple(key),
163                std::forward_as_tuple(name, frameNumber, glesComposition,
164                postedTime, 0, 0, acquireFence,
165                glesComposition ? Fence::NO_FENCE : prevReleaseFence));
166        if (glesComposition) {
167            wasGlesCompositionDone = true;
168        }
169#endif
170        frame.layers.emplace(std::piecewise_construct,
171                std::forward_as_tuple(key),
172                std::forward_as_tuple(name, frameNumber, glesComposition,
173                postedTime, 0, 0, acquireFence, prevReleaseFence));
174    }
175
176    frame.frameId = mFrameCounter;
177    frame.refreshStartTime = refreshStartTime;
178    frame.retireTime = 0;
179    frame.glesCompositionDoneTime = 0;
180    prevFrame.retireFence = retireFence;
181    frame.retireFence = Fence::NO_FENCE;
182    frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
183            Fence::NO_FENCE;
184
185    mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
186    mFrameCounter++;
187
188    checkFencesForCompletion();
189}
190
191} // namespace android
192