OSDN Git Service

surfaceflinger: make vsync injection more robust
[android-x86/frameworks-native.git] / services / surfaceflinger / SurfaceFlingerConsumer.cpp
1 /*
2  * Copyright (C) 2012 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 //#define LOG_NDEBUG 0
19
20 #include "SurfaceFlingerConsumer.h"
21 #include "Layer.h"
22
23 #include <private/gui/SyncFeatures.h>
24
25 #include <gui/BufferItem.h>
26 #include <gui/BufferQueue.h>
27
28 #include <utils/Errors.h>
29 #include <utils/NativeHandle.h>
30 #include <utils/Trace.h>
31
32 namespace android {
33
34 // ---------------------------------------------------------------------------
35
36 status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
37         const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
38         uint64_t maxFrameNumber)
39 {
40     ATRACE_CALL();
41     ALOGV("updateTexImage");
42     Mutex::Autolock lock(mMutex);
43
44     if (mAbandoned) {
45         ALOGE("updateTexImage: GLConsumer is abandoned!");
46         return NO_INIT;
47     }
48
49     // Make sure the EGL state is the same as in previous calls.
50     status_t err = checkAndUpdateEglStateLocked();
51     if (err != NO_ERROR) {
52         return err;
53     }
54
55     BufferItem item;
56
57     // Acquire the next buffer.
58     // In asynchronous mode the list is guaranteed to be one buffer
59     // deep, while in synchronous mode we use the oldest buffer.
60     err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
61             maxFrameNumber);
62     if (err != NO_ERROR) {
63         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
64             err = NO_ERROR;
65         } else if (err == BufferQueue::PRESENT_LATER) {
66             // return the error, without logging
67         } else {
68             ALOGE("updateTexImage: acquire failed: %s (%d)",
69                 strerror(-err), err);
70         }
71         return err;
72     }
73
74     if (autoRefresh) {
75         *autoRefresh = item.mAutoRefresh;
76     }
77
78     if (queuedBuffer) {
79         *queuedBuffer = item.mQueuedBuffer;
80     }
81
82     // We call the rejecter here, in case the caller has a reason to
83     // not accept this buffer.  This is used by SurfaceFlinger to
84     // reject buffers which have the wrong size
85     int slot = item.mSlot;
86     if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
87         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
88         return BUFFER_REJECTED;
89     }
90
91     // Release the previous buffer.
92 #ifdef USE_HWC2
93     err = updateAndReleaseLocked(item, &mPendingRelease);
94 #else
95     err = updateAndReleaseLocked(item);
96 #endif
97     if (err != NO_ERROR) {
98         return err;
99     }
100
101     if (!SyncFeatures::getInstance().useNativeFenceSync()) {
102         // Bind the new buffer to the GL texture.
103         //
104         // Older devices require the "implicit" synchronization provided
105         // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
106         // devices will either call this in Layer::onDraw, or (if it's not
107         // a GL-composited layer) not at all.
108         err = bindTextureImageLocked();
109     }
110
111     return err;
112 }
113
114 status_t SurfaceFlingerConsumer::bindTextureImage()
115 {
116     Mutex::Autolock lock(mMutex);
117
118     return bindTextureImageLocked();
119 }
120
121 status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
122         nsecs_t presentWhen, uint64_t maxFrameNumber) {
123     status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
124             maxFrameNumber);
125     if (result == NO_ERROR) {
126         mTransformToDisplayInverse = item->mTransformToDisplayInverse;
127         mSurfaceDamage = item->mSurfaceDamage;
128     }
129     return result;
130 }
131
132 bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
133     Mutex::Autolock lock(mMutex);
134     return mTransformToDisplayInverse;
135 }
136
137 const Region& SurfaceFlingerConsumer::getSurfaceDamage() const {
138     return mSurfaceDamage;
139 }
140
141 sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
142     sp<NativeHandle> stream;
143     mConsumer->getSidebandStream(&stream);
144     return stream;
145 }
146
147 // We need to determine the time when a buffer acquired now will be
148 // displayed.  This can be calculated:
149 //   time when previous buffer's actual-present fence was signaled
150 //    + current display refresh rate * HWC latency
151 //    + a little extra padding
152 //
153 // Buffer producers are expected to set their desired presentation time
154 // based on choreographer time stamps, which (coming from vsync events)
155 // will be slightly later then the actual-present timing.  If we get a
156 // desired-present time that is unintentionally a hair after the next
157 // vsync, we'll hold the frame when we really want to display it.  We
158 // need to take the offset between actual-present and reported-vsync
159 // into account.
160 //
161 // If the system is configured without a DispSync phase offset for the app,
162 // we also want to throw in a bit of padding to avoid edge cases where we
163 // just barely miss.  We want to do it here, not in every app.  A major
164 // source of trouble is the app's use of the display's ideal refresh time
165 // (via Display.getRefreshRate()), which could be off of the actual refresh
166 // by a few percent, with the error multiplied by the number of frames
167 // between now and when the buffer should be displayed.
168 //
169 // If the refresh reported to the app has a phase offset, we shouldn't need
170 // to tweak anything here.
171 nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
172 {
173     // The HWC doesn't currently have a way to report additional latency.
174     // Assume that whatever we submit now will appear right after the flip.
175     // For a smart panel this might be 1.  This is expressed in frames,
176     // rather than time, because we expect to have a constant frame delay
177     // regardless of the refresh rate.
178     const uint32_t hwcLatency = 0;
179
180     // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
181     const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
182
183     // The DispSync time is already adjusted for the difference between
184     // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
185     // we don't need to factor that in here.  Pad a little to avoid
186     // weird effects if apps might be requesting times right on the edge.
187     nsecs_t extraPadding = 0;
188     if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
189         extraPadding = 1000000;        // 1ms (6% of 60Hz)
190     }
191
192     return nextRefresh + extraPadding;
193 }
194
195 sp<Fence> SurfaceFlingerConsumer::getPrevFinalReleaseFence() const {
196     Mutex::Autolock lock(mMutex);
197     return ConsumerBase::mPrevFinalReleaseFence;
198 }
199
200 #ifdef USE_HWC2
201 void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
202 {
203     if (!mPendingRelease.isPending) {
204         GLConsumer::setReleaseFence(fence);
205         return;
206     }
207     auto currentTexture = mPendingRelease.currentTexture;
208     if (fence->isValid() &&
209             currentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
210         status_t result = addReleaseFence(currentTexture,
211                 mPendingRelease.graphicBuffer, fence);
212         ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the"
213                 " fence: %s (%d)", strerror(-result), result);
214     }
215 }
216
217 bool SurfaceFlingerConsumer::releasePendingBuffer()
218 {
219     if (!mPendingRelease.isPending) {
220         ALOGV("Pending buffer already released");
221         return false;
222     }
223     ALOGV("Releasing pending buffer");
224     Mutex::Autolock lock(mMutex);
225     status_t result = releaseBufferLocked(mPendingRelease.currentTexture,
226             mPendingRelease.graphicBuffer, mPendingRelease.display,
227             mPendingRelease.fence);
228     ALOGE_IF(result < NO_ERROR, "releasePendingBuffer failed: %s (%d)",
229             strerror(-result), result);
230     mPendingRelease = PendingRelease();
231     return true;
232 }
233 #endif
234
235 void SurfaceFlingerConsumer::setContentsChangedListener(
236         const wp<ContentsChangedListener>& listener) {
237     setFrameAvailableListener(listener);
238     Mutex::Autolock lock(mMutex);
239     mContentsChangedListener = listener;
240 }
241
242 void SurfaceFlingerConsumer::onSidebandStreamChanged() {
243     FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
244     {
245         Mutex::Autolock lock(mFrameAvailableMutex);
246         unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
247     }
248     sp<ContentsChangedListener> listener;
249     {   // scope for the lock
250         Mutex::Autolock lock(mMutex);
251         ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
252         listener = mContentsChangedListener.promote();
253     }
254
255     if (listener != NULL) {
256         listener->onSidebandStreamChanged();
257     }
258 }
259
260 void SurfaceFlingerConsumer::onDisconnect() {
261     sp<Layer> l = mLayer.promote();
262     if (l.get()) {
263         l->onDisconnect();
264     }
265 }
266
267 void SurfaceFlingerConsumer::addAndGetFrameTimestamps(
268         const NewFrameEventsEntry* newTimestamps,
269         FrameEventHistoryDelta *outDelta) {
270     sp<Layer> l = mLayer.promote();
271     if (l.get()) {
272         l->addAndGetFrameTimestamps(newTimestamps, outDelta);
273     }
274 }
275
276 // ---------------------------------------------------------------------------
277 }; // namespace android
278