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 {