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

Commit 1a025a71 authored by Stan Iliev's avatar Stan Iliev
Browse files

Refactor HWUI readback code to be backend independent

Implement readback from Surface, TextureView and HW Bitmap
for Vulkan pipeline by wrapping the graphics buffer in an SkImage.
Refactor both Vulkan and GL readback to use common code.
TextureView readback is moved from IRenderPipeline interface to
Readback class. Refactor all 3 readback flows to use common
implementation.

Test: Passed all view, uirendering and graphics CTS tests with GL
Test: Passed many CTS test with Vulkan, that require readback
Bug: 113673613
Change-Id: Ifbfd8170a5401f87a709b4b1b9fa058e8e11768d
parent cf1c58cd
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1198,6 +1198,10 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit

static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
    sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
    // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
    // format and SRGB color space.
    // To support any color space, we need to pass an additional ColorSpace argument to
    // java Bitmap.createHardwareBitmap.
    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
    if (!bitmap.get()) {
        ALOGW("failed to create hardware bitmap from graphic buffer");
+3 −0
Original line number Diff line number Diff line
@@ -1024,6 +1024,9 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode(
        // Continue I guess?
    }
    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
    // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
    // format and SRGB color space.
    // To support any color space, we could extract it from BufferItem and pass it to Bitmap.
    return bitmap::createBitmap(env, bitmap.release(),
            android::bitmap::kBitmapCreateFlag_Premultiplied);
}
+1 −2
Original line number Diff line number Diff line
@@ -170,7 +170,6 @@ cc_defaults {
        "pipeline/skia/SkiaDisplayList.cpp",
        "pipeline/skia/SkiaMemoryTracer.cpp",
        "pipeline/skia/SkiaOpenGLPipeline.cpp",
        "pipeline/skia/SkiaOpenGLReadback.cpp",
        "pipeline/skia/SkiaPipeline.cpp",
        "pipeline/skia/SkiaProfileRenderer.cpp",
        "pipeline/skia/SkiaRecordingCanvas.cpp",
@@ -217,13 +216,13 @@ cc_defaults {
        "Layer.cpp",
        "LayerUpdateQueue.cpp",
        "Matrix.cpp",
        "EglReadback.cpp",
        "PathParser.cpp",
        "ProfileData.cpp",
        "ProfileDataContainer.cpp",
        "Properties.cpp",
        "PropertyValuesAnimatorSet.cpp",
        "PropertyValuesHolder.cpp",
        "Readback.cpp",
        "RecordingCanvas.cpp",
        "RenderNode.cpp",
        "RenderProperties.cpp",
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ void DeferredLayerUpdater::destroyLayer() {
    }

    mLayer->postDecStrong();

    mLayer = nullptr;
}

libs/hwui/EglReadback.cpp

deleted100644 → 0
+0 −95
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "EglReadback.h"

#include "renderthread/EglManager.h"

#include <gui/Surface.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>

namespace android {
namespace uirenderer {

CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
    ATRACE_CALL();
    // Setup the source
    sp<GraphicBuffer> sourceBuffer;
    sp<Fence> sourceFence;
    Matrix4 texTransform;
    status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
    texTransform.invalidateType();
    if (err != NO_ERROR) {
        ALOGW("Failed to get last queued buffer, error = %d", err);
        return CopyResult::UnknownError;
    }
    if (!sourceBuffer.get()) {
        ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
        return CopyResult::SourceEmpty;
    }
    if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
        ALOGW("Surface is protected, unable to copy from it");
        return CopyResult::SourceInvalid;
    }
    err = sourceFence->wait(500 /* ms */);
    if (err != NO_ERROR) {
        ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
        return CopyResult::Timeout;
    }

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

CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
                                              const Rect& srcRect, SkBitmap* bitmap) {
    mRenderThread.requireGlContext();
    // 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)graphicBuffer->getNativeBuffer();
    EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};

    EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
                                                clientBuffer, attrs);

    if (sourceImage == EGL_NO_IMAGE_KHR) {
        ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
        return CopyResult::UnknownError;
    }

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

    eglDestroyImageKHR(display, sourceImage);
    return copyResult;
}

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

}  // namespace uirenderer
}  // namespace android
Loading