#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceTexture.h>
+#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
//
// 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
// 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;
// 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.
// 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
: 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
CpuConsumer.cpp
LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
libbinder \
+ libcutils \
+ libEGL \
+ libGLESv2 \
libhardware \
libhardware_legacy \
+ libsync \
libui \
- libEGL \
- libGLESv2 \
+ libutils \
LOCAL_MODULE:= libgui
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);
usage |= mConsumerUsageBits;
int found = -1;
- int foundSync = -1;
int dequeuedCount = 0;
bool tryAgain = true;
while (tryAgain) {
// 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;
bool isOlder = mSlots[i].mFrameNumber <
mSlots[found].mFrameNumber;
if (found < 0 || isOlder) {
- foundSync = i;
found = i;
}
}
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;
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) {
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);
eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
mSlots[i].mFence = EGL_NO_SYNC_KHR;
}
+ mSlots[i].mReleaseFence.clear();
}
void BufferQueue::freeAllBuffersLocked() {
}
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
- EGLSyncKHR fence) {
+ EGLSyncKHR fence, const sp<Fence>& releaseFence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
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) {
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;
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) {
// 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;
}
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;
}
// 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) {
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");
namespace android {
+const sp<Fence> Fence::NO_FENCE = sp<Fence>();
+
Fence::Fence() :
mFenceFd(-1) {
}
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));
}
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;
}
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;
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;
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;
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();
// LayerBaseClient interface
virtual wp<IBinder> getSurfaceTextureBinder() const;
- virtual void onLayerDisplayed();
+ virtual void onLayerDisplayed(HWComposer::HWCLayerInterface* layer);
virtual bool onPreComposition();
// only for debugging
/** called after page-flip
*/
- virtual void onLayerDisplayed() { }
+ virtual void onLayerDisplayed(HWComposer::HWCLayerInterface* layer) { }
/** called before composition.
* returns true if the layer has pending updates.
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;