blob: 6606b02e09a667b000d2f4e61edcdb7f3ef31480 [file] [log] [blame]
Stan Iliev500a0c32016-10-26 10:30:09 -04001/*
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"
Hal Canary10219fb2016-11-23 20:41:22 -050020#include <SkImageEncoder.h>
Stan Iliev500a0c32016-10-26 10:30:09 -040021#include <SkOSFile.h>
Matt Sarettf58cc922016-11-14 18:33:38 -050022#include <SkOverdrawCanvas.h>
23#include <SkOverdrawColorFilter.h>
Stan Iliev500a0c32016-10-26 10:30:09 -040024#include <SkPicture.h>
25#include <SkPictureRecorder.h>
26#include <SkPixelSerializer.h>
27#include <SkStream.h>
28
29using namespace android::uirenderer::renderthread;
30
31namespace android {
32namespace uirenderer {
33namespace skiapipeline {
34
35float SkiaPipeline::mLightRadius = 0;
36uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
37uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
38
39Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
40
41SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { }
42
43TaskManager* SkiaPipeline::getTaskManager() {
44 return &mTaskManager;
45}
46
47void SkiaPipeline::onDestroyHardwareResources() {
48 // No need to flush the caches here. There is a timer
49 // which will flush temporary resources over time.
50}
51
Derek Sollenbergerb7d34b62016-11-04 10:46:18 -040052bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
53 for (SkImage* image : mutableImages) {
Derek Sollenberger189e8742016-11-16 16:00:17 -050054 if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) {
55 mPinnedImages.emplace_back(sk_ref_sp(image));
56 } else {
57 return false;
58 }
Derek Sollenbergerb7d34b62016-11-04 10:46:18 -040059 }
60 return true;
61}
62
63void SkiaPipeline::unpinImages() {
64 for (auto& image : mPinnedImages) {
65 SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext());
66 }
67 mPinnedImages.clear();
68}
69
Stan Iliev500a0c32016-10-26 10:30:09 -040070void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
71 LayerUpdateQueue* layerUpdateQueue, bool opaque,
72 const BakedOpRenderer::LightInfo& lightInfo) {
73 updateLighting(lightGeometry, lightInfo);
74 ATRACE_NAME("draw layers");
75 renderLayersImpl(*layerUpdateQueue, opaque);
76 layerUpdateQueue->clear();
77}
78
79void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
80 // Render all layers that need to be updated, in order.
81 for (size_t i = 0; i < layers.entries().size(); i++) {
82 RenderNode* layerNode = layers.entries()[i].renderNode;
83 // only schedule repaint if node still on layer - possible it may have been
84 // removed during a dropped frame, but layers may still remain scheduled so
85 // as not to lose info on what portion is damaged
86 if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) {
87 SkASSERT(layerNode->getLayerSurface());
88 SkASSERT(layerNode->getDisplayList()->isSkiaDL());
89 SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
90 if (!displayList || displayList->isEmpty()) {
91 SkDEBUGF(("%p drawLayers(%s) : missing drawable", this, layerNode->getName()));
92 return;
93 }
94
95 const Rect& layerDamage = layers.entries()[i].damage;
96
97 SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
98
99 int saveCount = layerCanvas->save();
100 SkASSERT(saveCount == 1);
101
Mike Reed6e49c9f2016-12-02 15:36:59 -0500102 layerCanvas->clipRect(layerDamage.toSkRect(), kReplace_SkClipOp);
Stan Iliev500a0c32016-10-26 10:30:09 -0400103
104 auto savedLightCenter = mLightCenter;
105 // map current light center into RenderNode's coordinate space
106 layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter);
107
108 const RenderProperties& properties = layerNode->properties();
109 const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
110 if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
111 return;
112 }
113
Matt Sarett79756be2016-11-09 16:13:54 -0500114 layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
Stan Iliev500a0c32016-10-26 10:30:09 -0400115 layerCanvas->clear(SK_ColorTRANSPARENT);
116
117 RenderNodeDrawable root(layerNode, layerCanvas, false);
118 root.forceDraw(layerCanvas);
119 layerCanvas->restoreToCount(saveCount);
120 layerCanvas->flush();
121 mLightCenter = savedLightCenter;
122 }
123 }
124}
125
126bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
127 const DamageAccumulator& damageAccumulator) {
128 SkSurface* layer = node->getLayerSurface();
129 if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
130 SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
131 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
132 SkASSERT(mRenderThread.getGrContext() != nullptr);
133 node->setLayerSurface(
134 SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
135 info, 0, &props));
136 if (node->getLayerSurface()) {
137 // update the transform in window of the layer to reset its origin wrt light source
138 // position
139 Matrix4 windowTransform;
140 damageAccumulator.computeCurrentTransform(&windowTransform);
141 node->getSkiaLayer()->inverseTransformInWindow = windowTransform;
142 }
143 return true;
144 }
145 return false;
146}
147
148void SkiaPipeline::destroyLayer(RenderNode* node) {
149 node->setLayerSurface(nullptr);
150}
151
152void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
153 GrContext* context = thread.getGrContext();
154 if (context) {
155 ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
156 SkBitmap skiaBitmap;
157 bitmap->getSkBitmap(&skiaBitmap);
158 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
159 SkImage_pinAsTexture(image.get(), context);
160 SkImage_unpinAsTexture(image.get(), context);
161 }
162}
163
164// Encodes to PNG, unless there is already encoded data, in which case that gets
165// used.
166class PngPixelSerializer : public SkPixelSerializer {
167public:
168 bool onUseEncodedData(const void*, size_t) override { return true; }
169 SkData* onEncode(const SkPixmap& pixmap) override {
Hal Canary10219fb2016-11-23 20:41:22 -0500170 SkDynamicMemoryWStream buf;
171 return SkEncodeImage(&buf, pixmap, SkEncodedImageFormat::kPNG, 100)
172 ? buf.detachAsData().release()
173 : nullptr;
Stan Iliev500a0c32016-10-26 10:30:09 -0400174 }
175};
176
177void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
178 const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
179 sk_sp<SkSurface> surface) {
180
Stan Iliev500a0c32016-10-26 10:30:09 -0400181 // draw all layers up front
182 renderLayersImpl(layers, opaque);
183
184 // initialize the canvas for the current frame
185 SkCanvas* canvas = surface->getCanvas();
186
187 std::unique_ptr<SkPictureRecorder> recorder;
188 bool recordingPicture = false;
189 char prop[PROPERTY_VALUE_MAX];
190 if (skpCaptureEnabled()) {
191 property_get("debug.hwui.capture_frame_as_skp", prop, "0");
192 recordingPicture = prop[0] != '0' && !sk_exists(prop);
193 if (recordingPicture) {
194 recorder.reset(new SkPictureRecorder());
195 canvas = recorder->beginRecording(surface->width(), surface->height(),
196 nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
197 }
198 }
199
Matt Sarettf58cc922016-11-14 18:33:38 -0500200 renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
201
202 if (skpCaptureEnabled() && recordingPicture) {
203 sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
204 if (picture->approximateOpCount() > 0) {
205 SkFILEWStream stream(prop);
206 if (stream.isValid()) {
207 PngPixelSerializer serializer;
208 picture->serialize(&stream, &serializer);
209 stream.flush();
210 SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
211 }
212 }
213 surface->getCanvas()->drawPicture(picture);
214 }
215
216 if (CC_UNLIKELY(Properties::debugOverdraw)) {
217 renderOverdraw(layers, clip, nodes, contentDrawBounds, surface);
218 }
219
220 ATRACE_NAME("flush commands");
221 canvas->flush();
222}
223
Stan Iliev52771272016-11-17 09:54:38 -0500224namespace {
225static Rect nodeBounds(RenderNode& node) {
226 auto& props = node.properties();
227 return Rect(props.getLeft(), props.getTop(),
228 props.getRight(), props.getBottom());
229}
230}
231
Matt Sarettf58cc922016-11-14 18:33:38 -0500232void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
233 const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
234 SkCanvas* canvas) {
235
Mike Reed6e49c9f2016-12-02 15:36:59 -0500236 canvas->clipRect(clip, kReplace_SkClipOp);
Stan Iliev500a0c32016-10-26 10:30:09 -0400237
238 if (!opaque) {
239 canvas->clear(SK_ColorTRANSPARENT);
240 }
241
Stan Iliev52771272016-11-17 09:54:38 -0500242 if (1 == nodes.size()) {
243 if (!nodes[0]->nothingToDraw()) {
244 SkAutoCanvasRestore acr(canvas, true);
245 RenderNodeDrawable root(nodes[0].get(), canvas);
246 root.draw(canvas);
247 }
248 } else if (0 == nodes.size()) {
249 //nothing to draw
250 } else {
251 // It there are multiple render nodes, they are laid out as follows:
252 // #0 - backdrop (content + caption)
253 // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop)
254 // #2 - additional overlay nodes
255 // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
256 // resizing however it might become partially visible. The following render loop will crop the
257 // backdrop against the content and draw the remaining part of it. It will then draw the content
258 // cropped to the backdrop (since that indicates a shrinking of the window).
259 //
260 // Additional nodes will be drawn on top with no particular clipping semantics.
Stan Iliev500a0c32016-10-26 10:30:09 -0400261
Stan Iliev52771272016-11-17 09:54:38 -0500262 // Usually the contents bounds should be mContentDrawBounds - however - we will
263 // move it towards the fixed edge to give it a more stable appearance (for the moment).
264 // If there is no content bounds we ignore the layering as stated above and start with 2.
Stan Iliev500a0c32016-10-26 10:30:09 -0400265
Stan Iliev52771272016-11-17 09:54:38 -0500266 // Backdrop bounds in render target space
267 const Rect backdrop = nodeBounds(*nodes[0]);
Stan Iliev500a0c32016-10-26 10:30:09 -0400268
Stan Iliev52771272016-11-17 09:54:38 -0500269 // Bounds that content will fill in render target space (note content node bounds may be bigger)
270 Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight());
271 content.translate(backdrop.left, backdrop.top);
272 if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) {
273 // Content doesn't entirely overlap backdrop, so fill around content (right/bottom)
Stan Iliev500a0c32016-10-26 10:30:09 -0400274
Stan Iliev52771272016-11-17 09:54:38 -0500275 // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to
276 // also fill left/top. Currently, both 2up and freeform position content at the top/left of
277 // the backdrop, so this isn't necessary.
278 RenderNodeDrawable backdropNode(nodes[0].get(), canvas);
279 if (content.right < backdrop.right) {
280 // draw backdrop to right side of content
281 SkAutoCanvasRestore acr(canvas, true);
282 canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top,
283 backdrop.right, backdrop.bottom));
284 backdropNode.draw(canvas);
285 }
286 if (content.bottom < backdrop.bottom) {
287 // draw backdrop to bottom of content
288 // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
289 SkAutoCanvasRestore acr(canvas, true);
290 canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom,
291 content.right, backdrop.bottom));
292 backdropNode.draw(canvas);
293 }
Stan Iliev500a0c32016-10-26 10:30:09 -0400294 }
295
Stan Iliev52771272016-11-17 09:54:38 -0500296 RenderNodeDrawable contentNode(nodes[1].get(), canvas);
297 if (!backdrop.isEmpty()) {
298 // content node translation to catch up with backdrop
299 float dx = backdrop.left - contentDrawBounds.left;
300 float dy = backdrop.top - contentDrawBounds.top;
301
302 SkAutoCanvasRestore acr(canvas, true);
303 canvas->translate(dx, dy);
304 const SkRect contentLocalClip = SkRect::MakeXYWH(contentDrawBounds.left,
305 contentDrawBounds.top, backdrop.getWidth(), backdrop.getHeight());
306 canvas->clipRect(contentLocalClip);
307 contentNode.draw(canvas);
308 } else {
309 SkAutoCanvasRestore acr(canvas, true);
310 contentNode.draw(canvas);
311 }
312
313 // remaining overlay nodes, simply defer
314 for (size_t index = 2; index < nodes.size(); index++) {
315 if (!nodes[index]->nothingToDraw()) {
316 SkAutoCanvasRestore acr(canvas, true);
317 RenderNodeDrawable overlayNode(nodes[index].get(), canvas);
318 overlayNode.draw(canvas);
319 }
320 }
Stan Iliev500a0c32016-10-26 10:30:09 -0400321 }
Stan Iliev500a0c32016-10-26 10:30:09 -0400322}
323
Matt Sarett4bda6bf2016-11-07 15:43:41 -0500324void SkiaPipeline::dumpResourceCacheUsage() const {
325 int resources, maxResources;
326 size_t bytes, maxBytes;
327 mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes);
328 mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes);
329
330 SkString log("Resource Cache Usage:\n");
331 log.appendf("%8d items out of %d maximum items\n", resources, maxResources);
332 log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n",
333 bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
334
335 ALOGD("%s", log.c_str());
336}
337
Matt Sarettf58cc922016-11-14 18:33:38 -0500338// Overdraw debugging
339
340// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
341// This implementation:
342// (1) Requires transparent entries for "no overdraw" and "single draws".
343// (2) Requires premul colors (instead of unpremul).
344// (3) Requires RGBA colors (instead of BGRA).
345static const uint32_t kOverdrawColors[2][6] = {
346 { 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, },
347 { 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, },
348};
349
350void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
351 const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds,
352 sk_sp<SkSurface> surface) {
353 // Set up the overdraw canvas.
354 SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
355 sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
356 SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas());
357
358 // Fake a redraw to replay the draw commands. This will increment the alpha channel
359 // each time a pixel would have been drawn.
360 // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
361 // initialized.
362 renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
363 sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
364
365 // Draw overdraw colors to the canvas. The color filter will convert counts to colors.
366 SkPaint paint;
367 const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
368 paint.setColorFilter(SkOverdrawColorFilter::Make(colors));
369 surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
370}
371
Stan Iliev500a0c32016-10-26 10:30:09 -0400372} /* namespace skiapipeline */
373} /* namespace uirenderer */
374} /* namespace android */