summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Hall <jessehall@google.com>2012-06-28 12:52:05 -0700
committerJesse Hall <jessehall@google.com>2012-06-30 21:38:51 -0700
commitc777b0b3b9b0ea5d8e378fccde6935765e28e329 (patch)
tree83ef3d6288766dc474bb9a77ebc947b0857865df
parent02a7be74dd0c4eb47a522cb0f646736cb6d0de01 (diff)
downloadframeworks_native-c777b0b3b9b0ea5d8e378fccde6935765e28e329.tar.gz
frameworks_native-c777b0b3b9b0ea5d8e378fccde6935765e28e329.tar.bz2
frameworks_native-c777b0b3b9b0ea5d8e378fccde6935765e28e329.zip
Pass fences with buffers from SurfaceTextureClient
Change-Id: I09b49433788d01e8b2b3684bb4d0112be29538d3
-rw-r--r--include/gui/BufferQueue.h23
-rw-r--r--include/gui/ISurfaceTexture.h25
-rw-r--r--include/ui/Fence.h5
-rw-r--r--libs/gui/BufferQueue.cpp39
-rw-r--r--libs/gui/ISurfaceTexture.cpp86
-rw-r--r--libs/gui/SurfaceTextureClient.cpp23
-rw-r--r--libs/ui/Fence.cpp3
7 files changed, 147 insertions, 57 deletions
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 1ea22fdca..7c1fcb9ab 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -137,7 +137,7 @@ public:
virtual status_t queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output);
- virtual void cancelBuffer(int buf);
+ virtual void cancelBuffer(int buf, sp<Fence> fence);
// setSynchronousMode set whether dequeueBuffer is synchronous or
// asynchronous. In synchronous mode, dequeueBuffer blocks until
@@ -307,7 +307,7 @@ private:
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0),
mFrameNumber(0),
- mFence(EGL_NO_SYNC_KHR),
+ mEglFence(EGL_NO_SYNC_KHR),
mAcquireCalled(false),
mNeedsCleanupOnRelease(false) {
mCrop.makeInvalid();
@@ -380,15 +380,22 @@ private:
// mFrameNumber is the number of the queued frame for this slot.
uint64_t mFrameNumber;
- // mFence is the EGL sync object that must signal before the buffer
+ // mEglFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
// 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 must signal before the contents of
- // the buffer associated with this buffer slot may be overwritten.
- sp<Fence> mReleaseFence;
+ EGLSyncKHR mEglFence;
+
+ // mFence is a fence which will signal when work initiated by the
+ // previous owner of the buffer is finished. When the buffer is FREE,
+ // the fence indicates when the consumer has finished reading
+ // from the buffer, or when the producer has finished writing if it
+ // called cancelBuffer after queueing some writes. When the buffer is
+ // QUEUED, it indicates when the producer has finished filling the
+ // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
+ // passed to the consumer or producer along with ownership of the
+ // buffer, and mFence is empty.
+ sp<Fence> mFence;
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 019606a52..8b4025dd6 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -89,24 +89,37 @@ protected:
// and height of the window and current transform applied to buffers,
// respectively.
- // QueueBufferInput must be a POD structure
- struct QueueBufferInput {
+ struct QueueBufferInput : public Flattenable {
+ inline QueueBufferInput(const Parcel& parcel);
inline QueueBufferInput(int64_t timestamp,
- const Rect& crop, int scalingMode, uint32_t transform)
+ const Rect& crop, int scalingMode, uint32_t transform,
+ sp<Fence> fence)
: timestamp(timestamp), crop(crop), scalingMode(scalingMode),
- transform(transform) { }
+ transform(transform), fence(fence) { }
inline void deflate(int64_t* outTimestamp, Rect* outCrop,
- int* outScalingMode, uint32_t* outTransform) const {
+ int* outScalingMode, uint32_t* outTransform,
+ sp<Fence>* outFence) const {
*outTimestamp = timestamp;
*outCrop = crop;
*outScalingMode = scalingMode;
*outTransform = transform;
+ *outFence = fence;
}
+
+ // Flattenable interface
+ virtual size_t getFlattenedSize() const;
+ virtual size_t getFdCount() const;
+ virtual status_t flatten(void* buffer, size_t size,
+ int fds[], size_t count) const;
+ virtual status_t unflatten(void const* buffer, size_t size,
+ int fds[], size_t count);
+
private:
int64_t timestamp;
Rect crop;
int scalingMode;
uint32_t transform;
+ sp<Fence> fence;
};
// QueueBufferOutput must be a POD structure
@@ -141,7 +154,7 @@ protected:
// cancelBuffer indicates that the client does not wish to fill in the
// buffer associated with slot and transfers ownership of the slot back to
// the server.
- virtual void cancelBuffer(int slot) = 0;
+ virtual void cancelBuffer(int slot, sp<Fence> fence) = 0;
// query retrieves some information for this surface
// 'what' tokens allowed are that of android_natives.h
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 3d49e6a14..17cb018d0 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -51,6 +51,11 @@ public:
// closed.
Fence(int fenceFd);
+ // Check whether the Fence has an open fence file descriptor. Most Fence
+ // methods treat an invalid file descriptor just like a valid fence that
+ // is already signalled, so using this is usually not necessary.
+ bool isValid() const { return mFenceFd != -1; }
+
// wait waits for up to timeout milliseconds for the fence to signal. If
// the fence signals then NO_ERROR is returned. If the timeout expires
// before the fence signals then -ETIME is returned. A timeout of
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 40e43a18d..a86853755 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -306,7 +306,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
status_t returnFlags(OK);
EGLDisplay dpy = EGL_NO_DISPLAY;
- EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+ EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
{ // Scope for the lock
Mutex::Autolock lock(mMutex);
@@ -480,22 +480,22 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
mSlots[buf].mAcquireCalled = false;
mSlots[buf].mGraphicBuffer = graphicBuffer;
mSlots[buf].mRequestBufferCalled = false;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
- mSlots[buf].mReleaseFence.clear();
+ mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mFence.clear();
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
}
dpy = mSlots[buf].mEglDisplay;
- fence = mSlots[buf].mFence;
- outFence = mSlots[buf].mReleaseFence;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
- mSlots[buf].mReleaseFence.clear();
+ eglFence = mSlots[buf].mEglFence;
+ outFence = mSlots[buf].mFence;
+ mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mFence.clear();
} // end lock scope
- if (fence != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (eglFence != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
@@ -504,7 +504,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
ST_LOGE("dequeueBuffer: timeout waiting for fence");
}
- eglDestroySyncKHR(dpy, fence);
+ eglDestroySyncKHR(dpy, eglFence);
}
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
@@ -554,8 +554,9 @@ status_t BufferQueue::queueBuffer(int buf,
uint32_t transform;
int scalingMode;
int64_t timestamp;
+ sp<Fence> fence;
- input.deflate(&timestamp, &crop, &scalingMode, &transform);
+ input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence);
ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
"scale=%s",
@@ -622,6 +623,7 @@ status_t BufferQueue::queueBuffer(int buf,
mSlots[buf].mTimestamp = timestamp;
mSlots[buf].mCrop = crop;
mSlots[buf].mTransform = transform;
+ mSlots[buf].mFence = fence;
switch (scalingMode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
@@ -655,7 +657,7 @@ status_t BufferQueue::queueBuffer(int buf,
return OK;
}
-void BufferQueue::cancelBuffer(int buf) {
+void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
ATRACE_CALL();
ST_LOGV("cancelBuffer: slot=%d", buf);
Mutex::Autolock lock(mMutex);
@@ -676,6 +678,7 @@ void BufferQueue::cancelBuffer(int buf) {
}
mSlots[buf].mBufferState = BufferSlot::FREE;
mSlots[buf].mFrameNumber = 0;
+ mSlots[buf].mFence = fence;
mDequeueCondition.broadcast();
}
@@ -842,11 +845,11 @@ void BufferQueue::freeBufferLocked(int i) {
mSlots[i].mAcquireCalled = false;
// destroy fence as BufferQueue now takes ownership
- if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
- eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
- mSlots[i].mFence = EGL_NO_SYNC_KHR;
+ if (mSlots[i].mEglFence != EGL_NO_SYNC_KHR) {
+ eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mEglFence);
+ mSlots[i].mEglFence = EGL_NO_SYNC_KHR;
}
- mSlots[i].mReleaseFence.clear();
+ mSlots[i].mFence.clear();
}
void BufferQueue::freeAllBuffersLocked() {
@@ -897,7 +900,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
}
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
- EGLSyncKHR fence, const sp<Fence>& releaseFence) {
+ EGLSyncKHR eglFence, const sp<Fence>& fence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
@@ -908,8 +911,8 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
}
mSlots[buf].mEglDisplay = display;
+ mSlots[buf].mEglFence = eglFence;
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) {
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index c8fef0693..a0b1e7446 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -109,7 +109,7 @@ public:
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
- memcpy(data.writeInplace(sizeof(input)), &input, sizeof(input));
+ data.write(input);
status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
@@ -119,10 +119,15 @@ public:
return result;
}
- virtual void cancelBuffer(int buf) {
+ virtual void cancelBuffer(int buf, sp<Fence> fence) {
Parcel data, reply;
+ bool hasFence = fence.get() && fence->isValid();
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
+ data.writeInt32(hasFence);
+ if (hasFence) {
+ data.write(*fence.get());
+ }
remote()->transact(CANCEL_BUFFER, data, &reply);
}
@@ -213,9 +218,10 @@ status_t BnSurfaceTexture::onTransact(
int buf;
sp<Fence> fence;
int result = dequeueBuffer(&buf, fence, w, h, format, usage);
+ bool hasFence = fence.get() && fence->isValid();
reply->writeInt32(buf);
- reply->writeInt32(fence.get() != NULL);
- if (fence.get() != NULL) {
+ reply->writeInt32(hasFence);
+ if (hasFence) {
reply->write(*fence.get());
}
reply->writeInt32(result);
@@ -224,20 +230,24 @@ status_t BnSurfaceTexture::onTransact(
case QUEUE_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
- QueueBufferInput const* const input =
- reinterpret_cast<QueueBufferInput const *>(
- data.readInplace(sizeof(QueueBufferInput)));
+ QueueBufferInput input(data);
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput)));
- status_t result = queueBuffer(buf, *input, output);
+ status_t result = queueBuffer(buf, input, output);
reply->writeInt32(result);
return NO_ERROR;
} break;
case CANCEL_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
- cancelBuffer(buf);
+ sp<Fence> fence;
+ bool hasFence = data.readInt32();
+ if (hasFence) {
+ fence = new Fence();
+ data.read(*fence.get());
+ }
+ cancelBuffer(buf, fence);
return NO_ERROR;
} break;
case QUERY: {
@@ -279,4 +289,62 @@ status_t BnSurfaceTexture::onTransact(
// ----------------------------------------------------------------------------
+static bool isValid(const sp<Fence>& fence) {
+ return fence.get() && fence->isValid();
+}
+
+ISurfaceTexture::QueueBufferInput::QueueBufferInput(const Parcel& parcel) {
+ parcel.read(*this);
+}
+
+size_t ISurfaceTexture::QueueBufferInput::getFlattenedSize() const
+{
+ return sizeof(timestamp)
+ + sizeof(crop)
+ + sizeof(scalingMode)
+ + sizeof(transform)
+ + sizeof(bool)
+ + (isValid(fence) ? fence->getFlattenedSize() : 0);
+}
+
+size_t ISurfaceTexture::QueueBufferInput::getFdCount() const
+{
+ return isValid(fence) ? fence->getFdCount() : 0;
+}
+
+status_t ISurfaceTexture::QueueBufferInput::flatten(void* buffer, size_t size,
+ int fds[], size_t count) const
+{
+ status_t err = NO_ERROR;
+ bool haveFence = isValid(fence);
+ char* p = (char*)buffer;
+ memcpy(p, &timestamp, sizeof(timestamp)); p += sizeof(timestamp);
+ memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
+ memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
+ memcpy(p, &transform, sizeof(transform)); p += sizeof(transform);
+ memcpy(p, &haveFence, sizeof(haveFence)); p += sizeof(haveFence);
+ if (haveFence) {
+ err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
+ }
+ return err;
+}
+
+status_t ISurfaceTexture::QueueBufferInput::unflatten(void const* buffer,
+ size_t size, int fds[], size_t count)
+{
+ status_t err = NO_ERROR;
+ bool haveFence;
+ const char* p = (const char*)buffer;
+ memcpy(&timestamp, p, sizeof(timestamp)); p += sizeof(timestamp);
+ memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
+ memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
+ memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
+ memcpy(&haveFence, p, sizeof(haveFence)); p += sizeof(haveFence);
+ if (haveFence) {
+ fence = new Fence();
+ err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
+ }
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 84f2ff4e9..718fe8441 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -237,7 +237,8 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer,
return OK;
}
-int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer, int fenceFd) {
+int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer,
+ int fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
@@ -245,13 +246,8 @@ int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer, int fenc
if (i < 0) {
return i;
}
- sp<Fence> fence(new Fence(fenceFd));
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- if (err != OK) {
- ALOGE("queueBuffer: Fence::wait returned an error: %d", err);
- return err;
- }
- mSurfaceTexture->cancelBuffer(i);
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
+ mSurfaceTexture->cancelBuffer(i, fence);
return OK;
}
@@ -291,21 +287,16 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer, int fence
return i;
}
- sp<Fence> fence(new Fence(fenceFd));
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- if (err != OK) {
- ALOGE("queueBuffer: Fence::wait returned an error: %d", err);
- return err;
- }
// Make sure the crop rectangle is entirely inside the buffer.
Rect crop;
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
ISurfaceTexture::QueueBufferOutput output;
ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode,
- mTransform);
- err = mSurfaceTexture->queueBuffer(i, input, &output);
+ mTransform, fence);
+ status_t err = mSurfaceTexture->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 08340f24b..932bcdd4e 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -63,6 +63,9 @@ sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
}
int Fence::dup() const {
+ if (mFenceFd == -1) {
+ return -1;
+ }
return ::dup(mFenceFd);
}