diff options
-rw-r--r-- | libs/hwui/Android.bp | 3 | ||||
-rw-r--r-- | libs/hwui/EglReadback.cpp | 97 | ||||
-rw-r--r-- | libs/hwui/EglReadback.h (renamed from libs/hwui/OpenGLReadback.h) | 27 | ||||
-rw-r--r-- | libs/hwui/OpenGLReadback.cpp | 287 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLReadback.h | 6 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.cpp | 450 | ||||
-rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.h | 75 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/tests/common/TestUtils.cpp | 1 |
11 files changed, 108 insertions, 843 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index a27d519bf59b..7319354c7c5f 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -186,7 +186,6 @@ cc_defaults { "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 @@ cc_defaults { "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 000000000000..a836afe97c79 --- /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 index ca40738b4901..e723169ad795 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 @@ public: 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 @@ private: 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 11432d629650..000000000000 --- 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 4393f459315c..208910a06eaa 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -136,6 +136,8 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 // 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 cc9fb3b0a5e0..1ce4773e7d67 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 a0fc83e94f6a..3deed6e0ba77 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 19258084eb42..000000000000 --- 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 9859e931fd85..000000000000 --- 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 f4d230e7c76c..84f43ec1a206 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 f51e7cc04d8d..16c5afdc3dcf 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> |