Home | History | Annotate | Download | only in surfaceflinger
      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 
     28 namespace android {
     29 
     30 // ---------------------------------------------------------------------------
     31 
     32 status_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 
     97 status_t SurfaceFlingerConsumer::bindTextureImage()
     98 {
     99     Mutex::Autolock lock(mMutex);
    100 
    101     return bindTextureImageLocked();
    102 }
    103 
    104 status_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 
    113 bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
    114     return mTransformToDisplayInverse;
    115 }
    116 
    117 sp<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.
    145 nsecs_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 
    169 void SurfaceFlingerConsumer::setContentsChangedListener(
    170         const wp<ContentsChangedListener>& listener) {
    171     setFrameAvailableListener(listener);
    172     Mutex::Autolock lock(mMutex);
    173     mContentsChangedListener = listener;
    174 }
    175 
    176 void 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