SurfaceFlingerConsumer.cpp revision 399184a4cd728ea1421fb0bc1722274a29e38f4a
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{ 34 ATRACE_CALL(); 35 ALOGV("updateTexImage"); 36 Mutex::Autolock lock(mMutex); 37 38 if (mAbandoned) { 39 ALOGE("updateTexImage: GLConsumer is abandoned!"); 40 return NO_INIT; 41 } 42 43 // Make sure the EGL state is the same as in previous calls. 44 status_t err = checkAndUpdateEglStateLocked(); 45 if (err != NO_ERROR) { 46 return err; 47 } 48 49 BufferQueue::BufferItem item; 50 51 // Acquire the next buffer. 52 // In asynchronous mode the list is guaranteed to be one buffer 53 // deep, while in synchronous mode we use the oldest buffer. 54 err = acquireBufferLocked(&item, computeExpectedPresent()); 55 if (err != NO_ERROR) { 56 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 57 err = NO_ERROR; 58 } else if (err == BufferQueue::PRESENT_LATER) { 59 // return the error, without logging 60 } else { 61 ALOGE("updateTexImage: acquire failed: %s (%d)", 62 strerror(-err), err); 63 } 64 return err; 65 } 66 67 68 // We call the rejecter here, in case the caller has a reason to 69 // not accept this buffer. This is used by SurfaceFlinger to 70 // reject buffers which have the wrong size 71 int buf = item.mBuf; 72 if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { 73 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR); 74 return NO_ERROR; 75 } 76 77 // Release the previous buffer. 78 err = updateAndReleaseLocked(item); 79 if (err != NO_ERROR) { 80 return err; 81 } 82 83 if (!SyncFeatures::getInstance().useNativeFenceSync()) { 84 // Bind the new buffer to the GL texture. 85 // 86 // Older devices require the "implicit" synchronization provided 87 // by glEGLImageTargetTexture2DOES, which this method calls. Newer 88 // devices will either call this in Layer::onDraw, or (if it's not 89 // a GL-composited layer) not at all. 90 err = bindTextureImageLocked(); 91 } 92 93 return err; 94} 95 96status_t SurfaceFlingerConsumer::bindTextureImage() 97{ 98 Mutex::Autolock lock(mMutex); 99 100 return bindTextureImageLocked(); 101} 102 103status_t SurfaceFlingerConsumer::acquireBufferLocked( 104 BufferQueue::BufferItem *item, nsecs_t presentWhen) { 105 status_t result = GLConsumer::acquireBufferLocked(item, presentWhen); 106 if (result == NO_ERROR) { 107 mTransformToDisplayInverse = item->mTransformToDisplayInverse; 108 } 109 return result; 110} 111 112bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const { 113 return mTransformToDisplayInverse; 114} 115 116sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const { 117 return mConsumer->getSidebandStream(); 118} 119 120// We need to determine the time when a buffer acquired now will be 121// displayed. This can be calculated: 122// time when previous buffer's actual-present fence was signaled 123// + current display refresh rate * HWC latency 124// + a little extra padding 125// 126// Buffer producers are expected to set their desired presentation time 127// based on choreographer time stamps, which (coming from vsync events) 128// will be slightly later then the actual-present timing. If we get a 129// desired-present time that is unintentionally a hair after the next 130// vsync, we'll hold the frame when we really want to display it. We 131// want to use an expected-presentation time that is slightly late to 132// avoid this sort of edge case. 133nsecs_t SurfaceFlingerConsumer::computeExpectedPresent() 134{ 135 // Don't yet have an easy way to get actual buffer flip time for 136 // the specific display, so use the current time. This is typically 137 // 1.3ms past the vsync event time. 138 const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC); 139 140 // Given a SurfaceFlinger reference, and information about what display 141 // we're destined for, we could query the HWC for the refresh rate. This 142 // could change over time, e.g. we could switch to 24fps for a movie. 143 // For now, assume 60fps. 144 //const nsecs_t vsyncPeriod = 145 // getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); 146 const nsecs_t vsyncPeriod = 16700000; 147 148 // The HWC doesn't currently have a way to report additional latency. 149 // Assume that whatever we submit now will appear on the next flip, 150 // i.e. 1 frame of latency w.r.t. the previous flip. 151 const uint32_t hwcLatency = 1; 152 153 // A little extra padding to compensate for slack between actual vsync 154 // time and vsync event receipt. Currently not needed since we're 155 // using "now" instead of a vsync time. 156 const nsecs_t extraPadding = 0; 157 158 // Total it up. 159 return prevVsync + hwcLatency * vsyncPeriod + extraPadding; 160} 161 162void SurfaceFlingerConsumer::setContentsChangedListener( 163 const wp<ContentsChangedListener>& listener) { 164 setFrameAvailableListener(listener); 165 Mutex::Autolock lock(mMutex); 166 mContentsChangedListener = listener; 167} 168 169void SurfaceFlingerConsumer::onSidebandStreamChanged() { 170 sp<ContentsChangedListener> listener; 171 { // scope for the lock 172 Mutex::Autolock lock(mMutex); 173 ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get()); 174 listener = mContentsChangedListener.promote(); 175 } 176 177 if (listener != NULL) { 178 listener->onSidebandStreamChanged(); 179 } 180} 181 182// --------------------------------------------------------------------------- 183}; // namespace android 184 185