summaryrefslogtreecommitdiff
path: root/libs/hwui/pipeline/skia/SkiaPipeline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/pipeline/skia/SkiaPipeline.cpp')
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp429
1 files changed, 285 insertions, 144 deletions
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 1f9ab5a242b4..5088494d6a07 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -19,31 +19,33 @@
#include <SkImageEncoder.h>
#include <SkImageInfo.h>
#include <SkImagePriv.h>
+#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
-#include "TreeInfo.h"
+#include <SkSerialProcs.h>
+#include <SkTypeface.h>
+#include <android-base/properties.h>
+#include <unistd.h>
+
+#include <sstream>
+
+#include "LightingInfo.h"
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
+#include "tools/SkSharingProc.h"
+#include "utils/String8.h"
#include "utils/TraceUtils.h"
-#include <unistd.h>
-
using namespace android::uirenderer::renderthread;
namespace android {
namespace uirenderer {
namespace skiapipeline {
-float SkiaPipeline::mLightRadius = 0;
-uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
-uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
-
-Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
-
SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
- mVectorDrawables.reserve(30);
+ setSurfaceColorProperties(mColorMode);
}
SkiaPipeline::~SkiaPipeline() {
@@ -73,18 +75,11 @@ void SkiaPipeline::unpinImages() {
mPinnedImages.clear();
}
-void SkiaPipeline::onPrepareTree() {
- // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without
- // a renderFrame in the middle.
- mVectorDrawables.clear();
-}
-
void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, bool opaque,
const LightInfo& lightInfo) {
- updateLighting(lightGeometry, lightInfo);
+ LightingInfo::updateLighting(lightGeometry, lightInfo);
ATRACE_NAME("draw layers");
- renderVectorDrawableCache();
renderLayersImpl(*layerUpdateQueue, opaque);
layerUpdateQueue->clear();
}
@@ -98,54 +93,61 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque)
// only schedule repaint if node still on layer - possible it may have been
// removed during a dropped frame, but layers may still remain scheduled so
// as not to lose info on what portion is damaged
- if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) {
- SkASSERT(layerNode->getLayerSurface());
- SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
- if (!displayList || displayList->isEmpty()) {
- SkDEBUGF(("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName()));
- return;
- }
+ if (CC_UNLIKELY(layerNode->getLayerSurface() == nullptr)) {
+ continue;
+ }
+ SkASSERT(layerNode->getLayerSurface());
+ SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
+ if (!displayList || displayList->isEmpty()) {
+ ALOGE("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName());
+ return;
+ }
- const Rect& layerDamage = layers.entries()[i].damage;
+ const Rect& layerDamage = layers.entries()[i].damage;
- SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
+ SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
- int saveCount = layerCanvas->save();
- SkASSERT(saveCount == 1);
+ int saveCount = layerCanvas->save();
+ SkASSERT(saveCount == 1);
- layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
+ layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
- auto savedLightCenter = mLightCenter;
- // map current light center into RenderNode's coordinate space
- layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter);
+ // TODO: put localized light center calculation and storage to a drawable related code.
+ // It does not seem right to store something localized in a global state
+ // fix here and in recordLayers
+ const Vector3 savedLightCenter(LightingInfo::getLightCenterRaw());
+ Vector3 transformedLightCenter(savedLightCenter);
+ // map current light center into RenderNode's coordinate space
+ layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(transformedLightCenter);
+ LightingInfo::setLightCenterRaw(transformedLightCenter);
- const RenderProperties& properties = layerNode->properties();
- const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
- if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
- return;
- }
+ const RenderProperties& properties = layerNode->properties();
+ const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
+ if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
+ return;
+ }
+
+ ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
+ bounds.height());
- ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
- bounds.height());
-
- layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
- layerCanvas->clear(SK_ColorTRANSPARENT);
-
- RenderNodeDrawable root(layerNode, layerCanvas, false);
- root.forceDraw(layerCanvas);
- layerCanvas->restoreToCount(saveCount);
- mLightCenter = savedLightCenter;
-
- // cache the current context so that we can defer flushing it until
- // either all the layers have been rendered or the context changes
- GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
- if (cachedContext.get() != currentContext) {
- if (cachedContext.get()) {
- ATRACE_NAME("flush layers (context changed)");
- cachedContext->flush();
- }
- cachedContext.reset(SkSafeRef(currentContext));
+ layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
+ layerCanvas->clear(SK_ColorTRANSPARENT);
+
+ RenderNodeDrawable root(layerNode, layerCanvas, false);
+ root.forceDraw(layerCanvas);
+ layerCanvas->restoreToCount(saveCount);
+
+ LightingInfo::setLightCenterRaw(savedLightCenter);
+
+ // cache the current context so that we can defer flushing it until
+ // either all the layers have been rendered or the context changes
+ GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
+ if (cachedContext.get() != currentContext) {
+ if (cachedContext.get()) {
+ ATRACE_NAME("flush layers (context changed)");
+ cachedContext->flush();
}
+ cachedContext.reset(SkSafeRef(currentContext));
}
}
@@ -209,19 +211,6 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
}
}
-void SkiaPipeline::renderVectorDrawableCache() {
- if (!mVectorDrawables.empty()) {
- sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas();
- auto grContext = mRenderThread.getGrContext();
- atlas->prepareForDraw(grContext);
- ATRACE_NAME("Update VectorDrawables");
- for (auto vd : mVectorDrawables) {
- vd->updateCache(atlas, grContext);
- }
- mVectorDrawables.clear();
- }
-}
-
static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
CommonPool::post([data, filename] {
if (0 == access(filename.c_str(), F_OK)) {
@@ -232,57 +221,204 @@ static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filen
if (stream.isValid()) {
stream.write(data->data(), data->size());
stream.flush();
- SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
+ ALOGD("SKP Captured Drawing Output (%zu bytes) for frame. %s", stream.bytesWritten(),
filename.c_str());
}
});
}
-SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
- if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
- char prop[PROPERTY_VALUE_MAX] = {'\0'};
+// Note multiple SkiaPipeline instances may be loaded if more than one app is visible.
+// Each instance may observe the filename changing and try to record to a file of the same name.
+// Only the first one will succeed. There is no scope available here where we could coordinate
+// to cause this function to return true for only one of the instances.
+bool SkiaPipeline::shouldStartNewFileCapture() {
+ // Don't start a new file based capture if one is currently ongoing.
+ if (mCaptureMode != CaptureMode::None) { return false; }
+
+ // A new capture is started when the filename property changes.
+ // Read the filename property.
+ std::string prop = base::GetProperty(PROPERTY_CAPTURE_SKP_FILENAME, "0");
+ // if the filename property changed to a valid value
+ if (prop[0] != '0' && mCapturedFile != prop) {
+ // remember this new filename
+ mCapturedFile = prop;
+ // and get a property indicating how many frames to capture.
+ mCaptureSequence = base::GetIntProperty(PROPERTY_CAPTURE_SKP_FRAMES, 1);
if (mCaptureSequence <= 0) {
- property_get(PROPERTY_CAPTURE_SKP_FILENAME, prop, "0");
- if (prop[0] != '0' && mCapturedFile != prop) {
- mCapturedFile = prop;
- mCaptureSequence = property_get_int32(PROPERTY_CAPTURE_SKP_FRAMES, 1);
- }
+ return false;
+ } else if (mCaptureSequence == 1) {
+ mCaptureMode = CaptureMode::SingleFrameSKP;
+ } else {
+ mCaptureMode = CaptureMode::MultiFrameSKP;
}
- if (mCaptureSequence > 0 || mPictureCapturedCallback) {
- mRecorder.reset(new SkPictureRecorder());
- SkCanvas* pictureCanvas =
- mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
- SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
- mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
- mNwayCanvas->addCanvas(surface->getCanvas());
- mNwayCanvas->addCanvas(pictureCanvas);
- return mNwayCanvas.get();
+ return true;
+ }
+ return false;
+}
+
+// performs the first-frame work of a multi frame SKP capture. Returns true if successful.
+bool SkiaPipeline::setupMultiFrameCapture() {
+ ALOGD("Set up multi-frame capture, frames = %d", mCaptureSequence);
+ // We own this stream and need to hold it until close() finishes.
+ auto stream = std::make_unique<SkFILEWStream>(mCapturedFile.c_str());
+ if (stream->isValid()) {
+ mOpenMultiPicStream = std::move(stream);
+ mSerialContext.reset(new SkSharingSerialContext());
+ SkSerialProcs procs;
+ procs.fImageProc = SkSharingSerialContext::serializeImage;
+ procs.fImageCtx = mSerialContext.get();
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
+ // SkDocuments don't take owership of the streams they write.
+ // we need to keep it until after mMultiPic.close()
+ // procs is passed as a pointer, but just as a method of having an optional default.
+ // procs doesn't need to outlive this Make call.
+ mMultiPic = SkMakeMultiPictureDocument(mOpenMultiPicStream.get(), &procs);
+ return true;
+ } else {
+ ALOGE("Could not open \"%s\" for writing.", mCapturedFile.c_str());
+ mCaptureSequence = 0;
+ mCaptureMode = CaptureMode::None;
+ return false;
+ }
+}
+
+// recurse through the rendernode's children, add any nodes which are layers to the queue.
+static void collectLayers(RenderNode* node, LayerUpdateQueue* layers) {
+ SkiaDisplayList* dl = (SkiaDisplayList*)node->getDisplayList();
+ if (dl) {
+ const auto& prop = node->properties();
+ if (node->hasLayer()) {
+ layers->enqueueLayerWithDamage(node, Rect(prop.getWidth(), prop.getHeight()));
+ }
+ // The way to recurse through rendernodes is to call this with a lambda.
+ dl->updateChildren([&](RenderNode* child) { collectLayers(child, layers); });
+ }
+}
+
+// record the provided layers to the provided canvas as self-contained skpictures.
+static void recordLayers(const LayerUpdateQueue& layers,
+ SkCanvas* mskpCanvas) {
+ const Vector3 savedLightCenter(LightingInfo::getLightCenterRaw());
+ // Record the commands to re-draw each dirty layer into an SkPicture
+ for (size_t i = 0; i < layers.entries().size(); i++) {
+ RenderNode* layerNode = layers.entries()[i].renderNode.get();
+ const Rect& layerDamage = layers.entries()[i].damage;
+ const RenderProperties& properties = layerNode->properties();
+
+ // Temporarily map current light center into RenderNode's coordinate space
+ Vector3 transformedLightCenter(savedLightCenter);
+ layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(transformedLightCenter);
+ LightingInfo::setLightCenterRaw(transformedLightCenter);
+
+ SkPictureRecorder layerRec;
+ auto* recCanvas = layerRec.beginRecording(properties.getWidth(),
+ properties.getHeight());
+ // This is not recorded but still causes clipping.
+ recCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
+ RenderNodeDrawable root(layerNode, recCanvas, false);
+ root.forceDraw(recCanvas);
+ // Now write this picture into the SKP canvas with an annotation indicating what it is
+ mskpCanvas->drawAnnotation(layerDamage.toSkRect(), String8::format(
+ "OffscreenLayerDraw|%" PRId64, layerNode->uniqueId()).c_str(), nullptr);
+ mskpCanvas->drawPicture(layerRec.finishRecordingAsPicture());
+ }
+ LightingInfo::setLightCenterRaw(savedLightCenter);
+}
+
+SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface, RenderNode* root,
+ const LayerUpdateQueue& dirtyLayers) {
+ if (CC_LIKELY(!Properties::skpCaptureEnabled)) {
+ return surface->getCanvas(); // Bail out early when capture is not turned on.
+ }
+ // Note that shouldStartNewFileCapture tells us if this is the *first* frame of a capture.
+ bool firstFrameOfAnim = false;
+ if (shouldStartNewFileCapture() && mCaptureMode == CaptureMode::MultiFrameSKP) {
+ // set a reminder to record every layer near the end of this method, after we have set up
+ // the nway canvas.
+ firstFrameOfAnim = true;
+ if (!setupMultiFrameCapture()) {
+ return surface->getCanvas();
}
}
- return surface->getCanvas();
+
+ // Create a canvas pointer, fill it depending on what kind of capture is requested (if any)
+ SkCanvas* pictureCanvas = nullptr;
+ switch (mCaptureMode) {
+ case CaptureMode::CallbackAPI:
+ case CaptureMode::SingleFrameSKP:
+ mRecorder.reset(new SkPictureRecorder());
+ pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height());
+ break;
+ case CaptureMode::MultiFrameSKP:
+ // If a multi frame recording is active, initialize recording for a single frame of a
+ // multi frame file.
+ pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+ break;
+ case CaptureMode::None:
+ // Returning here in the non-capture case means we can count on pictureCanvas being
+ // non-null below.
+ return surface->getCanvas();
+ }
+
+ // Setting up an nway canvas is common to any kind of capture.
+ mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+ mNwayCanvas->addCanvas(surface->getCanvas());
+ mNwayCanvas->addCanvas(pictureCanvas);
+
+ if (firstFrameOfAnim) {
+ // On the first frame of any mskp capture we want to record any layers that are needed in
+ // frame but may have been rendered offscreen before recording began.
+ // We do not maintain a list of all layers, since it isn't needed outside this rare,
+ // recording use case. Traverse the tree to find them and put them in this LayerUpdateQueue.
+ LayerUpdateQueue luq;
+ collectLayers(root, &luq);
+ recordLayers(luq, mNwayCanvas.get());
+ } else {
+ // on non-first frames, we record any normal layer draws (dirty regions)
+ recordLayers(dirtyLayers, mNwayCanvas.get());
+ }
+
+ return mNwayCanvas.get();
}
void SkiaPipeline::endCapture(SkSurface* surface) {
+ if (CC_LIKELY(mCaptureMode == CaptureMode::None)) { return; }
mNwayCanvas.reset();
- if (CC_UNLIKELY(mRecorder.get())) {
- ATRACE_CALL();
+ ATRACE_CALL();
+ if (mCaptureSequence > 0 && mCaptureMode == CaptureMode::MultiFrameSKP) {
+ mMultiPic->endPage();
+ mCaptureSequence--;
+ if (mCaptureSequence == 0) {
+ mCaptureMode = CaptureMode::None;
+ // Pass mMultiPic and mOpenMultiPicStream to a background thread, which will handle
+ // the heavyweight serialization work and destroy them. mOpenMultiPicStream is released
+ // to a bare pointer because keeping it in a smart pointer makes the lambda
+ // non-copyable. The lambda is only called once, so this is safe.
+ SkFILEWStream* stream = mOpenMultiPicStream.release();
+ CommonPool::post([doc = std::move(mMultiPic), stream]{
+ ALOGD("Finalizing multi frame SKP");
+ doc->close();
+ delete stream;
+ ALOGD("Multi frame SKP complete.");
+ });
+ }
+ } else {
sk_sp<SkPicture> picture = mRecorder->finishRecordingAsPicture();
if (picture->approximateOpCount() > 0) {
- if (mCaptureSequence > 0) {
- ATRACE_BEGIN("picture->serialize");
- auto data = picture->serialize();
- ATRACE_END();
-
- // offload saving to file in a different thread
- if (1 == mCaptureSequence) {
- savePictureAsync(data, mCapturedFile);
- } else {
- savePictureAsync(data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
- }
- mCaptureSequence--;
- }
if (mPictureCapturedCallback) {
std::invoke(mPictureCapturedCallback, std::move(picture));
+ } else {
+ // single frame skp to file
+ SkSerialProcs procs;
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
+ auto data = picture->serialize();
+ savePictureAsync(data, mCapturedFile);
+ mCaptureSequence = 0;
+ mCaptureMode = CaptureMode::None;
}
}
mRecorder.reset();
@@ -298,22 +434,19 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
Properties::skpCaptureEnabled = true;
}
- renderVectorDrawableCache();
+ // Initialize the canvas for the current frame, that might be a recording canvas if SKP
+ // capture is enabled.
+ SkCanvas* canvas = tryCapture(surface.get(), nodes[0].get(), layers);
// draw all layers up front
renderLayersImpl(layers, opaque);
- // initialize the canvas for the current frame, that might be a recording canvas if SKP
- // capture is enabled.
- std::unique_ptr<SkPictureRecorder> recorder;
- SkCanvas* canvas = tryCapture(surface.get());
-
- renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
+ renderFrameImpl(clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
endCapture(surface.get());
if (CC_UNLIKELY(Properties::debugOverdraw)) {
- renderOverdraw(layers, clip, nodes, contentDrawBounds, surface, preTransform);
+ renderOverdraw(clip, nodes, contentDrawBounds, surface, preTransform);
}
ATRACE_NAME("flush commands");
@@ -329,12 +462,21 @@ static Rect nodeBounds(RenderNode& node) {
}
} // namespace
-void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
+void SkiaPipeline::renderFrameImpl(const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
const Rect& contentDrawBounds, SkCanvas* canvas,
const SkMatrix& preTransform) {
SkAutoCanvasRestore saver(canvas, true);
- canvas->androidFramework_setDeviceClipRestriction(preTransform.mapRect(clip).roundOut());
+ auto clipRestriction = preTransform.mapRect(clip).roundOut();
+ if (CC_UNLIKELY(mCaptureMode == CaptureMode::SingleFrameSKP
+ || mCaptureMode == CaptureMode::MultiFrameSKP)) {
+ canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction",
+ nullptr);
+ } else {
+ // clip drawing to dirty region only when not recording SKP files (which should contain all
+ // draw ops on every frame)
+ canvas->androidFramework_setDeviceClipRestriction(clipRestriction);
+ }
canvas->concat(preTransform);
// STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293
@@ -430,13 +572,13 @@ void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect&
}
void SkiaPipeline::dumpResourceCacheUsage() const {
- int resources, maxResources;
- size_t bytes, maxBytes;
+ int resources;
+ size_t bytes;
mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes);
- mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes);
+ size_t maxBytes = mRenderThread.getGrContext()->getResourceCacheLimit();
SkString log("Resource Cache Usage:\n");
- log.appendf("%8d items out of %d maximum items\n", resources, maxResources);
+ log.appendf("%8d items\n", resources);
log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", bytes,
bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
@@ -444,6 +586,7 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
}
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
+ mColorMode = colorMode;
if (colorMode == ColorMode::SRGB) {
mSurfaceColorType = SkColorType::kN32_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeSRGB();
@@ -458,49 +601,47 @@ void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
// Overdraw debugging
// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
-// This implementation:
-// (1) Requires transparent entries for "no overdraw" and "single draws".
-// (2) Requires premul colors (instead of unpremul).
-// (3) Requires RGBA colors (instead of BGRA).
-static const uint32_t kOverdrawColors[2][6] = {
- {
- 0x00000000,
- 0x00000000,
- 0x2f2f0000,
- 0x2f002f00,
- 0x3f00003f,
- 0x7f00007f,
- },
- {
- 0x00000000,
- 0x00000000,
- 0x2f2f0000,
- 0x4f004f4f,
- 0x5f50335f,
- 0x7f00007f,
- },
+// This implementation requires transparent entries for "no overdraw" and "single draws".
+static const SkColor kOverdrawColors[2][6] = {
+ {
+ 0x00000000,
+ 0x00000000,
+ 0x2f0000ff,
+ 0x2f00ff00,
+ 0x3fff0000,
+ 0x7fff0000,
+ },
+ {
+ 0x00000000,
+ 0x00000000,
+ 0x2f0000ff,
+ 0x4fffff00,
+ 0x5fff89d7,
+ 0x7fff0000,
+ },
};
-void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+void SkiaPipeline::renderOverdraw(const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes,
const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
const SkMatrix& preTransform) {
// Set up the overdraw canvas.
SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
+ LOG_ALWAYS_FATAL_IF(!offscreen, "Failed to create offscreen SkSurface for overdraw viz.");
SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas());
// Fake a redraw to replay the draw commands. This will increment the alpha channel
// each time a pixel would have been drawn.
// Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
// initialized.
- renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas, preTransform);
+ renderFrameImpl(clip, nodes, true, contentDrawBounds, &overdrawCanvas, preTransform);
sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
// Draw overdraw colors to the canvas. The color filter will convert counts to colors.
SkPaint paint;
- const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
- paint.setColorFilter(SkOverdrawColorFilter::Make(colors));
+ const SkColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
+ paint.setColorFilter(SkOverdrawColorFilter::MakeWithSkColors(colors));
surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
}