SkiaPipeline.cpp revision 52771272f4f018f4fc6846224bf047497e784af1
1500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev/* 2500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * Copyright (C) 2016 The Android Open Source Project 3500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * 4500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * Licensed under the Apache License, Version 2.0 (the "License"); 5500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * you may not use this file except in compliance with the License. 6500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * You may obtain a copy of the License at 7500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * 8500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * http://www.apache.org/licenses/LICENSE-2.0 9500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * 10500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * Unless required by applicable law or agreed to in writing, software 11500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * distributed under the License is distributed on an "AS IS" BASIS, 12500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * See the License for the specific language governing permissions and 14500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * limitations under the License. 15500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev */ 16500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 17500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "SkiaPipeline.h" 18500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 19500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "utils/TraceUtils.h" 2010219fb261606fcc71c607167b28295b4578a10dHal Canary#include <SkImageEncoder.h> 21500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include <SkOSFile.h> 22f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett#include <SkOverdrawCanvas.h> 23f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett#include <SkOverdrawColorFilter.h> 24500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include <SkPicture.h> 25500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include <SkPictureRecorder.h> 26500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include <SkPixelSerializer.h> 27500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include <SkStream.h> 28500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 29500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievusing namespace android::uirenderer::renderthread; 30500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 31500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievnamespace android { 32500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievnamespace uirenderer { 33500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievnamespace skiapipeline { 34500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 35500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievfloat SkiaPipeline::mLightRadius = 0; 36500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievuint8_t SkiaPipeline::mAmbientShadowAlpha = 0; 37500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievuint8_t SkiaPipeline::mSpotShadowAlpha = 0; 38500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 39500a0c30d4dcd012218c3e44a62926a1c34a259fStan IlievVector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN}; 40500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 41500a0c30d4dcd012218c3e44a62926a1c34a259fStan IlievSkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { } 42500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 43500a0c30d4dcd012218c3e44a62926a1c34a259fStan IlievTaskManager* SkiaPipeline::getTaskManager() { 44500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev return &mTaskManager; 45500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 46500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 47500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievvoid SkiaPipeline::onDestroyHardwareResources() { 48500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // No need to flush the caches here. There is a timer 49500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // which will flush temporary resources over time. 50500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 51500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 52b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenbergerbool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) { 53b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger for (SkImage* image : mutableImages) { 54189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) { 55189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger mPinnedImages.emplace_back(sk_ref_sp(image)); 56189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger } else { 57189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger return false; 58189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger } 59b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger } 60b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger return true; 61b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger} 62b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger 63b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenbergervoid SkiaPipeline::unpinImages() { 64b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger for (auto& image : mPinnedImages) { 65b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext()); 66b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger } 67b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger mPinnedImages.clear(); 68b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger} 69b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger 70500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievvoid SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, 71500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev LayerUpdateQueue* layerUpdateQueue, bool opaque, 72500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev const BakedOpRenderer::LightInfo& lightInfo) { 73500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev updateLighting(lightGeometry, lightInfo); 74500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev ATRACE_NAME("draw layers"); 75500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev renderLayersImpl(*layerUpdateQueue, opaque); 76500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev layerUpdateQueue->clear(); 77500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 78500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 79500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievvoid SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) { 80500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // Render all layers that need to be updated, in order. 81500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev for (size_t i = 0; i < layers.entries().size(); i++) { 82500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev RenderNode* layerNode = layers.entries()[i].renderNode; 83500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // only schedule repaint if node still on layer - possible it may have been 84500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // removed during a dropped frame, but layers may still remain scheduled so 85500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // as not to lose info on what portion is damaged 86500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) { 87500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkASSERT(layerNode->getLayerSurface()); 88500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkASSERT(layerNode->getDisplayList()->isSkiaDL()); 89500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList(); 90500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (!displayList || displayList->isEmpty()) { 91500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkDEBUGF(("%p drawLayers(%s) : missing drawable", this, layerNode->getName())); 92500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev return; 93500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 94500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 95500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev const Rect& layerDamage = layers.entries()[i].damage; 96500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 97500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas(); 98500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 99500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev int saveCount = layerCanvas->save(); 100500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkASSERT(saveCount == 1); 101500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 1026e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reed layerCanvas->clipRect(layerDamage.toSkRect(), kReplace_SkClipOp); 103500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 104500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev auto savedLightCenter = mLightCenter; 105500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // map current light center into RenderNode's coordinate space 106500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter); 107500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 108500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev const RenderProperties& properties = layerNode->properties(); 109500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); 110500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) { 111500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev return; 112500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 113500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 11479756be175dea78ee9d51bb22abba7621bd9b5ccMatt Sarett layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false; 115500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev layerCanvas->clear(SK_ColorTRANSPARENT); 116500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 117500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev RenderNodeDrawable root(layerNode, layerCanvas, false); 118500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev root.forceDraw(layerCanvas); 119500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev layerCanvas->restoreToCount(saveCount); 120500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev layerCanvas->flush(); 121500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev mLightCenter = savedLightCenter; 122500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 123500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 124500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 125500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 126500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievbool SkiaPipeline::createOrUpdateLayer(RenderNode* node, 127500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev const DamageAccumulator& damageAccumulator) { 128500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkSurface* layer = node->getLayerSurface(); 129500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) { 130500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); 131500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkSurfaceProps props(0, kUnknown_SkPixelGeometry); 132500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkASSERT(mRenderThread.getGrContext() != nullptr); 133500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev node->setLayerSurface( 134500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, 135500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev info, 0, &props)); 136500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (node->getLayerSurface()) { 137500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // update the transform in window of the layer to reset its origin wrt light source 138500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // position 139500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev Matrix4 windowTransform; 140500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev damageAccumulator.computeCurrentTransform(&windowTransform); 141500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev node->getSkiaLayer()->inverseTransformInWindow = windowTransform; 142500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 143500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev return true; 144500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 145500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev return false; 146500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 147500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 148500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievvoid SkiaPipeline::destroyLayer(RenderNode* node) { 149500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev node->setLayerSurface(nullptr); 150500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 151500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 152500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievvoid SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { 153500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev GrContext* context = thread.getGrContext(); 154500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (context) { 155500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); 156500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkBitmap skiaBitmap; 157500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev bitmap->getSkBitmap(&skiaBitmap); 158500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); 159500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkImage_pinAsTexture(image.get(), context); 160500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkImage_unpinAsTexture(image.get(), context); 161500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 162500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 163500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 164500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev// Encodes to PNG, unless there is already encoded data, in which case that gets 165500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev// used. 166500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievclass PngPixelSerializer : public SkPixelSerializer { 167500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievpublic: 168500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev bool onUseEncodedData(const void*, size_t) override { return true; } 169500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkData* onEncode(const SkPixmap& pixmap) override { 17010219fb261606fcc71c607167b28295b4578a10dHal Canary SkDynamicMemoryWStream buf; 17110219fb261606fcc71c607167b28295b4578a10dHal Canary return SkEncodeImage(&buf, pixmap, SkEncodedImageFormat::kPNG, 100) 17210219fb261606fcc71c607167b28295b4578a10dHal Canary ? buf.detachAsData().release() 17310219fb261606fcc71c607167b28295b4578a10dHal Canary : nullptr; 174500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 175500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}; 176500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 177500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievvoid SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip, 178500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds, 179500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev sk_sp<SkSurface> surface) { 180500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 181500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // draw all layers up front 182500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev renderLayersImpl(layers, opaque); 183500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 184500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev // initialize the canvas for the current frame 185500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev SkCanvas* canvas = surface->getCanvas(); 186500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 187500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev std::unique_ptr<SkPictureRecorder> recorder; 188500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev bool recordingPicture = false; 189500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev char prop[PROPERTY_VALUE_MAX]; 190500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (skpCaptureEnabled()) { 191500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev property_get("debug.hwui.capture_frame_as_skp", prop, "0"); 192500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev recordingPicture = prop[0] != '0' && !sk_exists(prop); 193500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (recordingPicture) { 194500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev recorder.reset(new SkPictureRecorder()); 195500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev canvas = recorder->beginRecording(surface->width(), surface->height(), 196500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag); 197500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 198500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 199500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 200f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas); 201f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 202f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett if (skpCaptureEnabled() && recordingPicture) { 203f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture(); 204f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett if (picture->approximateOpCount() > 0) { 205f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett SkFILEWStream stream(prop); 206f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett if (stream.isValid()) { 207f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett PngPixelSerializer serializer; 208f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett picture->serialize(&stream, &serializer); 209f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett stream.flush(); 210f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop); 211f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett } 212f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett } 213f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett surface->getCanvas()->drawPicture(picture); 214f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett } 215f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 216f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett if (CC_UNLIKELY(Properties::debugOverdraw)) { 217f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett renderOverdraw(layers, clip, nodes, contentDrawBounds, surface); 218f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett } 219f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 220f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett ATRACE_NAME("flush commands"); 221f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett canvas->flush(); 222f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett} 223f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 22452771272f4f018f4fc6846224bf047497e784af1Stan Ilievnamespace { 22552771272f4f018f4fc6846224bf047497e784af1Stan Ilievstatic Rect nodeBounds(RenderNode& node) { 22652771272f4f018f4fc6846224bf047497e784af1Stan Iliev auto& props = node.properties(); 22752771272f4f018f4fc6846224bf047497e784af1Stan Iliev return Rect(props.getLeft(), props.getTop(), 22852771272f4f018f4fc6846224bf047497e784af1Stan Iliev props.getRight(), props.getBottom()); 22952771272f4f018f4fc6846224bf047497e784af1Stan Iliev} 23052771272f4f018f4fc6846224bf047497e784af1Stan Iliev} 23152771272f4f018f4fc6846224bf047497e784af1Stan Iliev 232f58cc92066903b900396f640159ea3ea992fc67dMatt Sarettvoid SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, 233f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds, 234f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett SkCanvas* canvas) { 235f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 2366e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reed canvas->clipRect(clip, kReplace_SkClipOp); 237500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 238500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev if (!opaque) { 239500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev canvas->clear(SK_ColorTRANSPARENT); 240500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 241500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 24252771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (1 == nodes.size()) { 24352771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (!nodes[0]->nothingToDraw()) { 24452771272f4f018f4fc6846224bf047497e784af1Stan Iliev SkAutoCanvasRestore acr(canvas, true); 24552771272f4f018f4fc6846224bf047497e784af1Stan Iliev RenderNodeDrawable root(nodes[0].get(), canvas); 24652771272f4f018f4fc6846224bf047497e784af1Stan Iliev root.draw(canvas); 24752771272f4f018f4fc6846224bf047497e784af1Stan Iliev } 24852771272f4f018f4fc6846224bf047497e784af1Stan Iliev } else if (0 == nodes.size()) { 24952771272f4f018f4fc6846224bf047497e784af1Stan Iliev //nothing to draw 25052771272f4f018f4fc6846224bf047497e784af1Stan Iliev } else { 25152771272f4f018f4fc6846224bf047497e784af1Stan Iliev // It there are multiple render nodes, they are laid out as follows: 25252771272f4f018f4fc6846224bf047497e784af1Stan Iliev // #0 - backdrop (content + caption) 25352771272f4f018f4fc6846224bf047497e784af1Stan Iliev // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop) 25452771272f4f018f4fc6846224bf047497e784af1Stan Iliev // #2 - additional overlay nodes 25552771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Usually the backdrop cannot be seen since it will be entirely covered by the content. While 25652771272f4f018f4fc6846224bf047497e784af1Stan Iliev // resizing however it might become partially visible. The following render loop will crop the 25752771272f4f018f4fc6846224bf047497e784af1Stan Iliev // backdrop against the content and draw the remaining part of it. It will then draw the content 25852771272f4f018f4fc6846224bf047497e784af1Stan Iliev // cropped to the backdrop (since that indicates a shrinking of the window). 25952771272f4f018f4fc6846224bf047497e784af1Stan Iliev // 26052771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Additional nodes will be drawn on top with no particular clipping semantics. 26152771272f4f018f4fc6846224bf047497e784af1Stan Iliev 26252771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Usually the contents bounds should be mContentDrawBounds - however - we will 26352771272f4f018f4fc6846224bf047497e784af1Stan Iliev // move it towards the fixed edge to give it a more stable appearance (for the moment). 26452771272f4f018f4fc6846224bf047497e784af1Stan Iliev // If there is no content bounds we ignore the layering as stated above and start with 2. 26552771272f4f018f4fc6846224bf047497e784af1Stan Iliev 26652771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Backdrop bounds in render target space 26752771272f4f018f4fc6846224bf047497e784af1Stan Iliev const Rect backdrop = nodeBounds(*nodes[0]); 26852771272f4f018f4fc6846224bf047497e784af1Stan Iliev 26952771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Bounds that content will fill in render target space (note content node bounds may be bigger) 27052771272f4f018f4fc6846224bf047497e784af1Stan Iliev Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight()); 27152771272f4f018f4fc6846224bf047497e784af1Stan Iliev content.translate(backdrop.left, backdrop.top); 27252771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) { 27352771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Content doesn't entirely overlap backdrop, so fill around content (right/bottom) 27452771272f4f018f4fc6846224bf047497e784af1Stan Iliev 27552771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to 27652771272f4f018f4fc6846224bf047497e784af1Stan Iliev // also fill left/top. Currently, both 2up and freeform position content at the top/left of 27752771272f4f018f4fc6846224bf047497e784af1Stan Iliev // the backdrop, so this isn't necessary. 27852771272f4f018f4fc6846224bf047497e784af1Stan Iliev RenderNodeDrawable backdropNode(nodes[0].get(), canvas); 27952771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (content.right < backdrop.right) { 28052771272f4f018f4fc6846224bf047497e784af1Stan Iliev // draw backdrop to right side of content 28152771272f4f018f4fc6846224bf047497e784af1Stan Iliev SkAutoCanvasRestore acr(canvas, true); 28252771272f4f018f4fc6846224bf047497e784af1Stan Iliev canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top, 28352771272f4f018f4fc6846224bf047497e784af1Stan Iliev backdrop.right, backdrop.bottom)); 28452771272f4f018f4fc6846224bf047497e784af1Stan Iliev backdropNode.draw(canvas); 28552771272f4f018f4fc6846224bf047497e784af1Stan Iliev } 28652771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (content.bottom < backdrop.bottom) { 28752771272f4f018f4fc6846224bf047497e784af1Stan Iliev // draw backdrop to bottom of content 28852771272f4f018f4fc6846224bf047497e784af1Stan Iliev // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill 28952771272f4f018f4fc6846224bf047497e784af1Stan Iliev SkAutoCanvasRestore acr(canvas, true); 29052771272f4f018f4fc6846224bf047497e784af1Stan Iliev canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom, 29152771272f4f018f4fc6846224bf047497e784af1Stan Iliev content.right, backdrop.bottom)); 29252771272f4f018f4fc6846224bf047497e784af1Stan Iliev backdropNode.draw(canvas); 29352771272f4f018f4fc6846224bf047497e784af1Stan Iliev } 29452771272f4f018f4fc6846224bf047497e784af1Stan Iliev } 29552771272f4f018f4fc6846224bf047497e784af1Stan Iliev 29652771272f4f018f4fc6846224bf047497e784af1Stan Iliev RenderNodeDrawable contentNode(nodes[1].get(), canvas); 29752771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (!backdrop.isEmpty()) { 29852771272f4f018f4fc6846224bf047497e784af1Stan Iliev // content node translation to catch up with backdrop 29952771272f4f018f4fc6846224bf047497e784af1Stan Iliev float dx = backdrop.left - contentDrawBounds.left; 30052771272f4f018f4fc6846224bf047497e784af1Stan Iliev float dy = backdrop.top - contentDrawBounds.top; 30152771272f4f018f4fc6846224bf047497e784af1Stan Iliev 30252771272f4f018f4fc6846224bf047497e784af1Stan Iliev SkAutoCanvasRestore acr(canvas, true); 303500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev canvas->translate(dx, dy); 30452771272f4f018f4fc6846224bf047497e784af1Stan Iliev const SkRect contentLocalClip = SkRect::MakeXYWH(contentDrawBounds.left, 30552771272f4f018f4fc6846224bf047497e784af1Stan Iliev contentDrawBounds.top, backdrop.getWidth(), backdrop.getHeight()); 30652771272f4f018f4fc6846224bf047497e784af1Stan Iliev canvas->clipRect(contentLocalClip); 30752771272f4f018f4fc6846224bf047497e784af1Stan Iliev contentNode.draw(canvas); 30852771272f4f018f4fc6846224bf047497e784af1Stan Iliev } else { 30952771272f4f018f4fc6846224bf047497e784af1Stan Iliev SkAutoCanvasRestore acr(canvas, true); 31052771272f4f018f4fc6846224bf047497e784af1Stan Iliev contentNode.draw(canvas); 311500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 312500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 31352771272f4f018f4fc6846224bf047497e784af1Stan Iliev // remaining overlay nodes, simply defer 31452771272f4f018f4fc6846224bf047497e784af1Stan Iliev for (size_t index = 2; index < nodes.size(); index++) { 31552771272f4f018f4fc6846224bf047497e784af1Stan Iliev if (!nodes[index]->nothingToDraw()) { 31652771272f4f018f4fc6846224bf047497e784af1Stan Iliev SkAutoCanvasRestore acr(canvas, true); 31752771272f4f018f4fc6846224bf047497e784af1Stan Iliev RenderNodeDrawable overlayNode(nodes[index].get(), canvas); 31852771272f4f018f4fc6846224bf047497e784af1Stan Iliev overlayNode.draw(canvas); 31952771272f4f018f4fc6846224bf047497e784af1Stan Iliev } 32052771272f4f018f4fc6846224bf047497e784af1Stan Iliev } 321500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev } 322500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} 323500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev 3244bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarettvoid SkiaPipeline::dumpResourceCacheUsage() const { 3254bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett int resources, maxResources; 3264bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett size_t bytes, maxBytes; 3274bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes); 3284bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes); 3294bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett 3304bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett SkString log("Resource Cache Usage:\n"); 3314bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett log.appendf("%8d items out of %d maximum items\n", resources, maxResources); 3324bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", 3334bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f))); 3344bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett 3354bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett ALOGD("%s", log.c_str()); 3364bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett} 3374bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett 338f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett// Overdraw debugging 339f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 340f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences. 341f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett// This implementation: 342f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett// (1) Requires transparent entries for "no overdraw" and "single draws". 343f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett// (2) Requires premul colors (instead of unpremul). 344f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett// (3) Requires RGBA colors (instead of BGRA). 345f58cc92066903b900396f640159ea3ea992fc67dMatt Sarettstatic const uint32_t kOverdrawColors[2][6] = { 346f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett { 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, }, 347f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett { 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, }, 348f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett}; 349f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 350f58cc92066903b900396f640159ea3ea992fc67dMatt Sarettvoid SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip, 351f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds, 352f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett sk_sp<SkSurface> surface) { 353f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett // Set up the overdraw canvas. 354f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height()); 355f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo); 356f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas()); 357f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 358f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett // Fake a redraw to replay the draw commands. This will increment the alpha channel 359f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett // each time a pixel would have been drawn. 360f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero 361f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett // initialized. 362f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas); 363f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett sk_sp<SkImage> counts = offscreen->makeImageSnapshot(); 364f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 365f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett // Draw overdraw colors to the canvas. The color filter will convert counts to colors. 366f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett SkPaint paint; 367f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)]; 368f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett paint.setColorFilter(SkOverdrawColorFilter::Make(colors)); 369f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint); 370f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett} 371f58cc92066903b900396f640159ea3ea992fc67dMatt Sarett 372500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} /* namespace skiapipeline */ 373500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} /* namespace uirenderer */ 374500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev} /* namespace android */ 375