Pass fences with buffers from SurfaceTextureClient
Change-Id: I09b49433788d01e8b2b3684bb4d0112be29538d3
This commit is contained in:
parent
02a7be74dd
commit
c777b0b3b9
@ -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;
|
||||
EGLSyncKHR mEglFence;
|
||||
|
||||
// mReleaseFence is a fence which must signal before the contents of
|
||||
// the buffer associated with this buffer slot may be overwritten.
|
||||
sp<Fence> mReleaseFence;
|
||||
// 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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user