SkiaPipeline.cpp revision 4bda6bfaa6b8cb775f18f2453720d05f4cb29152
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 "utils/TraceUtils.h" 20#include <SkOSFile.h> 21#include <SkPicture.h> 22#include <SkPictureRecorder.h> 23#include <SkPixelSerializer.h> 24#include <SkStream.h> 25 26using namespace android::uirenderer::renderthread; 27 28namespace android { 29namespace uirenderer { 30namespace skiapipeline { 31 32float SkiaPipeline::mLightRadius = 0; 33uint8_t SkiaPipeline::mAmbientShadowAlpha = 0; 34uint8_t SkiaPipeline::mSpotShadowAlpha = 0; 35 36Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN}; 37 38SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { } 39 40TaskManager* SkiaPipeline::getTaskManager() { 41 return &mTaskManager; 42} 43 44void SkiaPipeline::onDestroyHardwareResources() { 45 // No need to flush the caches here. There is a timer 46 // which will flush temporary resources over time. 47} 48 49void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, 50 LayerUpdateQueue* layerUpdateQueue, bool opaque, 51 const BakedOpRenderer::LightInfo& lightInfo) { 52 updateLighting(lightGeometry, lightInfo); 53 ATRACE_NAME("draw layers"); 54 renderLayersImpl(*layerUpdateQueue, opaque); 55 layerUpdateQueue->clear(); 56} 57 58void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) { 59 // Render all layers that need to be updated, in order. 60 for (size_t i = 0; i < layers.entries().size(); i++) { 61 RenderNode* layerNode = layers.entries()[i].renderNode; 62 // only schedule repaint if node still on layer - possible it may have been 63 // removed during a dropped frame, but layers may still remain scheduled so 64 // as not to lose info on what portion is damaged 65 if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) { 66 SkASSERT(layerNode->getLayerSurface()); 67 SkASSERT(layerNode->getDisplayList()->isSkiaDL()); 68 SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList(); 69 if (!displayList || displayList->isEmpty()) { 70 SkDEBUGF(("%p drawLayers(%s) : missing drawable", this, layerNode->getName())); 71 return; 72 } 73 74 const Rect& layerDamage = layers.entries()[i].damage; 75 76 SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas(); 77 78 int saveCount = layerCanvas->save(); 79 SkASSERT(saveCount == 1); 80 81 layerCanvas->clipRect(layerDamage.toSkRect(), SkRegion::kReplace_Op); 82 83 auto savedLightCenter = mLightCenter; 84 // map current light center into RenderNode's coordinate space 85 layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter); 86 87 const RenderProperties& properties = layerNode->properties(); 88 const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); 89 if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) { 90 return; 91 } 92 93 layerCanvas->clear(SK_ColorTRANSPARENT); 94 95 RenderNodeDrawable root(layerNode, layerCanvas, false); 96 root.forceDraw(layerCanvas); 97 layerCanvas->restoreToCount(saveCount); 98 layerCanvas->flush(); 99 mLightCenter = savedLightCenter; 100 } 101 } 102} 103 104bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, 105 const DamageAccumulator& damageAccumulator) { 106 SkSurface* layer = node->getLayerSurface(); 107 if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) { 108 SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); 109 SkSurfaceProps props(0, kUnknown_SkPixelGeometry); 110 SkASSERT(mRenderThread.getGrContext() != nullptr); 111 node->setLayerSurface( 112 SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, 113 info, 0, &props)); 114 if (node->getLayerSurface()) { 115 // update the transform in window of the layer to reset its origin wrt light source 116 // position 117 Matrix4 windowTransform; 118 damageAccumulator.computeCurrentTransform(&windowTransform); 119 node->getSkiaLayer()->inverseTransformInWindow = windowTransform; 120 } 121 return true; 122 } 123 return false; 124} 125 126void SkiaPipeline::destroyLayer(RenderNode* node) { 127 node->setLayerSurface(nullptr); 128} 129 130void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { 131 GrContext* context = thread.getGrContext(); 132 if (context) { 133 ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); 134 SkBitmap skiaBitmap; 135 bitmap->getSkBitmap(&skiaBitmap); 136 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); 137 SkImage_pinAsTexture(image.get(), context); 138 SkImage_unpinAsTexture(image.get(), context); 139 } 140} 141 142// Encodes to PNG, unless there is already encoded data, in which case that gets 143// used. 144class PngPixelSerializer : public SkPixelSerializer { 145public: 146 bool onUseEncodedData(const void*, size_t) override { return true; } 147 SkData* onEncode(const SkPixmap& pixmap) override { 148 return SkImageEncoder::EncodeData(pixmap.info(), pixmap.addr(), pixmap.rowBytes(), 149 SkImageEncoder::kPNG_Type, 100); 150 } 151}; 152 153void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip, 154 const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds, 155 sk_sp<SkSurface> surface) { 156 157 // unpin all mutable images that were attached to nodes deleted while on the UI thread 158 SkiaDisplayList::cleanupImages(surface->getCanvas()->getGrContext()); 159 160 // draw all layers up front 161 renderLayersImpl(layers, opaque); 162 163 // initialize the canvas for the current frame 164 SkCanvas* canvas = surface->getCanvas(); 165 166 std::unique_ptr<SkPictureRecorder> recorder; 167 bool recordingPicture = false; 168 char prop[PROPERTY_VALUE_MAX]; 169 if (skpCaptureEnabled()) { 170 property_get("debug.hwui.capture_frame_as_skp", prop, "0"); 171 recordingPicture = prop[0] != '0' && !sk_exists(prop); 172 if (recordingPicture) { 173 recorder.reset(new SkPictureRecorder()); 174 canvas = recorder->beginRecording(surface->width(), surface->height(), 175 nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag); 176 } 177 } 178 179 canvas->clipRect(clip, SkRegion::kReplace_Op); 180 181 if (!opaque) { 182 canvas->clear(SK_ColorTRANSPARENT); 183 } 184 185 // If there are multiple render nodes, they are laid out as follows: 186 // #0 - backdrop (content + caption) 187 // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds) 188 // #2 - additional overlay nodes 189 // Usually the backdrop cannot be seen since it will be entirely covered by the content. While 190 // resizing however it might become partially visible. The following render loop will crop the 191 // backdrop against the content and draw the remaining part of it. It will then draw the content 192 // cropped to the backdrop (since that indicates a shrinking of the window). 193 // 194 // Additional nodes will be drawn on top with no particular clipping semantics. 195 196 // The bounds of the backdrop against which the content should be clipped. 197 Rect backdropBounds = contentDrawBounds; 198 // Usually the contents bounds should be mContentDrawBounds - however - we will 199 // move it towards the fixed edge to give it a more stable appearance (for the moment). 200 // If there is no content bounds we ignore the layering as stated above and start with 2. 201 int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0; 202 203 for (const sp<RenderNode>& node : nodes) { 204 if (node->nothingToDraw()) continue; 205 206 SkASSERT(node->getDisplayList()->isSkiaDL()); 207 208 int count = canvas->save(); 209 210 if (layer == 0) { 211 const RenderProperties& properties = node->properties(); 212 Rect targetBounds(properties.getLeft(), properties.getTop(), 213 properties.getRight(), properties.getBottom()); 214 // Move the content bounds towards the fixed corner of the backdrop. 215 const int x = targetBounds.left; 216 const int y = targetBounds.top; 217 // Remember the intersection of the target bounds and the intersection bounds against 218 // which we have to crop the content. 219 backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight()); 220 backdropBounds.doIntersect(targetBounds); 221 } else if (layer == 1) { 222 // We shift and clip the content to match its final location in the window. 223 const SkRect clip = SkRect::MakeXYWH(contentDrawBounds.left, contentDrawBounds.top, 224 backdropBounds.getWidth(), backdropBounds.getHeight()); 225 const float dx = backdropBounds.left - contentDrawBounds.left; 226 const float dy = backdropBounds.top - contentDrawBounds.top; 227 canvas->translate(dx, dy); 228 // It gets cropped against the bounds of the backdrop to stay inside. 229 canvas->clipRect(clip, SkRegion::kIntersect_Op); 230 } 231 232 RenderNodeDrawable root(node.get(), canvas); 233 root.draw(canvas); 234 canvas->restoreToCount(count); 235 layer++; 236 } 237 238 if (skpCaptureEnabled() && recordingPicture) { 239 sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture(); 240 if (picture->approximateOpCount() > 0) { 241 SkFILEWStream stream(prop); 242 if (stream.isValid()) { 243 PngPixelSerializer serializer; 244 picture->serialize(&stream, &serializer); 245 stream.flush(); 246 SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop); 247 } 248 } 249 surface->getCanvas()->drawPicture(picture); 250 } 251 252 ATRACE_NAME("flush commands"); 253 canvas->flush(); 254} 255 256void SkiaPipeline::dumpResourceCacheUsage() const { 257 int resources, maxResources; 258 size_t bytes, maxBytes; 259 mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes); 260 mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes); 261 262 SkString log("Resource Cache Usage:\n"); 263 log.appendf("%8d items out of %d maximum items\n", resources, maxResources); 264 log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", 265 bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f))); 266 267 ALOGD("%s", log.c_str()); 268} 269 270} /* namespace skiapipeline */ 271} /* namespace uirenderer */ 272} /* namespace android */ 273