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