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

Commit 39801c08 authored by Alec Mouri's avatar Alec Mouri
Browse files

Move image creation out of latchBuffer().

GLImage creation isn't necessary until an external texture needs to be
bound.

This also removes the BufferLayerConsumer::Image class, as it's not
really necessary now that image creation is deferred until the external
texture needs to be bound.

Bug: 116277151
Change-Id: Id9420941e9cf7df11233b427c7a98a947f9738d8
Test: SurfaceFlinger_test, libsurfaceflinger_unittest, go/wm-smoke
parent 304007e2
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -138,7 +138,7 @@ private:


    virtual void setFilteringEnabled(bool enabled) = 0;
    virtual void setFilteringEnabled(bool enabled) = 0;


    virtual status_t bindTextureImage() const = 0;
    virtual status_t bindTextureImage() = 0;
    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                                    const sp<Fence>& flushFence) = 0;
                                    const sp<Fence>& flushFence) = 0;


+53 −58
Original line number Original line Diff line number Diff line
@@ -232,8 +232,7 @@ void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
        return;
        return;
    }
    }


    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer : mCurrentTextureBuffer;
                                            : mCurrentTextureImage->graphicBuffer();
    auto err = addReleaseFence(slot, buffer, fence);
    auto err = addReleaseFence(slot, buffer, fence);
    if (err != OK) {
    if (err != OK) {
        BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
        BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
@@ -269,10 +268,9 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres
    }
    }


    // If item->mGraphicBuffer is not null, this buffer has not been acquired
    // If item->mGraphicBuffer is not null, this buffer has not been acquired
    // before, so any prior EglImage created is using a stale buffer. This
    // before.
    // replaces any old EglImage with a new one (using the new buffer).
    if (item->mGraphicBuffer != nullptr) {
    if (item->mGraphicBuffer != nullptr) {
        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
        mImages[item->mSlot] = nullptr;
    }
    }


    return NO_ERROR;
    return NO_ERROR;
@@ -299,19 +297,18 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
    }
    }


    BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
    BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
             mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : 0,
             mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
             slot, mSlots[slot].mGraphicBuffer->handle);
             mSlots[slot].mGraphicBuffer->handle);


    // Hang onto the pointer so that it isn't freed in the call to
    // Hang onto the pointer so that it isn't freed in the call to
    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
    // the same.
    // the same.
    sp<Image> nextTextureImage = mImages[slot];
    sp<GraphicBuffer> nextTextureBuffer = mSlots[slot].mGraphicBuffer;


    // release old buffer
    // release old buffer
    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
        if (pendingRelease == nullptr) {
        if (pendingRelease == nullptr) {
            status_t status =
            status_t status = releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer);
                    releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
            if (status < NO_ERROR) {
            if (status < NO_ERROR) {
                BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
                BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
                         status);
                         status);
@@ -320,14 +317,15 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
            }
            }
        } else {
        } else {
            pendingRelease->currentTexture = mCurrentTexture;
            pendingRelease->currentTexture = mCurrentTexture;
            pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
            pendingRelease->graphicBuffer = mCurrentTextureBuffer;
            pendingRelease->isPending = true;
            pendingRelease->isPending = true;
        }
        }
    }
    }


    // Update the BufferLayerConsumer state.
    // Update the BufferLayerConsumer state.
    mCurrentTexture = slot;
    mCurrentTexture = slot;
    mCurrentTextureImage = nextTextureImage;
    mCurrentTextureBuffer = nextTextureBuffer;
    mCurrentTextureImageFreed = nullptr;
    mCurrentCrop = item.mCrop;
    mCurrentCrop = item.mCrop;
    mCurrentTransform = item.mTransform;
    mCurrentTransform = item.mTransform;
    mCurrentScalingMode = item.mScalingMode;
    mCurrentScalingMode = item.mScalingMode;
@@ -348,22 +346,46 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,


