blob: 430d6bea70c1e8ce4330f517a9009c344e184b07 [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>
Leon Scroggins IIIee708fa2016-12-12 15:31:39 -050021#include <SkImagePriv.h>
Stan Iliev500a0c32016-10-26 10:30:09 -040022#include <SkOSFile.h>
Matt Sarettf58cc922016-11-14 18:33:38 -050023#include <SkOverdrawCanvas.h>
24#include <SkOverdrawColorFilter.h>
Stan Iliev500a0c32016-10-26 10:30:09 -040025#include <SkPicture.h>
26#include <SkPictureRecorder.h>
27#include <SkPixelSerializer.h>
28#include <SkStream.h>
29
30using namespace android::uirenderer::renderthread;
31
32namespace android {
33namespace uirenderer {
34namespace skiapipeline {
35
36float SkiaPipeline::mLightRadius = 0;
37uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
38uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
39
40Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
41
42SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { }
43
44TaskManager* SkiaPipeline::getTaskManager() {
45 return &mTaskManager;
46}
47
48void SkiaPipeline::onDestroyHardwareResources() {
49 // No need to flush the caches here. There is a timer
50 // which will flush temporary resources over time.
51}
52
Derek Sollenbergerb7d34b62016-11-04 10:46:18 -040053bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
54 for (SkImage* image : mutableImages) {
Derek Sollenberger189e8742016-11-16 16:00:17 -050055 if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) {
56 mPinnedImages.emplace_back(sk_ref_sp(image));
57 } else {
58 return false;
59 }
Derek Sollenbergerb7d34b62016-11-04 10:46:18 -040060 }
61 return true;
62}
63
64void SkiaPipeline::unpinImages() {
65 for (auto& image : mPinnedImages) {
66 SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext());
67 }
68 mPinnedImages.clear();
69}
70
Stan Iliev500a0c32016-10-26 10:30:09 -040071void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
72 LayerUpdateQueue* layerUpdateQueue, bool opaque,
73 const BakedOpRenderer::LightInfo& lightInfo) {
74 updateLighting(lightGeometry, lightInfo);
75 ATRACE_NAME("draw layers");
76 renderLayersImpl(*layerUpdateQueue, opaque);
77 layerUpdateQueue->clear();
78}
79
80void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
81 // Render all layers that need to be updated, in order.
82 for (size_t i = 0; i < layers.entries().size(); i++) {
83 RenderNode* layerNode = layers.entries()[i].renderNode;
84 // only schedule repaint if node still on layer - possible it may have been
85 // removed during a dropped frame, but layers may still remain scheduled so
86 // as not to lose info on what portion is damaged
87 if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) {
88 SkASSERT(layerNode->getLayerSurface());
89 SkASSERT(layerNode->getDisplayList()->isSkiaDL());
90 SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
91 if (!displayList || displayList->isEmpty()) {
92 SkDEBUGF(("%p drawLayers(%s) : missing drawable", this, layerNode->getName()));
93 return;
94 }
95
96 const Rect& layerDamage = layers.entries()[i].damage;
97
98 SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
99
100 int saveCount = layerCanvas->save();
101 SkASSERT(saveCount == 1);
102
Stan Ilievb66b8bb2016-12-15 18:17:42 -0500103 layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
Stan Iliev500a0c32016-10-26 10:30:09 -0400104
105 auto savedLightCenter = mLightCenter;
106 // map current light center into RenderNode's coordinate space
107 layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter);
108
109 const RenderProperties& properties = layerNode->properties();
110 const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
111 if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
112 return;
113 }
114
Matt Sarett79756be2016-11-09 16:13:54 -0500115 layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
Stan Iliev500a0c32016-10-26 10:30:09 -0400116 layerCanvas->clear(SK_ColorTRANSPARENT);
117
118 RenderNodeDrawable root(layerNode, layerCanvas, false);
119 root.forceDraw(layerCanvas);
120 layerCanvas->restoreToCount(saveCount);
121 layerCanvas->flush();
122 mLightCenter = savedLightCenter;
123 }
124 }
125}
126
127bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
128 const DamageAccumulator& damageAccumulator) {
129 SkSurface* layer = node->getLayerSurface();
130 if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
131 SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
132 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
133 SkASSERT(mRenderThread.getGrContext() != nullptr);
134 node->setLayerSurface(
135 SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
136 info, 0, &props));
137 if (node->getLayerSurface()) {
138 // update the transform in window of the layer to reset its origin wrt light source
139 // position
140 Matrix4 windowTransform;
141 damageAccumulator.computeCurrentTransform(&windowTransform);
142 node->getSkiaLayer()->inverseTransformInWindow = windowTransform;
143 }
144 return true;
145 }
146 return false;
147}
148
149void SkiaPipeline::destroyLayer(RenderNode* node) {
150 node->setLayerSurface(nullptr);
151}
152
153void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
154 GrContext* context = thread.getGrContext();
155 if (context) {
156 ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
157 SkBitmap skiaBitmap;
158 bitmap->getSkBitmap(&skiaBitmap);
159 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
160 SkImage_pinAsTexture(image.get(), context);
161 SkImage_unpinAsTexture(image.get(), context);
162 }
163}
164
165// Encodes to PNG, unless there is already encoded data, in which case that gets
166// used.
167class PngPixelSerializer : public SkPixelSerializer {
168public:
169 bool onUseEncodedData(const void*, size_t) override { return true; }
170 SkData* onEncode(const SkPixmap& pixmap) override {
Hal Canary10219fb2016-11-23 20:41:22 -0500171 SkDynamicMemoryWStream buf;
172 return SkEncodeImage(&buf, pixmap, SkEncodedImageFormat::kPNG, 100)
173 ? buf.detachAsData().release()
174 : nullptr;
Stan Iliev500a0c32016-10-26 10:30:09 -0400175 }
176};
177
178void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
179 const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
180 sk_sp<SkSurface> surface) {
181
Stan Iliev500a0c32016-10-26 10:30:09 -0400182 // draw all layers up front
183 renderLayersImpl(layers, opaque);
184
185 // initialize the canvas for the current frame
186 SkCanvas* canvas = surface->getCanvas();
187
188 std::unique_ptr<SkPictureRecorder> recorder;
189 bool recordingPicture = false;
190 char prop[PROPERTY_VALUE_MAX];
191 if (skpCaptureEnabled()) {
192 property_get("debug.hwui.capture_frame_as_skp", prop, "0");
193 recordingPicture = prop[0] != '0' && !sk_exists(prop);
194 if (recordingPicture) {
195 recorder.reset(new SkPictureRecorder());
196 canvas = recorder->beginRecording(surface->width(), surface->height(),
197 nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
198 }
199 }
200
Matt Sarettf58cc922016-11-14 18:33:38 -0500201 renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
202
203 if (skpCaptureEnabled() && recordingPicture) {
204 sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
205 if (picture->approximateOpCount() > 0) {
206 SkFILEWStream stream(prop);
207 if (stream.isValid()) {
208 PngPixelSerializer serializer;
209 picture->serialize(&stream, &serializer);
210 stream.flush();
211 SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
212 }
213 }
214 surface->getCanvas()->drawPicture(picture);
215 }
216
217 if (CC_UNLIKELY(Properties::debugOverdraw)) {
218 renderOverdraw(layers, clip, nodes, contentDrawBounds, surface);
219 }
220
221 ATRACE_NAME("flush commands");
222 canvas->flush();
223}
224
Stan Iliev52771272016-11-17 09:54:38 -0500225namespace {
226static Rect nodeBounds(RenderNode& node) {
227 auto& props = node.properties();
228 return Rect(props.getLeft(), props.getTop(),
229 props.getRight(), props.getBottom());
230}
231}
232
Matt Sarettf58cc922016-11-14 18:33:38 -0500233void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
234 const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
235 SkCanvas* canvas) {
Stan Ilievb66b8bb2016-12-15 18:17:42 -0500236 SkAutoCanvasRestore saver(canvas, true);
237 canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
Stan Iliev500a0c32016-10-26 10:30:09 -0400238
239 if (!opaque) {
240 canvas->clear(SK_ColorTRANSPARENT);
241 }
242
Stan Iliev52771272016-11-17 09:54:38 -0500243 if (1 == nodes.size()) {
244 if (!nodes[0]->nothingToDraw()) {
Stan Iliev52771272016-11-17 09:54:38 -0500245 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 */