diff options
| -rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.cpp | 17 | ||||
| -rw-r--r-- | libs/renderengine/skia/debug/SkiaCapture.cpp | 68 | ||||
| -rw-r--r-- | libs/renderengine/skia/debug/SkiaCapture.h | 20 |
3 files changed, 94 insertions, 11 deletions
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index dc14fc2cc7..55ec6ad351 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -518,7 +518,7 @@ sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> sh } 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 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, // 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 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } if (requiresCompositionLayer) { activeSurface = dstSurface->makeSurface(dstSurface->imageInfo()); - canvas = activeSurface->getCanvas(); + canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState); blurCompositionLayer = layer; break; } @@ -692,7 +693,15 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, // 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 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } 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 e9cfead8b6..40f5cf299d 100644 --- a/libs/renderengine/skia/debug/SkiaCapture.cpp +++ b/libs/renderengine/skia/debug/SkiaCapture.cpp @@ -41,11 +41,11 @@ SkiaCapture::~SkiaCapture() { 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 @@ SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) { // 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 @@ SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) { 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 eaaf598bd0..08a1359533 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 @@ public: // 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 @@ private: 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 |