status_t BufferLayerConsumer::bindTextureImageLocked() {
status_t BufferLayerConsumer::bindTextureImageLocked() {
    ATRACE_CALL();
    ATRACE_CALL();

    mRE.checkErrors();
    mRE.checkErrors();


    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
    // It is possible for the current slot's buffer to be freed before a new one
    // is bound. In that scenario we still want to bind the image.
    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureBuffer == nullptr) {
        BLC_LOGE("bindTextureImage: no currently-bound texture");
        BLC_LOGE("bindTextureImage: no currently-bound texture");
        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
        return NO_INIT;
        return NO_INIT;
    }
    }


    status_t err = mCurrentTextureImage->createIfNeeded();
    renderengine::Image* imageToRender;
    if (err != NO_ERROR) {

    // mCurrentTextureImageFreed is non-null iff mCurrentTexture ==
    // BufferQueue::INVALID_BUFFER_SLOT, so we can omit that check.
    if (mCurrentTextureImageFreed) {
        imageToRender = mCurrentTextureImageFreed.get();
    } else if (mImages[mCurrentTexture]) {
        imageToRender = mImages[mCurrentTexture].get();
    } else {
        std::unique_ptr<renderengine::Image> image = mRE.createImage();
        bool success = image->setNativeWindowBuffer(mCurrentTextureBuffer->getNativeBuffer(),
                                                    mCurrentTextureBuffer->getUsage() &
                                                            GRALLOC_USAGE_PROTECTED);
        if (!success) {
            BLC_LOGE("bindTextureImage: Failed to create image. size=%ux%u st=%u usage=%#" PRIx64
                     " fmt=%d",
                     mCurrentTextureBuffer->getWidth(), mCurrentTextureBuffer->getHeight(),
                     mCurrentTextureBuffer->getStride(), mCurrentTextureBuffer->getUsage(),
                     mCurrentTextureBuffer->getPixelFormat());
            BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
            BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
            mRE.bindExternalTextureImage(mTexName, *image);
            return UNKNOWN_ERROR;
            return UNKNOWN_ERROR;
        }
        }
        imageToRender = image.get();
        // Cache the image here so that we can reuse it.
        mImages[mCurrentTexture] = std::move(image);
    }


    mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
    mRE.bindExternalTextureImage(mTexName, *imageToRender);


    // Wait for the new buffer to be ready.
    // Wait for the new buffer to be ready.
    return doFenceWaitLocked();
    return doFenceWaitLocked();
@@ -380,8 +402,7 @@ status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence
                return UNKNOWN_ERROR;
                return UNKNOWN_ERROR;
            }
            }
            status_t err =
            status_t err =
                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
                                          releaseFence);
            if (err != OK) {
            if (err != OK) {
                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
                         "%s (%d)",
                         "%s (%d)",
@@ -408,24 +429,22 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
    bool needsRecompute = mFilteringEnabled != enabled;
    bool needsRecompute = mFilteringEnabled != enabled;
    mFilteringEnabled = enabled;
    mFilteringEnabled = enabled;


    if (needsRecompute && mCurrentTextureImage == nullptr) {
    if (needsRecompute && mCurrentTextureBuffer == nullptr) {
        BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == nullptr");
        BLC_LOGD("setFilteringEnabled called with mCurrentTextureBuffer == nullptr");
    }
    }


    if (needsRecompute && mCurrentTextureImage != nullptr) {
    if (needsRecompute && mCurrentTextureBuffer != nullptr) {
        computeCurrentTransformMatrixLocked();
        computeCurrentTransformMatrixLocked();
    }
    }
}
}


void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
    BLC_LOGV("computeCurrentTransformMatrixLocked");
    BLC_LOGV("computeCurrentTransformMatrixLocked");
    sp<GraphicBuffer> buf =
    if (mCurrentTextureBuffer == nullptr) {
            (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
    if (buf == nullptr) {
        BLC_LOGD("computeCurrentTransformMatrixLocked: "
        BLC_LOGD("computeCurrentTransformMatrixLocked: "
                 "mCurrentTextureImage is nullptr");
                 "mCurrentTextureBuffer is nullptr");
    }
    }
    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer, mCurrentCrop,
                                       mCurrentTransform, mFilteringEnabled);
                                       mCurrentTransform, mFilteringEnabled);
}
}


@@ -474,7 +493,7 @@ sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
        *outSlot = mCurrentTexture;
        *outSlot = mCurrentTexture;
    }
    }


    return (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
    return mCurrentTextureBuffer;
}
}


