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

Commit 902ce2a7 authored by Stan Iliev's avatar Stan Iliev
Browse files

Cache EGLImage and VkImage used by SurfaceTexture

Reuse EGLImage or VkImage for GraphicBuffer created by
SurfaceTexture. Destroy EGLImage/VkImage, when there is a new
GraphicBuffer or GrContext is about to be destroyed.

Test: Ran Camera lens and other TextureView apps with GL and Vk
Test: Passed TextureView CTS tests
Bug: 123953909
Change-Id: I6ad4aa889060bbb64380d7dbac13676a7339b2f8
parent 8bf530ae
Loading
Loading
Loading
Loading
+54 −16
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include "renderthread/RenderThread.h"
#include "renderthread/VulkanManager.h"
#include "utils/Color.h"
#include <GrAHardwareBufferUtils.h>

// Macro for including the SurfaceTexture name in log messages
#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
@@ -30,31 +31,67 @@
namespace android {

void ImageConsumer::onFreeBufferLocked(int slotIndex) {
    mImageSlots[slotIndex].mImage.reset();
    mImageSlots[slotIndex].clear();
}

void ImageConsumer::onAcquireBufferLocked(BufferItem* item) {
    // If item->mGraphicBuffer is not null, this buffer has not been acquired
    // before, so any prior SkImage is created with a stale buffer. This resets the stale SkImage.
    if (item->mGraphicBuffer != nullptr) {
        mImageSlots[item->mSlot].mImage.reset();
        mImageSlots[item->mSlot].clear();
    }
}

void ImageConsumer::onReleaseBufferLocked(int buf) {
    mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
    mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
}

void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
                                              android_dataspace dataspace, bool forceCreate) {
                                              android_dataspace dataspace, bool forceCreate,
                                              GrContext* context) {
    if (!mImage.get() || dataspace != mDataspace || forceCreate) {
        mImage = graphicBuffer.get()
                         ? SkImage::MakeFromAHardwareBuffer(
        if (!graphicBuffer.get()) {
            clear();
            return;
        }

        if (!mBackendTexture.isValid()) {
            clear();
            bool createProtectedImage =
                0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
            GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
                context,
                reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
                                   kPremul_SkAlphaType,
                                   uirenderer::DataSpaceToColorSpace(dataspace))
                         : nullptr;
                graphicBuffer->getPixelFormat(),
                false);
            mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
                context,
                reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
                graphicBuffer->getWidth(),
                graphicBuffer->getHeight(),
                &mDeleteProc,
                &mDeleteCtx,
                createProtectedImage,
                backendFormat,
                false);
        }
        mDataspace = dataspace;
        SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
            graphicBuffer->getPixelFormat());
        mImage = SkImage::MakeFromTexture(context,
            mBackendTexture,
            kTopLeft_GrSurfaceOrigin,
            colorType,
            kPremul_SkAlphaType,
            uirenderer::DataSpaceToColorSpace(dataspace));
    }
}

void ImageConsumer::ImageSlot::clear() {
    mImage.reset();
    if (mBackendTexture.isValid()) {
        mDeleteProc(mDeleteCtx);
        mBackendTexture = {};
    }
}

@@ -71,8 +108,8 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
            if (slot != BufferItem::INVALID_BUFFER_SLOT) {
                *queueEmpty = true;
                mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer,
                        st.mCurrentDataSpace, false);
                return mImageSlots[slot].mImage;
                        st.mCurrentDataSpace, false, renderState.getRenderThread().getGrContext());
                return mImageSlots[slot].getImage();
            }
        }
        return nullptr;
@@ -104,7 +141,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
            uirenderer::RenderPipelineType::SkiaGL) {
            auto& eglManager = renderState.getRenderThread().eglManager();
            display = eglManager.eglDisplay();
            err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].mEglFence,
            err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].eglFence(),
                                                releaseFence);
        } else {
            err = renderState.getRenderThread().vulkanManager().createReleaseFence(releaseFence);
@@ -129,7 +166,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
        // Finally release the old buffer.
        status_t status = st.releaseBufferLocked(
                st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display,
                mImageSlots[st.mCurrentTexture].mEglFence);
                mImageSlots[st.mCurrentTexture].eglFence());
        if (status < NO_ERROR) {
            IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status);
            err = status;
@@ -150,8 +187,9 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
    st.computeCurrentTransformMatrixLocked();

    *queueEmpty = false;
    mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace, true);
    return mImageSlots[slot].mImage;
    mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace, true,
        renderState.getRenderThread().getGrContext());
    return mImageSlots[slot].getImage();
}

} /* namespace android */
+24 −3
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@
#include <cutils/compiler.h>
#include <gui/BufferItem.h>
#include <system/graphics.h>
#include <GrBackendSurface.h>

namespace GrAHardwareBufferUtils {
typedef void* DeleteImageCtx;
typedef void (*DeleteImageProc)(DeleteImageCtx);
}

namespace android {

@@ -67,9 +73,21 @@ private:
     * ImageSlot contains the information and object references that
     * ImageConsumer maintains about a BufferQueue buffer slot.
     */
    struct ImageSlot {
    class ImageSlot {
    public:
        ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {}

        ~ImageSlot() { clear(); }

        void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
                            bool forceCreate, GrContext* context);
        void clear();

        inline EGLSyncKHR& eglFence() { return mEglFence; }

        inline sk_sp<SkImage> getImage() { return mImage; }

    private:
        // mImage is the SkImage created from mGraphicBuffer.
        sk_sp<SkImage> mImage;

@@ -82,8 +100,11 @@ private:
         */
        EGLSyncKHR mEglFence;

        void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
                            bool forceCreate);
        GrBackendTexture mBackendTexture;

        GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;

        GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
    };

    /**
+6 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

#include "Matrix.h"
#include "SurfaceTexture.h"
#include "ImageConsumer.h"

namespace android {

@@ -150,7 +151,7 @@ status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicB
    // buffer has reallocated the original buffer slot after this buffer
    // was acquired.
    status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence);
    // We could be releasing an EGL buffer, even if not currently attached to a GL context.
    // We could be releasing an EGL/Vulkan buffer, even if not currently attached to a GL context.
    mImageConsumer.onReleaseBufferLocked(buf);
    mEGLConsumer.onReleaseBufferLocked(buf);
    return err;
@@ -235,6 +236,10 @@ void SurfaceTexture::detachFromView() {

    if (mOpMode == OpMode::attachedToView) {
        mOpMode = OpMode::detached;
        // Free all EglImage and VkImage before the context is destroyed.
        for (int i=0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
            mImageConsumer.onFreeBufferLocked(i);
        }
    } else {
        SFT_LOGE("detachFromView: not attached to View");
    }