/* ** ** Copyright 2012 The Android Open Source Project ** ** Licensed under the Apache License Version 2.0(the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing software ** distributed under the License is distributed on an "AS IS" BASIS ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include #include #include #include #include #include #include #include #include #if ANDROID_VERSION == 17 #include #endif #include #include "FramebufferSurface.h" #include "GraphicBufferAlloc.h" #ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS #define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2) #endif // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- /* * This implements the (main) framebuffer management. This class * was adapted from the version in SurfaceFlinger */ FramebufferSurface::FramebufferSurface(int disp, uint32_t width, uint32_t height, uint32_t format, const sp& sc) : DisplaySurface(sc) , mDisplayType(disp) , mCurrentBufferSlot(-1) , mCurrentBuffer(0) { mName = "FramebufferSurface"; #if ANDROID_VERSION >= 19 sp consumer = mConsumer; #else sp consumer = mBufferQueue; consumer->setSynchronousMode(true); #endif consumer->setConsumerName(mName); consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); consumer->setDefaultBufferFormat(format); consumer->setDefaultBufferSize(width, height); consumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); } status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { return NO_ERROR; } status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) { return NO_ERROR; } status_t FramebufferSurface::advanceFrame() { // Once we remove FB HAL support, we can call nextBuffer() from here // instead of using onFrameAvailable(). No real benefit, except it'll be // more like VirtualDisplaySurface. return NO_ERROR; } status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& outFence) { Mutex::Autolock lock(mMutex); BufferQueue::BufferItem item; #if ANDROID_VERSION >= 19 status_t err = acquireBufferLocked(&item, 0); #else status_t err = acquireBufferLocked(&item); #endif if (err == BufferQueue::NO_BUFFER_AVAILABLE) { outBuffer = mCurrentBuffer; return NO_ERROR; } else if (err != NO_ERROR) { ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); return err; } // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot // then we may have acquired the slot we already own. If we had released // our current buffer before we call acquireBuffer then that release call // would have returned STALE_BUFFER_SLOT, and we would have called // freeBufferLocked on that slot. Because the buffer slot has already // been overwritten with the new buffer all we have to do is skip the // releaseBuffer call and we should be in the same state we'd be in if we // had released the old buffer first. if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mBuf != mCurrentBufferSlot) { // Release the previous buffer. #if ANDROID_VERSION >= 19 err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); #else err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); #endif if (err != NO_ERROR && err != StreamConsumer::STALE_BUFFER_SLOT) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; } } mCurrentBufferSlot = item.mBuf; mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; outFence = item.mFence; outBuffer = mCurrentBuffer; return NO_ERROR; } // Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. #if ANDROID_VERSION >= 22 void FramebufferSurface::onFrameAvailable(const ::android::BufferItem &item) { #else void FramebufferSurface::onFrameAvailable() { #endif sp buf; sp acquireFence; status_t err = nextBuffer(buf, acquireFence); if (err != NO_ERROR) { ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", strerror(-err), err); return; } if (acquireFence.get() && acquireFence->isValid()) mPrevFBAcquireFence = new Fence(acquireFence->dup()); else mPrevFBAcquireFence = Fence::NO_FENCE; lastHandle = buf->handle; } void FramebufferSurface::freeBufferLocked(int slotIndex) { ConsumerBase::freeBufferLocked(slotIndex); if (slotIndex == mCurrentBufferSlot) { mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; } } status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) { status_t err = NO_ERROR; if (fenceFd >= 0) { sp fence(new Fence(fenceFd)); if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { #if ANDROID_VERSION >= 19 status_t err = addReleaseFence(mCurrentBufferSlot, mCurrentBuffer, fence); #else status_t err = addReleaseFence(mCurrentBufferSlot, fence); #endif ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", strerror(-err), err); } } return err; } int FramebufferSurface::GetPrevDispAcquireFd() { if (mPrevFBAcquireFence.get() && mPrevFBAcquireFence->isValid()) { return mPrevFBAcquireFence->dup(); } return -1; } void FramebufferSurface::onFrameCommitted() { // XXX This role is almost same to setReleaseFenceFd(). } status_t FramebufferSurface::compositionComplete() { // Actual implementaiton is in GonkDisplay::SwapBuffers() // XXX need to move that to here. return NO_ERROR; } // ---------------------------------------------------------------------------- }; // namespace android // ----------------------------------------------------------------------------