Add continuous SKP capture test api
Bug: 122856066
Test: PictureCaptureDemo
Change-Id: Iaf3a4bc1c8a2c18c7dff635c5f1cf726b331f8bf
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index dd62bbb..7265692 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -551,6 +551,19 @@
SkPaint paint = inPaint;
paint.setAlpha(mProperties.getRootAlpha() * 255);
+ if (canvas->getGrContext() == nullptr) {
+ // Recording to picture, don't use the SkSurface which won't work off of renderthread.
+ Bitmap& bitmap = getBitmapUpdateIfDirty();
+ SkBitmap skiaBitmap;
+ bitmap.getSkBitmap(&skiaBitmap);
+
+ int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
+ int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
+ canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
+ &paint, SkCanvas::kFast_SrcRectConstraint);
+ return;
+ }
+
SkRect src;
sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
if (vdSurface) {
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 240efb4..60c8057 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -74,7 +74,13 @@
void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
if (canvas->getGrContext() == nullptr) {
- SkDEBUGF(("Attempting to draw GLFunctor into an unsupported surface"));
+ // We're dumping a picture, render a light-blue rectangle instead
+ // TODO: Draw the WebView text on top? Seemingly complicated as SkPaint doesn't
+ // seem to have a default typeface that works. We only ever use drawGlyphs, which
+ // requires going through minikin & hwui's canvas which we don't have here.
+ SkPaint paint;
+ paint.setColor(0xFF81D4FA);
+ canvas->drawRect(mBounds, paint);
return;
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index df82243..47c9094 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -111,7 +111,7 @@
const Rect& layerDamage = layers.entries()[i].damage;
- SkCanvas* layerCanvas = tryCapture(layerNode->getLayerSurface());
+ SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
int saveCount = layerCanvas->save();
SkASSERT(saveCount == 1);
@@ -139,8 +139,6 @@
layerCanvas->restoreToCount(saveCount);
mLightCenter = savedLightCenter;
- endCapture(layerNode->getLayerSurface());
-
// 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();
@@ -244,6 +242,7 @@
}
virtual void onProcess(const sp<Task<bool>>& task) override {
+ ATRACE_NAME("SavePictureTask");
SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
if (0 == access(t->filename.c_str(), F_OK)) {
@@ -265,46 +264,56 @@
SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
- bool recordingPicture = mCaptureSequence > 0;
char prop[PROPERTY_VALUE_MAX] = {'\0'};
- if (!recordingPicture) {
+ if (mCaptureSequence <= 0) {
property_get(PROPERTY_CAPTURE_SKP_FILENAME, prop, "0");
- recordingPicture = prop[0] != '0' &&
- mCapturedFile != prop; // ensure we capture only once per filename
- if (recordingPicture) {
+ if (prop[0] != '0' && mCapturedFile != prop) {
mCapturedFile = prop;
mCaptureSequence = property_get_int32(PROPERTY_CAPTURE_SKP_FRAMES, 1);
}
}
- if (recordingPicture) {
+ if (mCaptureSequence > 0 || mPictureCapturedCallback) {
mRecorder.reset(new SkPictureRecorder());
- return mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
- SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+ 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 surface->getCanvas();
}
void SkiaPipeline::endCapture(SkSurface* surface) {
+ mNwayCanvas.reset();
if (CC_UNLIKELY(mRecorder.get())) {
+ ATRACE_CALL();
sk_sp<SkPicture> picture = mRecorder->finishRecordingAsPicture();
- surface->getCanvas()->drawPicture(picture);
if (picture->approximateOpCount() > 0) {
- auto data = picture->serialize();
+ if (mCaptureSequence > 0) {
+ ATRACE_BEGIN("picture->serialize");
+ auto data = picture->serialize();
+ ATRACE_END();
- // offload saving to file in a different thread
- if (!mSavePictureProcessor.get()) {
- TaskManager* taskManager = getTaskManager();
- mSavePictureProcessor = new SavePictureProcessor(
- taskManager->canRunTasks() ? taskManager : nullptr);
+ // offload saving to file in a different thread
+ if (!mSavePictureProcessor.get()) {
+ TaskManager* taskManager = getTaskManager();
+ mSavePictureProcessor = new SavePictureProcessor(
+ taskManager->canRunTasks() ? taskManager : nullptr);
+ }
+ if (1 == mCaptureSequence) {
+ mSavePictureProcessor->savePicture(data, mCapturedFile);
+ } else {
+ mSavePictureProcessor->savePicture(
+ data,
+ mCapturedFile + "_" + std::to_string(mCaptureSequence));
+ }
+ mCaptureSequence--;
}
- if (1 == mCaptureSequence) {
- mSavePictureProcessor->savePicture(data, mCapturedFile);
- } else {
- mSavePictureProcessor->savePicture(
- data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
+ if (mPictureCapturedCallback) {
+ std::invoke(mPictureCapturedCallback, std::move(picture));
}
- mCaptureSequence--;
}
mRecorder.reset();
}
@@ -314,6 +323,11 @@
const std::vector<sp<RenderNode>>& nodes, bool opaque,
const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
const SkMatrix& preTransform) {
+ bool previousSkpEnabled = Properties::skpCaptureEnabled;
+ if (mPictureCapturedCallback) {
+ Properties::skpCaptureEnabled = true;
+ }
+
renderVectorDrawableCache();
// draw all layers up front
@@ -334,6 +348,8 @@
ATRACE_NAME("flush commands");
surface->getCanvas()->flush();
+
+ Properties::skpCaptureEnabled = previousSkpEnabled;
}
namespace {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index cf6f5b2..e9957df 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -105,6 +105,11 @@
mLightCenter = lightGeometry.center;
}
+ void setPictureCapturedCallback(
+ const std::function<void(sk_sp<SkPicture>&&)>& callback) override {
+ mPictureCapturedCallback = callback;
+ }
+
protected:
void dumpResourceCacheUsage() const;
void setSurfaceColorProperties(renderthread::ColorMode colorMode);
@@ -163,6 +168,8 @@
* parallel tryCapture calls (not really needed).
*/
std::unique_ptr<SkPictureRecorder> mRecorder;
+ std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+ std::function<void(sk_sp<SkPicture>&&)> mPictureCapturedCallback;
static float mLightRadius;
static uint8_t mAmbientShadowAlpha;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 9e7abf4..db97763 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -184,6 +184,10 @@
mFrameCompleteCallbacks.push_back(std::move(func));
}
+ void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback) {
+ mRenderPipeline->setPictureCapturedCallback(callback);
+ }
+
void setForceDark(bool enable) {
mUseForceDark = enable;
}
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index d4dd629..2cfc8df 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -59,15 +59,15 @@
virtual MakeCurrentResult makeCurrent() = 0;
virtual Frame getFrame() = 0;
virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
- bool opaque, const LightInfo& lightInfo,
+ const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) = 0;
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
- virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
+ virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior,
+ ColorMode colorMode) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
virtual bool isContextReady() = 0;
@@ -85,6 +85,8 @@
virtual SkColorType getSurfaceColorType() const = 0;
virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
+ virtual void setPictureCapturedCallback(
+ const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0;
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index aa6af23..ab59af7 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -21,6 +21,7 @@
#include "Properties.h"
#include "Readback.h"
#include "Rect.h"
+#include "WebViewFunctorManager.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/VectorDrawableAtlas.h"
#include "renderstate/RenderState.h"
@@ -30,7 +31,6 @@
#include "renderthread/RenderThread.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
-#include "WebViewFunctorManager.h"
#include <ui/GraphicBuffer.h>
@@ -147,9 +147,7 @@
void RenderProxy::destroyFunctor(int functor) {
ATRACE_CALL();
RenderThread& thread = RenderThread::getInstance();
- thread.queue().post([=]() {
- WebViewFunctorManager::instance().destroyFunctor(functor);
- });
+ thread.queue().post([=]() { WebViewFunctorManager::instance().destroyFunctor(functor); });
}
DeferredLayerUpdater* RenderProxy::createTextureLayer() {
@@ -164,9 +162,9 @@
bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
auto& thread = RenderThread::getInstance();
- return thread.queue().runSync(
- [&]() -> bool { return thread.readback().copyLayerInto(layer, &bitmap)
- == CopyResult::Success; });
+ return thread.queue().runSync([&]() -> bool {
+ return thread.readback().copyLayerInto(layer, &bitmap) == CopyResult::Success;
+ });
}
void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -204,9 +202,8 @@
}
int RenderProxy::maxTextureSize() {
- static int maxTextureSize = RenderThread::getInstance().queue().runSync([]() {
- return DeviceInfo::get()->maxTextureSize();
- });
+ static int maxTextureSize = RenderThread::getInstance().queue().runSync(
+ []() { return DeviceInfo::get()->maxTextureSize(); });
return maxTextureSize;
}
@@ -281,6 +278,12 @@
mDrawFrameTask.setContentDrawBounds(left, top, right, bottom);
}
+void RenderProxy::setPictureCapturedCallback(
+ const std::function<void(sk_sp<SkPicture>&&)>& callback) {
+ mRenderThread.queue().post(
+ [ this, cb = callback ]() { mContext->setPictureCapturedCallback(cb); });
+}
+
void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
mDrawFrameTask.setFrameCallback(std::move(callback));
}
@@ -302,9 +305,7 @@
}
void RenderProxy::setForceDark(bool enable) {
- mRenderThread.queue().post([this, enable]() {
- mContext->setForceDark(enable);
- });
+ mRenderThread.queue().post([this, enable]() { mContext->setForceDark(enable); });
}
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
@@ -348,9 +349,8 @@
// TODO: fix everything that hits this. We should never be triggering a readback ourselves.
return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
} else {
- return thread.queue().runSync([&]() -> int {
- return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
- });
+ return thread.queue().runSync(
+ [&]() -> int { return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap); });
}
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 9dc9181..6e1bfd7 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -114,6 +114,8 @@
ANDROID_API void removeRenderNode(RenderNode* node);
ANDROID_API void drawRenderNode(RenderNode* node);
ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
+ ANDROID_API void setPictureCapturedCallback(
+ const std::function<void(sk_sp<SkPicture>&&)>& callback);
ANDROID_API void setFrameCallback(std::function<void(int64_t)>&& callback);
ANDROID_API void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);