Rect BufferLayerConsumer::getCurrentCrop() const {
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -509,7 +528,6 @@ status_t BufferLayerConsumer::doFenceWaitLocked() const {
        BLC_LOGE("doFenceWait: RenderEngine is not current");
        BLC_LOGE("doFenceWait: RenderEngine is not current");
        return INVALID_OPERATION;
        return INVALID_OPERATION;
    }
    }

    if (mCurrentFence->isValid()) {
    if (mCurrentFence->isValid()) {
        if (mRE.useWaitSync()) {
        if (mRE.useWaitSync()) {
            base::unique_fd fenceFd(mCurrentFence->dup());
            base::unique_fd fenceFd(mCurrentFence->dup());
@@ -537,8 +555,10 @@ void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
    BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
    BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
    if (slotIndex == mCurrentTexture) {
    if (slotIndex == mCurrentTexture) {
        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
        mCurrentTextureImageFreed = std::move(mImages[slotIndex]);
    } else {
        mImages[slotIndex] = nullptr;
    }
    }
    mImages[slotIndex].clear();
    ConsumerBase::freeBufferLocked(slotIndex);
    ConsumerBase::freeBufferLocked(slotIndex);
}
}


@@ -577,7 +597,7 @@ void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* ne


void BufferLayerConsumer::abandonLocked() {
void BufferLayerConsumer::abandonLocked() {
    BLC_LOGV("abandonLocked");
    BLC_LOGV("abandonLocked");
    mCurrentTextureImage.clear();
    mCurrentTextureBuffer.clear();
    ConsumerBase::abandonLocked();
    ConsumerBase::abandonLocked();
}
}


@@ -595,29 +615,4 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const
    ConsumerBase::dumpLocked(result, prefix);
    ConsumerBase::dumpLocked(result, prefix);
}
}


BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer,
                                  renderengine::RenderEngine& engine)
      : mGraphicBuffer(graphicBuffer),
        mImage{engine.createImage()},
        mCreated(false),
        mCropWidth(0),
        mCropHeight(0) {}

BufferLayerConsumer::Image::~Image() = default;

status_t BufferLayerConsumer::Image::createIfNeeded() {
    if (mCreated) return OK;

    mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
    if (!mCreated) {
        const sp<GraphicBuffer>& buffer = mGraphicBuffer;
        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
              buffer->getPixelFormat());
    }

    return mCreated ? OK : UNKNOWN_ERROR;
}

}; // namespace android
}; // namespace android
+17 −55
Original line number Original line Diff line number Diff line
@@ -187,8 +187,7 @@ protected:
    // specific info in addition to the ConsumerBase behavior.
    // specific info in addition to the ConsumerBase behavior.
    virtual void dumpLocked(String8& result, const char* prefix) const;
    virtual void dumpLocked(String8& result, const char* prefix) const;


    // acquireBufferLocked overrides the ConsumerBase method to update the
    // See ConsumerBase::acquireBufferLocked
    // mImages array in addition to the ConsumerBase behavior.
    virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
    virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
                                         uint64_t maxFrameNumber = 0) override;
                                         uint64_t maxFrameNumber = 0) override;


@@ -212,53 +211,14 @@ protected:
                                    PendingRelease* pendingRelease = nullptr,
                                    PendingRelease* pendingRelease = nullptr,
                                    const sp<Fence>& releaseFence = Fence::NO_FENCE);
                                    const sp<Fence>& releaseFence = Fence::NO_FENCE);


    // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.  Uses
    // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
    // mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
    // If the bind succeeds, this calls doFenceWait.
    // bind succeeds, this calls doFenceWait.
    status_t bindTextureImageLocked();
    status_t bindTextureImageLocked();


private:
private:
    // Image is a utility class for tracking and creating renderengine::Images. There
    // is primarily just one image per slot, but there is also special cases:
    //  - After freeBuffer, we must still keep the current image/buffer
    // Reference counting renderengine::Images lets us handle all these cases easily while
    // also only creating new renderengine::Images from buffers when required.
    class Image : public LightRefBase<Image> {
    public:
        Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine);

        Image(const Image& rhs) = delete;
        Image& operator=(const Image& rhs) = delete;

        // createIfNeeded creates an renderengine::Image if we haven't created one yet.
        status_t createIfNeeded();

        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
        const native_handle* graphicBufferHandle() {
            return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
        }

        const renderengine::Image& image() const { return *mImage; }

    private:
        // Only allow instantiation using ref counting.
        friend class LightRefBase<Image>;
        virtual ~Image();

        // mGraphicBuffer is the buffer that was used to create this image.
        sp<GraphicBuffer> mGraphicBuffer;

        // mImage is the image created from mGraphicBuffer.
        std::unique_ptr<renderengine::Image> mImage;
        bool mCreated;
        int32_t mCropWidth;
        int32_t mCropHeight;
    };

    // freeBufferLocked frees up the given buffer slot. If the slot has been
    // freeBufferLocked frees up the given buffer slot. If the slot has been
    // initialized this will release the reference to the GraphicBuffer in
    // initialized this will release the reference to the GraphicBuffer in
    // that slot and destroy the renderengine::Image in that slot.  Otherwise it has no
    // that slot.  Otherwise it has no effect.
    // effect.
    //
    //
    // This method must be called with mMutex locked.
    // This method must be called with mMutex locked.
    virtual void freeBufferLocked(int slotIndex);
    virtual void freeBufferLocked(int slotIndex);
