diff options
author | Jesse Hall <jessehall@google.com> | 2012-06-28 12:52:05 -0700 |
---|---|---|
committer | Jesse Hall <jessehall@google.com> | 2012-06-30 21:38:51 -0700 |
commit | c777b0b3b9b0ea5d8e378fccde6935765e28e329 (patch) | |
tree | 83ef3d6288766dc474bb9a77ebc947b0857865df | |
parent | 02a7be74dd0c4eb47a522cb0f646736cb6d0de01 (diff) | |
download | frameworks_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.h | 23 | ||||
-rw-r--r-- | include/gui/ISurfaceTexture.h | 25 | ||||
-rw-r--r-- | include/ui/Fence.h | 5 | ||||
-rw-r--r-- | libs/gui/BufferQueue.cpp | 39 | ||||
-rw-r--r-- | libs/gui/ISurfaceTexture.cpp | 86 | ||||
-rw-r--r-- | libs/gui/SurfaceTextureClient.cpp | 23 | ||||
-rw-r--r-- | libs/ui/Fence.cpp | 3 |
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(×tamp, &crop, &scalingMode, &transform); + input.deflate(×tamp, &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, ×tamp, 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(×tamp, 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); } |