Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa940e0a authored by Derek Sollenberger's avatar Derek Sollenberger Committed by Android (Google) Code Review
Browse files

Merge "Enable offscreen buffers in mskp captures for RenderEngine" into sc-dev

parents d6bdaf4b 76664d60
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -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);
            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);
+61 −7
Original line number Diff line number Diff line
@@ -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() {
+20 −0
Original line number Diff line number Diff line
@@ -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