Home | History | Annotate | Download | only in renderthread
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "OpenGLPipeline.h"
     18 
     19 #include "DeferredLayerUpdater.h"
     20 #include "EglManager.h"
     21 #include "Frame.h"
     22 #include "GlLayer.h"
     23 #include "ProfileRenderer.h"
     24 #include "renderstate/RenderState.h"
     25 #include "OpenGLReadback.h"
     26 
     27 #include <cutils/properties.h>
     28 #include <strings.h>
     29 
     30 namespace android {
     31 namespace uirenderer {
     32 namespace renderthread {
     33 
     34 OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
     35         :  mEglManager(thread.eglManager())
     36         , mRenderThread(thread) {
     37 }
     38 
     39 MakeCurrentResult OpenGLPipeline::makeCurrent() {
     40     // TODO: Figure out why this workaround is needed, see b/13913604
     41     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
     42     EGLint error = 0;
     43     bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error);
     44 
     45     Caches::getInstance().textureCache.resetMarkInUse(this);
     46     if (!haveNewSurface) {
     47         return MakeCurrentResult::AlreadyCurrent;
     48     }
     49     return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
     50 }
     51 
     52 Frame OpenGLPipeline::getFrame() {
     53     LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
     54                 "drawRenderNode called on a context with no surface!");
     55     return mEglManager.beginFrame(mEglSurface);
     56 }
     57 
     58 bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
     59         const FrameBuilder::LightGeometry& lightGeometry,
     60         LayerUpdateQueue* layerUpdateQueue,
     61         const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
     62         const BakedOpRenderer::LightInfo& lightInfo,
     63         const std::vector< sp<RenderNode> >& renderNodes,
     64         FrameInfoVisualizer* profiler) {
     65 
     66     mEglManager.damageFrame(frame, dirty);
     67 
     68     bool drew = false;
     69 
     70 
     71     auto& caches = Caches::getInstance();
     72     FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
     73 
     74     frameBuilder.deferLayers(*layerUpdateQueue);
     75     layerUpdateQueue->clear();
     76 
     77     frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
     78 
     79     BakedOpRenderer renderer(caches, mRenderThread.renderState(),
     80             opaque, wideColorGamut, lightInfo);
     81     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
     82     ProfileRenderer profileRenderer(renderer);
     83     profiler->draw(profileRenderer);
     84     drew = renderer.didDraw();
     85 
     86     // post frame cleanup
     87     caches.clearGarbage();
     88     caches.pathCache.trim();
     89     caches.tessellationCache.trim();
     90 
     91 #if DEBUG_MEMORY_USAGE
     92     caches.dumpMemoryUsage();
     93 #else
     94     if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
     95         caches.dumpMemoryUsage();
     96     }
     97 #endif
     98 
     99     return drew;
    100 }
    101 
    102 bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
    103         FrameInfo* currentFrameInfo, bool* requireSwap) {
    104 
    105     GL_CHECKPOINT(LOW);
    106 
    107     // Even if we decided to cancel the frame, from the perspective of jank
    108     // metrics the frame was swapped at this point
    109     currentFrameInfo->markSwapBuffers();
    110 
    111     *requireSwap = drew || mEglManager.damageRequiresSwap();
    112 
    113     if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
    114         return false;
    115     }
    116 
    117     return *requireSwap;
    118 }
    119 
    120 bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
    121     ATRACE_CALL();
    122     // acquire most recent buffer for drawing
    123     layer->updateTexImage();
    124     layer->apply();
    125     return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
    126             static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
    127 }
    128 
    129 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
    130         SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
    131     GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
    132             mode, blend);
    133     Caches::getInstance().textureState().activateTexture(0);
    134     layer->generateTexture();
    135     return layer;
    136 }
    137 
    138 DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
    139     mEglManager.initialize();
    140     return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
    141 }
    142 
    143 void OpenGLPipeline::onStop() {
    144     if (mEglManager.isCurrent(mEglSurface)) {
    145         mEglManager.makeCurrent(EGL_NO_SURFACE);
    146     }
    147 }
    148 
    149 bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) {
    150 
    151     if (mEglSurface != EGL_NO_SURFACE) {
    152         mEglManager.destroySurface(mEglSurface);
    153         mEglSurface = EGL_NO_SURFACE;
    154     }
    155 
    156     if (surface) {
    157         const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
    158         mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
    159     }
    160 
    161     if (mEglSurface != EGL_NO_SURFACE) {
    162         const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
    163         mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
    164         return true;
    165     }
    166 
    167     return false;
    168 }
    169 
    170 bool OpenGLPipeline::isSurfaceReady() {
    171     return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
    172 }
    173 
    174 bool OpenGLPipeline::isContextReady() {
    175     return CC_LIKELY(mEglManager.hasEglContext());
    176 }
    177 
    178 void OpenGLPipeline::onDestroyHardwareResources() {
    179     Caches& caches = Caches::getInstance();
    180     // Make sure to release all the textures we were owning as there won't
    181     // be another draw
    182     caches.textureCache.resetMarkInUse(this);
    183     mRenderThread.renderState().flush(Caches::FlushMode::Layers);
    184 }
    185 
    186 void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
    187         LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
    188         const BakedOpRenderer::LightInfo& lightInfo) {
    189     static const std::vector< sp<RenderNode> > emptyNodeList;
    190     auto& caches = Caches::getInstance();
    191     FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
    192     layerUpdateQueue->clear();
    193     // TODO: Handle wide color gamut contexts
    194     BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo);
    195     LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
    196     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
    197 }
    198 
    199 TaskManager* OpenGLPipeline::getTaskManager() {
    200     return &Caches::getInstance().tasks;
    201 }
    202 
    203 static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
    204     return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height;
    205 }
    206 
    207 bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
    208         const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
    209     RenderState& renderState = mRenderThread.renderState();
    210     OffscreenBufferPool& layerPool = renderState.layerPool();
    211     bool transformUpdateNeeded = false;
    212     if (node->getLayer() == nullptr) {
    213         node->setLayer(layerPool.get(renderState,
    214                 node->getWidth(), node->getHeight(), wideColorGamut));
    215         transformUpdateNeeded = true;
    216     } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
    217         // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
    218         // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
    219         if (node->properties().fitsOnLayer()) {
    220             node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight()));
    221         } else {
    222             destroyLayer(node);
    223         }
    224         transformUpdateNeeded = true;
    225     }
    226 
    227     if (transformUpdateNeeded && node->getLayer()) {
    228         // update the transform in window of the layer to reset its origin wrt light source position
    229         Matrix4 windowTransform;
    230         damageAccumulator.computeCurrentTransform(&windowTransform);
    231         node->getLayer()->setWindowTransform(windowTransform);
    232     }
    233 
    234     return transformUpdateNeeded;
    235 }
    236 
    237 bool OpenGLPipeline::pinImages(LsaVector<sk_sp<Bitmap>>& images) {
    238     TextureCache& cache = Caches::getInstance().textureCache;
    239     bool prefetchSucceeded = true;
    240     for (auto& bitmapResource : images) {
    241         prefetchSucceeded &= cache.prefetchAndMarkInUse(this, bitmapResource.get());
    242     }
    243     return prefetchSucceeded;
    244 }
    245 
    246 void OpenGLPipeline::unpinImages() {
    247     Caches::getInstance().textureCache.resetMarkInUse(this);
    248 }
    249 
    250 void OpenGLPipeline::destroyLayer(RenderNode* node) {
    251     if (OffscreenBuffer* layer = node->getLayer()) {
    252         layer->renderState.layerPool().putOrDelete(layer);
    253         node->setLayer(nullptr);
    254     }
    255 }
    256 
    257 void OpenGLPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
    258     if (Caches::hasInstance() && thread.eglManager().hasEglContext()) {
    259         ATRACE_NAME("Bitmap#prepareToDraw task");
    260         Caches::getInstance().textureCache.prefetch(bitmap);
    261     }
    262 }
    263 
    264 void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
    265     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
    266     if (thread.eglManager().hasEglContext()) {
    267         mode = DrawGlInfo::kModeProcess;
    268     }
    269     thread.renderState().invokeFunctor(functor, mode, nullptr);
    270 }
    271 
    272 #define FENCE_TIMEOUT 2000000000
    273 
    274 class AutoEglFence {
    275 public:
    276     AutoEglFence(EGLDisplay display)
    277             : mDisplay(display) {
    278         fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
    279     }
    280 
    281     ~AutoEglFence() {
    282         if (fence != EGL_NO_SYNC_KHR) {
    283             eglDestroySyncKHR(mDisplay, fence);
    284         }
    285     }
    286 
    287     EGLSyncKHR fence = EGL_NO_SYNC_KHR;
    288 private:
    289     EGLDisplay mDisplay = EGL_NO_DISPLAY;
    290 };
    291 
    292 class AutoEglImage {
    293 public:
    294     AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
    295             : mDisplay(display) {
    296         EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
    297         image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
    298                 EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
    299     }
    300 
    301     ~AutoEglImage() {
    302         if (image != EGL_NO_IMAGE_KHR) {
    303             eglDestroyImageKHR(mDisplay, image);
    304         }
    305     }
    306 
    307     EGLImageKHR image = EGL_NO_IMAGE_KHR;
    308 private:
    309     EGLDisplay mDisplay = EGL_NO_DISPLAY;
    310 };
    311 
    312 class AutoGlTexture {
    313 public:
    314     AutoGlTexture(uirenderer::Caches& caches)
    315             : mCaches(caches) {
    316         glGenTextures(1, &mTexture);
    317         caches.textureState().bindTexture(mTexture);
    318     }
    319 
    320     ~AutoGlTexture() {
    321         mCaches.textureState().deleteTexture(mTexture);
    322     }
    323 
    324 private:
    325     uirenderer::Caches& mCaches;
    326     GLuint mTexture = 0;
    327 };
    328 
    329 static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
    330         GraphicBuffer& buffer, GLint format, GLint type) {
    331     EGLDisplay display = eglGetCurrentDisplay();
    332     LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
    333                 "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
    334                 uirenderer::renderthread::EglManager::eglErrorString());
    335     // We use an EGLImage to access the content of the GraphicBuffer
    336     // The EGL image is later bound to a 2D texture
    337     EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
    338     AutoEglImage autoImage(display, clientBuffer);
    339     if (autoImage.image == EGL_NO_IMAGE_KHR) {
    340         ALOGW("Could not create EGL image, err =%s",
    341                 uirenderer::renderthread::EglManager::eglErrorString());
    342         return false;
    343     }
    344     AutoGlTexture glTexture(caches);
    345     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
    346 
    347     GL_CHECKPOINT(MODERATE);
    348 
    349     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
    350             format, type, bitmap.getPixels());
    351 
    352     GL_CHECKPOINT(MODERATE);
    353 
    354     // The fence is used to wait for the texture upload to finish
    355     // properly. We cannot rely on glFlush() and glFinish() as
    356     // some drivers completely ignore these API calls
    357     AutoEglFence autoFence(display);
    358     if (autoFence.fence == EGL_NO_SYNC_KHR) {
    359         LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
    360         return false;
    361     }
    362     // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
    363     // pipeline flush (similar to what a glFlush() would do.)
    364     EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
    365             EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
    366     if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
    367         LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
    368         return false;
    369     }
    370     return true;
    371 }
    372 
    373 // TODO: handle SRGB sanely
    374 static PixelFormat internalFormatToPixelFormat(GLint internalFormat) {
    375     switch (internalFormat) {
    376     case GL_LUMINANCE:
    377         return PIXEL_FORMAT_RGBA_8888;
    378     case GL_SRGB8_ALPHA8:
    379         return PIXEL_FORMAT_RGBA_8888;
    380     case GL_RGBA:
    381         return PIXEL_FORMAT_RGBA_8888;
    382     case GL_RGB:
    383         return PIXEL_FORMAT_RGB_565;
    384     case GL_RGBA16F:
    385         return PIXEL_FORMAT_RGBA_FP16;
    386     default:
    387         LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
    388         return PIXEL_FORMAT_UNKNOWN;
    389     }
    390 }
    391 
    392 sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread,
    393         SkBitmap& skBitmap) {
    394     renderThread.eglManager().initialize();
    395     uirenderer::Caches& caches = uirenderer::Caches::getInstance();
    396 
    397     const SkImageInfo& info = skBitmap.info();
    398     if (info.colorType() == kUnknown_SkColorType || info.colorType() == kAlpha_8_SkColorType) {
    399         ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
    400         return nullptr;
    401     }
    402 
    403     bool needSRGB = uirenderer::transferFunctionCloseToSRGB(skBitmap.info().colorSpace());
    404     bool hasLinearBlending = caches.extensions().hasLinearBlending();
    405     GLint format, type, internalFormat;
    406     uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
    407             needSRGB && hasLinearBlending, &internalFormat, &format, &type);
    408 
    409     PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
    410     sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
    411             GraphicBuffer::USAGE_HW_TEXTURE |
    412             GraphicBuffer::USAGE_SW_WRITE_NEVER |
    413             GraphicBuffer::USAGE_SW_READ_NEVER,
    414             std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]");
    415 
    416     status_t error = buffer->initCheck();
    417     if (error < 0) {
    418         ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
    419         return nullptr;
    420     }
    421 
    422     SkBitmap bitmap;
    423     if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
    424             hasLinearBlending))) {
    425         sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
    426         bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
    427     } else {
    428         bitmap = skBitmap;
    429     }
    430 
    431     if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
    432         return nullptr;
    433     }
    434     return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
    435 }
    436 
    437 } /* namespace renderthread */
    438 } /* namespace uirenderer */
    439 } /* namespace android */
    440