So long OpenGLPipeline & OpenGLReadback (2/??)
Hello EglReadback
Test: hwuiunit & PixelCopyTests pass
Change-Id: I36a8cb45b11141b09e75a2e978ed13e336425625
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index a27d519..7319354 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -186,7 +186,6 @@
"renderstate/TextureState.cpp",
"renderthread/CacheManager.cpp",
"renderthread/CanvasContext.cpp",
- "renderthread/OpenGLPipeline.cpp",
"renderthread/DrawFrameTask.cpp",
"renderthread/EglManager.cpp",
"renderthread/VulkanManager.cpp",
@@ -237,7 +236,7 @@
"LayerUpdateQueue.cpp",
"Matrix.cpp",
"OpDumper.cpp",
- "OpenGLReadback.cpp",
+ "EglReadback.cpp",
"Patch.cpp",
"PatchCache.cpp",
"PathCache.cpp",
diff --git a/libs/hwui/EglReadback.cpp b/libs/hwui/EglReadback.cpp
new file mode 100644
index 0000000..a836afe
--- /dev/null
+++ b/libs/hwui/EglReadback.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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 "EglReadback.h"
+
+#include "renderthread/EglManager.h"
+
+#include <gui/Surface.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace uirenderer {
+
+CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
+ SkBitmap* bitmap) {
+ ATRACE_CALL();
+ // Setup the source
+ sp<GraphicBuffer> sourceBuffer;
+ sp<Fence> sourceFence;
+ Matrix4 texTransform;
+ status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
+ texTransform.invalidateType();
+ if (err != NO_ERROR) {
+ ALOGW("Failed to get last queued buffer, error = %d", err);
+ return CopyResult::UnknownError;
+ }
+ if (!sourceBuffer.get()) {
+ ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
+ return CopyResult::SourceEmpty;
+ }
+ if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
+ ALOGW("Surface is protected, unable to copy from it");
+ return CopyResult::SourceInvalid;
+ }
+ err = sourceFence->wait(500 /* ms */);
+ if (err != NO_ERROR) {
+ ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
+ return CopyResult::Timeout;
+ }
+
+ return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
+}
+
+CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
+ Matrix4& texTransform, const Rect& srcRect,
+ SkBitmap* bitmap) {
+ mRenderThread.eglManager().initialize();
+ // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
+ // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
+ // to be able to properly sample from the buffer.
+
+ // Create the EGLImage object that maps the GraphicBuffer
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+
+ EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, attrs);
+
+ if (sourceImage == EGL_NO_IMAGE_KHR) {
+ ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
+ return CopyResult::UnknownError;
+ }
+
+ uint32_t width = graphicBuffer->getWidth();
+ uint32_t height = graphicBuffer->getHeight();
+ CopyResult copyResult =
+ copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
+
+ eglDestroyImageKHR(display, sourceImage);
+ return copyResult;
+}
+
+CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
+ Rect srcRect;
+ Matrix4 transform;
+ transform.loadScale(1, -1, 1);
+ transform.translate(0, -1);
+ return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/EglReadback.h
similarity index 65%
rename from libs/hwui/OpenGLReadback.h
rename to libs/hwui/EglReadback.h
index ca40738..e723169 100644
--- a/libs/hwui/OpenGLReadback.h
+++ b/libs/hwui/EglReadback.h
@@ -18,16 +18,15 @@
#include "Readback.h"
+#include "Matrix.h"
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
namespace android {
namespace uirenderer {
-class Matrix4;
-class GlLayer;
-
-class OpenGLReadback : public Readback {
+class EglReadback : public Readback {
public:
virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
SkBitmap* bitmap) override;
@@ -35,8 +34,8 @@
SkBitmap* bitmap) override;
protected:
- explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
- virtual ~OpenGLReadback() {}
+ explicit EglReadback(renderthread::RenderThread& thread) : Readback(thread) {}
+ virtual ~EglReadback() {}
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
int imgWidth, int imgHeight, const Rect& srcRect,
@@ -47,21 +46,5 @@
const Rect& srcRect, SkBitmap* bitmap);
};
-class OpenGLReadbackImpl : public OpenGLReadback {
-public:
- OpenGLReadbackImpl(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}
-
- /**
- * Copies the layer's contents into the provided bitmap.
- */
- static bool copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
- SkBitmap* bitmap);
-
-protected:
- virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) override;
-};
-
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
deleted file mode 100644
index 11432d6..0000000
--- a/libs/hwui/OpenGLReadback.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2016 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 "OpenGLReadback.h"
-
-#include "Caches.h"
-#include "GlLayer.h"
-#include "GlopBuilder.h"
-#include "Image.h"
-#include "renderstate/RenderState.h"
-#include "renderthread/EglManager.h"
-#include "utils/GLUtils.h"
-
-#include <GLES2/gl2.h>
-#include <gui/Surface.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-namespace android {
-namespace uirenderer {
-
-CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) {
- ATRACE_CALL();
- // Setup the source
- sp<GraphicBuffer> sourceBuffer;
- sp<Fence> sourceFence;
- Matrix4 texTransform;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
- texTransform.invalidateType();
- if (err != NO_ERROR) {
- ALOGW("Failed to get last queued buffer, error = %d", err);
- return CopyResult::UnknownError;
- }
- if (!sourceBuffer.get()) {
- ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
- return CopyResult::SourceEmpty;
- }
- if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
- ALOGW("Surface is protected, unable to copy from it");
- return CopyResult::SourceInvalid;
- }
- err = sourceFence->wait(500 /* ms */);
- if (err != NO_ERROR) {
- ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
- return CopyResult::Timeout;
- }
-
- return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
-}
-
-CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- Matrix4& texTransform, const Rect& srcRect,
- SkBitmap* bitmap) {
- mRenderThread.eglManager().initialize();
- // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
- // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
- // to be able to properly sample from the buffer.
-
- // Create the EGLImage object that maps the GraphicBuffer
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
- EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-
- EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- clientBuffer, attrs);
-
- if (sourceImage == EGL_NO_IMAGE_KHR) {
- ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
- return CopyResult::UnknownError;
- }
-
- uint32_t width = graphicBuffer->getWidth();
- uint32_t height = graphicBuffer->getHeight();
- CopyResult copyResult =
- copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
-
- // All we're flushing & finishing is the deletion of the texture since
- // copyImageInto already did a major flush & finish as an implicit
- // part of glReadPixels, so this shouldn't pose any major stalls.
- glFinish();
- eglDestroyImageKHR(display, sourceImage);
- return copyResult;
-}
-
-CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
- Rect srcRect;
- Matrix4 transform;
- transform.loadScale(1, -1, 1);
- transform.translate(0, -1);
- return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
-}
-
-static float sFlipVInit[16] = {
- 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
-};
-
-static const Matrix4 sFlipV(sFlipVInit);
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, Texture& sourceTexture,
- const Matrix4& texTransform, const Rect& srcRect,
- SkBitmap* bitmap) {
- int destWidth = bitmap->width();
- int destHeight = bitmap->height();
- if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) {
- ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth,
- destHeight, caches.maxTextureSize);
- return CopyResult::DestinationInvalid;
- }
-
- if (bitmap->colorType() == kRGBA_F16_SkColorType &&
- !caches.extensions().hasRenderableFloatTextures()) {
- ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
- return CopyResult::DestinationInvalid;
- }
-
- GLuint fbo = renderState.createFramebuffer();
- if (!fbo) {
- ALOGW("Could not obtain an FBO");
- return CopyResult::UnknownError;
- }
-
- GLuint texture;
-
- GLenum format;
- GLenum internalFormat;
- GLenum type;
-
- switch (bitmap->colorType()) {
- case kAlpha_8_SkColorType:
- format = GL_ALPHA;
- internalFormat = GL_ALPHA;
- type = GL_UNSIGNED_BYTE;
- break;
- case kRGB_565_SkColorType:
- format = GL_RGB;
- internalFormat = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case kARGB_4444_SkColorType:
- format = GL_RGBA;
- internalFormat = GL_RGBA;
- type = GL_UNSIGNED_SHORT_4_4_4_4;
- break;
- case kRGBA_F16_SkColorType:
- format = GL_RGBA;
- internalFormat = GL_RGBA16F;
- type = GL_HALF_FLOAT;
- break;
- case kN32_SkColorType:
- default:
- format = GL_RGBA;
- internalFormat = GL_RGBA;
- type = GL_UNSIGNED_BYTE;
- break;
- }
-
- renderState.bindFramebuffer(fbo);
-
- // TODO: Use layerPool or something to get this maybe? But since we
- // need explicit format control we can't currently.
-
- // Setup the rendertarget
- glGenTextures(1, &texture);
- caches.textureState().activateTexture(0);
- caches.textureState().bindTexture(texture);
- glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
-
- {
- bool requiresFilter;
- // Draw & readback
- renderState.setViewport(destWidth, destHeight);
- renderState.scissor().setEnabled(false);
- renderState.blend().syncEnabled();
- renderState.stencil().disable();
-
- Matrix4 croppedTexTransform(texTransform);
- if (!srcRect.isEmpty()) {
- // We flipV to convert to 0,0 top-left for the srcRect
- // coordinates then flip back to 0,0 bottom-left for
- // GLES coordinates.
- croppedTexTransform.multiply(sFlipV);
- croppedTexTransform.translate(srcRect.left / sourceTexture.width(),
- srcRect.top / sourceTexture.height(), 0);
- croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
- srcRect.getHeight() / sourceTexture.height(), 1);
- croppedTexTransform.multiply(sFlipV);
- requiresFilter = srcRect.getWidth() != (float)destWidth ||
- srcRect.getHeight() != (float)destHeight;
- } else {
- requiresFilter = sourceTexture.width() != (uint32_t)destWidth ||
- sourceTexture.height() != (uint32_t)destHeight;
- }
- Glop glop;
- GlopBuilder(renderState, caches, &glop)
- .setRoundRectClipState(nullptr)
- .setMeshTexturedUnitQuad(nullptr)
- .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter)
- .setTransform(Matrix4::identity(), TransformFlags::None)
- .setModelViewMapUnitToRect(Rect(destWidth, destHeight))
- .build();
- Matrix4 ortho;
- ortho.loadOrtho(destWidth, destHeight);
- renderState.render(glop, ortho, false);
-
- // TODO: We should convert to linear space when the target is RGBA16F
- glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
- bitmap->notifyPixelsChanged();
- }
-
- // Cleanup
- caches.textureState().deleteTexture(texture);
- renderState.deleteFramebuffer(fbo);
-
- GL_CHECKPOINT(MODERATE);
-
- return CopyResult::Success;
-}
-
-CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) {
- // If this is a 90 or 270 degree rotation we need to swap width/height
- // This is a fuzzy way of checking that.
- if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
- std::swap(imgWidth, imgHeight);
- }
-
- Caches& caches = Caches::getInstance();
- GLuint sourceTexId;
- // Create a 2D texture to sample from the EGLImage
- glGenTextures(1, &sourceTexId);
- caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
-
- GLenum status = GL_NO_ERROR;
- while ((status = glGetError()) != GL_NO_ERROR) {
- ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
- return CopyResult::UnknownError;
- }
-
- Texture sourceTexture(caches);
- sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */,
- GL_TEXTURE_EXTERNAL_OES);
-
- CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture,
- imgTransform, srcRect, bitmap);
- sourceTexture.deleteTexture();
- return copyResult;
-}
-
-bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
- SkBitmap* bitmap) {
- if (!layer.isRenderable()) {
- // layer has never been updated by DeferredLayerUpdater, abort copy
- return false;
- }
-
- return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(),
- layer.getTexture(), layer.getTexTransform(),
- Rect(), bitmap);
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 4393f45..208910a 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -136,6 +136,8 @@
// make sure that we have deleted the texture (in the SkImage) before we
// destroy the EGLImage that it was created from
image.reset();
+ glFinish();
+
return copyResult;
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
index cc9fb3b..1ce4773 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
@@ -16,15 +16,15 @@
#pragma once
-#include "OpenGLReadback.h"
+#include "EglReadback.h"
namespace android {
namespace uirenderer {
namespace skiapipeline {
-class SkiaOpenGLReadback : public OpenGLReadback {
+class SkiaOpenGLReadback : public EglReadback {
public:
- SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}
+ SkiaOpenGLReadback(renderthread::RenderThread& thread) : EglReadback(thread) {}
protected:
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a0fc83e..3deed6e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -23,7 +23,6 @@
#include "EglManager.h"
#include "Frame.h"
#include "LayerUpdateQueue.h"
-#include "OpenGLPipeline.h"
#include "Properties.h"
#include "RenderThread.h"
#include "hwui/Canvas.h"
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
deleted file mode 100644
index 1925808..0000000
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright (C) 2016 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 "OpenGLPipeline.h"
-
-#include "DeferredLayerUpdater.h"
-#include "EglManager.h"
-#include "Frame.h"
-#include "GlLayer.h"
-#include "OpenGLReadback.h"
-#include "ProfileRenderer.h"
-#include "TreeInfo.h"
-#include "renderstate/RenderState.h"
-
-#include <cutils/properties.h>
-#include <strings.h>
-
-namespace android {
-namespace uirenderer {
-namespace renderthread {
-
-OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
- : mEglManager(thread.eglManager()), mRenderThread(thread) {}
-
-MakeCurrentResult OpenGLPipeline::makeCurrent() {
- // TODO: Figure out why this workaround is needed, see b/13913604
- // In the meantime this matches the behavior of GLRenderer, so it is not a regression
- EGLint error = 0;
- bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error);
-
- Caches::getInstance().textureCache.resetMarkInUse(this);
- if (!haveNewSurface) {
- return MakeCurrentResult::AlreadyCurrent;
- }
- return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
-}
-
-Frame OpenGLPipeline::getFrame() {
- LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "drawRenderNode called on a context with no surface!");
- return mEglManager.beginFrame(mEglSurface);
-}
-
-bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
- bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
- mEglManager.damageFrame(frame, dirty);
-
- bool drew = false;
-
- auto& caches = Caches::getInstance();
- FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
-
- frameBuilder.deferLayers(*layerUpdateQueue);
- layerUpdateQueue->clear();
-
- frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
-
- BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut,
- lightInfo);
- frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
- ProfileRenderer profileRenderer(renderer);
- profiler->draw(profileRenderer);
- drew = renderer.didDraw();
-
- // post frame cleanup
- caches.clearGarbage();
- caches.pathCache.trim();
- caches.tessellationCache.trim();
-
-#if DEBUG_MEMORY_USAGE
- caches.dumpMemoryUsage();
-#else
- if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
- caches.dumpMemoryUsage();
- }
-#endif
-
- return drew;
-}
-
-bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) {
- GL_CHECKPOINT(LOW);
-
- // Even if we decided to cancel the frame, from the perspective of jank
- // metrics the frame was swapped at this point
- currentFrameInfo->markSwapBuffers();
-
- *requireSwap = drew || mEglManager.damageRequiresSwap();
-
- if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
- return false;
- }
-
- return *requireSwap;
-}
-
-bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
- ATRACE_CALL();
- // acquire most recent buffer for drawing
- layer->updateTexImage();
- layer->apply();
- return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
- static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
-}
-
-static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
- GlLayer* layer =
- new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
- Caches::getInstance().textureState().activateTexture(0);
- layer->generateTexture();
- return layer;
-}
-
-DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
- mEglManager.initialize();
- return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
-}
-
-void OpenGLPipeline::onStop() {
- if (mEglManager.isCurrent(mEglSurface)) {
- mEglManager.makeCurrent(EGL_NO_SURFACE);
- }
-}
-
-bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) {
- if (mEglSurface != EGL_NO_SURFACE) {
- mEglManager.destroySurface(mEglSurface);
- mEglSurface = EGL_NO_SURFACE;
- }
-
- if (surface) {
- const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
- mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
- }
-
- if (mEglSurface != EGL_NO_SURFACE) {
- const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
- mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
- return true;
- }
-
- return false;
-}
-
-bool OpenGLPipeline::isSurfaceReady() {
- return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
-}
-
-bool OpenGLPipeline::isContextReady() {
- return CC_LIKELY(mEglManager.hasEglContext());
-}
-
-void OpenGLPipeline::onDestroyHardwareResources() {
- Caches& caches = Caches::getInstance();
- // Make sure to release all the textures we were owning as there won't
- // be another draw
- caches.textureCache.resetMarkInUse(this);
- mRenderThread.renderState().flush(Caches::FlushMode::Layers);
-}
-
-void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque,
- bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) {
- static const std::vector<sp<RenderNode>> emptyNodeList;
- auto& caches = Caches::getInstance();
- FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
- layerUpdateQueue->clear();
- // TODO: Handle wide color gamut contexts
- BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut,
- lightInfo);
- LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
- frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
-}
-
-TaskManager* OpenGLPipeline::getTaskManager() {
- return &Caches::getInstance().tasks;
-}
-
-static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
- return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height;
-}
-
-bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator,
- bool wideColorGamut, ErrorHandler* errorHandler) {
- RenderState& renderState = mRenderThread.renderState();
- OffscreenBufferPool& layerPool = renderState.layerPool();
- bool transformUpdateNeeded = false;
- if (node->getLayer() == nullptr) {
- node->setLayer(
- layerPool.get(renderState, node->getWidth(), node->getHeight(), wideColorGamut));
- transformUpdateNeeded = true;
- } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
- // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
- // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
- if (node->properties().fitsOnLayer()) {
- node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight()));
- } else {
- destroyLayer(node);
- }
- transformUpdateNeeded = true;
- }
-
- if (transformUpdateNeeded && node->getLayer()) {
- // update the transform in window of the layer to reset its origin wrt light source position
- Matrix4 windowTransform;
- damageAccumulator.computeCurrentTransform(&windowTransform);
- node->getLayer()->setWindowTransform(windowTransform);
- }
-
- if (!node->hasLayer()) {
- Caches::getInstance().dumpMemoryUsage();
- if (errorHandler) {
- std::ostringstream err;
- err << "Unable to create layer for " << node->getName();
- const int maxTextureSize = Caches::getInstance().maxTextureSize;
- if (node->getWidth() > maxTextureSize || node->getHeight() > maxTextureSize) {
- err << ", size " << node->getWidth() << "x" << node->getHeight()
- << " exceeds max size " << maxTextureSize;
- } else {
- err << ", see logcat for more info";
- }
- errorHandler->onError(err.str());
- }
- }
-
- return transformUpdateNeeded;
-}
-
-bool OpenGLPipeline::pinImages(LsaVector<sk_sp<Bitmap>>& images) {
- TextureCache& cache = Caches::getInstance().textureCache;
- bool prefetchSucceeded = true;
- for (auto& bitmapResource : images) {
- prefetchSucceeded &= cache.prefetchAndMarkInUse(this, bitmapResource.get());
- }
- return prefetchSucceeded;
-}
-
-void OpenGLPipeline::unpinImages() {
- Caches::getInstance().textureCache.resetMarkInUse(this);
-}
-
-void OpenGLPipeline::destroyLayer(RenderNode* node) {
- if (OffscreenBuffer* layer = node->getLayer()) {
- layer->renderState.layerPool().putOrDelete(layer);
- node->setLayer(nullptr);
- }
-}
-
-void OpenGLPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
- if (Caches::hasInstance() && thread.eglManager().hasEglContext()) {
- ATRACE_NAME("Bitmap#prepareToDraw task");
- Caches::getInstance().textureCache.prefetch(bitmap);
- }
-}
-
-void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
- DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
- if (thread.eglManager().hasEglContext()) {
- mode = DrawGlInfo::kModeProcess;
- }
- thread.renderState().invokeFunctor(functor, mode, nullptr);
-}
-
-#define FENCE_TIMEOUT 2000000000
-
-class AutoEglFence {
-public:
- AutoEglFence(EGLDisplay display) : mDisplay(display) {
- fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
- }
-
- ~AutoEglFence() {
- if (fence != EGL_NO_SYNC_KHR) {
- eglDestroySyncKHR(mDisplay, fence);
- }
- }
-
- EGLSyncKHR fence = EGL_NO_SYNC_KHR;
-
-private:
- EGLDisplay mDisplay = EGL_NO_DISPLAY;
-};
-
-class AutoEglImage {
-public:
- AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
- EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
- imageAttrs);
- }
-
- ~AutoEglImage() {
- if (image != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mDisplay, image);
- }
- }
-
- EGLImageKHR image = EGL_NO_IMAGE_KHR;
-
-private:
- EGLDisplay mDisplay = EGL_NO_DISPLAY;
-};
-
-class AutoGlTexture {
-public:
- AutoGlTexture(uirenderer::Caches& caches) : mCaches(caches) {
- glGenTextures(1, &mTexture);
- caches.textureState().bindTexture(mTexture);
- }
-
- ~AutoGlTexture() { mCaches.textureState().deleteTexture(mTexture); }
-
-private:
- uirenderer::Caches& mCaches;
- GLuint mTexture = 0;
-};
-
-static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
- GraphicBuffer& buffer, GLint format, GLint type) {
- EGLDisplay display = eglGetCurrentDisplay();
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
- // We use an EGLImage to access the content of the GraphicBuffer
- // The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer.getNativeBuffer();
- AutoEglImage autoImage(display, clientBuffer);
- if (autoImage.image == EGL_NO_IMAGE_KHR) {
- ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
- return false;
- }
- AutoGlTexture glTexture(caches);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
-
- GL_CHECKPOINT(MODERATE);
-
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format, type,
- bitmap.getPixels());
-
- GL_CHECKPOINT(MODERATE);
-
- // The fence is used to wait for the texture upload to finish
- // properly. We cannot rely on glFlush() and glFinish() as
- // some drivers completely ignore these API calls
- AutoEglFence autoFence(display);
- if (autoFence.fence == EGL_NO_SYNC_KHR) {
- LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
- return false;
- }
- // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
- // pipeline flush (similar to what a glFlush() would do.)
- EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
- if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
- LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
- return false;
- }
- return true;
-}
-
-// TODO: handle SRGB sanely
-static PixelFormat internalFormatToPixelFormat(GLint internalFormat) {
- switch (internalFormat) {
- case GL_LUMINANCE:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_SRGB8_ALPHA8:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_RGBA:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_RGB:
- return PIXEL_FORMAT_RGB_565;
- case GL_RGBA16F:
- return PIXEL_FORMAT_RGBA_FP16;
- default:
- LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
- return PIXEL_FORMAT_UNKNOWN;
- }
-}
-
-sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread,
- SkBitmap& skBitmap) {
- renderThread.eglManager().initialize();
- uirenderer::Caches& caches = uirenderer::Caches::getInstance();
-
- const SkImageInfo& info = skBitmap.info();
- if (info.colorType() == kUnknown_SkColorType || info.colorType() == kAlpha_8_SkColorType) {
- ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
- return nullptr;
- }
-
- bool needSRGB = uirenderer::transferFunctionCloseToSRGB(skBitmap.info().colorSpace());
- bool hasLinearBlending = caches.extensions().hasLinearBlending();
- GLint format, type, internalFormat;
- uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
- needSRGB && hasLinearBlending, &internalFormat,
- &format, &type);
-
- PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- info.width(), info.height(), pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]");
-
- status_t error = buffer->initCheck();
- if (error < 0) {
- ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
- return nullptr;
- }
-
- SkBitmap bitmap;
- if (CC_UNLIKELY(
- uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(), hasLinearBlending))) {
- sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
- bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
- } else {
- bitmap = skBitmap;
- }
-
- if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
- return nullptr;
- }
- return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
-}
-
-} /* namespace renderthread */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
deleted file mode 100644
index 9859e93..0000000
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 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 "BakedOpDispatcher.h"
-#include "BakedOpRenderer.h"
-#include "CanvasContext.h"
-#include "FrameBuilder.h"
-#include "IRenderPipeline.h"
-
-namespace android {
-namespace uirenderer {
-namespace renderthread {
-
-class OpenGLPipeline : public IRenderPipeline {
-public:
- OpenGLPipeline(RenderThread& thread);
- virtual ~OpenGLPipeline() {}
-
- MakeCurrentResult makeCurrent() override;
- Frame getFrame() override;
- bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) override;
- bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
- bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
- DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) override;
- void onStop() override;
- bool isSurfaceReady() override;
- bool isContextReady() override;
- void onDestroyHardwareResources() override;
- void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) override;
- TaskManager* getTaskManager() override;
- bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
- bool wideColorGamut, ErrorHandler* errorHandler) override;
- bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
- bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
- void unpinImages() override;
- void onPrepareTree() override {}
- static void destroyLayer(RenderNode* node);
- static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
- static void invokeFunctor(const RenderThread& thread, Functor* functor);
- static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread, SkBitmap& skBitmap);
-
-private:
- EglManager& mEglManager;
- EGLSurface mEglSurface = EGL_NO_SURFACE;
- bool mBufferPreserved = false;
- RenderThread& mRenderThread;
-};
-
-} /* namespace renderthread */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index f4d230e..84f43ec 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -19,7 +19,6 @@
#include "CanvasContext.h"
#include "DeviceInfo.h"
#include "EglManager.h"
-#include "OpenGLReadback.h"
#include "RenderProxy.h"
#include "VulkanManager.h"
#include "hwui/Bitmap.h"
@@ -28,7 +27,6 @@
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "pipeline/skia/SkiaVulkanReadback.h"
#include "renderstate/RenderState.h"
-#include "renderthread/OpenGLPipeline.h"
#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index f51e7cc..16c5afd 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -24,7 +24,6 @@
#include <pipeline/skia/SkiaOpenGLPipeline.h>
#include <pipeline/skia/SkiaVulkanPipeline.h>
#include <renderthread/EglManager.h>
-#include <renderthread/OpenGLPipeline.h>
#include <renderthread/VulkanManager.h>
#include <utils/Unicode.h>