surfaceflinger: remove EGL/GLES dependency from BufferLayerConsumer

Use RE::Image and RenderEngine for image creation and texture
binding.  After this change, BufferLayerConsumer no longer depends
on EGL/GLES.

Test: SurfaceFlinger_test
Change-Id: I7bade001181ffacf550130adf356b023a7da2d02
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index fb6fa03..e39ebcc 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -27,10 +27,6 @@
 
 #include <inttypes.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
 #include <cutils/compiler.h>
 
 #include <hardware/hardware.h>
@@ -49,11 +45,6 @@
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
-#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
-#define EGL_PROTECTED_CONTENT_EXT 0x32C0
-
 namespace android {
 
 // Macros for including the BufferLayerConsumer name in log messages
@@ -65,50 +56,6 @@
 
 static const mat4 mtxIdentity;
 
-static bool hasEglAndroidImageCropImpl() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen + 1);
-    bool atEnd = (cropExtLen + 1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen + 1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglAndroidImageCrop() {
-    // Only compute whether the extension is present once the first time this
-    // function is called.
-    static bool hasIt = hasEglAndroidImageCropImpl();
-    return hasIt;
-}
-
-static bool hasEglProtectedContentImpl() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
-    bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
-    bool atEnd = (cropExtLen + 1) < extsLen &&
-            !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
-    bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
-    return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglProtectedContent() {
-    // Only compute whether the extension is present once the first time this
-    // function is called.
-    static bool hasIt = hasEglProtectedContentImpl();
-    return hasIt;
-}
-
-static bool isEglImageCroppable(const Rect& crop) {
-    return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
-}
-
 BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine,
                                          uint32_t tex, Layer* layer)
       : ConsumerBase(bq, false),
@@ -125,7 +72,6 @@
         mDefaultHeight(1),
         mFilteringEnabled(true),
         mRE(engine),
-        mEglDisplay(mRE.getEGLDisplay()),
         mTexName(tex),
         mLayer(layer),
         mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
@@ -326,13 +272,20 @@
     // before, so any prior EglImage created is using a stale buffer. This
     // replaces any old EglImage with a new one (using the new buffer).
     if (item->mGraphicBuffer != NULL) {
-        int slot = item->mSlot;
-        mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
+        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
     }
 
     return NO_ERROR;
 }
 
+bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
+    // If the crop rect is not at the origin, we can't set the crop on the
+    // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+    // extension.  In the future we can add a layered extension that
+    // removes this restriction if there is hardware that can support it.
+    return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
+}
+
 status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
                                                      PendingRelease* pendingRelease) {
     status_t err = NO_ERROR;
@@ -344,10 +297,10 @@
     // ConsumerBase.
     // We may have to do this even when item.mGraphicBuffer == NULL (which
     // means the buffer was previously acquired).
-    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+    const Rect& imageCrop = canUseImageCrop(item.mCrop) ? item.mCrop : Rect::EMPTY_RECT;
+    err = mImages[slot]->createIfNeeded(imageCrop);
     if (err != NO_ERROR) {
-        BLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
-                 slot);
+        BLC_LOGW("updateAndRelease: unable to createImage on slot=%d", slot);
         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
         return UNKNOWN_ERROR;
     }
@@ -372,7 +325,7 @@
     // 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<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
+    sp<Image> nextTextureImage = mImages[slot];
 
     // release old buffer
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
@@ -414,19 +367,21 @@
 status_t BufferLayerConsumer::bindTextureImageLocked() {
     mRE.checkErrors();
 
-    glBindTexture(sTexTarget, mTexName);
     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) {
         BLC_LOGE("bindTextureImage: no currently-bound texture");
+        mRE.bindExternalTextureImage(mTexName, RE::Image(mRE));
         return NO_INIT;
     }
 
-    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop);
+    const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
+    status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
     if (err != NO_ERROR) {
-        BLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
-                 mCurrentTexture);
+        BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
+        mRE.bindExternalTextureImage(mTexName, RE::Image(mRE));
         return UNKNOWN_ERROR;
     }
-    mCurrentTextureImage->bindToTextureTarget(sTexTarget);
+
+    mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
 
     // Wait for the new buffer to be ready.
     return doFenceWaitLocked();
@@ -488,10 +443,9 @@
         BLC_LOGD("computeCurrentTransformMatrixLocked: "
                  "mCurrentTextureImage is NULL");
     }
