diff options
Diffstat (limited to 'libs/hwui/renderthread/OpenGLPipeline.cpp')
-rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.cpp | 450 |
1 files changed, 0 insertions, 450 deletions
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 */ |