surfaceflinger: add image abstraction to RenderEngine

Similar to Surface, Image manages the creation and destruction of an
EGLImageKHR.

Test: builds
Change-Id: I2ca98e99013f0a4028f0ea5036f37b20fd67d956
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index 81af21f..e6e4df1 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -99,6 +99,13 @@
     if (hasEGLExtension("EGL_KHR_wait_sync")) {
         mHasWaitSync = true;
     }
+
+    if (hasEGLExtension("EGL_ANDROID_image_crop")) {
+        mHasImageCrop = true;
+    }
+    if (hasEGLExtension("EGL_EXT_protected_content")) {
+        mHasProtectedContent = true;
+    }
 }
 
 char const* GLExtensions::getEGLVersion() const {
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index 1ec0fd9..81078e0 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -39,6 +39,8 @@
     bool mHasNativeFenceSync = false;
     bool mHasFenceSync = false;
     bool mHasWaitSync = false;
+    bool mHasImageCrop = false;
+    bool mHasProtectedContent = false;
 
     String8 mVendor;
     String8 mRenderer;
@@ -63,6 +65,8 @@
     bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
     bool hasFenceSync() const { return mHasFenceSync; }
     bool hasWaitSync() const { return mHasWaitSync; }
+    bool hasImageCrop() const { return mHasImageCrop; }
+    bool hasProtectedContent() const { return mHasProtectedContent; }
 
     void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
                            GLubyte const* extensions);
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp
new file mode 100644
index 0000000..1f8e75a
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Image.h"
+
+#include <vector>
+
+#include <log/log.h>
+
+#include "GLExtensions.h"
+#include "RenderEngine.h"
+
+namespace android {
+namespace RE {
+
+Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+Image::~Image() {
+    setNativeWindowBuffer(nullptr, false, 0, 0);
+}
+
+static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
+                                              int32_t cropHeight) {
+    std::vector<EGLint> attrs;
+    attrs.reserve(16);
+
+    attrs.push_back(EGL_IMAGE_PRESERVED_KHR);
+    attrs.push_back(EGL_TRUE);
+
+    if (isProtected && GLExtensions::getInstance().hasProtectedContent()) {
+        attrs.push_back(EGL_PROTECTED_CONTENT_EXT);
+        attrs.push_back(EGL_TRUE);
+    }
+
+    if (cropWidth > 0 && cropHeight > 0) {
+        attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
+        attrs.push_back(0);
+        attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
+        attrs.push_back(0);
+        attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
+        attrs.push_back(cropWidth);
+        attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
+        attrs.push_back(cropHeight);
+    }
+
+    attrs.push_back(EGL_NONE);
+
+    return attrs;
+}
+
+bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                                  int32_t cropHeight) {
+    if (mEGLImage != EGL_NO_IMAGE_KHR) {
+        if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
+            ALOGE("failed to destroy image: %#x", eglGetError());
+        }
+        mEGLImage = EGL_NO_IMAGE_KHR;
+    }
+
+    if (buffer) {
+        std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                      static_cast<EGLClientBuffer>(buffer), attrs.data());
+        if (mEGLImage == EGL_NO_IMAGE_KHR) {
+            ALOGE("failed to create EGLImage: %#x", eglGetError());
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
new file mode 100644
index 0000000..f55aa59
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+
+class RenderEngine;
+
+namespace RE {
+
+class Image {
+public:
+    Image(const RenderEngine& engine);
+    ~Image();
+
+    Image(const Image&) = delete;
+    Image& operator=(const Image&) = delete;
+
+    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                               int32_t cropHeight);
+
+private:
+    // methods internal to RenderEngine
+    friend class android::RenderEngine;
+    EGLSurface getEGLImage() const { return mEGLImage; }
+
+    EGLDisplay mEGLDisplay;
+    EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+};
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index d5471ad..f1415c9 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -20,6 +20,7 @@
 
 #include "GLES20RenderEngine.h"
 #include "GLExtensions.h"
+#include "Image.h"
 #include "Mesh.h"
 #include "RenderEngine.h"
 
@@ -152,6 +153,10 @@
     return mEGLConfig;
 }
 
+bool RenderEngine::supportsImageCrop() const {
+    return GLExtensions::getInstance().hasImageCrop();
+}
+
 bool RenderEngine::setCurrentSurface(const RE::Surface& surface) {
     bool success = true;
     EGLSurface eglSurface = surface.getEGLSurface();
@@ -324,6 +329,15 @@
     glDeleteTextures(count, names);
 }
 
+void RenderEngine::bindExternalTextureImage(uint32_t texName, const RE::Image& image) {
+    const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+    glBindTexture(target, texName);
+    if (image.getEGLImage() != EGL_NO_IMAGE_KHR) {
+        glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage()));
+    }
+}
+
 void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
     glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 }
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 32c669f..57662a4 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -44,8 +44,9 @@
 class Texture;
 
 namespace RE {
+class Image;
 class Surface;
-}
+} // namespace RE
 
 class RenderEngine {
     enum GlesVersion {
@@ -83,6 +84,8 @@
     // dump the extension strings. always call the base class.
     virtual void dump(String8& result);
 
+    bool supportsImageCrop() const;
+
     // synchronization
 
     // flush submits RenderEngine command stream for execution and returns a
@@ -106,6 +109,7 @@
     void disableScissor();
     void genTextures(size_t count, uint32_t* names);
     void deleteTextures(size_t count, uint32_t const* names);
+    void bindExternalTextureImage(uint32_t texName, const RE::Image& image);
     void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels);
 
     class BindNativeBufferAsFramebuffer {