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
32namespace android {
33
34// ---------------------------------------------------------------------------
35
36status_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
114status_t SurfaceFlingerConsumer::bindTextureImage()
115{
116    Mutex::Autolock lock(mMutex);
117
118    return bindTextureImageLocked();
119}
120
121status_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
132bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
133    Mutex::Autolock lock(mMutex);
134    return mTransformToDisplayInverse;
135}
136
137const Region& SurfaceFlingerConsumer::getSurfaceDamage() const {
138    return mSurfaceDamage;
139}
140
141sp<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.
171nsecs_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
195sp<Fence> SurfaceFlingerConsumer::getPrevFinalReleaseFence() const {
196    Mutex::Autolock lock(mMutex);
197    return ConsumerBase::mPrevFinalReleaseFence;
198}
199
200#ifdef USE_HWC2
201void 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
217bool 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
235void SurfaceFlingerConsumer::setContentsChangedListener(
236        const wp<ContentsChangedListener>& listener) {
237    setFrameAvailableListener(listener);
238    Mutex::Autolock lock(mMutex);
239    mContentsChangedListener = listener;
240}
241
242void 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
260void SurfaceFlingerConsumer::onDisconnect() {
261    sp<Layer> l = mLayer.promote();
262    if (l.get()) {
263        l->onDisconnect();
264    }
265}
266
267void 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
279