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

Commit 59eecb52 authored by sergeyv's avatar sergeyv
Browse files

Support readback from hardware bitmaps

Test: hwuimacro readbackFromHBitmap --onscreen.
bug:30999911
Change-Id: I369c069c40cb0f9adae5a94501815f29c2d7df0f
parent a79a655e
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -34,8 +34,6 @@ namespace uirenderer {
CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
        SkBitmap* bitmap) {
    ATRACE_CALL();
    mRenderThread.eglManager().initialize();

    // Setup the source
    sp<GraphicBuffer> sourceBuffer;
    sp<Fence> sourceFence;
@@ -61,13 +59,19 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
        return CopyResult::Timeout;
    }

    return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
}

CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
        Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) {
    mRenderThread.eglManager().initialize();
    // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
    // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
    // to be able to properly sample from the buffer.

    // Create the EGLImage object that maps the GraphicBuffer
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer();
    EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer();
    EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };

    EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
@@ -78,8 +82,8 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
        return CopyResult::UnknownError;
    }

    CopyResult copyResult = copyImageInto(sourceImage, texTransform, sourceBuffer->getWidth(),
            sourceBuffer->getHeight(), srcRect, bitmap);
    CopyResult copyResult = copyImageInto(sourceImage, texTransform, graphicBuffer->getWidth(),
            graphicBuffer->getHeight(), srcRect, bitmap);

    // All we're flushing & finishing is the deletion of the texture since
    // copyImageInto already did a major flush & finish as an implicit
@@ -89,6 +93,14 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
    return copyResult;
}

CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
    Rect srcRect;
    Matrix4 transform;
    transform.loadScale(1, -1, 1);
    transform.translate(0, -1);
    return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

+5 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ class OpenGLReadback : public Readback {
public:
    virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
            SkBitmap* bitmap) override;
    virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
            SkBitmap* bitmap) override;

protected:
    explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
@@ -35,6 +37,9 @@ protected:

    virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
            int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
private:
    CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
            const Rect& srcRect, SkBitmap* bitmap);
};

class OpenGLReadbackImpl : public OpenGLReadback {
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <gui/Surface.h>

namespace android {
class GraphicBuffer;
namespace uirenderer {

// Keep in sync with PixelCopy.java codes
@@ -42,6 +43,7 @@ public:
     */
    virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
            SkBitmap* bitmap) = 0;
    virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0;

protected:
    explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {}
+4 −3
Original line number Diff line number Diff line
@@ -459,14 +459,15 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) {
}

void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
    if (isHardware()) {
        //TODO: use readback to get pixels
        LOG_ALWAYS_FATAL("Not implemented");
        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
        outBitmap->allocPixels(info());
        uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
        return;
    }
    outBitmap->setInfo(info(), rowBytes());
    outBitmap->setPixelRef(this);
    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
}

void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
+14 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
#include "utils/Macros.h"
#include "utils/TimeUtils.h"

#include <ui/GraphicBuffer.h>

namespace android {
namespace uirenderer {
namespace renderthread {
@@ -663,6 +665,18 @@ sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
    return hardwareBitmap;
}

CREATE_BRIDGE3(copyGraphicBufferInto, RenderThread* thread, GraphicBuffer* buffer, SkBitmap* bitmap) {
    return (void*) args->thread->readback().copyGraphicBufferInto(args->buffer, args->bitmap);
}

int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
    SETUP_TASK(copyGraphicBufferInto);
    args->thread = &RenderThread::getInstance();
    args->bitmap = bitmap;
    args->buffer = buffer;
    return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task)));
}

void RenderProxy::post(RenderTask* task) {
    mRenderThread.queue(task);
}
Loading