-    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf,
-                                       isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT
-                                                                         : mCurrentCrop,
-                                       mCurrentTransform, mFilteringEnabled);
+    const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
+    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
+                                       mFilteringEnabled);
 }
 
 nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -592,7 +546,7 @@
     if (slotIndex == mCurrentTexture) {
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
     }
-    mEglSlots[slotIndex].mEglImage.clear();
+    mImages[slotIndex].clear();
     ConsumerBase::freeBufferLocked(slotIndex);
 }
 
@@ -649,106 +603,37 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
+BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine)
       : mGraphicBuffer(graphicBuffer),
-        mEglImage(EGL_NO_IMAGE_KHR),
-        mEglDisplay(EGL_NO_DISPLAY),
-        mCropRect(Rect::EMPTY_RECT) {}
+        mImage{engine},
+        mCreated(false),
+        mCropWidth(0),
+        mCropHeight(0) {}
 
-BufferLayerConsumer::EglImage::~EglImage() {
-    if (mEglImage != EGL_NO_IMAGE_KHR) {
-        if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
-            ALOGE("~EglImage: eglDestroyImageKHR failed");
-        }
-        eglTerminate(mEglDisplay);
-    }
-}
-
-status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
-                                                       const Rect& cropRect) {
-    // If there's an image and it's no longer valid, destroy it.
-    bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
-    bool displayInvalid = mEglDisplay != eglDisplay;
-    bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
-    if (haveImage && (displayInvalid || cropInvalid)) {
-        if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
-            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
-        }
-        eglTerminate(mEglDisplay);
-        mEglImage = EGL_NO_IMAGE_KHR;
-        mEglDisplay = EGL_NO_DISPLAY;
+status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
+    const int32_t cropWidth = imageCrop.width();
+    const int32_t cropHeight = imageCrop.height();
+    if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
+        return OK;
     }
 
-    // If there's no image, create one.
-    if (mEglImage == EGL_NO_IMAGE_KHR) {
-        mEglDisplay = eglDisplay;
-        mCropRect = cropRect;
-        mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
-    }
+    mCreated = mImage.setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
+                                            mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
+                                            cropWidth, cropHeight);
+    if (mCreated) {
+        mCropWidth = cropWidth;
+        mCropHeight = cropHeight;
+    } else {
+        mCropWidth = 0;
+        mCropHeight = 0;
 
-    // Fail if we can't create a valid image.
-    if (mEglImage == EGL_NO_IMAGE_KHR) {
-        mEglDisplay = EGL_NO_DISPLAY;
-        mCropRect.makeInvalid();
         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 UNKNOWN_ERROR;
     }
 
-    return OK;
-}
-
-void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
-    glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
-}
-
-EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
-                                                       const sp<GraphicBuffer>& graphicBuffer,
-                                                       const Rect& crop) {
-    EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
-    const bool createProtectedImage =
-            (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
-    EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,
-            EGL_TRUE,
-            EGL_IMAGE_CROP_LEFT_ANDROID,
-            crop.left,
-            EGL_IMAGE_CROP_TOP_ANDROID,
-            crop.top,
-            EGL_IMAGE_CROP_RIGHT_ANDROID,
-            crop.right,
-            EGL_IMAGE_CROP_BOTTOM_ANDROID,
-            crop.bottom,
-            createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
-            createProtectedImage ? EGL_TRUE : EGL_NONE,
-            EGL_NONE,
-    };
-    if (!crop.isValid()) {
-        // No crop rect to set, so leave the crop out of the attrib array. Make
-        // sure to propagate the protected content attrs if they are set.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    } else if (!isEglImageCroppable(crop)) {
-        // The crop rect is not at the origin, so we can't set the crop on the
-        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-        // extension.  In the future we can add a layered extension that
-        // removes this restriction if there is hardware that can support it.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    }
-    eglInitialize(dpy, 0, 0);
-    EGLImageKHR image =
-            eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
-    if (image == EGL_NO_IMAGE_KHR) {
-        EGLint error = eglGetError();
-        ALOGE("error creating EGLImage: %#x", error);
-        eglTerminate(dpy);
-    }
-    return image;
+    return mCreated ? OK : UNKNOWN_ERROR;
 }
 
 }; // namespace android