Merge "Cache EGLImage and VkImage used by SurfaceTexture"
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index 624c290..077a8f7 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -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(
-                                   reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
-                                   kPremul_SkAlphaType,
-                                   uirenderer::DataSpaceToColorSpace(dataspace))
-                         : nullptr;
+        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()),
+                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 @@
             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 @@
             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 @@
         // 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 @@
     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 */
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
index 5c41903..eee0a0a 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -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 @@
      * 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 @@
          */
         EGLSyncKHR mEglFence;
 
-        void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
-                            bool forceCreate);
+        GrBackendTexture mBackendTexture;
+
+        GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+
+        GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
     };
 
     /**
diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp
index da09444..a27db65 100644
--- a/libs/hwui/surfacetexture/SurfaceTexture.cpp
+++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp
@@ -23,6 +23,7 @@
 
 #include "Matrix.h"
 #include "SurfaceTexture.h"
+#include "ImageConsumer.h"
 
 namespace android {
 
@@ -150,7 +151,7 @@
     // 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 @@
 
     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");
     }