Merge "Enable offscreen buffers in mskp captures for RenderEngine" into sc-dev
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index dc14fc2..55ec6ad 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -518,7 +518,7 @@
}
void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
- if (mCapture->isCaptureRunning()) {
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
// Record display settings when capture is running.
std::stringstream displaySettings;
PrintTo(display, &displaySettings);
@@ -626,6 +626,7 @@
// offscreen buffer and when to render to the native buffer.
sk_sp<SkSurface> activeSurface(dstSurface);
SkCanvas* canvas = dstCanvas;
+ SkiaCapture::OffscreenState offscreenCaptureState;
const LayerSettings* blurCompositionLayer = nullptr;
if (mBlurFilter) {
bool requiresCompositionLayer = false;
@@ -642,7 +643,7 @@
}
if (requiresCompositionLayer) {
activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
- canvas = activeSurface->getCanvas();
+ canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
blurCompositionLayer = layer;
break;
}
@@ -692,7 +693,15 @@
// blit the offscreen framebuffer into the destination AHB
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
- activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+ dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+ String8::format("SurfaceID|%" PRId64, id).c_str(),
+ nullptr);
+ dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+ } else {
+ activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+ }
// assign dstCanvas to canvas and ensure that the canvas state is up to date
canvas = dstCanvas;
@@ -709,7 +718,7 @@
}
canvas->save();
- if (mCapture->isCaptureRunning()) {
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
// Record the name of the layer if the capture is running.
std::stringstream layerSettings;
PrintTo(*layer, &layerSettings);
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index e9cfead..40f5cf2 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -41,11 +41,11 @@
mTimer.stop();
}
-SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
// If we are not running yet, set up.
- if (!mCaptureRunning) {
+ if (CC_LIKELY(!mCaptureRunning)) {
mTimerInterval = std::chrono::milliseconds(
base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
// Set up the multi-frame capture. If we fail to set it up, then just return canvas.
@@ -56,7 +56,8 @@
// Start the new timer. When timer expires, write to file.
mTimer.setTimeout(
[this] {
- endCapture();
+ const std::scoped_lock lock(mMutex);
+ LOG_ALWAYS_FATAL_IF(mCurrentPageCanvas != nullptr);
writeToFile();
// To avoid going in circles, set the flag to 0. This way the capture can be
// restarted just by setting the flag and without restarting the process.
@@ -65,29 +66,82 @@
mTimerInterval);
}
+ mMutex.lock();
+
// Create a canvas pointer, fill it.
- SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+ mCurrentPageCanvas = mMultiPic->beginPage(surface->width(), surface->height());
// 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);
+ mNwayCanvas->addCanvas(mCurrentPageCanvas);
return mNwayCanvas.get();
}
-void SkiaCapture::endCapture() {
+void SkiaCapture::endCapture() NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
// Don't end anything if we are not running.
- if (!mCaptureRunning) {
+ if (CC_LIKELY(!mCaptureRunning)) {
return;
}
// Reset the canvas pointer.
+ mCurrentPageCanvas = nullptr;
mNwayCanvas.reset();
// End page.
if (mMultiPic) {
mMultiPic->endPage();
}
+ mMutex.unlock();
+}
+
+SkCanvas* SkiaCapture::tryOffscreenCapture(SkSurface* surface, OffscreenState* state) {
+ ATRACE_CALL();
+ // Don't start anything if we are not running.
+ if (CC_LIKELY(!mCaptureRunning)) {
+ return surface->getCanvas();
+ }
+
+ // Create a canvas pointer, fill it.
+ state->offscreenRecorder = std::make_unique<SkPictureRecorder>();
+ SkCanvas* pictureCanvas =
+ state->offscreenRecorder->beginRecording(surface->width(), surface->height());
+
+ // Setting up an nway canvas is common to any kind of capture.
+ state->offscreenCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+ state->offscreenCanvas->addCanvas(surface->getCanvas());
+ state->offscreenCanvas->addCanvas(pictureCanvas);
+
+ return state->offscreenCanvas.get();
+}
+
+uint64_t SkiaCapture::endOffscreenCapture(OffscreenState* state) {
+ ATRACE_CALL();
+ // Don't end anything if we are not running.
+ if (CC_LIKELY(!mCaptureRunning)) {
+ return 0;
+ }
+
+ // compute the uniqueID for this capture
+ static std::atomic<uint64_t> nextID{1};
+ const uint64_t uniqueID = nextID.fetch_add(1, std::memory_order_relaxed);
+
+ // Reset the canvas pointer as we are no longer drawing into it
+ state->offscreenCanvas.reset();
+
+ // Record the offscreen as a picture in the currently active page.
+ SkRect bounds =
+ SkRect::Make(state->offscreenRecorder->getRecordingCanvas()->imageInfo().dimensions());
+ mCurrentPageCanvas
+ ->drawAnnotation(bounds,
+ String8::format("OffscreenLayerDraw|%" PRId64, uniqueID).c_str(),
+ nullptr);
+ mCurrentPageCanvas->drawPicture(state->offscreenRecorder->finishRecordingAsPicture());
+
+ // Reset the offscreen picture recorder
+ state->offscreenRecorder.reset();
+
+ return uniqueID;
}
void SkiaCapture::writeToFile() {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index eaaf598..08a1359 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -18,8 +18,12 @@
#include <SkDocument.h>
#include <SkNWayCanvas.h>
+#include <SkPictureRecorder.h>
#include <SkSurface.h>
+
#include <chrono>
+#include <mutex>
+
#include "CaptureTimer.h"
#include "tools/SkSharingProc.h"
@@ -48,6 +52,16 @@
// Returns whether the capture is running.
bool isCaptureRunning() { return mCaptureRunning; }
+ // Offscreen state member variables are private to SkiaCapture, but the allocation
+ // and lifetime is managed by the caller. This enables nested offscreen
+ // captures to occur.
+ struct OffscreenState {
+ std::unique_ptr<SkPictureRecorder> offscreenRecorder;
+ std::unique_ptr<SkNWayCanvas> offscreenCanvas;
+ };
+ SkCanvas* tryOffscreenCapture(SkSurface* surface, OffscreenState* state);
+ uint64_t endOffscreenCapture(OffscreenState* state);
+
private:
// Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
bool setupMultiFrameCapture();
@@ -61,10 +75,16 @@
std::unique_ptr<SkSharingSerialContext> mSerialContext;
std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+ SkCanvas* mCurrentPageCanvas;
+
// Capturing and interval control.
bool mCaptureRunning = false;
CaptureTimer mTimer;
Interval mTimerInterval = 0ms;
+
+ // Mutex to ensure that a frame in progress when the timer fires is allowed to run to
+ // completion before we write the file to disk.
+ std::mutex mMutex;
};
} // namespace skia