@@ -292,10 +252,10 @@ private:
    // consume buffers as hardware textures.
    // consume buffers as hardware textures.
    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;


    // mCurrentTextureImage is the Image/buffer of the current texture. It's
    // mCurrentTextureImage is the buffer containing the current texture. It's
    // possible that this buffer is not associated with any buffer slot, so we
    // possible that this buffer is not associated with any buffer slot, so we
    // must track it separately in order to support the getCurrentBuffer method.
    // must track it separately in order to support the getCurrentBuffer method.
    sp<Image> mCurrentTextureImage;
    sp<GraphicBuffer> mCurrentTextureBuffer;


    // mCurrentCrop is the crop rectangle that applies to the current texture.
    // mCurrentCrop is the crop rectangle that applies to the current texture.
    // It gets set each time updateTexImage is called.
    // It gets set each time updateTexImage is called.
@@ -365,15 +325,6 @@ private:


    wp<ContentsChangedListener> mContentsChangedListener;
    wp<ContentsChangedListener> mContentsChangedListener;


    // mImages stores the buffers that have been allocated by the BufferQueue
    // for each buffer slot.  It is initialized to null pointers, and gets
    // filled in with the result of BufferQueue::acquire when the
    // client dequeues a buffer from a
    // slot that has not yet been used. The buffer allocated to a slot will also
    // be replaced if the requested buffer usage or geometry differs from that
    // of the buffer allocated to a slot.
    sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];

    // mCurrentTexture is the buffer slot index of the buffer that is currently
    // mCurrentTexture is the buffer slot index of the buffer that is currently
    // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
    // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
    // indicating that no buffer slot is currently bound to the texture. Note,
    // indicating that no buffer slot is currently bound to the texture. Note,
@@ -382,6 +333,17 @@ private:
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    int mCurrentTexture;
    int mCurrentTexture;


    // Cached image used for rendering the current texture through GPU
    // composition, which contains the cached image after freeBufferLocked is
    // called on the current buffer. Whenever latchBuffer is called, this is
    // expected to be cleared. Then, if bindTexImage is called before the next
    // buffer is acquired, then this image is bound.
    std::unique_ptr<renderengine::Image> mCurrentTextureImageFreed;

    // Cached images used for rendering the current texture through GPU
    // composition.
    std::unique_ptr<renderengine::Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];

    // A release that is pending on the receipt of a new release fence from
    // A release that is pending on the receipt of a new release fence from
    // presentDisplay
    // presentDisplay
    PendingRelease mPendingRelease;
    PendingRelease mPendingRelease;
+1 −1
Original line number Original line Diff line number Diff line
@@ -217,7 +217,7 @@ void BufferQueueLayer::setFilteringEnabled(bool enabled) {
    return mConsumer->setFilteringEnabled(enabled);
    return mConsumer->setFilteringEnabled(enabled);
}
}


status_t BufferQueueLayer::bindTextureImage() const {
status_t BufferQueueLayer::bindTextureImage() {
    return mConsumer->bindTextureImage();
    return mConsumer->bindTextureImage();
}
}


+1 −1
Original line number Original line Diff line number Diff line
@@ -89,7 +89,7 @@ private:


    void setFilteringEnabled(bool enabled) override;
    void setFilteringEnabled(bool enabled) override;


    status_t bindTextureImage() const override;
    status_t bindTextureImage() override;
    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                            const sp<Fence>& releaseFence) override;
                            const sp<Fence>& releaseFence) override;


Loading