Create EGLImages during buffer allocation

EGLImage creation is now performed on an async binder thread, so now GPU
composition should rarely be stalled by expensive image creation.

Bug: 129008989
Test: systrace
Change-Id: I9732f866933a8950a4c69ff51d5ac1622bbb3470
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 1980f50..fb71ce5 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -626,23 +626,26 @@
     }
 }
 
-status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
-                                                     sp<Fence> bufferFence) {
+status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    return cacheExternalTextureBufferLocked(buffer);
+}
+
+status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
+                                                     const sp<GraphicBuffer>& buffer,
+                                                     const sp<Fence>& bufferFence) {
     std::lock_guard<std::mutex> lock(mRenderingMutex);
     return bindExternalTextureBufferLocked(texName, buffer, bufferFence);
 }
 
-status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
-                                                           sp<GraphicBuffer> buffer,
-                                                           sp<Fence> bufferFence) {
+status_t GLESRenderEngine::cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) {
     if (buffer == nullptr) {
         return BAD_VALUE;
     }
-    ATRACE_CALL();
-    auto cachedImage = mImageCache.find(buffer->getId());
 
-    if (cachedImage != mImageCache.end()) {
-        bindExternalTextureImage(texName, *cachedImage->second);
+    ATRACE_CALL();
+
+    if (mImageCache.count(buffer->getId()) > 0) {
         return NO_ERROR;
     }
 
@@ -654,11 +657,32 @@
         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 NO_INIT;
+    }
+    mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
+
+    return NO_ERROR;
+}
+
+status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
+                                                           const sp<GraphicBuffer>& buffer,
+                                                           const sp<Fence>& bufferFence) {
+    ATRACE_CALL();
+    status_t cacheResult = cacheExternalTextureBufferLocked(buffer);
+
+    if (cacheResult != NO_ERROR) {
+        return cacheResult;
+    }
+
+    auto cachedImage = mImageCache.find(buffer->getId());
+
+    if (cachedImage == mImageCache.end()) {
+        // We failed creating the image if we got here, so bail out.
         bindExternalTextureImage(texName, *createImage());
         return NO_INIT;
     }
 
-    bindExternalTextureImage(texName, *newImage);
+    bindExternalTextureImage(texName, *cachedImage->second);
 
     // Wait for the new buffer to be ready.
     if (bufferFence != nullptr && bufferFence->isValid()) {
@@ -680,7 +704,6 @@
             }
         }
     }
-    mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
 
     return NO_ERROR;
 }
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 8c8f308..613629e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -72,8 +72,9 @@
     void genTextures(size_t count, uint32_t* names) override;
     void deleteTextures(size_t count, uint32_t const* names) override;
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
-    status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence)
-            EXCLUDES(mRenderingMutex);
+    status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+                                       const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
+    status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
     void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
     status_t bindFrameBuffer(Framebuffer* framebuffer) override;
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
@@ -219,8 +220,12 @@
 
     // See bindExternalTextureBuffer above, but requiring that mRenderingMutex
     // is held.
-    status_t bindExternalTextureBufferLocked(uint32_t texName, sp<GraphicBuffer> buffer,
-                                             sp<Fence> fence) REQUIRES(mRenderingMutex);
+    status_t bindExternalTextureBufferLocked(uint32_t texName, const sp<GraphicBuffer>& buffer,
+                                             const sp<Fence>& fence) REQUIRES(mRenderingMutex);
+    // See cacheExternalTextureBuffer above, but requiring that mRenderingMutex
+    // is held.
+    status_t cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer)
+            REQUIRES(mRenderingMutex);
 
     std::unique_ptr<Framebuffer> mDrawingBuffer;
 
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b211551..6773859 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -106,8 +106,14 @@
     virtual void genTextures(size_t count, uint32_t* names) = 0;
     virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
     virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
-    virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
-                                               sp<Fence> fence) = 0;
+    // Legacy public method used by devices that don't support native fence
+    // synchronization in their GPU driver, as this method provides implicit
+    // synchronization for latching buffers.
+    virtual status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+                                               const sp<Fence>& fence) = 0;
+    // Caches Image resources for this buffer, but does not bind the buffer to
+    // a particular texture.
+    virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
     // Removes internal resources referenced by the bufferId. This method should be
     // invoked when the caller will no longer hold a reference to a GraphicBuffer
     // and needs to clean up its resources.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 479c7ac..4f7d9f4 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -51,7 +51,9 @@
     MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
     MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
     MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
-    MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>));
+    MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+    MOCK_METHOD3(bindExternalTextureBuffer,
+                 status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
     MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
     MOCK_CONST_METHOD0(checkErrors, void());
     MOCK_METHOD4(setViewportAndProjection,
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 8c93cf4..24904cf 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1003,4 +1003,18 @@
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
 }
 
+TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
+    status_t result = sRE->cacheExternalTextureBuffer(nullptr);
+    ASSERT_EQ(BAD_VALUE, result);
+}
+
+TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
+    sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+    uint64_t bufferId = buf->getId();
+    sRE->cacheExternalTextureBuffer(buf);
+    EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+    sRE->unbindExternalTextureBuffer(bufferId);
+    EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+}
+
 } // namespace android