Home | History | Annotate | Download | only in skia
      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 "SkiaPipeline.h"
     18 
     19 #include <SkImageEncoder.h>
     20 #include <SkImageInfo.h>
     21 #include <SkImagePriv.h>
     22 #include <SkOverdrawCanvas.h>
     23 #include <SkOverdrawColorFilter.h>
     24 #include <SkPicture.h>
     25 #include <SkPictureRecorder.h>
     26 #include "TreeInfo.h"
     27 #include "VectorDrawable.h"
     28 #include "thread/CommonPool.h"
     29 #include "utils/TraceUtils.h"
     30 
     31 #include <unistd.h>
     32 
     33 using namespace android::uirenderer::renderthread;
     34 
     35 namespace android {
     36 namespace uirenderer {
     37 namespace skiapipeline {
     38 
     39 float SkiaPipeline::mLightRadius = 0;
     40 uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
     41 uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
     42 
     43 Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
     44 
     45 SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
     46     mVectorDrawables.reserve(30);
     47 }
     48 
     49 SkiaPipeline::~SkiaPipeline() {
     50     unpinImages();
     51 }
     52 
     53 void SkiaPipeline::onDestroyHardwareResources() {
     54     unpinImages();
     55     mRenderThread.cacheManager().trimStaleResources();
     56 }
     57 
     58 bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
     59     for (SkImage* image : mutableImages) {
     60         if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) {
     61             mPinnedImages.emplace_back(sk_ref_sp(image));
     62         } else {
     63             return false;
     64         }
     65     }
     66     return true;
     67 }
     68 
     69 void SkiaPipeline::unpinImages() {
     70     for (auto& image : mPinnedImages) {
     71         SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext());
     72     }
     73     mPinnedImages.clear();
     74 }
     75 
     76 void SkiaPipeline::onPrepareTree() {
     77     // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without
     78     // a renderFrame in the middle.
     79     mVectorDrawables.clear();
     80 }
     81 
     82 void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry,
     83                                 LayerUpdateQueue* layerUpdateQueue, bool opaque,
     84                                 const LightInfo& lightInfo) {
     85     updateLighting(lightGeometry, lightInfo);
     86     ATRACE_NAME("draw layers");
     87     renderVectorDrawableCache();
     88     renderLayersImpl(*layerUpdateQueue, opaque);
     89     layerUpdateQueue->clear();
     90 }
     91 
     92 void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
     93     sk_sp<GrContext> cachedContext;
     94 
     95     // Render all layers that need to be updated, in order.
     96     for (size_t i = 0; i < layers.entries().size(); i++) {
     97         RenderNode* layerNode = layers.entries()[i].renderNode.get();
     98         // only schedule repaint if node still on layer - possible it may have been
     99         // removed during a dropped frame, but layers may still remain scheduled so
    100         // as not to lose info on what portion is damaged
    101         if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) {
    102             SkASSERT(layerNode->getLayerSurface());
    103             SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
    104             if (!displayList || displayList->isEmpty()) {
    105                 SkDEBUGF(("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName()));
    106                 return;
    107             }
    108 
    109             const Rect& layerDamage = layers.entries()[i].damage;
    110 
    111             SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
    112 
    113             int saveCount = layerCanvas->save();
    114             SkASSERT(saveCount == 1);
    115 
    116             layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
    117 
    118             auto savedLightCenter = mLightCenter;
    119             // map current light center into RenderNode's coordinate space
    120             layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter);
    121 
    122             const RenderProperties& properties = layerNode->properties();
    123             const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
    124             if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
    125                 return;
    126             }
    127 
    128             ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
    129                           bounds.height());
    130 
    131             layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
    132             layerCanvas->clear(SK_ColorTRANSPARENT);
    133 
    134             RenderNodeDrawable root(layerNode, layerCanvas, false);
    135             root.forceDraw(layerCanvas);
    136             layerCanvas->restoreToCount(saveCount);
    137             mLightCenter = savedLightCenter;
    138 
    139             // cache the current context so that we can defer flushing it until
    140             // either all the layers have been rendered or the context changes
    141             GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
    142             if (cachedContext.get() != currentContext) {
    143                 if (cachedContext.get()) {
    144                     ATRACE_NAME("flush layers (context changed)");
    145                     cachedContext->flush();
    146                 }
    147                 cachedContext.reset(SkSafeRef(currentContext));
    148             }
    149         }
    150     }
    151 
    152     if (cachedContext.get()) {
    153         ATRACE_NAME("flush layers");
    154         cachedContext->flush();
    155     }
    156 }
    157 
    158 bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
    159                                        ErrorHandler* errorHandler) {
    160     // compute the size of the surface (i.e. texture) to be allocated for this layer
    161     const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE;
    162     const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE;
    163 
    164     SkSurface* layer = node->getLayerSurface();
    165     if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) {
    166         SkImageInfo info;
    167         info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(),
    168                                  kPremul_SkAlphaType, getSurfaceColorSpace());
    169         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
    170         SkASSERT(mRenderThread.getGrContext() != nullptr);
    171         node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
    172                                                           SkBudgeted::kYes, info, 0,
    173                                                           this->getSurfaceOrigin(), &props));
    174         if (node->getLayerSurface()) {
    175             // update the transform in window of the layer to reset its origin wrt light source
    176             // position
    177             Matrix4 windowTransform;
    178             damageAccumulator.computeCurrentTransform(&windowTransform);
    179             node->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
    180         } else {
    181             String8 cachesOutput;
    182             mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput,
    183                                                          &mRenderThread.renderState());
    184             ALOGE("%s", cachesOutput.string());
    185             if (errorHandler) {
    186                 std::ostringstream err;
    187                 err << "Unable to create layer for " << node->getName();
    188                 const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
    189                 err << ", size " << info.width() << "x" << info.height() << " max size "
    190                     << maxTextureSize << " color type " << (int)info.colorType() << " has context "
    191                     << (int)(mRenderThread.getGrContext() != nullptr);
    192                 errorHandler->onError(err.str());
    193             }
    194         }
    195         return true;
    196     }
    197     return false;
    198 }
    199 
    200 void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
    201     GrContext* context = thread.getGrContext();
    202     if (context) {
    203         ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
    204         auto image = bitmap->makeImage();
    205         if (image.get() && !bitmap->isHardware()) {
    206             SkImage_pinAsTexture(image.get(), context);
    207             SkImage_unpinAsTexture(image.get(), context);
    208         }
    209     }
    210 }
    211 
    212 void SkiaPipeline::renderVectorDrawableCache() {
    213     if (!mVectorDrawables.empty()) {
    214         sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas();
    215         auto grContext = mRenderThread.getGrContext();
    216         atlas->prepareForDraw(grContext);
    217         ATRACE_NAME("Update VectorDrawables");
    218         for (auto vd : mVectorDrawables) {
    219             vd->updateCache(atlas, grContext);
    220         }
    221         mVectorDrawables.clear();
    222     }
    223 }
    224 
    225 static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
    226     CommonPool::post([data, filename] {
    227         if (0 == access(filename.c_str(), F_OK)) {
    228             return;
    229         }
    230 
    231         SkFILEWStream stream(filename.c_str());
    232         if (stream.isValid()) {
    233             stream.write(data->data(), data->size());
    234             stream.flush();
    235             SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
    236                      filename.c_str());
    237         }
    238     });
    239 }
    240 
    241 SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
    242     if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
    243         char prop[PROPERTY_VALUE_MAX] = {'\0'};
    244         if (mCaptureSequence <= 0) {
    245             property_get(PROPERTY_CAPTURE_SKP_FILENAME, prop, "0");
    246             if (prop[0] != '0' && mCapturedFile != prop) {
    247                 mCapturedFile = prop;
    248                 mCaptureSequence = property_get_int32(PROPERTY_CAPTURE_SKP_FRAMES, 1);
    249             }
    250         }
    251         if (mCaptureSequence > 0 || mPictureCapturedCallback) {
    252             mRecorder.reset(new SkPictureRecorder());
    253             SkCanvas* pictureCanvas =
    254                     mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
    255                                               SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
    256             mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
    257             mNwayCanvas->addCanvas(surface->getCanvas());
    258             mNwayCanvas->addCanvas(pictureCanvas);
    259             return mNwayCanvas.get();
    260         }
    261     }
    262     return surface->getCanvas();
    263 }
    264 
    265 void SkiaPipeline::endCapture(SkSurface* surface) {
    266     mNwayCanvas.reset();
    267     if (CC_UNLIKELY(mRecorder.get())) {
    268         ATRACE_CALL();
    269         sk_sp<SkPicture> picture = mRecorder->finishRecordingAsPicture();
    270         if (picture->approximateOpCount() > 0) {
    271             if (mCaptureSequence > 0) {
    272                 ATRACE_BEGIN("picture->serialize");
    273                 auto data = picture->serialize();
    274                 ATRACE_END();
    275 
    276                 // offload saving to file in a different thread
    277                 if (1 == mCaptureSequence) {
    278                     savePictureAsync(data, mCapturedFile);
    279                 } else {
    280                     savePictureAsync(data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
    281                 }
    282                 mCaptureSequence--;
    283             }
    284             if (mPictureCapturedCallback) {
    285                 std::invoke(mPictureCapturedCallback, std::move(picture));
    286             }
    287         }
    288         mRecorder.reset();
    289     }
    290 }
    291 
    292 void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
    293                                const std::vector<sp<RenderNode>>& nodes, bool opaque,
    294                                const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
    295                                const SkMatrix& preTransform) {
    296     bool previousSkpEnabled = Properties::skpCaptureEnabled;
    297     if (mPictureCapturedCallback) {
    298         Properties::skpCaptureEnabled = true;
    299     }
    300 
    301     renderVectorDrawableCache();
    302 
    303     // draw all layers up front
    304     renderLayersImpl(layers, opaque);
    305 
    306     // initialize the canvas for the current frame, that might be a recording canvas if SKP
    307     // capture is enabled.
    308     std::unique_ptr<SkPictureRecorder> recorder;
    309     SkCanvas* canvas = tryCapture(surface.get());
    310 
    311     renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
    312 
    313     endCapture(surface.get());
    314 
    315     if (CC_UNLIKELY(Properties::debugOverdraw)) {
    316         renderOverdraw(layers, clip, nodes, contentDrawBounds, surface, preTransform);
    317     }
    318 
    319     ATRACE_NAME("flush commands");
    320     surface->getCanvas()->flush();
    321 
    322     Properties::skpCaptureEnabled = previousSkpEnabled;
    323 }
    324 
    325 namespace {
    326 static Rect nodeBounds(RenderNode& node) {
    327     auto& props = node.properties();
    328     return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
    329 }
    330 }  // namespace
    331 
    332 void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
    333                                    const std::vector<sp<RenderNode>>& nodes, bool opaque,
    334                                    const Rect& contentDrawBounds, SkCanvas* canvas,
    335                                    const SkMatrix& preTransform) {
    336     SkAutoCanvasRestore saver(canvas, true);
    337     canvas->androidFramework_setDeviceClipRestriction(preTransform.mapRect(clip).roundOut());
    338     canvas->concat(preTransform);
    339 
    340     // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293
    341     if (!opaque || getSurfaceColorType() == kRGBA_F16_SkColorType) {
    342         canvas->clear(SK_ColorTRANSPARENT);
    343     }
    344 
    345     if (1 == nodes.size()) {
    346         if (!nodes[0]->nothingToDraw()) {
    347             RenderNodeDrawable root(nodes[0].get(), canvas);
    348             root.draw(canvas);
    349         }
    350     } else if (0 == nodes.size()) {
    351         // nothing to draw
    352     } else {
    353         // It there are multiple render nodes, they are laid out as follows:
    354         // #0 - backdrop (content + caption)
    355         // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop)
    356         // #2 - additional overlay nodes
    357         // Usually the backdrop cannot be seen since it will be entirely covered by the content.
    358         // While
    359         // resizing however it might become partially visible. The following render loop will crop
    360         // the
    361         // backdrop against the content and draw the remaining part of it. It will then draw the
    362         // content
    363         // cropped to the backdrop (since that indicates a shrinking of the window).
    364         //
    365         // Additional nodes will be drawn on top with no particular clipping semantics.
    366 
    367         // Usually the contents bounds should be mContentDrawBounds - however - we will
    368         // move it towards the fixed edge to give it a more stable appearance (for the moment).
    369         // If there is no content bounds we ignore the layering as stated above and start with 2.
    370 
    371         // Backdrop bounds in render target space
    372         const Rect backdrop = nodeBounds(*nodes[0]);
    373 
    374         // Bounds that content will fill in render target space (note content node bounds may be
    375         // bigger)
    376         Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight());
    377         content.translate(backdrop.left, backdrop.top);
    378         if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) {
    379             // Content doesn't entirely overlap backdrop, so fill around content (right/bottom)
    380 
    381             // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to
    382             // also fill left/top. Currently, both 2up and freeform position content at the top/left
    383             // of
    384             // the backdrop, so this isn't necessary.
    385             RenderNodeDrawable backdropNode(nodes[0].get(), canvas);
    386             if (content.right < backdrop.right) {
    387                 // draw backdrop to right side of content
    388                 SkAutoCanvasRestore acr(canvas, true);
    389                 canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top, backdrop.right,
    390                                                   backdrop.bottom));
    391                 backdropNode.draw(canvas);
    392             }
    393             if (content.bottom < backdrop.bottom) {
    394                 // draw backdrop to bottom of content
    395                 // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
    396                 SkAutoCanvasRestore acr(canvas, true);
    397                 canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom, content.right,
    398                                                   backdrop.bottom));
    399                 backdropNode.draw(canvas);
    400             }
    401         }
    402 
    403         RenderNodeDrawable contentNode(nodes[1].get(), canvas);
    404         if (!backdrop.isEmpty()) {
    405             // content node translation to catch up with backdrop
    406             float dx = backdrop.left - contentDrawBounds.left;
    407             float dy = backdrop.top - contentDrawBounds.top;
    408 
    409             SkAutoCanvasRestore acr(canvas, true);
    410             canvas->translate(dx, dy);
    411             const SkRect contentLocalClip =
    412                     SkRect::MakeXYWH(contentDrawBounds.left, contentDrawBounds.top,
    413                                      backdrop.getWidth(), backdrop.getHeight());
    414             canvas->clipRect(contentLocalClip);
    415             contentNode.draw(canvas);
    416         } else {
    417             SkAutoCanvasRestore acr(canvas, true);
    418             contentNode.draw(canvas);
    419         }
    420 
    421         // remaining overlay nodes, simply defer
    422         for (size_t index = 2; index < nodes.size(); index++) {
    423             if (!nodes[index]->nothingToDraw()) {
    424                 SkAutoCanvasRestore acr(canvas, true);
    425                 RenderNodeDrawable overlayNode(nodes[index].get(), canvas);
    426                 overlayNode.draw(canvas);
    427             }
    428         }
    429     }
    430 }
    431 
    432 void SkiaPipeline::dumpResourceCacheUsage() const {
    433     int resources, maxResources;
    434     size_t bytes, maxBytes;
    435     mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes);
    436     mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes);
    437 
    438     SkString log("Resource Cache Usage:\n");
    439     log.appendf("%8d items out of %d maximum items\n", resources, maxResources);
    440     log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", bytes,
    441                 bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
    442 
    443     ALOGD("%s", log.c_str());
    444 }
    445 
    446 void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
    447     if (colorMode == ColorMode::SRGB) {
    448         mSurfaceColorType = SkColorType::kN32_SkColorType;
    449         mSurfaceColorSpace = SkColorSpace::MakeSRGB();
    450     } else if (colorMode == ColorMode::WideColorGamut) {
    451         mSurfaceColorType = DeviceInfo::get()->getWideColorType();
    452         mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
    453     } else {
    454         LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
    455     }
    456 }
    457 
    458 // Overdraw debugging
    459 
    460 // These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
    461 // This implementation:
    462 // (1) Requires transparent entries for "no overdraw" and "single draws".
    463 // (2) Requires premul colors (instead of unpremul).
    464 // (3) Requires RGBA colors (instead of BGRA).
    465 static const uint32_t kOverdrawColors[2][6] = {
    466         {
    467                 0x00000000,
    468                 0x00000000,
    469                 0x2f2f0000,
    470                 0x2f002f00,
    471                 0x3f00003f,
    472                 0x7f00007f,
    473         },
    474         {
    475                 0x00000000,
    476                 0x00000000,
    477                 0x2f2f0000,
    478                 0x4f004f4f,
    479                 0x5f50335f,
    480                 0x7f00007f,
    481         },
    482 };
    483 
    484 void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
    485                                   const std::vector<sp<RenderNode>>& nodes,
    486                                   const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
    487                                   const SkMatrix& preTransform) {
    488     // Set up the overdraw canvas.
    489     SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
    490     sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
    491     SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas());
    492 
    493     // Fake a redraw to replay the draw commands.  This will increment the alpha channel
    494     // each time a pixel would have been drawn.
    495     // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
    496     // initialized.
    497     renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas, preTransform);
    498     sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
    499 
    500     // Draw overdraw colors to the canvas.  The color filter will convert counts to colors.
    501     SkPaint paint;
    502     const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
    503     paint.setColorFilter(SkOverdrawColorFilter::Make(colors));
    504     surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
    505 }
    506 
    507 } /* namespace skiapipeline */
    508 } /* namespace uirenderer */
    509 } /* namespace android */
    510