OSDN Git Service

Pass fences with buffers from SurfaceTextureClient
authorJesse Hall <jessehall@google.com>
Thu, 28 Jun 2012 19:52:05 +0000 (12:52 -0700)
committerJesse Hall <jessehall@google.com>
Sun, 1 Jul 2012 04:38:51 +0000 (21:38 -0700)
Change-Id: I09b49433788d01e8b2b3684bb4d0112be29538d3

include/gui/BufferQueue.h
include/gui/ISurfaceTexture.h
include/ui/Fence.h
libs/gui/BufferQueue.cpp
libs/gui/ISurfaceTexture.cpp
libs/gui/SurfaceTextureClient.cpp
libs/ui/Fence.cpp

index 1ea22fd..7c1fcb9 100644 (file)
@@ -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;
index 019606a..8b4025d 100644 (file)
@@ -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
index 3d49e6a..17cb018 100644 (file)
@@ -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
index 40e43a1..a868537 100644 (file)
@@ -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) {
index c8fef06..a0b1e74 100644 (file)
@@ -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
index 84f2ff4..718fe84 100644 (file)
@@ -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);
     }
index 08340f2..932bcdd 100644 (file)
@@ -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);
 }