Merge "Transfer HWC release fences to BufferQueue"
This commit is contained in:
commit
a277b7a4d7
@ -23,6 +23,7 @@
|
||||
#include <gui/IGraphicBufferAlloc.h>
|
||||
#include <gui/ISurfaceTexture.h>
|
||||
|
||||
#include <ui/Fence.h>
|
||||
#include <ui/GraphicBuffer.h>
|
||||
|
||||
#include <utils/String8.h>
|
||||
@ -218,7 +219,8 @@ public:
|
||||
//
|
||||
// Note that the dependencies on EGL will be removed once we switch to using
|
||||
// the Android HW Sync HAL.
|
||||
status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence);
|
||||
status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence,
|
||||
const sp<Fence>& releaseFence = Fence::NO_FENCE);
|
||||
|
||||
// consumerConnect connects a consumer to the BufferQueue. Only one
|
||||
// consumer may be connected, and when that consumer disconnects the
|
||||
@ -378,6 +380,10 @@ private:
|
||||
// on a compile-time option) set to a new sync object in updateTexImage.
|
||||
EGLSyncKHR mFence;
|
||||
|
||||
// mReleaseFence is a fence which must signal before the contents of
|
||||
// the buffer associated with this buffer slot may be overwritten.
|
||||
sp<Fence> mReleaseFence;
|
||||
|
||||
// Indicates whether this buffer has been seen by a consumer yet
|
||||
bool mAcquireCalled;
|
||||
|
||||
|
@ -91,6 +91,14 @@ public:
|
||||
// target texture belongs is bound to the calling thread.
|
||||
status_t updateTexImage();
|
||||
|
||||
// setReleaseFence stores a fence file descriptor that will signal when the
|
||||
// current buffer is no longer being read. This fence will be returned to
|
||||
// the producer when the current buffer is released by updateTexImage().
|
||||
// Multiple fences can be set for a given buffer; they will be merged into
|
||||
// a single union fence. The SurfaceTexture will close the file descriptor
|
||||
// when finished with it.
|
||||
void setReleaseFence(int fenceFd);
|
||||
|
||||
// setBufferCountServer set the buffer count. If the client has requested
|
||||
// a buffer count using setBufferCount, the server-buffer count will
|
||||
// take effect once the client sets the count back to zero.
|
||||
@ -349,6 +357,13 @@ private:
|
||||
// to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
|
||||
// on a compile-time option) set to a new sync object in updateTexImage.
|
||||
EGLSyncKHR mFence;
|
||||
|
||||
// mReleaseFence is a fence which will signal when the buffer
|
||||
// associated with this buffer slot is no longer being used by the
|
||||
// consumer and can be overwritten. The buffer can be dequeued before
|
||||
// the fence signals; the producer is responsible for delaying writes
|
||||
// until it signals.
|
||||
sp<Fence> mReleaseFence;
|
||||
};
|
||||
|
||||
// mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently
|
||||
|
@ -39,6 +39,7 @@ class Fence
|
||||
: public LightRefBase<Fence>, public Flattenable
|
||||
{
|
||||
public:
|
||||
static const sp<Fence> NO_FENCE;
|
||||
|
||||
// Construct a new Fence object with an invalid file descriptor. This
|
||||
// should be done when the Fence object will be set up by unflattening
|
||||
|
@ -25,14 +25,15 @@ LOCAL_SRC_FILES:= \
|
||||
CpuConsumer.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils \
|
||||
libutils \
|
||||
libbinder \
|
||||
libhardware \
|
||||
libhardware_legacy \
|
||||
libui \
|
||||
libcutils \
|
||||
libEGL \
|
||||
libGLESv2 \
|
||||
libhardware \
|
||||
libhardware_legacy \
|
||||
libsync \
|
||||
libui \
|
||||
libutils \
|
||||
|
||||
|
||||
LOCAL_MODULE:= libgui
|
||||
|
@ -307,6 +307,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
status_t returnFlags(OK);
|
||||
EGLDisplay dpy = EGL_NO_DISPLAY;
|
||||
EGLSyncKHR fence = EGL_NO_SYNC_KHR;
|
||||
sp<Fence> releaseFence;
|
||||
|
||||
{ // Scope for the lock
|
||||
Mutex::Autolock lock(mMutex);
|
||||
@ -318,7 +319,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
usage |= mConsumerUsageBits;
|
||||
|
||||
int found = -1;
|
||||
int foundSync = -1;
|
||||
int dequeuedCount = 0;
|
||||
bool tryAgain = true;
|
||||
while (tryAgain) {
|
||||
@ -369,7 +369,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
|
||||
// look for a free buffer to give to the client
|
||||
found = INVALID_BUFFER_SLOT;
|
||||
foundSync = INVALID_BUFFER_SLOT;
|
||||
dequeuedCount = 0;
|
||||
for (int i = 0; i < mBufferCount; i++) {
|
||||
const int state = mSlots[i].mBufferState;
|
||||
@ -393,7 +392,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
bool isOlder = mSlots[i].mFrameNumber <
|
||||
mSlots[found].mFrameNumber;
|
||||
if (found < 0 || isOlder) {
|
||||
foundSync = i;
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
@ -484,6 +482,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
mSlots[buf].mGraphicBuffer = graphicBuffer;
|
||||
mSlots[buf].mRequestBufferCalled = false;
|
||||
mSlots[buf].mFence = EGL_NO_SYNC_KHR;
|
||||
mSlots[buf].mReleaseFence.clear();
|
||||
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
|
||||
|
||||
returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
|
||||
@ -491,7 +490,9 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
|
||||
dpy = mSlots[buf].mEglDisplay;
|
||||
fence = mSlots[buf].mFence;
|
||||
releaseFence = mSlots[buf].mReleaseFence;
|
||||
mSlots[buf].mFence = EGL_NO_SYNC_KHR;
|
||||
mSlots[buf].mReleaseFence.clear();
|
||||
} // end lock scope
|
||||
|
||||
if (fence != EGL_NO_SYNC_KHR) {
|
||||
@ -507,6 +508,16 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
eglDestroySyncKHR(dpy, fence);
|
||||
}
|
||||
|
||||
if (releaseFence.get()) {
|
||||
int err = releaseFence->wait(1000);
|
||||
if (err == -ETIME) {
|
||||
ALOGE("dequeueBuffer: timeout waiting for release fence");
|
||||
} else if (err != NO_ERROR) {
|
||||
ALOGE("dequeueBuffer: error waiting for sync fence: %d", err);
|
||||
}
|
||||
releaseFence.clear();
|
||||
}
|
||||
|
||||
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
|
||||
mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
|
||||
|
||||
@ -846,6 +857,7 @@ void BufferQueue::freeBufferLocked(int i) {
|
||||
eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
|
||||
mSlots[i].mFence = EGL_NO_SYNC_KHR;
|
||||
}
|
||||
mSlots[i].mReleaseFence.clear();
|
||||
}
|
||||
|
||||
void BufferQueue::freeAllBuffersLocked() {
|
||||
@ -896,7 +908,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
|
||||
}
|
||||
|
||||
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
|
||||
EGLSyncKHR fence) {
|
||||
EGLSyncKHR fence, const sp<Fence>& releaseFence) {
|
||||
ATRACE_CALL();
|
||||
ATRACE_BUFFER_INDEX(buf);
|
||||
|
||||
@ -908,6 +920,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
|
||||
|
||||
mSlots[buf].mEglDisplay = display;
|
||||
mSlots[buf].mFence = fence;
|
||||
mSlots[buf].mReleaseFence = releaseFence;
|
||||
|
||||
// The buffer can now only be released if its in the acquired state
|
||||
if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
|
||||
|
@ -107,7 +107,8 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
|
||||
if (b.mGraphicBuffer != NULL) {
|
||||
if (mBufferPointers[buf] != NULL) {
|
||||
CC_LOGE("Reallocation of buffer %d while in consumer use!", buf);
|
||||
mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
|
||||
mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
|
||||
Fence::NO_FENCE);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
mBufferSlot[buf] = b.mGraphicBuffer;
|
||||
@ -161,7 +162,8 @@ status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
|
||||
CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
|
||||
return err;
|
||||
}
|
||||
err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
|
||||
err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
|
||||
Fence::NO_FENCE);
|
||||
if (err == BufferQueue::STALE_BUFFER_SLOT) {
|
||||
freeBufferLocked(buf);
|
||||
} else if (err != OK) {
|
||||
|
@ -236,8 +236,10 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
|
||||
// not accept this buffer. this is used by SurfaceFlinger to
|
||||
// reject buffers which have the wrong size
|
||||
if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
|
||||
mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
|
||||
mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
|
||||
mEGLSlots[buf].mReleaseFence);
|
||||
mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
|
||||
mEGLSlots[buf].mReleaseFence.clear();
|
||||
glBindTexture(mTexTarget, mTexName);
|
||||
return NO_ERROR;
|
||||
}
|
||||
@ -284,8 +286,10 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
|
||||
if (err != NO_ERROR) {
|
||||
// Release the buffer we just acquired. It's not safe to
|
||||
// release the old buffer, so instead we just drop the new frame.
|
||||
mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
|
||||
mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
|
||||
mEGLSlots[buf].mReleaseFence);
|
||||
mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
|
||||
mEGLSlots[buf].mReleaseFence.clear();
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -297,9 +301,10 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
|
||||
// release old buffer
|
||||
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
|
||||
status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
|
||||
mEGLSlots[mCurrentTexture].mFence);
|
||||
|
||||
mEGLSlots[mCurrentTexture].mFence,
|
||||
mEGLSlots[mCurrentTexture].mReleaseFence);
|
||||
mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
|
||||
mEGLSlots[mCurrentTexture].mReleaseFence.clear();
|
||||
if (status == BufferQueue::STALE_BUFFER_SLOT) {
|
||||
freeBufferLocked(mCurrentTexture);
|
||||
} else if (status != NO_ERROR) {
|
||||
@ -328,6 +333,27 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
|
||||
return err;
|
||||
}
|
||||
|
||||
void SurfaceTexture::setReleaseFence(int fenceFd) {
|
||||
if (fenceFd == -1)
|
||||
return;
|
||||
sp<Fence> fence(new Fence(fenceFd));
|
||||
if (!mEGLSlots[mCurrentTexture].mReleaseFence.get()) {
|
||||
mEGLSlots[mCurrentTexture].mReleaseFence = fence;
|
||||
} else {
|
||||
sp<Fence> mergedFence = Fence::merge(
|
||||
String8("SurfaceTexture merged release"),
|
||||
mEGLSlots[mCurrentTexture].mReleaseFence, fence);
|
||||
if (mergedFence.get()) {
|
||||
ALOGE("failed to merge release fences");
|
||||
// synchronization is broken, the best we can do is hope fences
|
||||
// signal in order so the new fence will act like a union
|
||||
mEGLSlots[mCurrentTexture].mReleaseFence = fence;
|
||||
} else {
|
||||
mEGLSlots[mCurrentTexture].mReleaseFence = mergedFence;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status_t SurfaceTexture::detachFromContext() {
|
||||
ATRACE_CALL();
|
||||
ST_LOGV("detachFromContext");
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
const sp<Fence> Fence::NO_FENCE = sp<Fence>();
|
||||
|
||||
Fence::Fence() :
|
||||
mFenceFd(-1) {
|
||||
}
|
||||
@ -55,7 +57,7 @@ sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
|
||||
if (result == -1) {
|
||||
ALOGE("merge: sync_merge returned an error: %s (%d)", strerror(-errno),
|
||||
errno);
|
||||
return sp<Fence>();
|
||||
return NO_FENCE;
|
||||
}
|
||||
return sp<Fence>(new Fence(result));
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ void FramebufferSurface::onFirstRef() {
|
||||
self->fbDev->post(self->fbDev, self->mBuffers[item.mBuf]->handle);
|
||||
if (self->mCurrentBufferIndex >= 0) {
|
||||
self->mBufferQueue->releaseBuffer(self->mCurrentBufferIndex,
|
||||
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
|
||||
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
|
||||
}
|
||||
self->mCurrentBufferIndex = item.mBuf;
|
||||
}
|
||||
|
@ -346,6 +346,10 @@ public:
|
||||
virtual uint32_t getHints() const {
|
||||
return getLayer()->hints;
|
||||
}
|
||||
virtual int getAndResetReleaseFenceFd() {
|
||||
// not supported on VERSION_03
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual void setDefaultState() {
|
||||
getLayer()->compositionType = HWC_FRAMEBUFFER;
|
||||
@ -407,6 +411,11 @@ public:
|
||||
virtual uint32_t getHints() const {
|
||||
return getLayer()->hints;
|
||||
}
|
||||
virtual int getAndResetReleaseFenceFd() {
|
||||
int fd = getLayer()->releaseFenceFd;
|
||||
getLayer()->releaseFenceFd = -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
virtual void setDefaultState() {
|
||||
getLayer()->compositionType = HWC_FRAMEBUFFER;
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
public:
|
||||
virtual int32_t getCompositionType() const = 0;
|
||||
virtual uint32_t getHints() const = 0;
|
||||
virtual int getAndResetReleaseFenceFd() = 0;
|
||||
virtual void setDefaultState() = 0;
|
||||
virtual void setSkip(bool skip) = 0;
|
||||
virtual void setBlending(uint32_t blending) = 0;
|
||||
|
@ -71,7 +71,11 @@ Layer::Layer(SurfaceFlinger* flinger,
|
||||
glGenTextures(1, &mTextureName);
|
||||
}
|
||||
|
||||
void Layer::onLayerDisplayed() {
|
||||
void Layer::onLayerDisplayed(HWComposer::HWCLayerInterface* layer) {
|
||||
if (layer) {
|
||||
mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
|
||||
}
|
||||
|
||||
if (mFrameLatencyNeeded) {
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
// LayerBaseClient interface
|
||||
virtual wp<IBinder> getSurfaceTextureBinder() const;
|
||||
|
||||
virtual void onLayerDisplayed();
|
||||
virtual void onLayerDisplayed(HWComposer::HWCLayerInterface* layer);
|
||||
virtual bool onPreComposition();
|
||||
|
||||
// only for debugging
|
||||
|
@ -210,7 +210,7 @@ public:
|
||||
|
||||
/** called after page-flip
|
||||
*/
|
||||
virtual void onLayerDisplayed() { }
|
||||
virtual void onLayerDisplayed(HWComposer::HWCLayerInterface* layer) { }
|
||||
|
||||
/** called before composition.
|
||||
* returns true if the layer has pending updates.
|
||||
|
@ -472,8 +472,17 @@ void SurfaceFlinger::postFramebuffer()
|
||||
hw.flip(mSwapRegion);
|
||||
|
||||
size_t numLayers = mVisibleLayersSortedByZ.size();
|
||||
for (size_t i = 0; i < numLayers; i++) {
|
||||
mVisibleLayersSortedByZ[i]->onLayerDisplayed();
|
||||
HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
|
||||
if (hwc.initCheck() == NO_ERROR) {
|
||||
HWComposer::LayerListIterator cur = hwc.begin();
|
||||
const HWComposer::LayerListIterator end = hwc.end();
|
||||
for (size_t i = 0; cur != end && i < numLayers; ++i, ++cur) {
|
||||
mVisibleLayersSortedByZ[i]->onLayerDisplayed(&*cur);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < numLayers; i++) {
|
||||
mVisibleLayersSortedByZ[i]->onLayerDisplayed(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
mLastSwapBufferTime = systemTime() - now;
|
||||
|
Loading…
Reference in New Issue
Block a user