Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c777b0b3 authored by Jesse Hall's avatar Jesse Hall
Browse files

Pass fences with buffers from SurfaceTextureClient

Change-Id: I09b49433788d01e8b2b3684bb4d0112be29538d3
parent 02a7be74
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -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;
+19 −6
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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
+21 −18
Original line number Diff line number Diff line
@@ -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) {
+77 −9
Original line number Diff line number Diff line
@@ -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
Loading