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
22#include <private/gui/SyncFeatures.h>
23
24#include <utils/Errors.h>
25#include <utils/NativeHandle.h>
26#include <utils/Trace.h>
27
28namespace android {
29
30// ---------------------------------------------------------------------------
31
32status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
33        const DispSync& dispSync)
34{
35    ATRACE_CALL();
36    ALOGV("updateTexImage");
37    Mutex::Autolock lock(mMutex);
38
39    if (mAbandoned) {
40        ALOGE("updateTexImage: GLConsumer is abandoned!");
41        return NO_INIT;
42    }
43
44    // Make sure the EGL state is the same as in previous calls.
45    status_t err = checkAndUpdateEglStateLocked();
46    if (err != NO_ERROR) {
47        return err;
48    }
49
50    BufferQueue::BufferItem item;
51
52    // Acquire the next buffer.
53    // In asynchronous mode the list is guaranteed to be one buffer
54    // deep, while in synchronous mode we use the oldest buffer.
55    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
56    if (err != NO_ERROR) {
57        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
58            err = NO_ERROR;
59        } else if (err == BufferQueue::PRESENT_LATER) {
60            // return the error, without logging
61        } else {
62            ALOGE("updateTexImage: acquire failed: %s (%d)",
63                strerror(-err), err);
64        }
65        return err;
66    }
67
68
69    // We call the rejecter here, in case the caller has a reason to
70    // not accept this buffer.  This is used by SurfaceFlinger to
71    // reject buffers which have the wrong size
72    int buf = item.mBuf;
73    if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
74        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
75        return NO_ERROR;
76    }
77
78    // Release the previous buffer.
79    err = updateAndReleaseLocked(item);
80    if (err != NO_ERROR) {
81        return err;
82    }
83
84    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
85        // Bind the new buffer to the GL texture.
86        //
87        // Older devices require the "implicit" synchronization provided
88        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
89        // devices will either call this in Layer::onDraw, or (if it's not
90        // a GL-composited layer) not at all.
91        err = bindTextureImageLocked();
92    }
93
94    return err;
95}
96
97status_t SurfaceFlingerConsumer::bindTextureImage()
98{
99    Mutex::Autolock lock(mMutex);
100
101    return bindTextureImageLocked();
102}
103
104status_t SurfaceFlingerConsumer::acquireBufferLocked(
105        BufferQueue::BufferItem *item, nsecs_t presentWhen) {
106    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
107    if (result == NO_ERROR) {
108        mTransformToDisplayInverse = item->mTransformToDisplayInverse;
109    }
110    return result;
111}
112
113bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
114    return mTransformToDisplayInverse;
115}
116
117sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
118    return mConsumer->getSidebandStream();
119}
120
121// We need to determine the time when a buffer acquired now will be
122// displayed.  This can be calculated:
123//   time when previous buffer's actual-present fence was signaled
124//    + current display refresh rate * HWC latency
125//    + a little extra padding
126//
127// Buffer producers are expected to set their desired presentation time
128// based on choreographer time stamps, which (coming from vsync events)
129// will be slightly later then the actual-present timing.  If we get a
130// desired-present time that is unintentionally a hair after the next
131// vsync, we'll hold the frame when we really want to display it.  We
132// need to take the offset between actual-present and reported-vsync
133// into account.
134//
135// If the system is configured without a DispSync phase offset for the app,
136// we also want to throw in a bit of padding to avoid edge cases where we
137// just barely miss.  We want to do it here, not in every app.  A major
138// source of trouble is the app's use of the display's ideal refresh time
139// (via Display.getRefreshRate()), which could be off of the actual refresh
140// by a few percent, with the error multiplied by the number of frames
141// between now and when the buffer should be displayed.
142//
143// If the refresh reported to the app has a phase offset, we shouldn't need
144// to tweak anything here.
145nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
146{
147    // The HWC doesn't currently have a way to report additional latency.
148    // Assume that whatever we submit now will appear right after the flip.
149    // For a smart panel this might be 1.  This is expressed in frames,
150    // rather than time, because we expect to have a constant frame delay
151    // regardless of the refresh rate.
152    const uint32_t hwcLatency = 0;
153
154    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
155    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
156
157    // The DispSync time is already adjusted for the difference between
158    // vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so
159    // we don't need to factor that in here.  Pad a little to avoid
160    // weird effects if apps might be requesting times right on the edge.
161    nsecs_t extraPadding = 0;
162    if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
163        extraPadding = 1000000;        // 1ms (6% of 60Hz)
164    }
165
166    return nextRefresh + extraPadding;
167}
168
169void SurfaceFlingerConsumer::setContentsChangedListener(
170        const wp<ContentsChangedListener>& listener) {
171    setFrameAvailableListener(listener);
172    Mutex::Autolock lock(mMutex);
173    mContentsChangedListener = listener;
174}
175
176void SurfaceFlingerConsumer::onSidebandStreamChanged() {
177    sp<ContentsChangedListener> listener;
178    {   // scope for the lock
179        Mutex::Autolock lock(mMutex);
180        ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
181        listener = mContentsChangedListener.promote();
182    }
183
184    if (listener != NULL) {
185        listener->onSidebandStreamChanged();
186    }
187}
188
189// ---------------------------------------------------------------------------
190}; // namespace android
191
192