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

Commit abcda352 authored by Dan Stoza's avatar Dan Stoza
Browse files

SF: Add ImageHolder for screenshot code

Adds a simple ImageHolder class, which holds an EGLImage and destroys
it either when an explicit destroy() method is called or when the class
is destructed (whichever occurs first). This allows us to reduce the
nesting of, and otherwise simplify, the captureScreenImplLocked method
of SurfaceFlinger.

Bug: 62257775
Test: SurfaceFlinger_test and manually verified that screenshots still
      work
Change-Id: I800208e8f6bedd2ce66827268ecc64968dbe616d
parent a9b1aa0b
Loading
Loading
Loading
Loading
+82 −62
Original line number Diff line number Diff line
@@ -4346,6 +4346,26 @@ private:
    const int mApi;
};

// A simple RAII class that holds an EGLImage and destroys it either:
//   a) When the destroy() method is called
//   b) When the object goes out of scope
class ImageHolder {
public:
    ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
    ~ImageHolder() { destroy(); }

    void destroy() {
        if (mImage != EGL_NO_IMAGE_KHR) {
            eglDestroyImageKHR(mDisplay, mImage);
            mImage = EGL_NO_IMAGE_KHR;
        }
    }

private:
    const EGLDisplay mDisplay;
    EGLImageKHR mImage;
};

status_t SurfaceFlinger::captureScreenImplLocked(
        const sp<const DisplayDevice>& hw,
        const sp<IGraphicBufferProducer>& producer,
@@ -4443,10 +4463,18 @@ status_t SurfaceFlinger::captureScreenImplLocked(
        return BAD_VALUE;
    }

    // This will automatically destroy the image if we return before calling its destroy method
    ImageHolder imageHolder(mEGLDisplay, image);

    // this binds the given EGLImage as a framebuffer for the
    // duration of this scope.
    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
    if (imageBond.getStatus() == NO_ERROR) {
    if (imageBond.getStatus() != NO_ERROR) {
        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
        window->cancelBuffer(window, buffer, syncFd);
        return INVALID_OPERATION;
    }

    // this will in fact render into our dequeued buffer
    // via an FBO, which means we didn't have to create
    // an EGLSurface and therefore we're not
@@ -4464,14 +4492,13 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    // Attempt to create a sync khr object that can produce a sync point. If that
    // isn't available, create a non-dupable sync object in the fallback path and
    // wait on it directly.
        EGLSyncKHR sync;
    EGLSyncKHR sync = EGL_NO_SYNC_KHR;
    if (!DEBUG_SCREENSHOTS) {
       sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
       // native fence fd will not be populated until flush() is done.
       getRenderEngine().flush();
        } else {
            sync = EGL_NO_SYNC_KHR;
    }

    if (sync != EGL_NO_SYNC_KHR) {
        // get the sync fd
        syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
@@ -4498,6 +4525,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
            ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
        }
    }

    if (DEBUG_SCREENSHOTS) {
        uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
        getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
@@ -4506,19 +4534,11 @@ status_t SurfaceFlinger::captureScreenImplLocked(
        delete [] pixels;
    }

    } else {
        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
        result = INVALID_OPERATION;
        window->cancelBuffer(window, buffer, syncFd);
        buffer = NULL;
    }
    // destroy our image
    eglDestroyImageKHR(mEGLDisplay, image);
    imageHolder.destroy();

    if (buffer) {
    // queueBuffer takes ownership of syncFd
    result = window->queueBuffer(window, buffer, syncFd);
    }

    return result;
}