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 Diff line number Diff line
@@ -138,7 +138,7 @@ private:

    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,
                                    const sp<Fence>& flushFence) = 0;

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

    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
                                            : mCurrentTextureImage->graphicBuffer();
    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer : mCurrentTextureBuffer;
    auto err = addReleaseFence(slot, buffer, fence);
    if (err != OK) {
        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
    // before, so any prior EglImage created is using a stale buffer. This
    // replaces any old EglImage with a new one (using the new buffer).
    // before.
    if (item->mGraphicBuffer != nullptr) {
        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
        mImages[item->mSlot] = nullptr;
    }

    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,
             mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : 0,
             slot, mSlots[slot].mGraphicBuffer->handle);
             mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
             mSlots[slot].mGraphicBuffer->handle);

    // 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
    // the same.
    sp<Image> nextTextureImage = mImages[slot];
    sp<GraphicBuffer> nextTextureBuffer = mSlots[slot].mGraphicBuffer;

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

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

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

    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");
        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
        return NO_INIT;
    }

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

    // 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);
        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
            mRE.bindExternalTextureImage(mTexName, *image);
            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.
    return doFenceWaitLocked();
@@ -380,8 +402,7 @@ status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence
                return UNKNOWN_ERROR;
            }
            status_t err =
                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
                                          releaseFence);
                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
            if (err != OK) {
                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
                         "%s (%d)",
@@ -408,24 +429,22 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
    bool needsRecompute = mFilteringEnabled != enabled;
    mFilteringEnabled = enabled;

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

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

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

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

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

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

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

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

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

@@ -595,29 +615,4 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const
    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
+17 −55
Original line number Diff line number Diff line
@@ -187,8 +187,7 @@ protected:
    // specific info in addition to the ConsumerBase behavior.
    virtual void dumpLocked(String8& result, const char* prefix) const;

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

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

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

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
    // initialized this will release the reference to the GraphicBuffer in
    // that slot and destroy the renderengine::Image in that slot.  Otherwise it has no
    // effect.
    // that slot.  Otherwise it has no effect.
    //
    // This method must be called with mMutex locked.
    virtual void freeBufferLocked(int slotIndex);
@@ -292,10 +252,10 @@ private:
    // consume buffers as hardware textures.
    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
    // 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.
    // It gets set each time updateTexImage is called.
@@ -365,15 +325,6 @@ private:

    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
    // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
    // indicating that no buffer slot is currently bound to the texture. Note,
@@ -382,6 +333,17 @@ private:
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    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
    // presentDisplay
    PendingRelease mPendingRelease;
+1 −1
Original line number Diff line number Diff line
@@ -217,7 +217,7 @@ void BufferQueueLayer::setFilteringEnabled(bool enabled) {
    return mConsumer->setFilteringEnabled(enabled);
}

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

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

    void setFilteringEnabled(bool enabled) override;

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

Loading