851cfe8342
HWComposer didn't allow the virtual display output buffer to be set directly, instead it always used the framebuffer target buffer. DisplayDevice was only providing the framebuffer release fence to DisplaySurfaces after a commit. This change fixes both of these, so both HWComposer and DisplayDevice should continue to work if VirtualDisplaySurface changes to use separate framebuffer and output buffers. It's also more correct since VirtualDisplaySurface uses the correct release fence when queueing the buffer to the sink. Bug: 8384764 Change-Id: I95c71e8d4f67705e23f122259ec8dd5dbce70dcf
188 lines
6.6 KiB
C++
188 lines
6.6 KiB
C++
/*
|
|
**
|
|
** 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <cutils/log.h>
|
|
|
|
#include <utils/String8.h>
|
|
|
|
#include <ui/Rect.h>
|
|
|
|
#include <EGL/egl.h>
|
|
|
|
#include <hardware/hardware.h>
|
|
#include <gui/Surface.h>
|
|
#include <gui/GraphicBufferAlloc.h>
|
|
#include <ui/GraphicBuffer.h>
|
|
|
|
#include "DisplayHardware/FramebufferSurface.h"
|
|
#include "DisplayHardware/HWComposer.h"
|
|
|
|
#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
|
|
#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2)
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
namespace android {
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
* This implements the (main) framebuffer management. This class is used
|
|
* mostly by SurfaceFlinger, but also by command line GL application.
|
|
*
|
|
*/
|
|
|
|
FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) :
|
|
ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
|
|
mDisplayType(disp),
|
|
mCurrentBufferSlot(-1),
|
|
mCurrentBuffer(0),
|
|
mHwc(hwc)
|
|
{
|
|
mName = "FramebufferSurface";
|
|
mBufferQueue->setConsumerName(mName);
|
|
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
|
|
GRALLOC_USAGE_HW_RENDER |
|
|
GRALLOC_USAGE_HW_COMPOSER);
|
|
mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp));
|
|
mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
|
|
mBufferQueue->setSynchronousMode(true);
|
|
mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
|
|
}
|
|
|
|
sp<IGraphicBufferProducer> FramebufferSurface::getIGraphicBufferProducer() const {
|
|
return getBufferQueue();
|
|
}
|
|
|
|
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<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
|
|
Mutex::Autolock lock(mMutex);
|
|
|
|
BufferQueue::BufferItem item;
|
|
status_t err = acquireBufferLocked(&item);
|
|
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.
|
|
err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
|
|
EGL_NO_SYNC_KHR);
|
|
if (err != NO_ERROR && err != BufferQueue::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.
|
|
void FramebufferSurface::onFrameAvailable() {
|
|
sp<GraphicBuffer> buf;
|
|
sp<Fence> acquireFence;
|
|
status_t err = nextBuffer(buf, acquireFence);
|
|
if (err != NO_ERROR) {
|
|
ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
|
|
strerror(-err), err);
|
|
return;
|
|
}
|
|
err = mHwc.fbPost(mDisplayType, acquireFence, buf);
|
|
if (err != NO_ERROR) {
|
|
ALOGE("error posting framebuffer: %d", err);
|
|
}
|
|
}
|
|
|
|
void FramebufferSurface::freeBufferLocked(int slotIndex) {
|
|
ConsumerBase::freeBufferLocked(slotIndex);
|
|
if (slotIndex == mCurrentBufferSlot) {
|
|
mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
|
|
}
|
|
}
|
|
|
|
void FramebufferSurface::onFrameCommitted() {
|
|
sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType);
|
|
if (fence->isValid() &&
|
|
mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
|
|
status_t err = addReleaseFence(mCurrentBufferSlot, fence);
|
|
ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
|
|
strerror(-err), err);
|
|
}
|
|
}
|
|
|
|
status_t FramebufferSurface::compositionComplete()
|
|
{
|
|
return mHwc.fbCompositionComplete();
|
|
}
|
|
|
|
// Since DisplaySurface and ConsumerBase both have a method with this
|
|
// signature, results will vary based on the static pointer type the caller is
|
|
// using:
|
|
// void dump(FrameBufferSurface* fbs, String8& s) {
|
|
// // calls FramebufferSurface::dump()
|
|
// fbs->dump(s);
|
|
//
|
|
// // calls ConsumerBase::dump() since it is non-virtual
|
|
// static_cast<ConsumerBase*>(fbs)->dump(s);
|
|
//
|
|
// // calls FramebufferSurface::dump() since it is virtual
|
|
// static_cast<DisplaySurface*>(fbs)->dump(s);
|
|
// }
|
|
// To make sure that all of these end up doing the same thing, we just redirect
|
|
// to ConsumerBase::dump() here. It will take the internal lock, and then call
|
|
// virtual dumpLocked(), which is where the real work happens.
|
|
void FramebufferSurface::dump(String8& result) const {
|
|
ConsumerBase::dump(result);
|
|
}
|
|
|
|
void FramebufferSurface::dumpLocked(String8& result, const char* prefix,
|
|
char* buffer, size_t SIZE) const
|
|
{
|
|
mHwc.fbDump(result);
|
|
ConsumerBase::dumpLocked(result, prefix, buffer, SIZE);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
}; // namespace android
|
|
// ----------------------------------------------------------------------------
|