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

Commit 02995ec8 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge changes Id3285b63,Ie8e9398c

* changes:
  Move all non-GL HW Bitmap work off RT
  Remove RenderThread from EglManager
parents b81e6f55 b90d4cb3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
                                                 Matrix4& texTransform, const Rect& srcRect,
                                                 SkBitmap* bitmap) {
    mRenderThread.eglManager().initialize();
    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.
+103 −83
Original line number Diff line number Diff line
@@ -166,7 +166,7 @@ static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_
}

DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
    mEglManager.initialize();
    mRenderThread.requireGlContext();
    return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
}

@@ -184,6 +184,7 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
    }

    if (surface) {
        mRenderThread.requireGlContext();
        const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
        mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
    }
@@ -221,24 +222,6 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func

#define FENCE_TIMEOUT 2000000000

class AutoEglFence {
public:
    AutoEglFence(EGLDisplay display) : mDisplay(display) {
        fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
    }

    ~AutoEglFence() {
        if (fence != EGL_NO_SYNC_KHR) {
            eglDestroySyncKHR(mDisplay, fence);
        }
    }

    EGLSyncKHR fence = EGL_NO_SYNC_KHR;

private:
    EGLDisplay mDisplay = EGL_NO_DISPLAY;
};

class AutoEglImage {
public:
    AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
@@ -272,73 +255,102 @@ private:
    GLuint mTexture = 0;
};

sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
                                                         SkBitmap& skBitmap) {
    renderThread.eglManager().initialize();
struct FormatInfo {

    sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
    const SkImageInfo& info = skBitmap.info();
    PixelFormat pixelFormat;
    GLint format, type;
    bool isSupported = false;
    bool valid = true;
};

static bool gpuSupportsHalfFloatTextures(renderthread::RenderThread& renderThread) {
    static bool isSupported = renderThread.queue().runSync([&renderThread]() -> bool {
        renderThread.requireGlContext();
        sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
        return grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
    });
    return isSupported;
}

static FormatInfo determineFormat(renderthread::RenderThread& renderThread,
                                  const SkBitmap& skBitmap) {
    FormatInfo formatInfo;
    // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
    switch (info.colorType()) {
    switch (skBitmap.info().colorType()) {
        case kRGBA_8888_SkColorType:
            isSupported = true;
            formatInfo.isSupported = true;
        // ARGB_4444 is upconverted to RGBA_8888
        case kARGB_4444_SkColorType:
            pixelFormat = PIXEL_FORMAT_RGBA_8888;
            format = GL_RGBA;
            type = GL_UNSIGNED_BYTE;
            formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
            formatInfo.format = GL_RGBA;
            formatInfo.type = GL_UNSIGNED_BYTE;
            break;
        case kRGBA_F16_SkColorType:
            isSupported = grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
            if (isSupported) {
                type = GL_HALF_FLOAT;
                pixelFormat = PIXEL_FORMAT_RGBA_FP16;
            formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread);
            if (formatInfo.isSupported) {
                formatInfo.type = GL_HALF_FLOAT;
                formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
            } else {
                type = GL_UNSIGNED_BYTE;
                pixelFormat = PIXEL_FORMAT_RGBA_8888;
                formatInfo.type = GL_UNSIGNED_BYTE;
                formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
            }
            format = GL_RGBA;
            formatInfo.format = GL_RGBA;
            break;
        case kRGB_565_SkColorType:
            isSupported = true;
            pixelFormat = PIXEL_FORMAT_RGB_565;
            format = GL_RGB;
            type = GL_UNSIGNED_SHORT_5_6_5;
            formatInfo.isSupported = true;
            formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
            formatInfo.format = GL_RGB;
            formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
            break;
        case kGray_8_SkColorType:
            isSupported = true;
            pixelFormat = PIXEL_FORMAT_RGBA_8888;
            format = GL_LUMINANCE;
            type = GL_UNSIGNED_BYTE;
            formatInfo.isSupported = true;
            formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
            formatInfo.format = GL_LUMINANCE;
            formatInfo.type = GL_UNSIGNED_BYTE;
            break;
        default:
            ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
            return nullptr;
            ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
            formatInfo.valid = false;
    }
    return formatInfo;
}

    SkBitmap bitmap;
    if (isSupported) {
        bitmap = skBitmap;
static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
    if (format.isSupported) {
        return source;
    } else {
        SkBitmap bitmap;
        const SkImageInfo& info = source.info();
        bitmap.allocPixels(
                SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
        bitmap.eraseColor(0);
        if (info.colorType() == kRGBA_F16_SkColorType) {
            // Drawing RGBA_F16 onto ARGB_8888 is not supported
            skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
            source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
                              bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
        } else {
            SkCanvas canvas(bitmap);
            canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
            canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
        }
        return bitmap;
    }
}

sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& thread,
                                                         const SkBitmap& sourceBitmap) {
    ATRACE_CALL();

    LOG_ALWAYS_FATAL_IF(thread.isCurrent(), "Must not be called on RenderThread");

    FormatInfo format = determineFormat(thread, sourceBitmap);
    if (!format.valid) {
        return nullptr;
    }

    SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
    sp<GraphicBuffer> buffer = new GraphicBuffer(
            info.width(), info.height(), pixelFormat,
            static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
            format.pixelFormat,
            GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
                    GraphicBuffer::USAGE_SW_READ_NEVER,
            std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
@@ -350,8 +362,11 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
        return nullptr;
    }

    // upload the bitmap into a texture
    EGLDisplay display = eglGetCurrentDisplay();
    EGLDisplay display = thread.queue().runSync([&]() -> EGLDisplay {
        thread.requireGlContext();
        return eglGetCurrentDisplay();
    });

    LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
                        uirenderer::renderthread::EglManager::eglErrorString());
    // We use an EGLImage to access the content of the GraphicBuffer
@@ -363,35 +378,40 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
              uirenderer::renderthread::EglManager::eglErrorString());
        return nullptr;
    }

    {
        ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
        EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR {
            thread.requireGlContext();
            sk_sp<GrContext> grContext = sk_ref_sp(thread.getGrContext());
            AutoSkiaGlTexture glTexture;
            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
            GL_CHECKPOINT(MODERATE);

    // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we provide.
    // But asynchronous in sense that driver may upload texture onto hardware buffer when we first
            // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
            // provide.
            // But asynchronous in sense that driver may upload texture onto hardware buffer when we
            // first
            // use it in drawing
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
                    bitmap.getPixels());
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
                            format.type, bitmap.getPixels());
            GL_CHECKPOINT(MODERATE);

    // The fence is used to wait for the texture upload to finish
    // properly. We cannot rely on glFlush() and glFinish() as
    // some drivers completely ignore these API calls
    AutoEglFence autoFence(display);
    if (autoFence.fence == EGL_NO_SYNC_KHR) {
        LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
        return nullptr;
    }
    // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
    // pipeline flush (similar to what a glFlush() would do.)
    EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
                                             EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
    if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
        LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
        return nullptr;
    }

            EGLSyncKHR uploadFence =
                    eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
            LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
                                eglGetError());
            glFlush();
            grContext->resetContext(kTextureBinding_GrGLBackendState);
            return uploadFence;
        });

        EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
        LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
                            "Failed to wait for the fence %#x", eglGetError());

        eglDestroySyncKHR(display, fence);
    }

    return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
}
+3 −1
Original line number Diff line number Diff line
@@ -49,8 +49,10 @@ public:
    bool isContextReady() override;

    static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);

    // May be called by any thread except RenderThread.
    static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
                                                SkBitmap& skBitmap);
                                                const SkBitmap& skBitmap);

private:
    renderthread::EglManager& mEglManager;
