summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Stan Iliev <stani@google.com> 2018-08-14 13:30:17 -0400
committer Stan Iliev <stani@google.com> 2018-08-29 10:22:03 -0400
commitc8e22a653297837da9a80b0ba65f6854c8986c96 (patch)
tree7344df1a8aff45ccbf5b9ffb5b4de49499cc7c94
parent660bb2f3a1dde0b5cca5c8293bf0e72d47b2b6fc (diff)
TextureView Vulkan support and optimized OpenGL draw
Render TextureView as hardware bitmaps, instead of GL textures. Cache SkImage for each observed GraphicBuffer, which is faster even for GL. Implement C++ SurfaceTexture, which allows Java SurfaceTexture to be used with Vulkan HWUI render thread and application GL. threads. Delete GLLayer and VkLayer classes and texture code from old HWUI pipeline. Test: Ran skiagl and skiavk pipeline with a TextureView app. Test: TextureView CTS tests pass for GL pipeline. Test: Ran Android NDK Native codec sample app. Change-Id: Idc94f864ce2d34fd6ceff4be4fc7d3327e99879c
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp2
-rw-r--r--core/jni/android/graphics/Matrix.cpp1
-rw-r--r--core/jni/android/graphics/Shader.cpp1
-rw-r--r--core/jni/android/graphics/SurfaceTexture.cpp47
-rw-r--r--core/jni/android_view_TextureLayer.cpp3
-rw-r--r--core/jni/include/android_runtime/android_graphics_SurfaceTexture.h6
-rw-r--r--libs/hwui/Android.bp10
-rw-r--r--libs/hwui/Caches.cpp103
-rw-r--r--libs/hwui/Caches.h135
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp123
-rw-r--r--libs/hwui/DeferredLayerUpdater.h34
-rw-r--r--libs/hwui/GlLayer.cpp68
-rw-r--r--libs/hwui/GlLayer.h75
-rw-r--r--libs/hwui/GpuMemoryTracker.cpp17
-rw-r--r--libs/hwui/Layer.cpp8
-rw-r--r--libs/hwui/Layer.h57
-rw-r--r--libs/hwui/PixelBuffer.cpp156
-rw-r--r--libs/hwui/PixelBuffer.h198
-rw-r--r--libs/hwui/RenderProperties.h1
-rw-r--r--libs/hwui/ResourceCache.cpp23
-rw-r--r--libs/hwui/Texture.cpp413
-rw-r--r--libs/hwui/Texture.h228
-rw-r--r--libs/hwui/VkLayer.cpp40
-rw-r--r--libs/hwui/VkLayer.h70
-rw-r--r--libs/hwui/hwui/Bitmap.cpp2
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp32
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp12
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp9
-rw-r--r--libs/hwui/renderstate/PixelBufferState.cpp42
-rw-r--r--libs/hwui/renderstate/PixelBufferState.h38
-rw-r--r--libs/hwui/renderstate/RenderState.cpp83
-rw-r--r--libs/hwui/renderstate/RenderState.h20
-rw-r--r--libs/hwui/renderstate/TextureState.cpp147
-rw-r--r--libs/hwui/renderstate/TextureState.h98
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp4
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp8
-rw-r--r--libs/hwui/renderthread/EglManager.cpp104
-rw-r--r--libs/hwui/renderthread/EglManager.h10
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp4
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp20
-rw-r--r--libs/hwui/renderthread/VulkanManager.h8
-rw-r--r--libs/hwui/surfacetexture/EGLConsumer.cpp675
-rw-r--r--libs/hwui/surfacetexture/EGLConsumer.h311
-rw-r--r--libs/hwui/surfacetexture/ImageConsumer.cpp152
-rw-r--r--libs/hwui/surfacetexture/ImageConsumer.h97
-rw-r--r--libs/hwui/surfacetexture/SurfaceTexture.cpp496
-rw-r--r--libs/hwui/surfacetexture/SurfaceTexture.h452
-rw-r--r--libs/hwui/tests/common/LeakChecker.cpp4
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp11
-rw-r--r--libs/hwui/tests/common/TestUtils.h1
-rw-r--r--libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp23
-rw-r--r--libs/hwui/tests/unit/main.cpp3
-rw-r--r--libs/hwui/utils/PaintUtils.h1
-rw-r--r--native/android/Android.bp1
-rw-r--r--native/android/surface_texture.cpp5
55 files changed, 2490 insertions, 2202 deletions
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 3fcedd0264ae..6ebf35c8e1dc 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -22,8 +22,6 @@
#include "SkColorFilter.h"
#include "SkColorMatrixFilter.h"
-#include <Caches.h>
-
namespace android {
using namespace uirenderer;
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index f8bb77a9650c..755fcfb27141 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -20,7 +20,6 @@
#include "SkMatrix.h"
#include "core_jni_helpers.h"
-#include <Caches.h>
#include <jni.h>
namespace android {
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index cff772002b14..68f5bef18de1 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -6,7 +6,6 @@
#include "SkBlendMode.h"
#include "core_jni_helpers.h"
-#include <Caches.h>
#include <jni.h>
using namespace android::uirenderer;
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index d098a355085e..3e464c61665f 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -36,6 +36,7 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
+#include "surfacetexture/SurfaceTexture.h"
// ----------------------------------------------------------------------------
@@ -80,10 +81,10 @@ static bool isProtectedContext() {
// ----------------------------------------------------------------------------
static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
- const sp<GLConsumer>& surfaceTexture)
+ const sp<SurfaceTexture>& surfaceTexture)
{
- GLConsumer* const p =
- (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture);
+ SurfaceTexture* const p =
+ (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
if (surfaceTexture.get()) {
surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture);
}
@@ -108,10 +109,10 @@ static void SurfaceTexture_setProducer(JNIEnv* env, jobject thiz,
}
static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
- jobject thiz, sp<GLConsumer::FrameAvailableListener> listener)
+ jobject thiz, sp<SurfaceTexture::FrameAvailableListener> listener)
{
- GLConsumer::FrameAvailableListener* const p =
- (GLConsumer::FrameAvailableListener*)
+ SurfaceTexture::FrameAvailableListener* const p =
+ (SurfaceTexture::FrameAvailableListener*)
env->GetLongField(thiz, fields.frameAvailableListener);
if (listener.get()) {
listener->incStrong((void*)SurfaceTexture_setSurfaceTexture);
@@ -122,8 +123,8 @@ static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
env->SetLongField(thiz, fields.frameAvailableListener, (jlong)listener.get());
}
-sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
- return (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture);
+sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
+ return (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
}
sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
@@ -131,7 +132,7 @@ sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz)
}
sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz) {
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
return surfaceTextureClient;
@@ -144,7 +145,7 @@ bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
// ----------------------------------------------------------------------------
-class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener
+class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
{
public:
JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
@@ -266,12 +267,12 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
consumer->setMaxBufferCount(1);
}
- sp<GLConsumer> surfaceTexture;
+ sp<SurfaceTexture> surfaceTexture;
if (isDetached) {
- surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,
+ surfaceTexture = new SurfaceTexture(consumer, GL_TEXTURE_EXTERNAL_OES,
true, !singleBufferMode);
} else {
- surfaceTexture = new GLConsumer(consumer, texName,
+ surfaceTexture = new SurfaceTexture(consumer, texName,
GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
}
@@ -306,7 +307,7 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->setFrameAvailableListener(0);
SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
SurfaceTexture_setSurfaceTexture(env, thiz, 0);
@@ -315,13 +316,13 @@ static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
static void SurfaceTexture_setDefaultBufferSize(
JNIEnv* env, jobject thiz, jint width, jint height) {
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->setDefaultBufferSize(width, height);
}
static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
status_t err = surfaceTexture->updateTexImage();
if (err == INVALID_OPERATION) {
jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
@@ -333,7 +334,7 @@ static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
status_t err = surfaceTexture->releaseTexImage();
if (err == INVALID_OPERATION) {
jniThrowException(env, IllegalStateException, "Unable to release texture contents (see "
@@ -345,20 +346,20 @@ static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz)
static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
return surfaceTexture->detachFromContext();
}
static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
return surfaceTexture->attachToContext((GLuint)tex);
}
static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
jfloatArray jmtx)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
float* mtx = env->GetFloatArrayElements(jmtx, NULL);
surfaceTexture->getTransformMatrix(mtx);
env->ReleaseFloatArrayElements(jmtx, mtx, 0);
@@ -366,19 +367,19 @@ static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
return surfaceTexture->getTimestamp();
}
static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->abandon();
}
static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz)
{
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
return surfaceTexture->isAbandoned();
}
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index d3a447f1f7dc..1ccb6a8f610c 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -67,8 +67,7 @@ static void TextureLayer_setTransform(JNIEnv* env, jobject clazz,
static void TextureLayer_setSurfaceTexture(JNIEnv* env, jobject clazz,
jlong layerUpdaterPtr, jobject surface) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
- layer->setSurfaceTexture(surfaceTexture);
+ layer->setSurfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
}
static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz,
diff --git a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
index c534d4bb9e0a..0ad25876a008 100644
--- a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
+++ b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -23,14 +23,14 @@
namespace android {
-class GLConsumer;
class IGraphicBufferProducer;
+class SurfaceTexture;
extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz);
extern bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz);
-/* Gets the underlying GLConsumer from a SurfaceTexture Java object. */
-extern sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
+/* Gets the underlying C++ SurfaceTexture object from a SurfaceTexture Java object. */
+extern sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
/* gets the producer end of the SurfaceTexture */
extern sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 83e90b654ff6..62ab7900737e 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -175,9 +175,7 @@ cc_defaults {
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/SkiaVulkanPipeline.cpp",
"pipeline/skia/VectorDrawableAtlas.cpp",
- "renderstate/PixelBufferState.cpp",
"renderstate/RenderState.cpp",
- "renderstate/TextureState.cpp",
"renderthread/CacheManager.cpp",
"renderthread/CanvasContext.cpp",
"renderthread/DrawFrameTask.cpp",
@@ -189,6 +187,9 @@ cc_defaults {
"renderthread/TimeLord.cpp",
"renderthread/Frame.cpp",
"service/GraphicsStatsService.cpp",
+ "surfacetexture/EGLConsumer.cpp",
+ "surfacetexture/ImageConsumer.cpp",
+ "surfacetexture/SurfaceTexture.cpp",
"thread/TaskManager.cpp",
"utils/Blur.cpp",
"utils/Color.cpp",
@@ -200,7 +201,6 @@ cc_defaults {
"AnimationContext.cpp",
"Animator.cpp",
"AnimatorManager.cpp",
- "Caches.cpp",
"CanvasState.cpp",
"CanvasTransform.cpp",
"ClipArea.cpp",
@@ -209,7 +209,6 @@ cc_defaults {
"DeviceInfo.cpp",
"FrameInfo.cpp",
"FrameInfoVisualizer.cpp",
- "GlLayer.cpp",
"GpuMemoryTracker.cpp",
"HardwareBitmapUploader.cpp",
"Interpolator.cpp",
@@ -219,7 +218,6 @@ cc_defaults {
"Matrix.cpp",
"EglReadback.cpp",
"PathParser.cpp",
- "PixelBuffer.cpp",
"ProfileData.cpp",
"ProfileDataContainer.cpp",
"Properties.cpp",
@@ -230,9 +228,7 @@ cc_defaults {
"ResourceCache.cpp",
"SkiaCanvas.cpp",
"Snapshot.cpp",
- "Texture.cpp",
"VectorDrawable.cpp",
- "VkLayer.cpp",
"protos/graphicsstats.proto",
],
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
deleted file mode 100644
index 254144448859..000000000000
--- a/libs/hwui/Caches.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 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 "Caches.h"
-
-#include "GlLayer.h"
-#include "Properties.h"
-#include "renderstate/RenderState.h"
-#include "utils/GLUtils.h"
-
-#include <cutils/properties.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-namespace android {
-namespace uirenderer {
-
-Caches* Caches::sInstance = nullptr;
-
-///////////////////////////////////////////////////////////////////////////////
-// Macros
-///////////////////////////////////////////////////////////////////////////////
-
-#if DEBUG_CACHE_FLUSH
-#define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
-#else
-#define FLUSH_LOGD(...)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Constructors/destructor
-///////////////////////////////////////////////////////////////////////////////
-
-Caches::Caches(RenderState& renderState) : mInitialized(false) {
- INIT_LOGD("Creating OpenGL renderer caches");
- init();
- initStaticProperties();
-}
-
-bool Caches::init() {
- if (mInitialized) return false;
-
- ATRACE_NAME("Caches::init");
-
- mRegionMesh = nullptr;
-
- mInitialized = true;
-
- mPixelBufferState = new PixelBufferState();
- mTextureState = new TextureState();
- mTextureState->constructTexture(*this);
-
- return true;
-}
-
-void Caches::initStaticProperties() {
- // OpenGL ES 3.0+ specific features
- gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects() &&
- property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
-}
-
-void Caches::terminate() {
- if (!mInitialized) return;
- mRegionMesh.reset(nullptr);
-
- clearGarbage();
-
- delete mPixelBufferState;
- mPixelBufferState = nullptr;
- delete mTextureState;
- mTextureState = nullptr;
- mInitialized = false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Memory management
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::clearGarbage() {}
-
-void Caches::flush(FlushMode mode) {
- clearGarbage();
- glFinish();
- // Errors during cleanup should be considered non-fatal, dump them and
- // and move on. TODO: All errors or just errors like bad surface?
- GLUtils::dumpGLErrors();
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
deleted file mode 100644
index 642f9dc50eb1..000000000000
--- a/libs/hwui/Caches.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2010 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 "DeviceInfo.h"
-#include "Extensions.h"
-#include "ResourceCache.h"
-#include "renderstate/PixelBufferState.h"
-#include "renderstate/TextureState.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
-
-#include <memory>
-#include <vector>
-
-#include <GLES3/gl3.h>
-
-#include <utils/KeyedVector.h>
-
-#include <cutils/compiler.h>
-
-#include <SkPath.h>
-
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Caches
-///////////////////////////////////////////////////////////////////////////////
-
-class RenderNode;
-class RenderState;
-
-class ANDROID_API Caches {
-public:
- static Caches& createInstance(RenderState& renderState) {
- LOG_ALWAYS_FATAL_IF(sInstance, "double create of Caches attempted");
- sInstance = new Caches(renderState);
- return *sInstance;
- }
-
- static Caches& getInstance() {
- LOG_ALWAYS_FATAL_IF(!sInstance, "instance not yet created");
- return *sInstance;
- }
-
- static bool hasInstance() { return sInstance != nullptr; }
-
-private:
- explicit Caches(RenderState& renderState);
- static Caches* sInstance;
-
-public:
- enum class FlushMode { Layers = 0, Moderate, Full };
-
- /**
- * Initialize caches.
- */
- bool init();
-
- bool isInitialized() { return mInitialized; }
-
- /**
- * Flush the cache.
- *
- * @param mode Indicates how much of the cache should be flushed
- */
- void flush(FlushMode mode);
-
- /**
- * Destroys all resources associated with this cache. This should
- * be called after a flush(FlushMode::Full).
- */
- void terminate();
-
- /**
- * Call this on each frame to ensure that garbage is deleted from
- * GPU memory.
- */
- void clearGarbage();
-
- /**
- * Returns the GL RGBA internal format to use for the current device
- * If the device supports linear blending and needSRGB is true,
- * this function returns GL_SRGB8_ALPHA8, otherwise it returns GL_RGBA
- */
- constexpr GLint rgbaInternalFormat(bool needSRGB = true) const {
- return extensions().hasLinearBlending() && needSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA;
- }
-
-public:
- TaskManager tasks;
-
- bool gpuPixelBuffersEnabled;
-
- const Extensions& extensions() const { return DeviceInfo::get()->extensions(); }
- PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
- TextureState& textureState() { return *mTextureState; }
-
-private:
- void initStaticProperties();
-
- static void eventMarkNull(GLsizei length, const GLchar* marker) {}
- static void startMarkNull(GLsizei length, const GLchar* marker) {}
- static void endMarkNull() {}
-
- // Used to render layers
- std::unique_ptr<TextureVertex[]> mRegionMesh;
-
- bool mInitialized;
-
- // TODO: move below to RenderState
- PixelBufferState* mPixelBufferState = nullptr;
- TextureState* mTextureState = nullptr;
-
-}; // class Caches
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 569de76f294e..00916559a9c2 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -15,27 +15,20 @@
*/
#include "DeferredLayerUpdater.h"
-#include "GlLayer.h"
-#include "VkLayer.h"
#include "renderstate/RenderState.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/RenderTask.h"
#include "utils/PaintUtils.h"
namespace android {
namespace uirenderer {
-DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
- Layer::Api layerApi)
+DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState)
: mRenderState(renderState)
, mBlend(false)
, mSurfaceTexture(nullptr)
, mTransform(nullptr)
, mGLContextAttached(false)
, mUpdateTexImage(false)
- , mLayer(nullptr)
- , mLayerApi(layerApi)
- , mCreateLayerFn(createLayerFn) {
+ , mLayer(nullptr) {
renderState.registerDeferredLayerUpdater(this);
}
@@ -50,13 +43,9 @@ void DeferredLayerUpdater::destroyLayer() {
return;
}
- if (mSurfaceTexture.get() && mLayerApi == Layer::Api::OpenGL && mGLContextAttached) {
- status_t err = mSurfaceTexture->detachFromContext();
+ if (mSurfaceTexture.get() && mGLContextAttached) {
+ mSurfaceTexture->detachFromView();
mGLContextAttached = false;
- if (err != 0) {
- // TODO: Elevate to fatal exception
- ALOGE("Failed to detach SurfaceTexture from context %d", err);
- }
}
mLayer->postDecStrong();
@@ -75,99 +64,53 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
void DeferredLayerUpdater::apply() {
if (!mLayer) {
- mLayer = mCreateLayerFn(mRenderState, mWidth, mHeight, mColorFilter, mAlpha, mMode, mBlend);
+ mLayer = new Layer(mRenderState, mColorFilter, mAlpha, mMode);
}
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
if (mSurfaceTexture.get()) {
- if (mLayer->getApi() == Layer::Api::Vulkan) {
- if (mUpdateTexImage) {
- mUpdateTexImage = false;
- doUpdateVkTexImage();
- }
- } else {
- LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
- "apply surfaceTexture with non GL backend %x, GL %x, VK %x",
- mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
- if (!mGLContextAttached) {
- mGLContextAttached = true;
- mUpdateTexImage = true;
- mSurfaceTexture->attachToContext(static_cast<GlLayer*>(mLayer)->getTextureId());
- }
- if (mUpdateTexImage) {
- mUpdateTexImage = false;
- doUpdateTexImage();
+ if (!mGLContextAttached) {
+ mGLContextAttached = true;
+ mUpdateTexImage = true;
+ mSurfaceTexture->attachToView();
+ }
+ if (mUpdateTexImage) {
+ mUpdateTexImage = false;
+ sk_sp<SkImage> layerImage;
+ SkMatrix textureTransform;
+ android_dataspace dataSpace;
+ bool queueEmpty = true;
+ // If the SurfaceTexture queue is in synchronous mode, need to discard all
+ // but latest frame. Since we can't tell which mode it is in,
+ // do this unconditionally.
+ do {
+ layerImage = mSurfaceTexture->dequeueImage(textureTransform, dataSpace, &queueEmpty,
+ mRenderState);
+ } while (layerImage.get() && (!queueEmpty));
+ if (layerImage.get()) {
+ // force filtration if buffer size != layer size
+ bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height();
+ updateLayer(forceFilter, textureTransform, dataSpace, layerImage);
}
- GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
- static_cast<GlLayer*>(mLayer)->setRenderTarget(renderTarget);
}
+
if (mTransform) {
- mLayer->getTransform().load(*mTransform);
+ mLayer->getTransform() = *mTransform;
setTransform(nullptr);
}
}
}
-void DeferredLayerUpdater::doUpdateTexImage() {
- LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
- "doUpdateTexImage non GL backend %x, GL %x, VK %x", mLayer->getApi(),
- Layer::Api::OpenGL, Layer::Api::Vulkan);
- if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
- float transform[16];
-
- int64_t frameNumber = mSurfaceTexture->getFrameNumber();
- // If the GLConsumer queue is in synchronous mode, need to discard all
- // but latest frame, using the frame number to tell when we no longer
- // have newer frames to target. Since we can't tell which mode it is in,
- // do this unconditionally.
- int dropCounter = 0;
- while (mSurfaceTexture->updateTexImage() == NO_ERROR) {
- int64_t newFrameNumber = mSurfaceTexture->getFrameNumber();
- if (newFrameNumber == frameNumber) break;
- frameNumber = newFrameNumber;
- dropCounter++;
- }
-
- bool forceFilter = false;
- sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
- if (buffer != nullptr) {
- // force filtration if buffer size != layer size
- forceFilter = mWidth != static_cast<int>(buffer->getWidth()) ||
- mHeight != static_cast<int>(buffer->getHeight());
- }
-
-#if DEBUG_RENDERER
- if (dropCounter > 0) {
- RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
- }
-#endif
- mSurfaceTexture->getTransformMatrix(transform);
-
- updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
- }
-}
-
-void DeferredLayerUpdater::doUpdateVkTexImage() {
- LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
- "updateLayer non Vulkan backend %x, GL %x, VK %x", mLayer->getApi(),
- Layer::Api::OpenGL, Layer::Api::Vulkan);
-
- static const mat4 identityMatrix;
- updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
-
- VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
- vkLayer->updateTexture();
-}
-
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
- android_dataspace dataspace) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform,
+ android_dataspace dataspace, const sk_sp<SkImage>& layerImage) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
- mLayer->getTexTransform().load(textureTransform);
+ mLayer->getTexTransform() = textureTransform;
mLayer->setDataSpace(dataspace);
+ mLayer->setImage(layerImage);
}
void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index fe3ee7a2b4c6..4c323b861002 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -17,18 +17,19 @@
#pragma once
#include <SkColorFilter.h>
+#include <SkImage.h>
#include <SkMatrix.h>
#include <cutils/compiler.h>
-#include <gui/GLConsumer.h>
+#include <map>
#include <system/graphics.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include "surfacetexture/SurfaceTexture.h"
#include "Layer.h"
#include "Rect.h"
-#include "renderthread/RenderThread.h"
namespace android {
namespace uirenderer {
@@ -41,12 +42,7 @@ class DeferredLayerUpdater : public VirtualLightRefBase {
public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
- typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
- uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha,
- SkBlendMode mode, bool blend)>
- CreateLayerFn;
- ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
- Layer::Api layerApi);
+ ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState);
ANDROID_API ~DeferredLayerUpdater();
@@ -70,13 +66,13 @@ public:
return false;
}
- ANDROID_API void setSurfaceTexture(const sp<GLConsumer>& texture) {
- if (texture.get() != mSurfaceTexture.get()) {
- mSurfaceTexture = texture;
+ ANDROID_API void setSurfaceTexture(const sp<SurfaceTexture>& consumer) {
+ if (consumer.get() != mSurfaceTexture.get()) {
+ mSurfaceTexture = consumer;
- GLenum target = texture->getCurrentTextureTarget();
+ GLenum target = consumer->getCurrentTextureTarget();
LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
- "set unsupported GLConsumer with target %x", target);
+ "set unsupported SurfaceTexture with target %x", target);
}
}
@@ -97,12 +93,11 @@ public:
void detachSurfaceTexture();
- void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace);
+ void updateLayer(bool forceFilter, const SkMatrix& textureTransform,
+ android_dataspace dataspace, const sk_sp<SkImage>& layerImage);
void destroyLayer();
- Layer::Api getBackingLayerApi() { return mLayerApi; }
-
private:
RenderState& mRenderState;
@@ -113,17 +108,12 @@ private:
sk_sp<SkColorFilter> mColorFilter;
int mAlpha = 255;
SkBlendMode mMode = SkBlendMode::kSrcOver;
- sp<GLConsumer> mSurfaceTexture;
+ sp<SurfaceTexture> mSurfaceTexture;
SkMatrix* mTransform;
bool mGLContextAttached;
bool mUpdateTexImage;
Layer* mLayer;
- Layer::Api mLayerApi;
- CreateLayerFn mCreateLayerFn;
-
- void doUpdateTexImage();
- void doUpdateVkTexImage();
};
} /* namespace uirenderer */
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
deleted file mode 100644
index 432bb8526465..000000000000
--- a/libs/hwui/GlLayer.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 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 "GlLayer.h"
-
-#include "Caches.h"
-#include "RenderNode.h"
-#include "renderstate/RenderState.h"
-
-namespace android {
-namespace uirenderer {
-
-GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
- : Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
- , caches(Caches::getInstance())
- , texture(caches) {
- texture.mWidth = layerWidth;
- texture.mHeight = layerHeight;
- texture.blend = blend;
-}
-
-GlLayer::~GlLayer() {
- // There's a rare possibility that Caches could have been destroyed already
- // since this method is queued up as a task.
- // Since this is a reset method, treat this as non-fatal.
- if (caches.isInitialized() && texture.mId) {
- texture.deleteTexture();
- }
-}
-
-void GlLayer::onGlContextLost() {
- texture.deleteTexture();
-}
-
-void GlLayer::setRenderTarget(GLenum renderTarget) {
- if (renderTarget != getRenderTarget()) {
- // new render target: bind with new target, and update filter/wrap
- texture.mTarget = renderTarget;
- if (texture.mId) {
- caches.textureState().bindTexture(texture.target(), texture.mId);
- }
- texture.setFilter(GL_NEAREST, false, true);
- texture.setWrap(GL_CLAMP_TO_EDGE, false, true);
- }
-}
-
-void GlLayer::generateTexture() {
- if (!texture.mId) {
- glGenTextures(1, &texture.mId);
- }
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
deleted file mode 100644
index 9f70fdae6790..000000000000
--- a/libs/hwui/GlLayer.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 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 "Layer.h"
-
-#include "Texture.h"
-
-namespace android {
-namespace uirenderer {
-
-// Forward declarations
-class Caches;
-
-/**
- * A layer has dimensions and is backed by an OpenGL texture or FBO.
- */
-class GlLayer : public Layer {
-public:
- GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend);
- virtual ~GlLayer();
-
- uint32_t getWidth() const override { return texture.mWidth; }
-
- uint32_t getHeight() const override { return texture.mHeight; }
-
- void setSize(uint32_t width, uint32_t height) override {
- texture.updateLayout(width, height, texture.internalFormat(), texture.format(),
- texture.target());
- }
-
- void setBlend(bool blend) override { texture.blend = blend; }
-
- bool isBlend() const override { return texture.blend; }
-
- inline GLuint getTextureId() const { return texture.id(); }
-
- inline GLenum getRenderTarget() const { return texture.target(); }
-
- void setRenderTarget(GLenum renderTarget);
-
- void generateTexture();
-
- /**
- * Lost the GL context but the layer is still around, mark it invalid internally
- * so the dtor knows not to do any GL work
- */
- void onGlContextLost();
-
-private:
- Caches& caches;
-
- /**
- * The texture backing this layer.
- */
- Texture texture;
-}; // struct GlLayer
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp
index 612bfde1a3fa..a9a7af8f22f3 100644
--- a/libs/hwui/GpuMemoryTracker.cpp
+++ b/libs/hwui/GpuMemoryTracker.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "Texture.h"
#include "utils/StringUtils.h"
#include <GpuMemoryTracker.h>
@@ -117,22 +116,6 @@ void GpuMemoryTracker::onFrameCompleted() {
ATRACE_INT(buf, stats.count);
}
}
-
- std::vector<const Texture*> freeList;
- for (const auto& obj : gObjectSet) {
- if (obj->objectType() == GpuObjectType::Texture) {
- const Texture* texture = static_cast<Texture*>(obj);
- if (texture->cleanup) {
- ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(),
- texture->width(), texture->height());
- freeList.push_back(texture);
- }
- }
- }
- for (auto& texture : freeList) {
- const_cast<Texture*>(texture)->deleteTexture();
- delete texture;
- }
}
} // namespace uirenderer
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index fb8f0337c95e..f59a2e6ee5c1 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -17,17 +17,17 @@
#include "Layer.h"
#include "renderstate/RenderState.h"
+#include "utils/Color.h"
#include <SkToSRGBColorFilter.h>
namespace android {
namespace uirenderer {
-Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha,
- SkBlendMode mode)
+Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alpha,
+ SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
- , mApi(api)
, mColorFilter(colorFilter)
, alpha(alpha)
, mode(mode) {
@@ -36,6 +36,8 @@ Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter
incStrong(nullptr);
buildColorSpaceWithFilter();
renderState.registerLayer(this);
+ texTransform.setIdentity();
+ transform.setIdentity();
}
Layer::~Layer() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 31878ac23642..c4e4c1c96ba6 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -23,8 +23,9 @@
#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkPaint.h>
-
-#include "Matrix.h"
+#include <SkImage.h>
+#include <SkMatrix.h>
+#include <system/graphics.h>
namespace android {
namespace uirenderer {
@@ -40,24 +41,19 @@ class RenderState;
*/
class Layer : public VirtualLightRefBase, GpuMemoryTracker {
public:
- enum class Api {
- OpenGL = 0,
- Vulkan = 1,
- };
-
- Api getApi() const { return mApi; }
+ Layer(RenderState& renderState, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode);
~Layer();
- virtual uint32_t getWidth() const = 0;
+ virtual uint32_t getWidth() const { return mWidth; }
- virtual uint32_t getHeight() const = 0;
+ virtual uint32_t getHeight() const { return mHeight; }
- virtual void setSize(uint32_t width, uint32_t height) = 0;
+ virtual void setSize(uint32_t width, uint32_t height) { mWidth = width; mHeight = height; }
- virtual void setBlend(bool blend) = 0;
+ virtual void setBlend(bool blend) { mBlend = blend; }
- virtual bool isBlend() const = 0;
+ virtual bool isBlend() const { return mBlend; }
inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; }
@@ -84,9 +80,9 @@ public:
inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; }
- inline mat4& getTexTransform() { return texTransform; }
+ inline SkMatrix& getTexTransform() { return texTransform; }
- inline mat4& getTransform() { return transform; }
+ inline SkMatrix& getTransform() { return transform; }
/**
* Posts a decStrong call to the appropriate thread.
@@ -94,16 +90,17 @@ public:
*/
void postDecStrong();
+ inline void setImage(const sk_sp<SkImage>& image) { this->layerImage = image; }
+
+ inline sk_sp<SkImage> getImage() const { return this->layerImage; }
+
protected:
- Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode);
RenderState& mRenderState;
private:
void buildColorSpaceWithFilter();
- Api mApi;
-
/**
* Color filter used to draw this layer. Optional.
*/
@@ -137,12 +134,32 @@ private:
/**
* Optional texture coordinates transform.
*/
- mat4 texTransform;
+ SkMatrix texTransform;
/**
* Optional transform.
*/
- mat4 transform;
+ SkMatrix transform;
+
+ /**
+ * An image backing the layer.
+ */
+ sk_sp<SkImage> layerImage;
+
+ /**
+ * layer width.
+ */
+ uint32_t mWidth = 0;
+
+ /**
+ * layer height.
+ */
+ uint32_t mHeight = 0;
+
+ /**
+ * enable blending
+ */
+ bool mBlend = false;
}; // struct Layer
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
deleted file mode 100644
index 910a9889db1f..000000000000
--- a/libs/hwui/PixelBuffer.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2013 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 "PixelBuffer.h"
-
-#include "Debug.h"
-#include "Extensions.h"
-#include "Properties.h"
-#include "renderstate/RenderState.h"
-#include "utils/GLUtils.h"
-
-#include <utils/Log.h>
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// CPU pixel buffer
-///////////////////////////////////////////////////////////////////////////////
-
-class CpuPixelBuffer : public PixelBuffer {
-public:
- CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
-
- uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
-
- void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
-
-protected:
- void unmap() override;
-
-private:
- std::unique_ptr<uint8_t[]> mBuffer;
-};
-
-CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
- : PixelBuffer(format, width, height)
- , mBuffer(new uint8_t[width * height * formatSize(format)]) {}
-
-uint8_t* CpuPixelBuffer::map(AccessMode mode) {
- if (mAccessMode == kAccessMode_None) {
- mAccessMode = mode;
- }
- return mBuffer.get();
-}
-
-void CpuPixelBuffer::unmap() {
- mAccessMode = kAccessMode_None;
-}
-
-void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
- &mBuffer[offset]);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// GPU pixel buffer
-///////////////////////////////////////////////////////////////////////////////
-
-class GpuPixelBuffer : public PixelBuffer {
-public:
- GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
- ~GpuPixelBuffer();
-
- uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
-
- void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
-
-protected:
- void unmap() override;
-
-private:
- GLuint mBuffer;
- uint8_t* mMappedPointer;
- Caches& mCaches;
-};
-
-GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
- : PixelBuffer(format, width, height)
- , mMappedPointer(nullptr)
- , mCaches(Caches::getInstance()) {
- glGenBuffers(1, &mBuffer);
-
- mCaches.pixelBufferState().bind(mBuffer);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW);
- mCaches.pixelBufferState().unbind();
-}
-
-GpuPixelBuffer::~GpuPixelBuffer() {
- glDeleteBuffers(1, &mBuffer);
-}
-
-uint8_t* GpuPixelBuffer::map(AccessMode mode) {
- if (mAccessMode == kAccessMode_None) {
- mCaches.pixelBufferState().bind(mBuffer);
- mMappedPointer = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
- if (CC_UNLIKELY(!mMappedPointer)) {
- GLUtils::dumpGLErrors();
- LOG_ALWAYS_FATAL("Failed to map PBO");
- }
- mAccessMode = mode;
- mCaches.pixelBufferState().unbind();
- }
-
- return mMappedPointer;
-}
-
-void GpuPixelBuffer::unmap() {
- if (mAccessMode != kAccessMode_None) {
- if (mMappedPointer) {
- mCaches.pixelBufferState().bind(mBuffer);
- GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
- if (status == GL_FALSE) {
- ALOGE("Corrupted GPU pixel buffer");
- }
- }
- mAccessMode = kAccessMode_None;
- mMappedPointer = nullptr;
- }
-}
-
-void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
- // If the buffer is not mapped, unmap() will not bind it
- mCaches.pixelBufferState().bind(mBuffer);
- unmap();
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
- reinterpret_cast<void*>(offset));
- mCaches.pixelBufferState().unbind();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Factory
-///////////////////////////////////////////////////////////////////////////////
-
-PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
- if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
- return new GpuPixelBuffer(format, width, height);
- }
- return new CpuPixelBuffer(format, width, height);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
deleted file mode 100644
index e7e341b90ad3..000000000000
--- a/libs/hwui/PixelBuffer.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_PIXEL_BUFFER_H
-#define ANDROID_HWUI_PIXEL_BUFFER_H
-
-#include <GLES3/gl3.h>
-
-#include <log/log.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Represents a pixel buffer. A pixel buffer will be backed either by a
- * PBO on OpenGL ES 3.0 and higher or by an array of uint8_t on other
- * versions. If the buffer is backed by a PBO it will of type
- * GL_PIXEL_UNPACK_BUFFER.
- *
- * To read from or write into a PixelBuffer you must first map the
- * buffer using the map(AccessMode) method. This method returns a
- * pointer to the beginning of the buffer.
- *
- * Before the buffer can be used by the GPU, for instance to upload
- * a texture, you must first unmap the buffer. To do so, call the
- * unmap() method.
- *
- * Mapping and unmapping a PixelBuffer can have the side effect of
- * changing the currently active GL_PIXEL_UNPACK_BUFFER. It is
- * therefore recommended to call Caches::unbindPixelbuffer() after
- * using a PixelBuffer to upload to a texture.
- */
-class PixelBuffer {
-public:
- enum BufferType { kBufferType_Auto, kBufferType_CPU };
-
- enum AccessMode {
- kAccessMode_None = 0,
- kAccessMode_Read = GL_MAP_READ_BIT,
- kAccessMode_Write = GL_MAP_WRITE_BIT,
- kAccessMode_ReadWrite = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
- };
-
- /**
- * Creates a new PixelBuffer object with the specified format and
- * dimensions. The buffer is immediately allocated.
- *
- * The buffer type specifies how the buffer should be allocated.
- * By default this method will automatically choose whether to allocate
- * a CPU or GPU buffer.
- */
- static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
- BufferType type = kBufferType_Auto);
-
- virtual ~PixelBuffer() {}
-
- /**
- * Returns the format of this render buffer.
- */
- GLenum getFormat() const { return mFormat; }
-
- /**
- * Maps this before with the specified access mode. This method
- * returns a pointer to the region of memory where the buffer was
- * mapped.
- *
- * If the buffer is already mapped when this method is invoked,
- * this method will return the previously mapped pointer. The
- * access mode can only be changed by calling unmap() first.
- *
- * The specified access mode cannot be kAccessMode_None.
- */
- virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0;
-
- /**
- * Returns the current access mode for this buffer. If the buffer
- * is not mapped, this method returns kAccessMode_None.
- */
- AccessMode getAccessMode() const { return mAccessMode; }
-
- /**
- * Upload the specified rectangle of this pixel buffer as a
- * GL_TEXTURE_2D texture. Calling this method will trigger
- * an unmap() if necessary.
- */
- virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0;
-
- /**
- * Upload the specified rectangle of this pixel buffer as a
- * GL_TEXTURE_2D texture. Calling this method will trigger
- * an unmap() if necessary.
- *
- * This is a convenience function provided to save callers the
- * trouble of computing the offset parameter.
- */
- void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
- upload(x, y, width, height, getOffset(x, y));
- }
-
- /**
- * Returns the width of the render buffer in pixels.
- */
- uint32_t getWidth() const { return mWidth; }
-
- /**
- * Returns the height of the render buffer in pixels.
- */
- uint32_t getHeight() const { return mHeight; }
-
- /**
- * Returns the size of this pixel buffer in bytes.
- */
- uint32_t getSize() const { return mWidth * mHeight * formatSize(mFormat); }
-
- /**
- * Returns the offset of a pixel in this pixel buffer, in bytes.
- */
- uint32_t getOffset(uint32_t x, uint32_t y) const {
- return (y * mWidth + x) * formatSize(mFormat);
- }
-
- /**
- * Returns the number of bytes per pixel in the specified format.
- *
- * Supported formats:
- * GL_ALPHA
- * GL_RGBA
- */
- static uint32_t formatSize(GLenum format) {
- switch (format) {
- case GL_ALPHA:
- return 1;
- case GL_RGBA:
- return 4;
- }
- return 0;
- }
-
- /**
- * Returns the alpha channel offset in the specified format.
- *
- * Supported formats:
- * GL_ALPHA
- * GL_RGBA
- */
- static uint32_t formatAlphaOffset(GLenum format) {
- switch (format) {
- case GL_ALPHA:
- return 0;
- case GL_RGBA:
- return 3;
- }
-
- ALOGE("unsupported format: %d", format);
- return 0;
- }
-
-protected:
- /**
- * Creates a new render buffer in the specified format and dimensions.
- * The format must be GL_ALPHA or GL_RGBA.
- */
- PixelBuffer(GLenum format, uint32_t width, uint32_t height)
- : mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {}
-
- /**
- * Unmaps this buffer, if needed. After the buffer is unmapped,
- * the pointer previously returned by map() becomes invalid and
- * should not be used.
- */
- virtual void unmap() = 0;
-
- GLenum mFormat;
-
- uint32_t mWidth;
- uint32_t mHeight;
-
- AccessMode mAccessMode;
-
-}; // class PixelBuffer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_PIXEL_BUFFER_H
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 0766e3b7ed28..7966845ff814 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -16,7 +16,6 @@
#pragma once
-#include "Caches.h"
#include "DeviceInfo.h"
#include "Outline.h"
#include "Rect.h"
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 464a58d0c0f8..65bee476f14d 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -15,7 +15,6 @@
*/
#include "ResourceCache.h"
-#include "Caches.h"
namespace android {
@@ -112,13 +111,9 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) {
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
if (ref == nullptr) {
// If we're not tracking this resource, just delete it
- if (Caches::hasInstance()) {
- // DEAD CODE
- } else {
- // A Res_png_9patch is actually an array of byte that's larger
- // than sizeof(Res_png_9patch). It must be freed as an array.
- delete[](int8_t*) resource;
- }
+ // A Res_png_9patch is actually an array of byte that's larger
+ // than sizeof(Res_png_9patch). It must be freed as an array.
+ delete[](int8_t*) resource;
return;
}
ref->destroyed = true;
@@ -135,14 +130,10 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource
if (ref->destroyed) {
switch (ref->resourceType) {
case kNinePatch: {
- if (Caches::hasInstance()) {
- // DEAD CODE
- } else {
- // A Res_png_9patch is actually an array of byte that's larger
- // than sizeof(Res_png_9patch). It must be freed as an array.
- int8_t* patch = (int8_t*)resource;
- delete[] patch;
- }
+ // A Res_png_9patch is actually an array of byte that's larger
+ // than sizeof(Res_png_9patch). It must be freed as an array.
+ int8_t* patch = (int8_t*)resource;
+ delete[] patch;
} break;
}
}
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
deleted file mode 100644
index 1e90eebe3bb8..000000000000
--- a/libs/hwui/Texture.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2013 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 "Texture.h"
-#include "Caches.h"
-#include "utils/GLUtils.h"
-#include "utils/MathUtils.h"
-#include "utils/TraceUtils.h"
-
-#include <utils/Log.h>
-
-#include <math/mat4.h>
-
-#include <SkCanvas.h>
-
-namespace android {
-namespace uirenderer {
-
-// Number of bytes used by a texture in the given format
-static int bytesPerPixel(GLint glFormat) {
- switch (glFormat) {
- // The wrapped-texture case, usually means a SurfaceTexture
- case 0:
- return 0;
- case GL_LUMINANCE:
- case GL_ALPHA:
- return 1;
- case GL_SRGB8:
- case GL_RGB:
- return 3;
- case GL_SRGB8_ALPHA8:
- case GL_RGBA:
- return 4;
- case GL_RGBA16F:
- return 8;
- default:
- LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
- }
-}
-
-void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force) {
- if (force || wrapS != mWrapS || wrapT != mWrapT) {
- mWrapS = wrapS;
- mWrapT = wrapT;
-
- if (bindTexture) {
- mCaches.textureState().bindTexture(mTarget, mId);
- }
-
- glTexParameteri(mTarget, GL_TEXTURE_WRAP_S, wrapS);
- glTexParameteri(mTarget, GL_TEXTURE_WRAP_T, wrapT);
- }
-}
-
-void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool force) {
- if (force || min != mMinFilter || mag != mMagFilter) {
- mMinFilter = min;
- mMagFilter = mag;
-
- if (bindTexture) {
- mCaches.textureState().bindTexture(mTarget, mId);
- }
-
- if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
-
- glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, min);
- glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, mag);
- }
-}
-
-void Texture::deleteTexture() {
- mCaches.textureState().deleteTexture(mId);
- mId = 0;
- mTarget = GL_NONE;
- if (mEglImageHandle != EGL_NO_IMAGE_KHR) {
- EGLDisplay eglDisplayHandle = eglGetCurrentDisplay();
- eglDestroyImageKHR(eglDisplayHandle, mEglImageHandle);
- mEglImageHandle = EGL_NO_IMAGE_KHR;
- }
-}
-
-bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format,
- GLenum target) {
- if (mWidth == width && mHeight == height && mFormat == format &&
- mInternalFormat == internalFormat && mTarget == target) {
- return false;
- }
- mWidth = width;
- mHeight = height;
- mFormat = format;
- mInternalFormat = internalFormat;
- mTarget = target;
- notifySizeChanged(mWidth * mHeight * bytesPerPixel(internalFormat));
- return true;
-}
-
-void Texture::resetCachedParams() {
- mWrapS = GL_REPEAT;
- mWrapT = GL_REPEAT;
- mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
- mMagFilter = GL_LINEAR;
-}
-
-void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format,
- GLenum type, const void* pixels) {
- GL_CHECKPOINT(MODERATE);
-
- // We don't have color space information, we assume the data is gamma encoded
- mIsLinear = false;
-
- bool needsAlloc = updateLayout(width, height, internalFormat, format, GL_TEXTURE_2D);
- if (!mId) {
- glGenTextures(1, &mId);
- needsAlloc = true;
- resetCachedParams();
- }
- mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId);
- if (needsAlloc) {
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels);
- } else if (pixels) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels);
- }
- GL_CHECKPOINT(MODERATE);
-}
-
-void Texture::uploadHardwareBitmapToTexture(GraphicBuffer* buffer) {
- EGLDisplay eglDisplayHandle = eglGetCurrentDisplay();
- if (mEglImageHandle != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(eglDisplayHandle, mEglImageHandle);
- mEglImageHandle = EGL_NO_IMAGE_KHR;
- }
- mEglImageHandle = eglCreateImageKHR(eglDisplayHandle, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- buffer->getNativeBuffer(), 0);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, mEglImageHandle);
-}
-
-static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GLenum type,
- GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height,
- const GLvoid* data) {
- const bool useStride =
- stride != width && Caches::getInstance().extensions().hasUnpackRowLength();
- if ((stride == width) || useStride) {
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
- }
-
- if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data);
- } else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
- }
-
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- }
- } else {
- // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
- // if the stride doesn't match the width
-
- GLvoid* temp = (GLvoid*)malloc(width * height * bpp);
- if (!temp) return;
-
- uint8_t* pDst = (uint8_t*)temp;
- uint8_t* pSrc = (uint8_t*)data;
- for (GLsizei i = 0; i < height; i++) {
- memcpy(pDst, pSrc, width * bpp);
- pDst += width * bpp;
- pSrc += stride * bpp;
- }
-
- if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, temp);
- } else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
- }
-
- free(temp);
- }
-}
-
-void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType, bool needSRGB,
- GLint* outInternalFormat, GLint* outFormat,
- GLint* outType) {
- switch (colorType) {
- case kAlpha_8_SkColorType:
- *outFormat = GL_ALPHA;
- *outInternalFormat = GL_ALPHA;
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kRGB_565_SkColorType:
- if (needSRGB) {
- // We would ideally use a GL_RGB/GL_SRGB8 texture but the
- // intermediate Skia bitmap needs to be ARGB_8888
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat();
- *outType = GL_UNSIGNED_BYTE;
- } else {
- *outFormat = GL_RGB;
- *outInternalFormat = GL_RGB;
- *outType = GL_UNSIGNED_SHORT_5_6_5;
- }
- break;
- // ARGB_4444 is upconverted to RGBA_8888
- case kARGB_4444_SkColorType:
- case kN32_SkColorType:
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat(needSRGB);
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kGray_8_SkColorType:
- *outFormat = GL_LUMINANCE;
- *outInternalFormat = GL_LUMINANCE;
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kRGBA_F16_SkColorType:
- if (caches.extensions().getMajorGlVersion() >= 3) {
- // This format is always linear
- *outFormat = GL_RGBA;
- *outInternalFormat = GL_RGBA16F;
- *outType = GL_HALF_FLOAT;
- } else {
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat(true);
- *outType = GL_UNSIGNED_BYTE;
- }
- break;
- default:
- LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
- break;
- }
-}
-
-SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
- sk_sp<SkColorSpace> sRGB) {
- SkBitmap rgbaBitmap;
- rgbaBitmap.allocPixels(SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
- bitmap.info().alphaType(),
- hasLinearBlending ? sRGB : nullptr));
- rgbaBitmap.eraseColor(0);
-
- if (bitmap.colorType() == kRGBA_F16_SkColorType) {
- // Drawing RGBA_F16 onto ARGB_8888 is not supported
- bitmap.readPixels(rgbaBitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
- rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0);
- } else {
- SkCanvas canvas(rgbaBitmap);
- canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
- }
-
- return rgbaBitmap;
-}
-
-bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending) {
- return info.colorType() == kARGB_4444_SkColorType ||
- (info.colorType() == kRGB_565_SkColorType && hasLinearBlending &&
- info.colorSpace()->isSRGB()) ||
- (info.colorType() == kRGBA_F16_SkColorType &&
- Caches::getInstance().extensions().getMajorGlVersion() < 3);
-}
-
-void Texture::upload(Bitmap& bitmap) {
- ATRACE_FORMAT("Upload %ux%u Texture", bitmap.width(), bitmap.height());
-
- // We could also enable mipmapping if both bitmap dimensions are powers
- // of 2 but we'd have to deal with size changes. Let's keep this simple
- const bool canMipMap = mCaches.extensions().hasNPot();
-
- // If the texture had mipmap enabled but not anymore,
- // force a glTexImage2D to discard the mipmap levels
- bool needsAlloc = canMipMap && mipMap && !bitmap.hasHardwareMipMap();
- bool setDefaultParams = false;
-
- if (!mId) {
- glGenTextures(1, &mId);
- needsAlloc = true;
- setDefaultParams = true;
- }
-
- bool hasLinearBlending = mCaches.extensions().hasLinearBlending();
- bool needSRGB = transferFunctionCloseToSRGB(bitmap.info().colorSpace());
-
- GLint internalFormat, format, type;
- colorTypeToGlFormatAndType(mCaches, bitmap.colorType(), needSRGB && hasLinearBlending,
- &internalFormat, &format, &type);
-
- // Some devices don't support GL_RGBA16F, so we need to compare the color type
- // and internal GL format to decide what to do with 16 bit bitmaps
- bool rgba16fNeedsConversion =
- bitmap.colorType() == kRGBA_F16_SkColorType && internalFormat != GL_RGBA16F;
-
- // RGBA16F is always linear extended sRGB
- if (internalFormat == GL_RGBA16F) {
- mIsLinear = true;
- }
-
- mConnector.reset();
-
- // Alpha masks don't have color profiles
- // If an RGBA16F bitmap needs conversion, we know the target will be sRGB
- if (!mIsLinear && internalFormat != GL_ALPHA && !rgba16fNeedsConversion) {
- SkColorSpace* colorSpace = bitmap.info().colorSpace();
- // If the bitmap is sRGB we don't need conversion
- if (colorSpace != nullptr && !colorSpace->isSRGB()) {
- SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
- if (!colorSpace->toXYZD50(&xyzMatrix)) {
- ALOGW("Incompatible color space!");
- } else {
- SkColorSpaceTransferFn fn;
- if (!colorSpace->isNumericalTransferFn(&fn)) {
- ALOGW("Incompatible color space, no numerical transfer function!");
- } else {
- float data[16];
- xyzMatrix.asColMajorf(data);
-
- ColorSpace::TransferParameters p = {fn.fG, fn.fA, fn.fB, fn.fC,
- fn.fD, fn.fE, fn.fF};
- ColorSpace src("Unnamed", mat4f((const float*)&data[0]).upperLeft(), p);
- mConnector.reset(new ColorSpaceConnector(src, ColorSpace::sRGB()));
-
- // A non-sRGB color space might have a transfer function close enough to sRGB
- // that we can save shader instructions by using an sRGB sampler
- // This is only possible if we have hardware support for sRGB textures
- if (needSRGB && internalFormat == GL_RGBA && mCaches.extensions().hasSRGB() &&
- !bitmap.isHardware()) {
- internalFormat = GL_SRGB8_ALPHA8;
- }
- }
- }
- }
- }
-
- GLenum target = bitmap.isHardware() ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
- needsAlloc |= updateLayout(bitmap.width(), bitmap.height(), internalFormat, format, target);
-
- blend = !bitmap.isOpaque();
- mCaches.textureState().bindTexture(mTarget, mId);
-
- // TODO: Handle sRGB gray bitmaps
- if (CC_UNLIKELY(hasUnsupportedColorType(bitmap.info(), hasLinearBlending))) {
- SkBitmap skBitmap;
- bitmap.getSkBitmap(&skBitmap);
- sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
- SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
- uploadToTexture(needsAlloc, internalFormat, format, type, rgbaBitmap.rowBytesAsPixels(),
- rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(), rgbaBitmap.height(),
- rgbaBitmap.getPixels());
- } else if (bitmap.isHardware()) {
- uploadHardwareBitmapToTexture(bitmap.graphicBuffer());
- } else {
- uploadToTexture(needsAlloc, internalFormat, format, type, bitmap.rowBytesAsPixels(),
- bitmap.info().bytesPerPixel(), bitmap.width(), bitmap.height(),
- bitmap.pixels());
- }
-
- if (canMipMap) {
- mipMap = bitmap.hasHardwareMipMap();
- if (mipMap) {
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- }
-
- if (setDefaultParams) {
- setFilter(GL_NEAREST);
- setWrap(GL_CLAMP_TO_EDGE);
- }
-}
-
-void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format,
- GLenum target) {
- mId = id;
- mWidth = width;
- mHeight = height;
- mFormat = format;
- mInternalFormat = internalFormat;
- mTarget = target;
- mConnector.reset();
- // We're wrapping an existing texture, so don't double count this memory
- notifySizeChanged(0);
-}
-
-TransferFunctionType Texture::getTransferFunctionType() const {
- if (mConnector.get() != nullptr && mInternalFormat != GL_SRGB8_ALPHA8) {
- const ColorSpace::TransferParameters& p = mConnector->getSource().getTransferParameters();
- if (MathUtils::isZero(p.e) && MathUtils::isZero(p.f)) {
- if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b) &&
- MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) {
- if (MathUtils::areEqual(p.g, 1.0f)) {
- return TransferFunctionType::None;
- }
- return TransferFunctionType::Gamma;
- }
- return TransferFunctionType::Limited;
- }
- return TransferFunctionType::Full;
- }
- return TransferFunctionType::None;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
deleted file mode 100644
index 5b7e4e261f30..000000000000
--- a/libs/hwui/Texture.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef ANDROID_HWUI_TEXTURE_H
-#define ANDROID_HWUI_TEXTURE_H
-
-#include "GpuMemoryTracker.h"
-#include "hwui/Bitmap.h"
-#include "utils/Color.h"
-
-#include <memory>
-
-#include <math/mat3.h>
-
-#include <ui/ColorSpace.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES3/gl3.h>
-#include <SkBitmap.h>
-
-namespace android {
-
-class GraphicBuffer;
-
-namespace uirenderer {
-
-class Caches;
-class UvMapper;
-class Layer;
-
-/**
- * Represents an OpenGL texture.
- */
-class Texture : public GpuMemoryTracker {
-public:
- static SkBitmap uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
- sk_sp<SkColorSpace> sRGB);
- static bool hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending);
- static void colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
- bool needSRGB, GLint* outInternalFormat,
- GLint* outFormat, GLint* outType);
-
- explicit Texture(Caches& caches) : GpuMemoryTracker(GpuObjectType::Texture), mCaches(caches) {}
-
- virtual ~Texture() {}
-
- inline void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
- setWrapST(wrap, wrap, bindTexture, force);
- }
-
- virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
- bool force = false);
-
- inline void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
- setFilterMinMag(filter, filter, bindTexture, force);
- }
-
- virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
- bool force = false);
-
- /**
- * Convenience method to call glDeleteTextures() on this texture's id.
- */
- void deleteTexture();
-
- /**
- * Sets the width, height, and format of the texture along with allocating
- * the texture ID. Does nothing if the width, height, and format are already
- * the requested values.
- *
- * The image data is undefined after calling this.
- */
- void resize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
- upload(internalFormat, width, height, format,
- internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr);
- }
-
- /**
- * Updates this Texture with the contents of the provided Bitmap,
- * also setting the appropriate width, height, and format. It is not necessary
- * to call resize() prior to this.
- *
- * Note this does not set the generation from the Bitmap.
- */
- void upload(Bitmap& source);
-
- /**
- * Basically glTexImage2D/glTexSubImage2D.
- */
- void upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format, GLenum type,
- const void* pixels);
-
- /**
- * Wraps an existing texture.
- */
- void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format,
- GLenum target);
-
- GLuint id() const { return mId; }
-
- uint32_t width() const { return mWidth; }
-
- uint32_t height() const { return mHeight; }
-
- GLint format() const { return mFormat; }
-
- GLint internalFormat() const { return mInternalFormat; }
-
- GLenum target() const { return mTarget; }
-
- /**
- * Returns nullptr if this texture does not require color space conversion
- * to sRGB, or a valid pointer to a ColorSpaceConnector if a conversion
- * is required.
- */
- constexpr const ColorSpaceConnector* getColorSpaceConnector() const { return mConnector.get(); }
-
- constexpr bool hasColorSpaceConversion() const { return mConnector.get() != nullptr; }
-
- TransferFunctionType getTransferFunctionType() const;
-
- /**
- * Returns true if this texture uses a linear encoding format.
- */
- constexpr bool isLinear() const { return mIsLinear; }
-
- /**
- * Generation of the backing bitmap,
- */
- uint32_t generation = 0;
- /**
- * Indicates whether the texture requires blending.
- */
- bool blend = false;
- /**
- * Indicates whether this texture should be cleaned up after use.
- */
- bool cleanup = false;
- /**
- * Optional, size of the original bitmap.
- */
- uint32_t bitmapSize = 0;
- /**
- * Indicates whether this texture will use trilinear filtering.
- */
- bool mipMap = false;
-
- /**
- * Optional, pointer to a texture coordinates mapper.
- */
- const UvMapper* uvMapper = nullptr;
-
- /**
- * Whether or not the Texture is marked in use and thus not evictable for
- * the current frame. This is reset at the start of a new frame.
- */
- void* isInUse = nullptr;
-
-private:
- // TODO: Temporarily grant private access to GlLayer, remove once
- // GlLayer can be de-tangled from being a dual-purpose render target
- // and external texture wrapper
- friend class GlLayer;
-
- // Returns true if the texture layout (size, format, etc.) changed, false if it was the same
- bool updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format,
- GLenum target);
- void uploadHardwareBitmapToTexture(GraphicBuffer* buffer);
- void resetCachedParams();
-
- GLuint mId = 0;
- uint32_t mWidth = 0;
- uint32_t mHeight = 0;
- GLint mFormat = 0;
- GLint mInternalFormat = 0;
- GLenum mTarget = GL_NONE;
- EGLImageKHR mEglImageHandle = EGL_NO_IMAGE_KHR;
-
- /* See GLES spec section 3.8.14
- * "In the initial state, the value assigned to TEXTURE_MIN_FILTER is
- * NEAREST_MIPMAP_LINEAR and the value for TEXTURE_MAG_FILTER is LINEAR.
- * s, t, and r wrap modes are all set to REPEAT."
- */
- GLenum mWrapS = GL_REPEAT;
- GLenum mWrapT = GL_REPEAT;
- GLenum mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
- GLenum mMagFilter = GL_LINEAR;
-
- // Indicates whether the content of the texture is in linear space
- bool mIsLinear = false;
-
- Caches& mCaches;
-
- std::unique_ptr<ColorSpaceConnector> mConnector;
-}; // struct Texture
-
-class AutoTexture {
-public:
- explicit AutoTexture(Texture* texture) : texture(texture) {}
- ~AutoTexture() {
- if (texture && texture->cleanup) {
- texture->deleteTexture();
- delete texture;
- }
- }
-
- Texture* const texture;
-}; // class AutoTexture
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_TEXTURE_H
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
deleted file mode 100644
index 30fba7ae7d9b..000000000000
--- a/libs/hwui/VkLayer.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 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 "VkLayer.h"
-
-#include "renderstate/RenderState.h"
-
-#include <SkCanvas.h>
-#include <SkSurface.h>
-
-namespace android {
-namespace uirenderer {
-
-void VkLayer::updateTexture() {
- sk_sp<SkSurface> surface;
- SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType);
- surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info);
- surface->getCanvas()->clear(SK_ColorBLUE);
- mImage = surface->makeImageSnapshot();
-}
-
-void VkLayer::onVkContextDestroyed() {
- mImage = nullptr;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
deleted file mode 100644
index e9664d04b7a5..000000000000
--- a/libs/hwui/VkLayer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 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 "Layer.h"
-
-#include <SkImage.h>
-
-namespace android {
-namespace uirenderer {
-/**
- * A layer has dimensions and is backed by a VkImage.
- */
-class VkLayer : public Layer {
-public:
- VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
- : Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
- , mWidth(layerWidth)
- , mHeight(layerHeight)
- , mBlend(blend) {}
-
- virtual ~VkLayer() {}
-
- uint32_t getWidth() const override { return mWidth; }
-
- uint32_t getHeight() const override { return mHeight; }
-
- void setSize(uint32_t width, uint32_t height) override {
- mWidth = width;
- mHeight = height;
- }
-
- void setBlend(bool blend) override { mBlend = blend; }
-
- bool isBlend() const override { return mBlend; }
-
- sk_sp<SkImage> getImage() { return mImage; }
-
- void updateTexture();
-
- // If we've destroyed the vulkan context (VkInstance, VkDevice, etc.), we must make sure to
- // destroy any VkImages that were made with that context.
- void onVkContextDestroyed();
-
-private:
- int mWidth;
- int mHeight;
- bool mBlend;
-
- sk_sp<SkImage> mImage;
-
-}; // struct VkLayer
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 7a8d026df3b4..e7d12de44c0c 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -15,11 +15,11 @@
*/
#include "Bitmap.h"
-#include "Caches.h"
#include "HardwareBitmapUploader.h"
#include "Properties.h"
#include "renderthread/RenderProxy.h"
#include "utils/Color.h"
+#include <utils/Trace.h>
#include <sys/mman.h>
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index c41f6a6f0ee6..fb66b50f0159 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -15,8 +15,6 @@
*/
#include "LayerDrawable.h"
-#include "GlLayer.h"
-#include "VkLayer.h"
#include "GrBackendSurface.h"
#include "SkColorFilter.h"
@@ -41,35 +39,14 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
return false;
}
// transform the matrix based on the layer
- SkMatrix layerTransform;
- layer->getTransform().copyTo(layerTransform);
- sk_sp<SkImage> layerImage;
+ SkMatrix layerTransform = layer->getTransform();
+ sk_sp<SkImage> layerImage = layer->getImage();
const int layerWidth = layer->getWidth();
const int layerHeight = layer->getHeight();
- if (layer->getApi() == Layer::Api::OpenGL) {
- GlLayer* glLayer = static_cast<GlLayer*>(layer);
- GrGLTextureInfo externalTexture;
- externalTexture.fTarget = glLayer->getRenderTarget();
- externalTexture.fID = glLayer->getTextureId();
- // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't
- // expose that info we use it as our default. Further, given that we only use this texture
- // as a source this will not impact how Skia uses the texture. The only potential affect
- // this is anticipated to have is that for some format types if we are not bound as an OES
- // texture we may get invalid results for SKP capture if we read back the texture.
- externalTexture.fFormat = GL_RGBA8;
- GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture);
- layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
- kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
- } else {
- SkASSERT(layer->getApi() == Layer::Api::Vulkan);
- VkLayer* vkLayer = static_cast<VkLayer*>(layer);
- canvas->clear(SK_ColorGREEN);
- layerImage = vkLayer->getImage();
- }
if (layerImage) {
SkMatrix textureMatrixInv;
- layer->getTexTransform().copyTo(textureMatrixInv);
+ textureMatrixInv = layer->getTexTransform();
// TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
// use bottom left origin and remove flipV and invert transformations.
SkMatrix flipV;
@@ -95,6 +72,9 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
paint.setAlpha(layer->getAlpha());
paint.setBlendMode(layer->getMode());
paint.setColorFilter(layer->getColorSpaceWithFilter());
+ if (layer->getForceFilter()) {
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ }
const bool nonIdentityMatrix = !matrix.isIdentity();
if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 78f5a71dee3b..2ae37233098e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -17,7 +17,6 @@
#include "SkiaOpenGLPipeline.h"
#include "DeferredLayerUpdater.h"
-#include "GlLayer.h"
#include "LayerDrawable.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
@@ -187,18 +186,9 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi
return false;
}
-static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
- bool blend) {
- GlLayer* layer =
- new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
- layer->generateTexture();
- return layer;
-}
-
DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
mRenderThread.requireGlContext();
- return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
+ return new DeferredLayerUpdater(mRenderThread.renderState());
}
void SkiaOpenGLPipeline::onStop() {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index b2519fe59891..5f2eee4523fc 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -20,7 +20,6 @@
#include "Readback.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
-#include "VkLayer.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
@@ -114,16 +113,10 @@ bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bi
return false;
}
-static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
- bool blend) {
- return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
-}
-
DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
mVkManager.initialize();
- return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::Vulkan);
+ return new DeferredLayerUpdater(mRenderThread.renderState());
}
void SkiaVulkanPipeline::onStop() {}
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
deleted file mode 100644
index 3a6efb833c47..000000000000
--- a/libs/hwui/renderstate/PixelBufferState.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 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 "renderstate/PixelBufferState.h"
-
-namespace android {
-namespace uirenderer {
-
-PixelBufferState::PixelBufferState() : mCurrentPixelBuffer(0) {}
-
-bool PixelBufferState::bind(GLuint buffer) {
- if (mCurrentPixelBuffer != buffer) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
- mCurrentPixelBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool PixelBufferState::unbind() {
- if (mCurrentPixelBuffer) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- mCurrentPixelBuffer = 0;
- return true;
- }
- return false;
-}
-
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
deleted file mode 100644
index f7ae6c575f6a..000000000000
--- a/libs/hwui/renderstate/PixelBufferState.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-#ifndef RENDERSTATE_PIXELBUFFERSTATE_H
-#define RENDERSTATE_PIXELBUFFERSTATE_H
-
-#include <GLES3/gl3.h>
-
-namespace android {
-namespace uirenderer {
-
-class PixelBufferState {
- friend class Caches; // TODO: move to RenderState
-public:
- bool bind(GLuint buffer);
- bool unbind();
-
-private:
- PixelBufferState();
- GLuint mCurrentPixelBuffer;
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 3be84f588a20..b524bcb096da 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -16,8 +16,6 @@
#include "renderstate/RenderState.h"
#include <GpuMemoryTracker.h>
#include "DeferredLayerUpdater.h"
-#include "GlLayer.h"
-#include "VkLayer.h"
#include "Snapshot.h"
#include "renderthread/CanvasContext.h"
@@ -39,44 +37,11 @@ RenderState::RenderState(renderthread::RenderThread& thread)
RenderState::~RenderState() {
}
-void RenderState::onGLContextCreated() {
+void RenderState::onContextCreated() {
GpuMemoryTracker::onGpuContextCreated();
-
- // This is delayed because the first access of Caches makes GL calls
- if (!mCaches) {
- mCaches = &Caches::createInstance(*this);
- }
- mCaches->init();
}
-static void layerLostGlContext(Layer* layer) {
- LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL,
- "layerLostGlContext on non GL layer");
- static_cast<GlLayer*>(layer)->onGlContextLost();
-}
-
-void RenderState::onGLContextDestroyed() {
- // TODO: reset all cached state in state objects
- std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
-
- mCaches->terminate();
-
- destroyLayersInUpdater();
- GpuMemoryTracker::onGpuContextDestroyed();
-}
-
-void RenderState::onVkContextCreated() {
- GpuMemoryTracker::onGpuContextCreated();
-}
-
-static void layerDestroyedVkContext(Layer* layer) {
- LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::Vulkan,
- "layerLostVkContext on non Vulkan layer");
- static_cast<VkLayer*>(layer)->onVkContextDestroyed();
-}
-
-void RenderState::onVkContextDestroyed() {
- std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext);
+void RenderState::onContextDestroyed() {
destroyLayersInUpdater();
GpuMemoryTracker::onGpuContextDestroyed();
}
@@ -85,10 +50,6 @@ GrContext* RenderState::getGrContext() const {
return mRenderThread.getGrContext();
}
-void RenderState::flush(Caches::FlushMode mode) {
- if (mCaches) mCaches->flush(mode);
-}
-
void RenderState::onBitmapDestroyed(uint32_t pixelRefId) {
// DEAD CODE
}
@@ -126,42 +87,6 @@ void RenderState::deleteFramebuffer(GLuint fbo) {
glDeleteFramebuffers(1, &fbo);
}
-void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
- if (mode == DrawGlInfo::kModeProcessNoContext) {
- // If there's no context we don't need to interrupt as there's
- // no gl state to save/restore
- (*functor)(mode, info);
- } else {
- interruptForFunctorInvoke();
- (*functor)(mode, info);
- resumeFromFunctorInvoke();
- }
-}
-
-void RenderState::interruptForFunctorInvoke() {
- mCaches->textureState().resetActiveTexture();
- debugOverdraw(false, false);
- // TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
- if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
- glDisable(GL_FRAMEBUFFER_SRGB_EXT);
- }
-}
-
-void RenderState::resumeFromFunctorInvoke() {
- if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
- glEnable(GL_FRAMEBUFFER_SRGB_EXT);
- }
-
- glViewport(0, 0, mViewportWidth, mViewportHeight);
- glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
- debugOverdraw(false, false);
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
- mCaches->textureState().activateTexture(0);
- mCaches->textureState().resetBoundTextures();
-}
-
void RenderState::debugOverdraw(bool enable, bool clear) {
// DEAD CODE
}
@@ -190,5 +115,9 @@ void RenderState::dump() {
// DEAD CODE
}
+renderthread::RenderThread& RenderState::getRenderThread() {
+ return mRenderThread;
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 97785a46dcd7..f39aa4b96547 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -16,8 +16,6 @@
#ifndef RENDERSTATE_H
#define RENDERSTATE_H
-#include "Caches.h"
-#include "renderstate/PixelBufferState.h"
#include "utils/Macros.h"
#include <GLES2/gl2.h>
@@ -34,7 +32,6 @@ class GrContext;
namespace android {
namespace uirenderer {
-class Caches;
class Layer;
class DeferredLayerUpdater;
@@ -44,22 +41,16 @@ class CanvasContext;
class RenderThread;
}
-// TODO: Replace Cache's GL state tracking with this. For now it's more a thin
// wrapper of Caches for users to migrate to.
class RenderState {
PREVENT_COPY_AND_ASSIGN(RenderState);
friend class renderthread::RenderThread;
- friend class Caches;
friend class renderthread::CacheManager;
public:
- void onGLContextCreated();
- void onGLContextDestroyed();
+ void onContextCreated();
+ void onContextDestroyed();
- void onVkContextCreated();
- void onVkContextDestroyed();
-
- void flush(Caches::FlushMode flushMode);
void onBitmapDestroyed(uint32_t pixelRefId);
void setViewport(GLsizei width, GLsizei height);
@@ -70,8 +61,6 @@ public:
GLuint createFramebuffer();
void deleteFramebuffer(GLuint fbo);
- void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
-
void debugOverdraw(bool enable, bool clear);
void registerLayer(Layer* layer) { mActiveLayers.insert(layer); }
@@ -101,16 +90,15 @@ public:
void dump();
+ renderthread::RenderThread& getRenderThread();
+
private:
- void interruptForFunctorInvoke();
- void resumeFromFunctorInvoke();
void destroyLayersInUpdater();
explicit RenderState(renderthread::RenderThread& thread);
~RenderState();
renderthread::RenderThread& mRenderThread;
- Caches* mCaches = nullptr;
std::set<Layer*> mActiveLayers;
std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
deleted file mode 100644
index 470b4f5de97f..000000000000
--- a/libs/hwui/renderstate/TextureState.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2015 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 "renderstate/TextureState.h"
-
-#include "Caches.h"
-#include "utils/TraceUtils.h"
-
-#include <GLES3/gl3.h>
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <memory>
-
-namespace android {
-namespace uirenderer {
-
-// Width of mShadowLutTexture, defines how accurate the shadow alpha lookup table is
-static const int SHADOW_LUT_SIZE = 128;
-
-// Must define as many texture units as specified by kTextureUnitsCount
-const GLenum kTextureUnits[] = {GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3};
-
-TextureState::TextureState() : mTextureUnit(0) {
- glActiveTexture(kTextureUnits[0]);
- resetBoundTextures();
-
- GLint maxTextureUnits;
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
- LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
- "At least %d texture units are required!", kTextureUnitsCount);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-}
-
-TextureState::~TextureState() {
- if (mShadowLutTexture != nullptr) {
- mShadowLutTexture->deleteTexture();
- }
-}
-
-/**
- * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to
- * darkness at that spot. Input values of 0->1 should be mapped within the same
- * range, but can affect the curve for a different visual falloff.
- *
- * This is used to populate the shadow LUT texture for quick lookup in the
- * shadow shader.
- */
-static float computeShadowOpacity(float ratio) {
- // exponential falloff function provided by UX
- float val = 1 - ratio;
- return exp(-val * val * 4.0) - 0.018;
-}
-
-void TextureState::constructTexture(Caches& caches) {
- if (mShadowLutTexture == nullptr) {
- mShadowLutTexture.reset(new Texture(caches));
-
- unsigned char bytes[SHADOW_LUT_SIZE];
- for (int i = 0; i < SHADOW_LUT_SIZE; i++) {
- float inputRatio = i / (SHADOW_LUT_SIZE - 1.0f);
- bytes[i] = computeShadowOpacity(inputRatio) * 255;
- }
- mShadowLutTexture->upload(GL_ALPHA, SHADOW_LUT_SIZE, 1, GL_ALPHA, GL_UNSIGNED_BYTE, &bytes);
- mShadowLutTexture->setFilter(GL_LINEAR);
- mShadowLutTexture->setWrap(GL_CLAMP_TO_EDGE);
- }
-}
-
-void TextureState::activateTexture(GLuint textureUnit) {
- LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount,
- "Tried to use texture unit index %d, only %d exist", textureUnit,
- kTextureUnitsCount);
- if (mTextureUnit != textureUnit) {
- glActiveTexture(kTextureUnits[textureUnit]);
- mTextureUnit = textureUnit;
- }
-}
-
-void TextureState::resetActiveTexture() {
- mTextureUnit = -1;
-}
-
-void TextureState::bindTexture(GLuint texture) {
- if (mBoundTextures[mTextureUnit] != texture) {
- glBindTexture(GL_TEXTURE_2D, texture);
- mBoundTextures[mTextureUnit] = texture;
- }
-}
-
-void TextureState::bindTexture(GLenum target, GLuint texture) {
- if (target == GL_TEXTURE_2D) {
- bindTexture(texture);
- } else {
- // GLConsumer directly calls glBindTexture() with
- // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
- // since the cached state could be stale
- glBindTexture(target, texture);
- }
-}
-
-void TextureState::deleteTexture(GLuint texture) {
- // When glDeleteTextures() is called on a currently bound texture,
- // OpenGL ES specifies that the texture is then considered unbound
- // Consider the following series of calls:
- //
- // glGenTextures -> creates texture name 2
- // glBindTexture(2)
- // glDeleteTextures(2) -> 2 is now unbound
- // glGenTextures -> can return 2 again
- //
- // If we don't call glBindTexture(2) after the second glGenTextures
- // call, any texture operation will be performed on the default
- // texture (name=0)
-
- unbindTexture(texture);
-
- glDeleteTextures(1, &texture);
-}
-
-void TextureState::resetBoundTextures() {
- for (int i = 0; i < kTextureUnitsCount; i++) {
- mBoundTextures[i] = 0;
- }
-}
-
-void TextureState::unbindTexture(GLuint texture) {
- for (int i = 0; i < kTextureUnitsCount; i++) {
- if (mBoundTextures[i] == texture) {
- mBoundTextures[i] = 0;
- }
- }
-}
-
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
deleted file mode 100644
index f1996d431fa2..000000000000
--- a/libs/hwui/renderstate/TextureState.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-#ifndef RENDERSTATE_TEXTURESTATE_H
-#define RENDERSTATE_TEXTURESTATE_H
-
-#include "Texture.h"
-#include "Vertex.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <memory>
-
-namespace android {
-namespace uirenderer {
-
-class Texture;
-
-class TextureState {
- friend class Caches; // TODO: move to RenderState
-public:
- void constructTexture(Caches& caches);
-
- /**
- * Activate the specified texture unit. The texture unit must
- * be specified using an integer number (0 for GL_TEXTURE0 etc.)
- */
- void activateTexture(GLuint textureUnit);
-
- /**
- * Invalidate the cached value of the active texture unit.
- */
- void resetActiveTexture();
-
- /**
- * Binds the specified texture as a GL_TEXTURE_2D texture.
- * All texture bindings must be performed with this method or
- * bindTexture(GLenum, GLuint).
- */
- void bindTexture(GLuint texture);
-
- /**
- * Binds the specified texture with the specified render target.
- * All texture bindings must be performed with this method or
- * bindTexture(GLuint).
- */
- void bindTexture(GLenum target, GLuint texture);
-
- /**
- * Deletes the specified texture and clears it from the cache
- * of bound textures.
- * All textures must be deleted using this method.
- */
- void deleteTexture(GLuint texture);
-
- /**
- * Signals that the cache of bound textures should be cleared.
- * Other users of the context may have altered which textures are bound.
- */
- void resetBoundTextures();
-
- /**
- * Clear the cache of bound textures.
- */
- void unbindTexture(GLuint texture);
-
- Texture* getShadowLutTexture() { return mShadowLutTexture.get(); }
-
-private:
- // total number of texture units available for use
- static const int kTextureUnitsCount = 4;
-
- TextureState();
- ~TextureState();
- GLuint mTextureUnit;
-
- // Caches texture bindings for the GL_TEXTURE_2D target
- GLuint mBoundTextures[kTextureUnitsCount];
-
- std::unique_ptr<Texture> mShadowLutTexture;
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index bec80b1e6011..c45eedad775c 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -21,6 +21,7 @@
#include "RenderThread.h"
#include "pipeline/skia/ShaderCache.h"
#include "pipeline/skia/SkiaMemoryTracer.h"
+#include "Properties.h"
#include "renderstate/RenderState.h"
#include <GrContextOptions.h>
@@ -214,11 +215,12 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState)
log.appendFormat(" Layer Info:\n");
}
+ const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL
+ ? "GlLayer" : "VkLayer";
size_t layerMemoryTotal = 0;
for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
it != renderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
- const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer";
log.appendFormat(" %s size %dx%d\n", layerType, layer->getWidth(),
layer->getHeight());
layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5d7252304bf2..8b07d1dadeb6 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -18,7 +18,6 @@
#include <GpuMemoryTracker.h>
#include "AnimationContext.h"
-#include "Caches.h"
#include "EglManager.h"
#include "Frame.h"
#include "LayerUpdateQueue.h"
@@ -495,13 +494,6 @@ void CanvasContext::draw() {
}
GpuMemoryTracker::onFrameCompleted();
-#ifdef BUGREPORT_FONT_CACHE_USAGE
- auto renderType = Properties::getRenderPipelineType();
- if (RenderPipelineType::OpenGL == renderType) {
- Caches& caches = Caches::getInstance();
- caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
- }
-#endif
}
// Called by choreographer to do an RT-driven animation
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index cd21822df5b1..5f8d7ad3373a 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -18,6 +18,7 @@
#include <cutils/properties.h>
#include <log/log.h>
+#include <private/gui/SyncFeatures.h>
#include <utils/Trace.h>
#include "utils/StringUtils.h"
@@ -464,6 +465,109 @@ bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
return preserved;
}
+status_t EglManager::fenceWait(sp<Fence>& fence) {
+ if (!hasEglContext()) {
+ ALOGE("EglManager::fenceWait: EGLDisplay not initialized");
+ return INVALID_OPERATION;
+ }
+
+ if (SyncFeatures::getInstance().useWaitSync() &&
+ SyncFeatures::getInstance().useNativeFenceSync()) {
+ // Block GPU on the fence.
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = fence->dup();
+ if (fenceFd == -1) {
+ ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+ EGL_NONE
+ };
+ EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncKHR(mEglDisplay, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(mEglDisplay, sync);
+ if (eglErr != EGL_SUCCESS) {
+ ALOGE("EglManager::fenceWait: error waiting for EGL fence: %#x", eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ // Block CPU on the fence.
+ status_t err = fence->waitForever("EglManager::fenceWait");
+ if (err != NO_ERROR) {
+ ALOGE("EglManager::fenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ return OK;
+}
+
+status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence,
+ sp<Fence>& nativeFence) {
+ if (!hasEglContext()) {
+ ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized");
+ return INVALID_OPERATION;
+ }
+
+ if (SyncFeatures::getInstance().useNativeFenceSync()) {
+ EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ int fenceFd = eglDupNativeFenceFDANDROID(mEglDisplay, sync);
+ eglDestroySyncKHR(mEglDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGE("EglManager::createReleaseFence: error dup'ing native fence "
+ "fd: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ nativeFence = new Fence(fenceFd);
+ *eglFence = EGL_NO_SYNC_KHR;
+ } else if (useFenceSync && SyncFeatures::getInstance().useFenceSync()) {
+ if (*eglFence != EGL_NO_SYNC_KHR) {
+ // There is already a fence for the current slot. We need to
+ // wait on that before replacing it with another fence to
+ // ensure that all outstanding buffer accesses have completed
+ // before the producer accesses it.
+ EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000);
+ if (result == EGL_FALSE) {
+ ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence");
+ return TIMED_OUT;
+ }
+ eglDestroySyncKHR(mEglDisplay, *eglFence);
+ }
+
+ // Create a fence for the outstanding accesses in the current
+ // OpenGL ES context.
+ *eglFence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+ if (*eglFence == EGL_NO_SYNC_KHR) {
+ ALOGE("EglManager::createReleaseFence: error creating fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ }
+ return OK;
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 8e8bb8b68a1c..507673adf26e 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -17,8 +17,10 @@
#define EGLMANAGER_H
#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include <SkRect.h>
#include <cutils/compiler.h>
+#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
@@ -66,6 +68,14 @@ public:
EGLDisplay eglDisplay() const { return mEglDisplay; }
+ // Inserts a wait on fence command into the OpenGL ES command stream. If EGL extension
+ // support is missing, block the CPU on the fence.
+ status_t fenceWait(sp<Fence>& fence);
+
+ // Creates a fence that is signaled, when all the pending GL commands are flushed.
+ // Depending on installed extensions, the result is either Android native fence or EGL fence.
+ status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence);
+
private:
void initExtensions();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 3eaf43b65f69..51be54ced5ec 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -178,7 +178,7 @@ void RenderThread::requireGlContext() {
return;
}
mEglManager->initialize();
- renderState().onGLContextCreated();
+ renderState().onContextCreated();
#ifdef HWUI_GLES_WRAP_ENABLED
debug::GlesDriver* driver = debug::GlesDriver::get();
@@ -199,7 +199,7 @@ void RenderThread::requireGlContext() {
void RenderThread::destroyGlContext() {
if (mEglManager->hasEglContext()) {
setGrContext(nullptr);
- renderState().onGLContextDestroyed();
+ renderState().onContextDestroyed();
mEglManager->destroy();
}
}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a19edae26cb3..67b1972e874f 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -38,7 +38,7 @@ namespace renderthread {
VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
void VulkanManager::destroy() {
- mRenderThread.renderState().onVkContextDestroyed();
+ mRenderThread.renderState().onContextDestroyed();
mRenderThread.setGrContext(nullptr);
if (VK_NULL_HANDLE != mCommandPool) {
@@ -367,7 +367,7 @@ void VulkanManager::initialize() {
mSwapBehavior = SwapBehavior::BufferAge;
}
- mRenderThread.renderState().onVkContextCreated();
+ mRenderThread.renderState().onContextCreated();
}
// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
@@ -944,6 +944,22 @@ int VulkanManager::getAge(VulkanSurface* surface) {
return surface->mCurrentTime - lastUsed;
}
+status_t VulkanManager::fenceWait(sp<Fence>& fence) {
+ //TODO: Insert a wait on fence command into the Vulkan command buffer.
+ // Block CPU on the fence.
+ status_t err = fence->waitForever("VulkanManager::fenceWait");
+ if (err != NO_ERROR) {
+ ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ return OK;
+}
+
+status_t VulkanManager::createReleaseFence(sp<Fence>& nativeFence) {
+ //TODO: Create a fence that is signaled, when all the pending Vulkan commands are flushed.
+ return OK;
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 69641d57ccbb..7051ee686659 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -23,6 +23,8 @@
#include <vulkan/vulkan.h>
#include <SkSurface.h>
+#include <ui/Fence.h>
+#include <utils/StrongPointer.h>
#include <vk/GrVkBackendContext.h>
namespace android {
@@ -108,6 +110,12 @@ public:
// Presents the current VkImage.
void swapBuffers(VulkanSurface* surface);
+ // Inserts a wait on fence command into the Vulkan command buffer.
+ status_t fenceWait(sp<Fence>& fence);
+
+ // Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
+ status_t createReleaseFence(sp<Fence>& nativeFence);
+
private:
friend class RenderThread;
diff --git a/libs/hwui/surfacetexture/EGLConsumer.cpp b/libs/hwui/surfacetexture/EGLConsumer.cpp
new file mode 100644
index 000000000000..c8220c6cb0d4
--- /dev/null
+++ b/libs/hwui/surfacetexture/EGLConsumer.cpp
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2018 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 <inttypes.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cutils/compiler.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <private/gui/SyncFeatures.h>
+#include "EGLConsumer.h"
+#include "SurfaceTexture.h"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+
+namespace android {
+
+// Macros for including the SurfaceTexture name in log messages
+#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+
+static const struct {
+ uint32_t width, height;
+ char const* bits;
+} kDebugData = {15, 12,
+ "_______________"
+ "_______________"
+ "_____XX_XX_____"
+ "__X_X_____X_X__"
+ "__X_XXXXXXX_X__"
+ "__XXXXXXXXXXX__"
+ "___XX_XXX_XX___"
+ "____XXXXXXX____"
+ "_____X___X_____"
+ "____X_____X____"
+ "_______________"
+ "_______________"};
+
+Mutex EGLConsumer::sStaticInitLock;
+sp<GraphicBuffer> EGLConsumer::sReleasedTexImageBuffer;
+
+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;
+}
+
+EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {}
+
+status_t EGLConsumer::updateTexImage(SurfaceTexture& st) {
+ // Make sure the EGL state is the same as in previous calls.
+ status_t err = checkAndUpdateEglStateLocked(st);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ BufferItem item;
+
+ // Acquire the next buffer.
+ // In asynchronous mode the list is guaranteed to be one buffer
+ // deep, while in synchronous mode we use the oldest buffer.
+ err = st.acquireBufferLocked(&item, 0);
+ if (err != NO_ERROR) {
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ // We always bind the texture even if we don't update its contents.
+ EGC_LOGV("updateTexImage: no buffers were available");
+ glBindTexture(st.mTexTarget, st.mTexName);
+ err = NO_ERROR;
+ } else {
+ EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
+ }
+ return err;
+ }
+
+ // Release the previous buffer.
+ err = updateAndReleaseLocked(item, nullptr, st);
+ if (err != NO_ERROR) {
+ // We always bind the texture.
+ glBindTexture(st.mTexTarget, st.mTexName);
+ return err;
+ }
+
+ // Bind the new buffer to the GL texture, and wait until it's ready.
+ return bindTextureImageLocked(st);
+}
+
+status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) {
+ // Make sure the EGL state is the same as in previous calls.
+ status_t err = NO_ERROR;
+
+ // if we're detached, no need to validate EGL's state -- we won't use it.
+ if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
+ err = checkAndUpdateEglStateLocked(st, true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
+ // Update the EGLConsumer state.
+ int buf = st.mCurrentTexture;
+ if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
+ EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode);
+
+ // if we're detached, we just use the fence that was created in detachFromContext()
+ // so... basically, nothing more to do here.
+ if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
+ // Do whatever sync ops we need to do before releasing the slot.
+ err = syncForReleaseLocked(mEglDisplay, st);
+ if (err != NO_ERROR) {
+ EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
+ return err;
+ }
+ }
+
+ err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer, mEglDisplay,
+ EGL_NO_SYNC_KHR);
+ if (err < NO_ERROR) {
+ EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err);
+ return err;
+ }
+
+ if (mReleasedTexImage == nullptr) {
+ mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
+ }
+
+ st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
+ mCurrentTextureImage = mReleasedTexImage;
+ st.mCurrentCrop.makeInvalid();
+ st.mCurrentTransform = 0;
+ st.mCurrentTimestamp = 0;
+ st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
+ st.mCurrentFence = Fence::NO_FENCE;
+ st.mCurrentFenceTime = FenceTime::NO_FENCE;
+
+ // detached, don't touch the texture (and we may not even have an
+ // EGLDisplay here.
+ if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
+ // This binds a dummy buffer (mReleasedTexImage).
+ status_t result = bindTextureImageLocked(st);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+sp<GraphicBuffer> EGLConsumer::getDebugTexImageBuffer() {
+ Mutex::Autolock _l(sStaticInitLock);
+ if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
+ // The first time, create the debug texture in case the application
+ // continues to use it.
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
+ GraphicBuffer::USAGE_SW_WRITE_RARELY, "[EGLConsumer debug texture]");
+ uint32_t* bits;
+ buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
+ uint32_t stride = buffer->getStride();
+ uint32_t height = buffer->getHeight();
+ memset(bits, 0, stride * height * 4);
+ for (uint32_t y = 0; y < kDebugData.height; y++) {
+ for (uint32_t x = 0; x < kDebugData.width; x++) {
+ bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000
+ : 0xFFFFFFFF;
+ }
+ bits += stride;
+ }
+ buffer->unlock();
+ sReleasedTexImageBuffer = buffer;
+ }
+ return sReleasedTexImageBuffer;
+}
+
+void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) {
+ // If item->mGraphicBuffer is not null, this buffer has not been acquired
+ // before, so any prior EglImage created is using a stale buffer. This
+ // replaces any old EglImage with a new one (using the new buffer).
+ int slot = item->mSlot;
+ if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) {
+ mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
+ }
+}
+
+void EGLConsumer::onReleaseBufferLocked(int buf) {
+ mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+}
+
+status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
+ SurfaceTexture& st) {
+ status_t err = NO_ERROR;
+
+ int slot = item.mSlot;
+
+ if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) {
+ EGC_LOGE(
+ "updateAndRelease: EGLConsumer is not attached to an OpenGL "
+ "ES context");
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
+ return INVALID_OPERATION;
+ }
+
+ // Confirm state.
+ err = checkAndUpdateEglStateLocked(st);
+ if (err != NO_ERROR) {
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
+ return err;
+ }
+
+ // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
+ // if nessessary, for the gralloc buffer currently in the slot in
+ // 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);
+ if (err != NO_ERROR) {
+ EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
+ slot);
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
+ return UNKNOWN_ERROR;
+ }
+
+ // Do whatever sync ops we need to do before releasing the old slot.
+ if (slot != st.mCurrentTexture) {
+ err = syncForReleaseLocked(mEglDisplay, st);
+ if (err != NO_ERROR) {
+ // Release the buffer we just acquired. It's not safe to
+ // release the old buffer, so instead we just drop the new frame.
+ // As we are still under lock since acquireBuffer, it is safe to
+ // release by slot.
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay,
+ EGL_NO_SYNC_KHR);
+ return err;
+ }
+ }
+
+ EGC_LOGV(
+ "updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture,
+ mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : nullptr,
+ slot, st.mSlots[slot].mGraphicBuffer->handle);
+
+ // 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;
+
+ // release old buffer
+ if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ if (pendingRelease == nullptr) {
+ status_t status = st.releaseBufferLocked(
+ st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay,
+ mEglSlots[st.mCurrentTexture].mEglFence);
+ if (status < NO_ERROR) {
+ EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
+ status);
+ err = status;
+ // keep going, with error raised [?]
+ }
+ } else {
+ pendingRelease->currentTexture = st.mCurrentTexture;
+ pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
+ pendingRelease->display = mEglDisplay;
+ pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence;
+ pendingRelease->isPending = true;
+ }
+ }
+
+ // Update the EGLConsumer state.
+ st.mCurrentTexture = slot;
+ mCurrentTextureImage = nextTextureImage;
+ st.mCurrentCrop = item.mCrop;
+ st.mCurrentTransform = item.mTransform;
+ st.mCurrentScalingMode = item.mScalingMode;
+ st.mCurrentTimestamp = item.mTimestamp;
+ st.mCurrentDataSpace = item.mDataSpace;
+ st.mCurrentFence = item.mFence;
+ st.mCurrentFenceTime = item.mFenceTime;
+ st.mCurrentFrameNumber = item.mFrameNumber;
+
+ st.computeCurrentTransformMatrixLocked();
+
+ return err;
+}
+
+status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) {
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ ALOGE("bindTextureImage: invalid display");
+ return INVALID_OPERATION;
+ }
+
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
+ }
+
+ glBindTexture(st.mTexTarget, st.mTexName);
+ if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
+ EGC_LOGE("bindTextureImage: no currently-bound texture");
+ return NO_INIT;
+ }
+
+ status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
+ if (err != NO_ERROR) {
+ EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
+ st.mCurrentTexture);
+ return UNKNOWN_ERROR;
+ }
+ mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
+
+ // In the rare case that the display is terminated and then initialized
+ // again, we can't detect that the display changed (it didn't), but the
+ // image is invalid. In this case, repeat the exact same steps while
+ // forcing the creation of a new image.
+ if ((error = glGetError()) != GL_NO_ERROR) {
+ glBindTexture(st.mTexTarget, st.mTexName);
+ status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
+ if (result != NO_ERROR) {
+ EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
+ st.mCurrentTexture);
+ return UNKNOWN_ERROR;
+ }
+ mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
+ if ((error = glGetError()) != GL_NO_ERROR) {
+ EGC_LOGE("bindTextureImage: error binding external image: %#04x", error);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Wait for the new buffer to be ready.
+ return doGLFenceWaitLocked(st);
+}
+
+status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (!contextCheck) {
+ // if this is the first time we're called, mEglDisplay/mEglContext have
+ // never been set, so don't error out (below).
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ mEglDisplay = dpy;
+ }
+ if (mEglContext == EGL_NO_CONTEXT) {
+ mEglContext = ctx;
+ }
+ }
+
+ if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
+ EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
+ EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ mEglDisplay = dpy;
+ mEglContext = ctx;
+ return NO_ERROR;
+}
+
+status_t EGLConsumer::detachFromContext(SurfaceTexture& st) {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
+ EGC_LOGE("detachFromContext: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
+ EGC_LOGE("detachFromContext: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
+ status_t err = syncForReleaseLocked(dpy, st);
+ if (err != OK) {
+ return err;
+ }
+
+ glDeleteTextures(1, &st.mTexName);
+ }
+
+ mEglDisplay = EGL_NO_DISPLAY;
+ mEglContext = EGL_NO_CONTEXT;
+
+ return OK;
+}
+
+status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) {
+ // Initialize mCurrentTextureImage if there is a current buffer from past attached state.
+ int slot = st.mCurrentTexture;
+ if (slot != BufferItem::INVALID_BUFFER_SLOT) {
+ if (!mEglSlots[slot].mEglImage.get()) {
+ mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
+ }
+ mCurrentTextureImage = mEglSlots[slot].mEglImage;
+ }
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (dpy == EGL_NO_DISPLAY) {
+ EGC_LOGE("attachToContext: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (ctx == EGL_NO_CONTEXT) {
+ EGC_LOGE("attachToContext: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ // We need to bind the texture regardless of whether there's a current
+ // buffer.
+ glBindTexture(st.mTexTarget, GLuint(tex));
+
+ mEglDisplay = dpy;
+ mEglContext = ctx;
+ st.mTexName = tex;
+ st.mOpMode = SurfaceTexture::OpMode::attachedToGL;
+
+ if (mCurrentTextureImage != nullptr) {
+ // This may wait for a buffer a second time. This is likely required if
+ // this is a different context, since otherwise the wait could be skipped
+ // by bouncing through another context. For the same context the extra
+ // wait is redundant.
+ status_t err = bindTextureImageLocked(st);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
+ return OK;
+}
+
+status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) {
+ EGC_LOGV("syncForReleaseLocked");
+
+ if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ if (SyncFeatures::getInstance().useNativeFenceSync()) {
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
+ eglDestroySyncKHR(dpy, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ EGC_LOGE(
+ "syncForReleaseLocked: error dup'ing native fence "
+ "fd: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ sp<Fence> fence(new Fence(fenceFd));
+ status_t err = st.addReleaseFenceLocked(st.mCurrentTexture,
+ mCurrentTextureImage->graphicBuffer(), fence);
+ if (err != OK) {
+ EGC_LOGE(
+ "syncForReleaseLocked: error adding release fence: "
+ "%s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
+ EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence;
+ if (fence != EGL_NO_SYNC_KHR) {
+ // There is already a fence for the current slot. We need to
+ // wait on that before replacing it with another fence to
+ // ensure that all outstanding buffer accesses have completed
+ // before the producer accesses it.
+ EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (result == EGL_FALSE) {
+ EGC_LOGE(
+ "syncForReleaseLocked: error waiting for previous "
+ "fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ EGC_LOGE(
+ "syncForReleaseLocked: timeout waiting for previous "
+ "fence");
+ return TIMED_OUT;
+ }
+ eglDestroySyncKHR(dpy, fence);
+ }
+
+ // Create a fence for the outstanding accesses in the current
+ // OpenGL ES context.
+ fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
+ if (fence == EGL_NO_SYNC_KHR) {
+ EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ mEglSlots[st.mCurrentTexture].mEglFence = fence;
+ }
+ }
+
+ return OK;
+}
+
+status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
+ EGC_LOGE("doGLFenceWait: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
+ EGC_LOGE("doGLFenceWait: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ if (st.mCurrentFence->isValid()) {
+ if (SyncFeatures::getInstance().useWaitSync() &&
+ SyncFeatures::getInstance().useNativeFenceSync()) {
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = st.mCurrentFence->dup();
+ if (fenceFd == -1) {
+ EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncKHR(dpy, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(dpy, sync);
+ if (eglErr != EGL_SUCCESS) {
+ EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked");
+ if (err != NO_ERROR) {
+ EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+void EGLConsumer::onFreeBufferLocked(int slotIndex) {
+ mEglSlots[slotIndex].mEglImage.clear();
+}
+
+void EGLConsumer::onAbandonLocked() {
+ mCurrentTextureImage.clear();
+}
+
+EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
+ : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {}
+
+EGLConsumer::EglImage::~EglImage() {
+ if (mEglImage != EGL_NO_IMAGE_KHR) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+ ALOGE("~EglImage: eglDestroyImageKHR failed");
+ }
+ eglTerminate(mEglDisplay);
+ }
+}
+
+status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) {
+ // If there's an image and it's no longer valid, destroy it.
+ bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
+ bool displayInvalid = mEglDisplay != eglDisplay;
+ if (haveImage && (displayInvalid || forceCreation)) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+ ALOGE("createIfNeeded: eglDestroyImageKHR failed");
+ }
+ eglTerminate(mEglDisplay);
+ mEglImage = EGL_NO_IMAGE_KHR;
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+
+ // If there's no image, create one.
+ if (mEglImage == EGL_NO_IMAGE_KHR) {
+ mEglDisplay = eglDisplay;
+ mEglImage = createImage(mEglDisplay, mGraphicBuffer);
+ }
+
+ // Fail if we can't create a valid image.
+ if (mEglImage == EGL_NO_IMAGE_KHR) {
+ mEglDisplay = EGL_NO_DISPLAY;
+ 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 EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
+ glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
+}
+
+EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer) {
+ EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
+ const bool createProtectedImage =
+ (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
+ EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR,
+ EGL_TRUE,
+ createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+ createProtectedImage ? EGL_TRUE : EGL_NONE,
+ EGL_NONE,
+ };
+ eglInitialize(dpy, nullptr, nullptr);
+ 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;
+}
+
+}; // namespace android
diff --git a/libs/hwui/surfacetexture/EGLConsumer.h b/libs/hwui/surfacetexture/EGLConsumer.h
new file mode 100644
index 000000000000..eccb08298f6f
--- /dev/null
+++ b/libs/hwui/surfacetexture/EGLConsumer.h
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2018 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 <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueueDefs.h>
+
+#include <ui/FenceTime.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+class SurfaceTexture;
+
+/*
+ * EGLConsumer implements the parts of SurfaceTexture that deal with
+ * textures attached to an GL context.
+ */
+class EGLConsumer {
+public:
+ EGLConsumer();
+
+ /**
+ * updateTexImage acquires the most recently queued buffer, and sets the
+ * image contents of the target texture to it.
+ *
+ * This call may only be made while the OpenGL ES context to which the
+ * target texture belongs is bound to the calling thread.
+ *
+ * This calls doGLFenceWait to ensure proper synchronization.
+ */
+ status_t updateTexImage(SurfaceTexture& st);
+
+ /*
+ * releaseTexImage releases the texture acquired in updateTexImage().
+ * This is intended to be used in single buffer mode.
+ *
+ * This call may only be made while the OpenGL ES context to which the
+ * target texture belongs is bound to the calling thread.
+ */
+ status_t releaseTexImage(SurfaceTexture& st);
+
+ /**
+ * detachFromContext detaches the EGLConsumer from the calling thread's
+ * current OpenGL ES context. This context must be the same as the context
+ * that was current for previous calls to updateTexImage.
+ *
+ * Detaching a EGLConsumer from an OpenGL ES context will result in the
+ * deletion of the OpenGL ES texture object into which the images were being
+ * streamed. After a EGLConsumer has been detached from the OpenGL ES
+ * context calls to updateTexImage will fail returning INVALID_OPERATION
+ * until the EGLConsumer is attached to a new OpenGL ES context using the
+ * attachToContext method.
+ */
+ status_t detachFromContext(SurfaceTexture& st);
+
+ /**
+ * attachToContext attaches a EGLConsumer that is currently in the
+ * 'detached' state to the current OpenGL ES context. A EGLConsumer is
+ * in the 'detached' state iff detachFromContext has successfully been
+ * called and no calls to attachToContext have succeeded since the last
+ * detachFromContext call. Calls to attachToContext made on a
+ * EGLConsumer that is not in the 'detached' state will result in an
+ * INVALID_OPERATION error.
+ *
+ * The tex argument specifies the OpenGL ES texture object name in the
+ * new context into which the image contents will be streamed. A successful
+ * call to attachToContext will result in this texture object being bound to
+ * the texture target and populated with the image contents that were
+ * current at the time of the last call to detachFromContext.
+ */
+ status_t attachToContext(uint32_t tex, SurfaceTexture& st);
+
+ /**
+ * onAcquireBufferLocked amends the ConsumerBase method to update the
+ * mEglSlots array in addition to the ConsumerBase behavior.
+ */
+ void onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st);
+
+ /**
+ * onReleaseBufferLocked amends the ConsumerBase method to update the
+ * mEglSlots array in addition to the ConsumerBase.
+ */
+ void onReleaseBufferLocked(int slot);
+
+ /**
+ * onFreeBufferLocked frees up the given buffer slot. If the slot has been
+ * initialized this will release the reference to the GraphicBuffer in that
+ * slot and destroy the EGLImage in that slot. Otherwise it has no effect.
+ */
+ void onFreeBufferLocked(int slotIndex);
+
+ /**
+ * onAbandonLocked amends the ConsumerBase method to clear
+ * mCurrentTextureImage in addition to the ConsumerBase behavior.
+ */
+ void onAbandonLocked();
+
+protected:
+ struct PendingRelease {
+ PendingRelease()
+ : isPending(false)
+ , currentTexture(-1)
+ , graphicBuffer()
+ , display(nullptr)
+ , fence(nullptr) {}
+
+ bool isPending;
+ int currentTexture;
+ sp<GraphicBuffer> graphicBuffer;
+ EGLDisplay display;
+ EGLSyncKHR fence;
+ };
+
+ /**
+ * This releases the buffer in the slot referenced by mCurrentTexture,
+ * then updates state to refer to the BufferItem, which must be a
+ * newly-acquired buffer. If pendingRelease is not null, the parameters
+ * which would have been passed to releaseBufferLocked upon the successful
+ * completion of the method will instead be returned to the caller, so that
+ * it may call releaseBufferLocked itself later.
+ */
+ status_t updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
+ SurfaceTexture& st);
+
+ /**
+ * Binds mTexName and the current buffer to mTexTarget. Uses
+ * mCurrentTexture if it's set, mCurrentTextureImage if not. If the
+ * bind succeeds, this calls doGLFenceWait.
+ */
+ status_t bindTextureImageLocked(SurfaceTexture& st);
+
+ /**
+ * Gets the current EGLDisplay and EGLContext values, and compares them
+ * to mEglDisplay and mEglContext. If the fields have been previously
+ * set, the values must match; if not, the fields are set to the current
+ * values.
+ * The contextCheck argument is used to ensure that a GL context is
+ * properly set; when set to false, the check is not performed.
+ */
+ status_t checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck = false);
+
+ /**
+ * EglImage is a utility class for tracking and creating EGLImageKHRs. There
+ * is primarily just one image per slot, but there is also special cases:
+ * - For releaseTexImage, we use a debug image (mReleasedTexImage)
+ * - After freeBuffer, we must still keep the current image/buffer
+ * Reference counting EGLImages lets us handle all these cases easily while
+ * also only creating new EGLImages from buffers when required.
+ */
+ class EglImage : public LightRefBase<EglImage> {
+ public:
+ EglImage(sp<GraphicBuffer> graphicBuffer);
+
+ /**
+ * createIfNeeded creates an EGLImage if required (we haven't created
+ * one yet, or the EGLDisplay or crop-rect has changed).
+ */
+ status_t createIfNeeded(EGLDisplay display, bool forceCreate = false);
+
+ /**
+ * This calls glEGLImageTargetTexture2DOES to bind the image to the
+ * texture in the specified texture target.
+ */
+ void bindToTextureTarget(uint32_t texTarget);
+
+ const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+ const native_handle* graphicBufferHandle() {
+ return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
+ }
+
+ private:
+ // Only allow instantiation using ref counting.
+ friend class LightRefBase<EglImage>;
+ virtual ~EglImage();
+
+ // createImage creates a new EGLImage from a GraphicBuffer.
+ EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer);
+
+ // Disallow copying
+ EglImage(const EglImage& rhs);
+ void operator=(const EglImage& rhs);
+
+ // mGraphicBuffer is the buffer that was used to create this image.
+ sp<GraphicBuffer> mGraphicBuffer;
+
+ // mEglImage is the EGLImage created from mGraphicBuffer.
+ EGLImageKHR mEglImage;
+
+ // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
+ EGLDisplay mEglDisplay;
+
+ // mCropRect is the crop rectangle passed to EGL when mEglImage
+ // was created.
+ Rect mCropRect;
+ };
+
+ /**
+ * doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
+ * stream to ensure that it is safe for future OpenGL ES commands to
+ * access the current texture buffer.
+ */
+ status_t doGLFenceWaitLocked(SurfaceTexture& st) const;
+
+ /**
+ * syncForReleaseLocked performs the synchronization needed to release the
+ * current slot from an OpenGL ES context. If needed it will set the
+ * current slot's fence to guard against a producer accessing the buffer
+ * before the outstanding accesses have completed.
+ */
+ status_t syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st);
+
+ /**
+ * returns a graphic buffer used when the texture image has been released
+ */
+ static sp<GraphicBuffer> getDebugTexImageBuffer();
+
+ /**
+ * The default consumer usage flags that EGLConsumer always sets on its
+ * BufferQueue instance; these will be OR:d with any additional flags passed
+ * from the EGLConsumer user. In particular, EGLConsumer will always
+ * consume buffers as hardware textures.
+ */
+ static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+
+ /**
+ * mCurrentTextureImage is the EglImage/buffer of the current texture. It's
+ * possible that this buffer is not associated with any buffer slot, so we
+ * must track it separately in order to support the getCurrentBuffer method.
+ */
+ sp<EglImage> mCurrentTextureImage;
+
+ /**
+ * EGLSlot contains the information and object references that
+ * EGLConsumer maintains about a BufferQueue buffer slot.
+ */
+ struct EglSlot {
+ EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
+
+ /**
+ * mEglImage is the EGLImage created from mGraphicBuffer.
+ */
+ sp<EglImage> mEglImage;
+
+ /**
+ * mFence is the EGL sync object that must signal before the buffer
+ * associated with this buffer slot may be dequeued. It is initialized
+ * to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+ * on a compile-time option) set to a new sync object in updateTexImage.
+ */
+ EGLSyncKHR mEglFence;
+ };
+
+ /**
+ * mEglDisplay is the EGLDisplay with which this EGLConsumer is currently
+ * associated. It is intialized to EGL_NO_DISPLAY and gets set to the
+ * current display when updateTexImage is called for the first time and when
+ * attachToContext is called.
+ */
+ EGLDisplay mEglDisplay;
+
+ /**
+ * mEglContext is the OpenGL ES context with which this EGLConsumer is
+ * currently associated. It is initialized to EGL_NO_CONTEXT and gets set
+ * to the current GL context when updateTexImage is called for the first
+ * time and when attachToContext is called.
+ */
+ EGLContext mEglContext;
+
+ /**
+ * mEGLSlots stores the buffers that have been allocated by the BufferQueue
+ * for each buffer slot. It is initialized to null pointers, and gets
+ * filled in with the result of BufferQueue::acquire when the
+ * client dequeues a buffer from a
+ * slot that has not yet been used. The buffer allocated to a slot will also
+ * be replaced if the requested buffer usage or geometry differs from that
+ * of the buffer allocated to a slot.
+ */
+ EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
+ /**
+ * protects static initialization
+ */
+ static Mutex sStaticInitLock;
+
+ /**
+ * mReleasedTexImageBuffer is a dummy buffer used when in single buffer
+ * mode and releaseTexImage() has been called
+ */
+ static sp<GraphicBuffer> sReleasedTexImageBuffer;
+ sp<EglImage> mReleasedTexImage;
+};
+
+}; // namespace android
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
new file mode 100644
index 000000000000..c86cd962ebed
--- /dev/null
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 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 "ImageConsumer.h"
+#include <gui/BufferQueue.h>
+#include "Properties.h"
+#include "SurfaceTexture.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/RenderThread.h"
+#include "renderthread/VulkanManager.h"
+
+// Macro for including the SurfaceTexture name in log messages
+#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+void ImageConsumer::onFreeBufferLocked(int slotIndex) {
+ mImageSlots[slotIndex].mImage.reset();
+}
+
+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();
+ }
+}
+
+void ImageConsumer::onReleaseBufferLocked(int buf) {
+ mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+}
+
+void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer) {
+ if (!mImage.get()) {
+ mImage = graphicBuffer.get()
+ ? SkImage::MakeFromAHardwareBuffer(
+ reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
+ kPremul_SkAlphaType, SkColorSpace::MakeSRGB())
+ : nullptr;
+ }
+}
+
+sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
+ uirenderer::RenderState& renderState) {
+ BufferItem item;
+ status_t err;
+ err = st.acquireBufferLocked(&item, 0);
+ if (err != OK) {
+ if (err != BufferQueue::NO_BUFFER_AVAILABLE) {
+ IMG_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+ } else {
+ int slot = st.mCurrentTexture;
+ if (slot != BufferItem::INVALID_BUFFER_SLOT) {
+ *queueEmpty = true;
+ mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer);
+ return mImageSlots[slot].mImage;
+ }
+ }
+ return nullptr;
+ }
+
+ int slot = item.mSlot;
+ if (item.mFence->isValid()) {
+ // Wait on the producer fence for the buffer to be ready.
+ if (uirenderer::Properties::getRenderPipelineType() ==
+ uirenderer::RenderPipelineType::SkiaGL) {
+ err = renderState.getRenderThread().eglManager().fenceWait(item.mFence);
+ } else {
+ err = renderState.getRenderThread().vulkanManager().fenceWait(item.mFence);
+ }
+ if (err != OK) {
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR);
+ return nullptr;
+ }
+ }
+
+ // Release old buffer.
+ if (st.mCurrentTexture != BufferItem::INVALID_BUFFER_SLOT) {
+ // If needed, set the released slot's fence to guard against a producer accessing the
+ // buffer before the outstanding accesses have completed.
+ sp<Fence> releaseFence;
+ EGLDisplay display = EGL_NO_DISPLAY;
+ if (uirenderer::Properties::getRenderPipelineType() ==
+ uirenderer::RenderPipelineType::SkiaGL) {
+ auto& eglManager = renderState.getRenderThread().eglManager();
+ display = eglManager.eglDisplay();
+ err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].mEglFence,
+ releaseFence);
+ } else {
+ err = renderState.getRenderThread().vulkanManager().createReleaseFence(releaseFence);
+ }
+ if (OK != err) {
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR);
+ return nullptr;
+ }
+
+ if (releaseFence.get()) {
+ status_t err = st.addReleaseFenceLocked(
+ st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, releaseFence);
+ if (err != OK) {
+ IMG_LOGE("dequeueImage: error adding release fence: %s (%d)", strerror(-err), err);
+ st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR);
+ return nullptr;
+ }
+ }
+
+ // Finally release the old buffer.
+ status_t status = st.releaseBufferLocked(
+ st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display,
+ mImageSlots[st.mCurrentTexture].mEglFence);
+ if (status < NO_ERROR) {
+ IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status);
+ err = status;
+ // Keep going, with error raised.
+ }
+ }
+
+ // Update the state.
+ st.mCurrentTexture = slot;
+ st.mCurrentCrop = item.mCrop;
+ st.mCurrentTransform = item.mTransform;
+ st.mCurrentScalingMode = item.mScalingMode;
+ st.mCurrentTimestamp = item.mTimestamp;
+ st.mCurrentDataSpace = item.mDataSpace;
+ st.mCurrentFence = item.mFence;
+ st.mCurrentFenceTime = item.mFenceTime;
+ st.mCurrentFrameNumber = item.mFrameNumber;
+ st.computeCurrentTransformMatrixLocked();
+
+ *queueEmpty = false;
+ mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer);
+ return mImageSlots[slot].mImage;
+}
+
+} /* namespace android */
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
new file mode 100644
index 000000000000..31ee8db52874
--- /dev/null
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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 <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueueDefs.h>
+
+#include <SkImage.h>
+#include <cutils/compiler.h>
+#include <gui/BufferItem.h>
+#include <system/graphics.h>
+
+namespace android {
+
+namespace uirenderer {
+class RenderState;
+}
+
+class SurfaceTexture;
+
+/*
+ * ImageConsumer implements the parts of SurfaceTexture that deal with
+ * images consumed by HWUI view system.
+ */
+class ImageConsumer {
+public:
+ sk_sp<SkImage> dequeueImage(bool* queueEmpty, SurfaceTexture& cb,
+ uirenderer::RenderState& renderState);
+
+ /**
+ * onAcquireBufferLocked amends the ConsumerBase method to update the
+ * mImageSlots array in addition to the ConsumerBase behavior.
+ */
+ void onAcquireBufferLocked(BufferItem* item);
+
+ /**
+ * onReleaseBufferLocked amends the ConsumerBase method to update the
+ * mImageSlots array in addition to the ConsumerBase.
+ */
+ void onReleaseBufferLocked(int slot);
+
+ /**
+ * onFreeBufferLocked frees up the given buffer slot. If the slot has been
+ * initialized this will release the reference to the GraphicBuffer in that
+ * slot and destroy the SkImage in that slot. Otherwise it has no effect.
+ */
+ void onFreeBufferLocked(int slotIndex);
+
+private:
+ /**
+ * ImageSlot contains the information and object references that
+ * ImageConsumer maintains about a BufferQueue buffer slot.
+ */
+ struct ImageSlot {
+ ImageSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
+
+ // mImage is the SkImage created from mGraphicBuffer.
+ sk_sp<SkImage> mImage;
+
+ /**
+ * mEglFence is the EGL sync object that must signal before the buffer
+ * associated with this buffer slot may be dequeued.
+ */
+ EGLSyncKHR mEglFence;
+
+ void createIfNeeded(sp<GraphicBuffer> graphicBuffer);
+ };
+
+ /**
+ * ImageConsumer stores the SkImages that have been allocated by the BufferQueue
+ * for each buffer slot. It is initialized to null pointers, and gets
+ * filled in with the result of BufferQueue::acquire when the
+ * client dequeues a buffer from a
+ * slot that has not yet been used. The buffer allocated to a slot will also
+ * be replaced if the requested buffer usage or geometry differs from that
+ * of the buffer allocated to a slot.
+ */
+ ImageSlot mImageSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
+};
+
+}; /* namespace android */
diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp
new file mode 100644
index 000000000000..4bff715822e8
--- /dev/null
+++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2018 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 <cutils/compiler.h>
+#include <gui/BufferQueue.h>
+#include <math/mat4.h>
+#include <system/window.h>
+
+#include <utils/Trace.h>
+
+#include "Matrix.h"
+#include "SurfaceTexture.h"
+
+namespace android {
+
+// Macros for including the SurfaceTexture name in log messages
+#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+
+static const mat4 mtxIdentity;
+
+SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
+ uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
+ : ConsumerBase(bq, isControlledByApp)
+ , mCurrentCrop(Rect::EMPTY_RECT)
+ , mCurrentTransform(0)
+ , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE)
+ , mCurrentFence(Fence::NO_FENCE)
+ , mCurrentTimestamp(0)
+ , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN)
+ , mCurrentFrameNumber(0)
+ , mDefaultWidth(1)
+ , mDefaultHeight(1)
+ , mFilteringEnabled(true)
+ , mTexName(tex)
+ , mUseFenceSync(useFenceSync)
+ , mTexTarget(texTarget)
+ , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
+ , mOpMode(OpMode::attachedToGL) {
+ SFT_LOGV("SurfaceTexture");
+
+ memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
+
+ mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+}
+
+SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
+ bool useFenceSync, bool isControlledByApp)
+ : ConsumerBase(bq, isControlledByApp)
+ , mCurrentCrop(Rect::EMPTY_RECT)
+ , mCurrentTransform(0)
+ , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE)
+ , mCurrentFence(Fence::NO_FENCE)
+ , mCurrentTimestamp(0)
+ , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN)
+ , mCurrentFrameNumber(0)
+ , mDefaultWidth(1)
+ , mDefaultHeight(1)
+ , mFilteringEnabled(true)
+ , mTexName(0)
+ , mUseFenceSync(useFenceSync)
+ , mTexTarget(texTarget)
+ , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
+ , mOpMode(OpMode::detached) {
+ SFT_LOGV("SurfaceTexture");
+
+ memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
+
+ mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+}
+
+status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) {
+ Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ SFT_LOGE("setDefaultBufferSize: SurfaceTexture is abandoned!");
+ return NO_INIT;
+ }
+ mDefaultWidth = w;
+ mDefaultHeight = h;
+ return mConsumer->setDefaultBufferSize(w, h);
+}
+
+status_t SurfaceTexture::updateTexImage() {
+ ATRACE_CALL();
+ SFT_LOGV("updateTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ SFT_LOGE("updateTexImage: SurfaceTexture is abandoned!");
+ return NO_INIT;
+ }
+
+ return mEGLConsumer.updateTexImage(*this);
+}
+
+status_t SurfaceTexture::releaseTexImage() {
+ // releaseTexImage can be invoked even when not attached to a GL context.
+ ATRACE_CALL();
+ SFT_LOGV("releaseTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ SFT_LOGE("releaseTexImage: SurfaceTexture is abandoned!");
+ return NO_INIT;
+ }
+
+ return mEGLConsumer.releaseTexImage(*this);
+}
+
+status_t SurfaceTexture::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber) {
+ status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ switch (mOpMode) {
+ case OpMode::attachedToView:
+ mImageConsumer.onAcquireBufferLocked(item);
+ break;
+ case OpMode::attachedToGL:
+ mEGLConsumer.onAcquireBufferLocked(item, *this);
+ break;
+ case OpMode::detached:
+ break;
+ }
+
+ return NO_ERROR;
+}
+
+status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer,
+ EGLDisplay display, EGLSyncKHR eglFence) {
+ // release the buffer if it hasn't already been discarded by the
+ // BufferQueue. This can happen, for example, when the producer of this
+ // 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.
+ mImageConsumer.onReleaseBufferLocked(buf);
+ mEGLConsumer.onReleaseBufferLocked(buf);
+ return err;
+}
+
+status_t SurfaceTexture::detachFromContext() {
+ ATRACE_CALL();
+ SFT_LOGV("detachFromContext");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ SFT_LOGE("detachFromContext: abandoned SurfaceTexture");
+ return NO_INIT;
+ }
+
+ if (mOpMode != OpMode::attachedToGL) {
+ SFT_LOGE("detachFromContext: SurfaceTexture is not attached to a GL context");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mEGLConsumer.detachFromContext(*this);
+ if (err == OK) {
+ mOpMode = OpMode::detached;
+ }
+
+ return err;
+}
+
+status_t SurfaceTexture::attachToContext(uint32_t tex) {
+ ATRACE_CALL();
+ SFT_LOGV("attachToContext");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ SFT_LOGE("attachToContext: abandoned SurfaceTexture");
+ return NO_INIT;
+ }
+
+ if (mOpMode != OpMode::detached) {
+ SFT_LOGE(
+ "attachToContext: SurfaceTexture is already attached to a "
+ "context");
+ return INVALID_OPERATION;
+ }
+
+ if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ // release possible ImageConsumer cache
+ mImageConsumer.onFreeBufferLocked(mCurrentTexture);
+ }
+
+ return mEGLConsumer.attachToContext(tex, *this);
+}
+
+void SurfaceTexture::attachToView() {
+ ATRACE_CALL();
+ Mutex::Autolock _l(mMutex);
+ if (mAbandoned) {
+ SFT_LOGE("attachToView: abandoned SurfaceTexture");
+ return;
+ }
+ if (mOpMode == OpMode::detached) {
+ mOpMode = OpMode::attachedToView;
+
+ if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ // release possible EGLConsumer texture cache
+ mEGLConsumer.onFreeBufferLocked(mCurrentTexture);
+ mEGLConsumer.onAbandonLocked();
+ }
+ } else {
+ SFT_LOGE("attachToView: already attached");
+ }
+}
+
+void SurfaceTexture::detachFromView() {
+ ATRACE_CALL();
+ Mutex::Autolock _l(mMutex);
+
+ if (mAbandoned) {
+ SFT_LOGE("detachFromView: abandoned SurfaceTexture");
+ return;
+ }
+
+ if (mOpMode == OpMode::attachedToView) {
+ mOpMode = OpMode::detached;
+ } else {
+ SFT_LOGE("detachFromView: not attached to View");
+ }
+}
+
+uint32_t SurfaceTexture::getCurrentTextureTarget() const {
+ return mTexTarget;
+}
+
+void SurfaceTexture::getTransformMatrix(float mtx[16]) {
+ Mutex::Autolock lock(mMutex);
+ memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void SurfaceTexture::setFilteringEnabled(bool enabled) {
+ Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ SFT_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!");
+ return;
+ }
+ bool needsRecompute = mFilteringEnabled != enabled;
+ mFilteringEnabled = enabled;
+
+ if (needsRecompute && mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
+ SFT_LOGD("setFilteringEnabled called with no current item");
+ }
+
+ if (needsRecompute && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ computeCurrentTransformMatrixLocked();
+ }
+}
+
+void SurfaceTexture::computeCurrentTransformMatrixLocked() {
+ SFT_LOGV("computeCurrentTransformMatrixLocked");
+ sp<GraphicBuffer> buf = (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
+ ? nullptr
+ : mSlots[mCurrentTexture].mGraphicBuffer;
+ if (buf == nullptr) {
+ SFT_LOGD("computeCurrentTransformMatrixLocked: no current item");
+ }
+ computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop, mCurrentTransform,
+ mFilteringEnabled);
+}
+
+void SurfaceTexture::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf,
+ const Rect& cropRect, uint32_t transform,
+ bool filtering) {
+ // Transform matrices
+ static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+ static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
+ static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+
+ mat4 xform;
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ xform *= mtxFlipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ xform *= mtxFlipV;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ xform *= mtxRot90;
+ }
+
+ if (!cropRect.isEmpty() && buf.get()) {
+ float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
+ float bufferWidth = buf->getWidth();
+ float bufferHeight = buf->getHeight();
+ float shrinkAmount = 0.0f;
+ if (filtering) {
+ // In order to prevent bilinear sampling beyond the edge of the
+ // crop rectangle we may need to shrink it by 2 texels in each
+ // dimension. Normally this would just need to take 1/2 a texel
+ // off each end, but because the chroma channels of YUV420 images
+ // are subsampled we may need to shrink the crop region by a whole
+ // texel on each side.
+ switch (buf->getPixelFormat()) {
+ case PIXEL_FORMAT_RGBA_8888:
+ case PIXEL_FORMAT_RGBX_8888:
+ case PIXEL_FORMAT_RGBA_FP16:
+ case PIXEL_FORMAT_RGBA_1010102:
+ case PIXEL_FORMAT_RGB_888:
+ case PIXEL_FORMAT_RGB_565:
+ case PIXEL_FORMAT_BGRA_8888:
+ // We know there's no subsampling of any channels, so we
+ // only need to shrink by a half a pixel.
+ shrinkAmount = 0.5;
+ break;
+
+ default:
+ // If we don't recognize the format, we must assume the
+ // worst case (that we care about), which is YUV420.
+ shrinkAmount = 1.0;
+ break;
+ }
+ }
+
+ // Only shrink the dimensions that are not the size of the buffer.
+ if (cropRect.width() < bufferWidth) {
+ tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+ sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth;
+ }
+ if (cropRect.height() < bufferHeight) {
+ ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight;
+ sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight;
+ }
+
+ mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1);
+ xform = crop * xform;
+ }
+
+ // SurfaceFlinger expects the top of its window textures to be at a Y
+ // coordinate of 0, so SurfaceTexture must behave the same way. We don't
+ // want to expose this to applications, however, so we must add an
+ // additional vertical flip to the transform after all the other transforms.
+ xform = mtxFlipV * xform;
+
+ memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+Rect SurfaceTexture::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
+ Rect outCrop = crop;
+
+ uint32_t newWidth = static_cast<uint32_t>(crop.width());
+ uint32_t newHeight = static_cast<uint32_t>(crop.height());
+
+ if (newWidth * bufferHeight > newHeight * bufferWidth) {
+ newWidth = newHeight * bufferWidth / bufferHeight;
+ ALOGV("too wide: newWidth = %d", newWidth);
+ } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
+ newHeight = newWidth * bufferHeight / bufferWidth;
+ ALOGV("too tall: newHeight = %d", newHeight);
+ }
+
+ uint32_t currentWidth = static_cast<uint32_t>(crop.width());
+ uint32_t currentHeight = static_cast<uint32_t>(crop.height());
+
+ // The crop is too wide
+ if (newWidth < currentWidth) {
+ uint32_t dw = currentWidth - newWidth;
+ auto halfdw = dw / 2;
+ outCrop.left += halfdw;
+ // Not halfdw because it would subtract 1 too few when dw is odd
+ outCrop.right -= (dw - halfdw);
+ // The crop is too tall
+ } else if (newHeight < currentHeight) {
+ uint32_t dh = currentHeight - newHeight;
+ auto halfdh = dh / 2;
+ outCrop.top += halfdh;
+ // Not halfdh because it would subtract 1 too few when dh is odd
+ outCrop.bottom -= (dh - halfdh);
+ }
+
+ ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
+ outCrop.bottom);
+
+ return outCrop;
+}
+
+nsecs_t SurfaceTexture::getTimestamp() {
+ SFT_LOGV("getTimestamp");
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTimestamp;
+}
+
+android_dataspace SurfaceTexture::getCurrentDataSpace() {
+ SFT_LOGV("getCurrentDataSpace");
+ Mutex::Autolock lock(mMutex);
+ return mCurrentDataSpace;
+}
+
+uint64_t SurfaceTexture::getFrameNumber() {
+ SFT_LOGV("getFrameNumber");
+ Mutex::Autolock lock(mMutex);
+ return mCurrentFrameNumber;
+}
+
+Rect SurfaceTexture::getCurrentCrop() const {
+ Mutex::Autolock lock(mMutex);
+ return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+ ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+ : mCurrentCrop;
+}
+
+uint32_t SurfaceTexture::getCurrentTransform() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTransform;
+}
+
+uint32_t SurfaceTexture::getCurrentScalingMode() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentScalingMode;
+}
+
+sp<Fence> SurfaceTexture::getCurrentFence() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentFence;
+}
+
+std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentFenceTime;
+}
+
+void SurfaceTexture::freeBufferLocked(int slotIndex) {
+ SFT_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+ if (slotIndex == mCurrentTexture) {
+ mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
+ }
+ // The slotIndex buffer could have EGL or SkImage cache, but there is no way to tell for sure.
+ // Buffers can be freed after SurfaceTexture has detached from GL context or View.
+ mImageConsumer.onFreeBufferLocked(slotIndex);
+ mEGLConsumer.onFreeBufferLocked(slotIndex);
+ ConsumerBase::freeBufferLocked(slotIndex);
+}
+
+void SurfaceTexture::abandonLocked() {
+ SFT_LOGV("abandonLocked");
+ mEGLConsumer.onAbandonLocked();
+ ConsumerBase::abandonLocked();
+}
+
+status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) {
+ return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
+}
+
+void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const {
+ result.appendFormat(
+ "%smTexName=%d mCurrentTexture=%d\n"
+ "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
+ prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top,
+ mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform);
+
+ ConsumerBase::dumpLocked(result, prefix);
+}
+
+sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace,
+ bool* queueEmpty,
+ uirenderer::RenderState& renderState) {
+ Mutex::Autolock _l(mMutex);
+
+ if (mAbandoned) {
+ SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!");
+ return nullptr;
+ }
+
+ if (mOpMode != OpMode::attachedToView) {
+ SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View");
+ return nullptr;
+ }
+
+ auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState);
+ if (image.get()) {
+ uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix);
+ dataSpace = mCurrentDataSpace;
+ }
+ return image;
+}
+
+}; // namespace android
diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h
new file mode 100644
index 000000000000..db392a9f8476
--- /dev/null
+++ b/libs/hwui/surfacetexture/SurfaceTexture.h
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2018 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 <gui/BufferQueueDefs.h>
+#include <gui/ConsumerBase.h>
+
+#include <ui/FenceTime.h>
+#include <ui/GraphicBuffer.h>
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+
+#include "EGLConsumer.h"
+#include "ImageConsumer.h"
+
+namespace android {
+
+namespace uirenderer {
+class RenderState;
+}
+
+/*
+ * SurfaceTexture consumes buffers of graphics data from a BufferQueue,
+ * and makes them available to HWUI render thread as a SkImage and to
+ * an application GL render thread as an OpenGL texture.
+ *
+ * When attached to an application GL render thread, a typical usage
+ * pattern is to set up the SurfaceTexture with the
+ * desired options, and call updateTexImage() when a new frame is desired.
+ * If a new frame is available, the texture will be updated. If not,
+ * the previous contents are retained.
+ *
+ * When attached to a HWUI render thread, the TextureView implementation
+ * calls dequeueImage, which either pulls a new SkImage or returns the
+ * last cached SkImage if BufferQueue is empty.
+ * When attached to HWUI render thread, SurfaceTexture is compatible to
+ * both Vulkan and GL drawing pipelines.
+ */
+class ANDROID_API SurfaceTexture : public ConsumerBase {
+public:
+ enum { TEXTURE_EXTERNAL = 0x8D65 }; // GL_TEXTURE_EXTERNAL_OES
+ typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
+
+ /**
+ * SurfaceTexture constructs a new SurfaceTexture object. If the constructor with
+ * the tex parameter is used, tex indicates the name of the OpenGL ES
+ * texture to which images are to be streamed. texTarget specifies the
+ * OpenGL ES texture target to which the texture will be bound in
+ * updateTexImage. useFenceSync specifies whether fences should be used to
+ * synchronize access to buffers if that behavior is enabled at
+ * compile-time.
+ *
+ * A SurfaceTexture may be detached from one OpenGL ES context and then
+ * attached to a different context using the detachFromContext and
+ * attachToContext methods, respectively. The intention of these methods is
+ * purely to allow a SurfaceTexture to be transferred from one consumer
+ * context to another. If such a transfer is not needed there is no
+ * requirement that either of these methods be called.
+ *
+ * If the constructor with the tex parameter is used, the SurfaceTexture is
+ * created in a state where it is considered attached to an OpenGL ES
+ * context for the purposes of the attachToContext and detachFromContext
+ * methods. However, despite being considered "attached" to a context, the
+ * specific OpenGL ES context doesn't get latched until the first call to
+ * updateTexImage. After that point, all calls to updateTexImage must be
+ * made with the same OpenGL ES context current.
+ *
+ * If the constructor without the tex parameter is used, the SurfaceTexture is
+ * created in a detached state, and attachToContext must be called before
+ * calls to updateTexImage.
+ */
+ SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texureTarget,
+ bool useFenceSync, bool isControlledByApp);
+
+ SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texureTarget, bool useFenceSync,
+ bool isControlledByApp);
+
+ /**
+ * updateTexImage acquires the most recently queued buffer, and sets the
+ * image contents of the target texture to it.
+ *
+ * This call may only be made while the OpenGL ES context to which the
+ * target texture belongs is bound to the calling thread.
+ *
+ * This calls doGLFenceWait to ensure proper synchronization.
+ */
+ status_t updateTexImage();
+
+ /**
+ * releaseTexImage releases the texture acquired in updateTexImage().
+ * This is intended to be used in single buffer mode.
+ *
+ * This call may only be made while the OpenGL ES context to which the
+ * target texture belongs is bound to the calling thread.
+ */
+ status_t releaseTexImage();
+
+ /**
+ * getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
+ * associated with the texture image set by the most recent call to
+ * updateTexImage.
+ *
+ * This transform matrix maps 2D homogeneous texture coordinates of the form
+ * (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture
+ * coordinate that should be used to sample that location from the texture.
+ * Sampling the texture outside of the range of this transform is undefined.
+ *
+ * This transform is necessary to compensate for transforms that the stream
+ * content producer may implicitly apply to the content. By forcing users of
+ * a SurfaceTexture to apply this transform we avoid performing an extra
+ * copy of the data that would be needed to hide the transform from the
+ * user.
+ *
+ * The matrix is stored in column-major order so that it may be passed
+ * directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv
+ * functions.
+ */
+ void getTransformMatrix(float mtx[16]);
+
+ /**
+ * Computes the transform matrix documented by getTransformMatrix
+ * from the BufferItem sub parts.
+ */
+ static void computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf,
+ const Rect& cropRect, uint32_t transform, bool filtering);
+
+ /**
+ * Scale the crop down horizontally or vertically such that it has the
+ * same aspect ratio as the buffer does.
+ */
+ static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+
+ /**
+ * getTimestamp retrieves the timestamp associated with the texture image
+ * set by the most recent call to updateTexImage.
+ *
+ * The timestamp is in nanoseconds, and is monotonically increasing. Its
+ * other semantics (zero point, etc) are source-dependent and should be
+ * documented by the source.
+ */
+ int64_t getTimestamp();
+
+ /**
+ * getDataSpace retrieves the DataSpace associated with the texture image
+ * set by the most recent call to updateTexImage.
+ */
+ android_dataspace getCurrentDataSpace();
+
+ /**
+ * getFrameNumber retrieves the frame number associated with the texture
+ * image set by the most recent call to updateTexImage.
+ *
+ * The frame number is an incrementing counter set to 0 at the creation of
+ * the BufferQueue associated with this consumer.
+ */
+ uint64_t getFrameNumber();
+
+ /**
+ * setDefaultBufferSize is used to set the size of buffers returned by
+ * requestBuffers when a with and height of zero is requested.
+ * A call to setDefaultBufferSize() may trigger requestBuffers() to
+ * be called from the client.
+ * The width and height parameters must be no greater than the minimum of
+ * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+ * An error due to invalid dimensions might not be reported until
+ * updateTexImage() is called.
+ */
+ status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+ /**
+ * setFilteringEnabled sets whether the transform matrix should be computed
+ * for use with bilinear filtering.
+ */
+ void setFilteringEnabled(bool enabled);
+
+ /**
+ * getCurrentTextureTarget returns the texture target of the current
+ * texture as returned by updateTexImage().
+ */
+ uint32_t getCurrentTextureTarget() const;
+
+ /**
+ * getCurrentCrop returns the cropping rectangle of the current buffer.
+ */
+ Rect getCurrentCrop() const;
+
+ /**
+ * getCurrentTransform returns the transform of the current buffer.
+ */
+ uint32_t getCurrentTransform() const;
+
+ /**
+ * getCurrentScalingMode returns the scaling mode of the current buffer.
+ */
+ uint32_t getCurrentScalingMode() const;
+
+ /**
+ * getCurrentFence returns the fence indicating when the current buffer is
+ * ready to be read from.
+ */
+ sp<Fence> getCurrentFence() const;
+
+ /**
+ * getCurrentFence returns the FenceTime indicating when the current
+ * buffer is ready to be read from.
+ */
+ std::shared_ptr<FenceTime> getCurrentFenceTime() const;
+
+ /**
+ * setConsumerUsageBits overrides the ConsumerBase method to OR
+ * DEFAULT_USAGE_FLAGS to usage.
+ */
+ status_t setConsumerUsageBits(uint64_t usage);
+
+ /**
+ * detachFromContext detaches the SurfaceTexture from the calling thread's
+ * current OpenGL ES context. This context must be the same as the context
+ * that was current for previous calls to updateTexImage.
+ *
+ * Detaching a SurfaceTexture from an OpenGL ES context will result in the
+ * deletion of the OpenGL ES texture object into which the images were being
+ * streamed. After a SurfaceTexture has been detached from the OpenGL ES
+ * context calls to updateTexImage will fail returning INVALID_OPERATION
+ * until the SurfaceTexture is attached to a new OpenGL ES context using the
+ * attachToContext method.
+ */
+ status_t detachFromContext();
+
+ /**
+ * attachToContext attaches a SurfaceTexture that is currently in the
+ * 'detached' state to the current OpenGL ES context. A SurfaceTexture is
+ * in the 'detached' state iff detachFromContext has successfully been
+ * called and no calls to attachToContext have succeeded since the last
+ * detachFromContext call. Calls to attachToContext made on a
+ * SurfaceTexture that is not in the 'detached' state will result in an
+ * INVALID_OPERATION error.
+ *
+ * The tex argument specifies the OpenGL ES texture object name in the
+ * new context into which the image contents will be streamed. A successful
+ * call to attachToContext will result in this texture object being bound to
+ * the texture target and populated with the image contents that were
+ * current at the time of the last call to detachFromContext.
+ */
+ status_t attachToContext(uint32_t tex);
+
+ sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace,
+ bool* queueEmpty, uirenderer::RenderState& renderState);
+
+ /**
+ * attachToView attaches a SurfaceTexture that is currently in the
+ * 'detached' state to HWUI View system.
+ */
+ void attachToView();
+
+ /**
+ * detachFromView detaches a SurfaceTexture from HWUI View system.
+ */
+ void detachFromView();
+
+protected:
+ /**
+ * abandonLocked overrides the ConsumerBase method to clear
+ * mCurrentTextureImage in addition to the ConsumerBase behavior.
+ */
+ virtual void abandonLocked();
+
+ /**
+ * dumpLocked overrides the ConsumerBase method to dump SurfaceTexture-
+ * specific info in addition to the ConsumerBase behavior.
+ */
+ virtual void dumpLocked(String8& result, const char* prefix) const override;
+
+ /**
+ * acquireBufferLocked overrides the ConsumerBase method to update the
+ * mEglSlots array in addition to the ConsumerBase behavior.
+ */
+ virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) override;
+
+ /**
+ * releaseBufferLocked overrides the ConsumerBase method to update the
+ * mEglSlots array in addition to the ConsumerBase.
+ */
+ virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer,
+ EGLDisplay display, EGLSyncKHR eglFence) override;
+
+ /**
+ * freeBufferLocked frees up the given buffer slot. If the slot has been
+ * initialized this will release the reference to the GraphicBuffer in that
+ * slot and destroy the EGLImage in that slot. Otherwise it has no effect.
+ *
+ * This method must be called with mMutex locked.
+ */
+ virtual void freeBufferLocked(int slotIndex);
+
+ /**
+ * computeCurrentTransformMatrixLocked computes the transform matrix for the
+ * current texture. It uses mCurrentTransform and the current GraphicBuffer
+ * to compute this matrix and stores it in mCurrentTransformMatrix.
+ * mCurrentTextureImage must not be NULL.
+ */
+ void computeCurrentTransformMatrixLocked();
+
+ /**
+ * The default consumer usage flags that SurfaceTexture always sets on its
+ * BufferQueue instance; these will be OR:d with any additional flags passed
+ * from the SurfaceTexture user. In particular, SurfaceTexture will always
+ * consume buffers as hardware textures.
+ */
+ static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+
+ /**
+ * mCurrentCrop is the crop rectangle that applies to the current texture.
+ * It gets set each time updateTexImage is called.
+ */
+ Rect mCurrentCrop;
+
+ /**
+ * mCurrentTransform is the transform identifier for the current texture. It
+ * gets set each time updateTexImage is called.
+ */
+ uint32_t mCurrentTransform;
+
+ /**
+ * mCurrentScalingMode is the scaling mode for the current texture. It gets
+ * set each time updateTexImage is called.
+ */
+ uint32_t mCurrentScalingMode;
+
+ /**
+ * mCurrentFence is the fence received from BufferQueue in updateTexImage.
+ */
+ sp<Fence> mCurrentFence;
+
+ /**
+ * The FenceTime wrapper around mCurrentFence.
+ */
+ std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE};
+
+ /**
+ * mCurrentTransformMatrix is the transform matrix for the current texture.
+ * It gets computed by computeTransformMatrix each time updateTexImage is
+ * called.
+ */
+ float mCurrentTransformMatrix[16];
+
+ /**
+ * mCurrentTimestamp is the timestamp for the current texture. It
+ * gets set each time updateTexImage is called.
+ */
+ int64_t mCurrentTimestamp;
+
+ /**
+ * mCurrentDataSpace is the dataspace for the current texture. It
+ * gets set each time updateTexImage is called.
+ */
+ android_dataspace mCurrentDataSpace;
+
+ /**
+ * mCurrentFrameNumber is the frame counter for the current texture.
+ * It gets set each time updateTexImage is called.
+ */
+ uint64_t mCurrentFrameNumber;
+
+ uint32_t mDefaultWidth, mDefaultHeight;
+
+ /**
+ * mFilteringEnabled indicates whether the transform matrix is computed for
+ * use with bilinear filtering. It defaults to true and is changed by
+ * setFilteringEnabled().
+ */
+ bool mFilteringEnabled;
+
+ /**
+ * mTexName is the name of the OpenGL texture to which streamed images will
+ * be bound when updateTexImage is called. It is set at construction time
+ * and can be changed with a call to attachToContext.
+ */
+ uint32_t mTexName;
+
+ /**
+ * mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
+ * extension should be used to prevent buffers from being dequeued before
+ * it's safe for them to be written. It gets set at construction time and
+ * never changes.
+ */
+ const bool mUseFenceSync;
+
+ /**
+ * mTexTarget is the GL texture target with which the GL texture object is
+ * associated. It is set in the constructor and never changed. It is
+ * almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android
+ * Browser. In that case it is set to GL_TEXTURE_2D to allow
+ * glCopyTexSubImage to read from the texture. This is a hack to work
+ * around a GL driver limitation on the number of FBO attachments, which the
+ * browser's tile cache exceeds.
+ */
+ const uint32_t mTexTarget;
+
+ /**
+ * mCurrentTexture is the buffer slot index of the buffer that is currently
+ * bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+ * indicating that no buffer slot is currently bound to the texture. Note,
+ * however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+ * that no buffer is bound to the texture. A call to setBufferCount will
+ * reset mCurrentTexture to INVALID_BUFFER_SLOT.
+ */
+ int mCurrentTexture;
+
+ enum class OpMode { detached, attachedToView, attachedToGL };
+ /**
+ * mOpMode indicates whether the SurfaceTexture is currently attached to
+ * an OpenGL ES context or the HWUI view system. For legacy reasons, this is initialized to,
+ * "attachedToGL" indicating that the SurfaceTexture is considered to be attached to
+ * whatever GL context is current at the time of the first updateTexImage call.
+ * It is set to "detached" by detachFromContext, and then set to "attachedToGL" again by
+ * attachToContext.
+ * attachToView/detachFromView are used to attach/detach from HWUI view system.
+ */
+ OpMode mOpMode;
+
+ /**
+ * mEGLConsumer has SurfaceTexture logic used when attached to GL context.
+ */
+ EGLConsumer mEGLConsumer;
+
+ /**
+ * mImageConsumer has SurfaceTexture logic used when attached to HWUI view system.
+ */
+ ImageConsumer mImageConsumer;
+
+ friend class ImageConsumer;
+ friend class EGLConsumer;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp
index 5b361548eeda..d2d37dcb34f2 100644
--- a/libs/hwui/tests/common/LeakChecker.cpp
+++ b/libs/hwui/tests/common/LeakChecker.cpp
@@ -16,7 +16,6 @@
#include "LeakChecker.h"
-#include "Caches.h"
#include "TestUtils.h"
#include <memunreachable/memunreachable.h>
@@ -71,9 +70,6 @@ void LeakChecker::checkForLeaks() {
// thread-local caches so some leaks will not be properly tagged as leaks
UnreachableMemoryInfo rtMemInfo;
TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
- if (Caches::hasInstance()) {
- Caches::getInstance().tasks.stop();
- }
// Check for leaks
if (!GetUnreachableMemory(rtMemInfo)) {
cerr << "Failed to get unreachable memory!" << endl;
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 69586345319e..66b9b85bdbe7 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -67,16 +67,14 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
const SkMatrix& transform) {
sp<DeferredLayerUpdater> layerUpdater = createTextureLayerUpdater(renderThread);
- layerUpdater->backingLayer()->getTransform().load(transform);
+ layerUpdater->backingLayer()->getTransform() = transform;
layerUpdater->setSize(width, height);
layerUpdater->setTransform(&transform);
// updateLayer so it's ready to draw
- layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN);
- if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
- static_cast<GlLayer*>(layerUpdater->backingLayer())
- ->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
- }
+ SkMatrix identity;
+ identity.setIdentity();
+ layerUpdater->updateLayer(true, identity, HAL_DATASPACE_UNKNOWN, nullptr);
return layerUpdater;
}
@@ -117,7 +115,6 @@ void TestUtils::TestTask::run() {
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
renderThread.vulkanManager().destroy();
} else {
- renderThread.renderState().flush(Caches::FlushMode::Full);
renderThread.destroyGlContext();
}
}
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 743f8093bfa8..0e6582c59a36 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -18,7 +18,6 @@
#include <DeviceInfo.h>
#include <DisplayList.h>
-#include <GlLayer.h>
#include <Matrix.h>
#include <Properties.h>
#include <Rect.h>
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index f29830f0e34b..6c8775b1bdbb 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -15,12 +15,13 @@
*/
#include "DeferredLayerUpdater.h"
-#include "GlLayer.h"
#include "Properties.h"
#include "tests/common/TestUtils.h"
#include <gtest/gtest.h>
+#include <SkBitmap.h>
+#include <SkImage.h>
using namespace android;
using namespace android::uirenderer;
@@ -31,10 +32,6 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
layerUpdater->setBlend(true);
// updates are deferred so the backing layer should still be in its default state
- if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
- GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
- EXPECT_EQ((uint32_t)GL_NONE, glLayer->getRenderTarget());
- }
EXPECT_EQ(0u, layerUpdater->backingLayer()->getWidth());
EXPECT_EQ(0u, layerUpdater->backingLayer()->getHeight());
EXPECT_FALSE(layerUpdater->backingLayer()->getForceFilter());
@@ -42,19 +39,13 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
EXPECT_EQ(Matrix4::identity(), layerUpdater->backingLayer()->getTexTransform());
// push the deferred updates to the layer
- Matrix4 scaledMatrix;
- scaledMatrix.loadScale(0.5, 0.5, 0.0);
- layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN);
- if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
- GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
- glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
- }
+ SkMatrix scaledMatrix = SkMatrix::MakeScale(0.5, 0.5);
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(16, 16);
+ sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap);
+ layerUpdater->updateLayer(true, scaledMatrix, HAL_DATASPACE_UNKNOWN, layerImage);
// the backing layer should now have all the properties applied.
- if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
- GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
- EXPECT_EQ((uint32_t)GL_TEXTURE_EXTERNAL_OES, glLayer->getRenderTarget());
- }
EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth());
EXPECT_EQ(100u, layerUpdater->backingLayer()->getHeight());
EXPECT_TRUE(layerUpdater->backingLayer()->getForceFilter());
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index 9e6d9a8c27de..aecceb3609f5 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -17,12 +17,13 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "Caches.h"
#include "debug/GlesDriver.h"
#include "debug/NullGlesDriver.h"
#include "hwui/Typeface.h"
#include "Properties.h"
#include "tests/common/LeakChecker.h"
+#include "thread/TaskProcessor.h"
+#include "thread/Task.h"
#include "thread/TaskManager.h"
#include <signal.h>
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index f8e8a0a18284..ebf2343c5518 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -16,6 +16,7 @@
#ifndef PAINT_UTILS_H
#define PAINT_UTILS_H
+#include <GLES2/gl2.h>
#include <utils/Blur.h>
#include <SkColorFilter.h>
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 4fb5e748aaac..43847cc4ab06 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -64,6 +64,7 @@ cc_library_shared {
"libsensor",
"libandroid_runtime",
"libnetd_client",
+ "libhwui",
],
static_libs: [
diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp
index b26688190ccd..ced2792775d4 100644
--- a/native/android/surface_texture.cpp
+++ b/native/android/surface_texture.cpp
@@ -21,15 +21,16 @@
#include <utils/Log.h>
-#include <gui/GLConsumer.h>
#include <gui/Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
+#include "surfacetexture/SurfaceTexture.h"
+
using namespace android;
struct ASurfaceTexture {
- sp<GLConsumer> consumer;
+ sp<SurfaceTexture> consumer;
sp<IGraphicBufferProducer> producer;
};