+1 −1
Original line number Diff line number Diff line
@@ -552,7 +552,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) {
    ATRACE_CALL();
    if (level >= TRIM_MEMORY_COMPLETE) {
        thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
        thread.eglManager().destroy();
        thread.destroyGlContext();
        thread.vulkanManager().destroy();
    } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
        thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
+21 −42
Original line number Diff line number Diff line
@@ -16,27 +16,19 @@

#include "EglManager.h"

#include <string>

#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Trace.h>
#include "utils/StringUtils.h"

#include "Caches.h"
#include "DeviceInfo.h"
#include "Frame.h"
#include "Properties.h"
#include "RenderThread.h"
#include "Texture.h"
#include "renderstate/RenderState.h"

#include <EGL/eglext.h>
#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>

#ifdef HWUI_GLES_WRAP_ENABLED
#include "debug/GlesDriver.h"
#endif
#include <string>
#include <vector>

#define GLES_VERSION 2

@@ -83,17 +75,21 @@ static struct {
    bool glColorSpace = false;
    bool scRGB = false;
    bool contextPriority = false;
    bool surfacelessContext = false;
} EglExtensions;

EglManager::EglManager(RenderThread& thread)
        : mRenderThread(thread)
        , mEglDisplay(EGL_NO_DISPLAY)
EglManager::EglManager()
        : mEglDisplay(EGL_NO_DISPLAY)
        , mEglConfig(nullptr)
        , mEglConfigWideGamut(nullptr)
        , mEglContext(EGL_NO_CONTEXT)
        , mPBufferSurface(EGL_NO_SURFACE)
        , mCurrentSurface(EGL_NO_SURFACE) {}

EglManager::~EglManager() {
    destroy();
}

void EglManager::initialize() {
    if (hasEglContext()) return;

@@ -126,26 +122,8 @@ void EglManager::initialize() {
    loadConfigs();
    createContext();
    createPBufferSurface();
    makeCurrent(mPBufferSurface);
    makeCurrent(mPBufferSurface, nullptr, /* force */ true);
    DeviceInfo::initialize();
    mRenderThread.renderState().onGLContextCreated();

    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
#ifdef HWUI_GLES_WRAP_ENABLED
        debug::GlesDriver* driver = debug::GlesDriver::get();
        sk_sp<const GrGLInterface> glInterface(driver->getSkiaInterface());
#else
        sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
#endif
        LOG_ALWAYS_FATAL_IF(!glInterface.get());

        GrContextOptions options;
        options.fDisableDistanceFieldPaths = true;
        mRenderThread.cacheManager().configureContext(&options);
        sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
        LOG_ALWAYS_FATAL_IF(!grContext.get());
        mRenderThread.setGrContext(grContext);
    }
}

void EglManager::initExtensions() {
@@ -170,6 +148,7 @@ void EglManager::initExtensions() {
    EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
#endif
    EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
    EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
}

bool EglManager::hasEglContext() {
@@ -195,7 +174,7 @@ void EglManager::loadConfigs() {
                        EGL_CONFIG_CAVEAT,
                        EGL_NONE,
                        EGL_STENCIL_SIZE,
                        Stencil::getStencilSize(),
                        STENCIL_BUFFER_SIZE,
                        EGL_SURFACE_TYPE,
                        EGL_WINDOW_BIT | swapBehavior,
                        EGL_NONE};
@@ -232,7 +211,7 @@ void EglManager::loadConfigs() {
                               EGL_DEPTH_SIZE,
                               0,
                               EGL_STENCIL_SIZE,
                               Stencil::getStencilSize(),
                               STENCIL_BUFFER_SIZE,
                               EGL_SURFACE_TYPE,
                               EGL_WINDOW_BIT | swapBehavior,
                               EGL_NONE};
@@ -269,14 +248,14 @@ void EglManager::createPBufferSurface() {
    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
                        "usePBufferSurface() called on uninitialized GlobalContext!");

    if (mPBufferSurface == EGL_NO_SURFACE) {
    if (mPBufferSurface == EGL_NO_SURFACE && !EglExtensions.surfacelessContext) {
        EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
        mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
    }
}

EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
    initialize();
    LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");

    wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB &&
                     EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
@@ -350,10 +329,10 @@ void EglManager::destroySurface(EGLSurface surface) {
void EglManager::destroy() {
    if (mEglDisplay == EGL_NO_DISPLAY) return;

    mRenderThread.setGrContext(nullptr);
    mRenderThread.renderState().onGLContextDestroyed();
    eglDestroyContext(mEglDisplay, mEglContext);
    if (mPBufferSurface != EGL_NO_SURFACE) {
        eglDestroySurface(mEglDisplay, mPBufferSurface);
    }
    eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglTerminate(mEglDisplay);
    eglReleaseThread();
@@ -364,8 +343,8 @@ void EglManager::destroy() {
    mCurrentSurface = EGL_NO_SURFACE;
}

bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
    if (isCurrent(surface)) return false;
bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut, bool force) {
    if (!force && isCurrent(surface)) return false;

    if (surface == EGL_NO_SURFACE) {
        // Ensure we always have a valid surface & context
Loading