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

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

Merge changes Ie7b336ea,I36a8cb45

* changes:
  Remove Properties::isSkiaPipeline (3/!?)
  So long OpenGLPipeline & OpenGLReadback (2/??)
parents cd10b0da 1072fffd
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -185,7 +185,6 @@ cc_defaults {
        "renderstate/TextureState.cpp",
        "renderthread/CacheManager.cpp",
        "renderthread/CanvasContext.cpp",
        "renderthread/OpenGLPipeline.cpp",
        "renderthread/DrawFrameTask.cpp",
        "renderthread/EglManager.cpp",
        "renderthread/VulkanManager.cpp",
@@ -217,7 +216,6 @@ cc_defaults {
        "DeferredLayerUpdater.cpp",
        "DeviceInfo.cpp",
        "DisplayList.cpp",
        "Extensions.cpp",
        "FboCache.cpp",
        "FontRenderer.cpp",
        "FrameBuilder.cpp",
@@ -236,7 +234,7 @@ cc_defaults {
        "LayerUpdateQueue.cpp",
        "Matrix.cpp",
        "OpDumper.cpp",
        "OpenGLReadback.cpp",
        "EglReadback.cpp",
        "Patch.cpp",
        "PatchCache.cpp",
        "PathCache.cpp",
+97 −0
Original line number Diff line number Diff line
@@ -14,17 +14,10 @@
 * limitations under the License.
 */

#include "OpenGLReadback.h"
#include "EglReadback.h"

#include "Caches.h"
#include "GlLayer.h"
#include "GlopBuilder.h"
#include "Image.h"
#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "utils/GLUtils.h"

#include <GLES2/gl2.h>
#include <gui/Surface.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -32,7 +25,7 @@
namespace android {
namespace uirenderer {

CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
                                           SkBitmap* bitmap) {
    ATRACE_CALL();
    // Setup the source
@@ -62,7 +55,7 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
    return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
}

CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
                                                 Matrix4& texTransform, const Rect& srcRect,
                                                 SkBitmap* bitmap) {
    mRenderThread.eglManager().initialize();
@@ -88,15 +81,11 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
    CopyResult copyResult =
            copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);

    // All we're flushing & finishing is the deletion of the texture since
    // copyImageInto already did a major flush & finish as an implicit
    // part of glReadPixels, so this shouldn't pose any major stalls.
    glFinish();
    eglDestroyImageKHR(display, sourceImage);
    return copyResult;
}

CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
    Rect srcRect;
    Matrix4 transform;
    transform.loadScale(1, -1, 1);
@@ -104,184 +93,5 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, S
    return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
}

static float sFlipVInit[16] = {
        1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
};

static const Matrix4 sFlipV(sFlipVInit);

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

inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, Texture& sourceTexture,
                                  const Matrix4& texTransform, const Rect& srcRect,
                                  SkBitmap* bitmap) {
    int destWidth = bitmap->width();
    int destHeight = bitmap->height();
    if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) {
        ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth,
              destHeight, caches.maxTextureSize);
        return CopyResult::DestinationInvalid;
    }

    if (bitmap->colorType() == kRGBA_F16_SkColorType &&
        !caches.extensions().hasRenderableFloatTextures()) {
        ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
        return CopyResult::DestinationInvalid;
    }

    GLuint fbo = renderState.createFramebuffer();
    if (!fbo) {
        ALOGW("Could not obtain an FBO");
        return CopyResult::UnknownError;
    }

    GLuint texture;

    GLenum format;
    GLenum internalFormat;
    GLenum type;

    switch (bitmap->colorType()) {
        case kAlpha_8_SkColorType:
            format = GL_ALPHA;
            internalFormat = GL_ALPHA;
            type = GL_UNSIGNED_BYTE;
            break;
        case kRGB_565_SkColorType:
            format = GL_RGB;
            internalFormat = GL_RGB;
            type = GL_UNSIGNED_SHORT_5_6_5;
            break;
        case kARGB_4444_SkColorType:
            format = GL_RGBA;
            internalFormat = GL_RGBA;
            type = GL_UNSIGNED_SHORT_4_4_4_4;
            break;
        case kRGBA_F16_SkColorType:
            format = GL_RGBA;
            internalFormat = GL_RGBA16F;
            type = GL_HALF_FLOAT;
            break;
        case kN32_SkColorType:
        default:
            format = GL_RGBA;
            internalFormat = GL_RGBA;
            type = GL_UNSIGNED_BYTE;
            break;
    }

    renderState.bindFramebuffer(fbo);

    // TODO: Use layerPool or something to get this maybe? But since we
    // need explicit format control we can't currently.

    // Setup the rendertarget
    glGenTextures(1, &texture);
    caches.textureState().activateTexture(0);
    caches.textureState().bindTexture(texture);
    glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

    {
        bool requiresFilter;
        // Draw & readback
        renderState.setViewport(destWidth, destHeight);
        renderState.scissor().setEnabled(false);
        renderState.blend().syncEnabled();
        renderState.stencil().disable();

        Matrix4 croppedTexTransform(texTransform);
        if (!srcRect.isEmpty()) {
            // We flipV to convert to 0,0 top-left for the srcRect
            // coordinates then flip back to 0,0 bottom-left for
            // GLES coordinates.
            croppedTexTransform.multiply(sFlipV);
            croppedTexTransform.translate(srcRect.left / sourceTexture.width(),
                                          srcRect.top / sourceTexture.height(), 0);
            croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
                                      srcRect.getHeight() / sourceTexture.height(), 1);
            croppedTexTransform.multiply(sFlipV);
            requiresFilter = srcRect.getWidth() != (float)destWidth ||
                             srcRect.getHeight() != (float)destHeight;
        } else {
            requiresFilter = sourceTexture.width() != (uint32_t)destWidth ||
                             sourceTexture.height() != (uint32_t)destHeight;
        }
        Glop glop;
        GlopBuilder(renderState, caches, &glop)
                .setRoundRectClipState(nullptr)
                .setMeshTexturedUnitQuad(nullptr)
                .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter)
                .setTransform(Matrix4::identity(), TransformFlags::None)
                .setModelViewMapUnitToRect(Rect(destWidth, destHeight))
                .build();
        Matrix4 ortho;
        ortho.loadOrtho(destWidth, destHeight);
        renderState.render(glop, ortho, false);

        // TODO: We should convert to linear space when the target is RGBA16F
        glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
        bitmap->notifyPixelsChanged();
    }

    // Cleanup
    caches.textureState().deleteTexture(texture);
    renderState.deleteFramebuffer(fbo);

    GL_CHECKPOINT(MODERATE);

    return CopyResult::Success;
}

CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
                                             int imgWidth, int imgHeight, const Rect& srcRect,
                                             SkBitmap* bitmap) {
    // If this is a 90 or 270 degree rotation we need to swap width/height
    // This is a fuzzy way of checking that.
    if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
        std::swap(imgWidth, imgHeight);
    }

    Caches& caches = Caches::getInstance();
    GLuint sourceTexId;
    // Create a 2D texture to sample from the EGLImage
    glGenTextures(1, &sourceTexId);
    caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);

    GLenum status = GL_NO_ERROR;
    while ((status = glGetError()) != GL_NO_ERROR) {
        ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
        return CopyResult::UnknownError;
    }

    Texture sourceTexture(caches);
    sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */,
                       GL_TEXTURE_EXTERNAL_OES);

    CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture,
                                            imgTransform, srcRect, bitmap);
    sourceTexture.deleteTexture();
    return copyResult;
}

bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
                                       SkBitmap* bitmap) {
    if (!layer.isRenderable()) {
        // layer has never been updated by DeferredLayerUpdater, abort copy
        return false;
    }

    return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(),
                                                  layer.getTexture(), layer.getTexTransform(),
                                                  Rect(), bitmap);
}

}  // namespace uirenderer
}  // namespace android
+5 −22
Original line number Diff line number Diff line
@@ -18,16 +18,15 @@

#include "Readback.h"

#include "Matrix.h"

#include <EGL/egl.h>
#include <EGL/eglext.h>

namespace android {
namespace uirenderer {

class Matrix4;
class GlLayer;

class OpenGLReadback : public Readback {
class EglReadback : public Readback {
public:
    virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
                                       SkBitmap* bitmap) override;
@@ -35,8 +34,8 @@ public:
                                             SkBitmap* bitmap) override;

protected:
    explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
    virtual ~OpenGLReadback() {}
    explicit EglReadback(renderthread::RenderThread& thread) : Readback(thread) {}
    virtual ~EglReadback() {}

    virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
                                     int imgWidth, int imgHeight, const Rect& srcRect,
@@ -47,21 +46,5 @@ private:
                                     const Rect& srcRect, SkBitmap* bitmap);
};

class OpenGLReadbackImpl : public OpenGLReadback {
public:
    OpenGLReadbackImpl(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}

    /**
     * Copies the layer's contents into the provided bitmap.
     */
    static bool copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
                              SkBitmap* bitmap);

protected:
    virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
                                     int imgWidth, int imgHeight, const Rect& srcRect,
                                     SkBitmap* bitmap) override;
};

}  // namespace uirenderer
}  // namespace android

libs/hwui/Extensions.cpp

deleted100644 → 0
+0 −83
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 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 "Extensions.h"

#include "Debug.h"
#include "Properties.h"
#include "utils/StringUtils.h"

#include <cutils/compiler.h>

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <utils/Log.h>

namespace android {
namespace uirenderer {

Extensions::Extensions() {
    if (Properties::isSkiaEnabled()) {
        return;
    }
    const char* version = (const char*)glGetString(GL_VERSION);

    // Section 6.1.5 of the OpenGL ES specification indicates the GL version
    // string strictly follows this format:
    //
    // OpenGL<space>ES<space><version number><space><vendor-specific information>
    //
    // In addition section 6.1.5 describes the version number thusly:
    //
    // "The version number is either of the form major number.minor number or
    // major number.minor number.release number, where the numbers all have one
    // or more digits. The release number and vendor specific information are
    // optional."

    if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) {
        // If we cannot parse the version number, assume OpenGL ES 2.0
        mVersionMajor = 2;
        mVersionMinor = 0;
    }

    auto extensions = StringUtils::split((const char*)glGetString(GL_EXTENSIONS));
    mHasNPot = extensions.has("GL_OES_texture_npot");
    mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
    mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer");
    mHasDebugMarker = extensions.has("GL_EXT_debug_marker");
    mHas1BitStencil = extensions.has("GL_OES_stencil1");
    mHas4BitStencil = extensions.has("GL_OES_stencil4");
    mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage");
    mHasRenderableFloatTexture = extensions.has("GL_OES_texture_half_float");

    mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB");
    mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control");

#ifdef ANDROID_ENABLE_LINEAR_BLENDING
    // If linear blending is enabled, the device must have (ES3.0 or EXT_sRGB)
    // and EXT_sRGB_write_control
    LOG_ALWAYS_FATAL_IF(!mHasSRGB, "Linear blending requires ES 3.0 or EXT_sRGB");
    LOG_ALWAYS_FATAL_IF(!mHasSRGBWriteControl, "Linear blending requires EXT_sRGB_write_control");

    mHasLinearBlending = true;
#else
    mHasLinearBlending = false;
#endif
}

};  // namespace uirenderer
};  // namespace android
+15 −27
Original line number Diff line number Diff line
@@ -26,43 +26,31 @@ namespace uirenderer {

class Extensions {
public:
    Extensions();

    inline bool hasNPot() const { return mHasNPot; }
    inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
    inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
    inline bool hasDebugMarker() const { return mHasDebugMarker; }
    inline bool has1BitStencil() const { return mHas1BitStencil; }
    inline bool has4BitStencil() const { return mHas4BitStencil; }
    inline bool hasUnpackRowLength() const { return mVersionMajor >= 3 || mHasUnpackSubImage; }
    Extensions() {}

    inline bool hasNPot() const { return false; }
    inline bool hasFramebufferFetch() const { return false; }
    inline bool hasDiscardFramebuffer() const { return false; }
    inline bool hasDebugMarker() const { return false; }
    inline bool has1BitStencil() const { return false; }
    inline bool has4BitStencil() const { return false; }
    inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; }
    inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
    inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
    inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
    inline bool hasRenderableFloatTextures() const {
        return (mVersionMajor >= 3 && mVersionMinor >= 2) || mHasRenderableFloatTexture;
        return (mVersionMajor >= 3 && mVersionMinor >= 2);
    }
    inline bool hasSRGB() const { return mHasSRGB; }
    inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; }
    inline bool hasLinearBlending() const { return hasSRGB() && mHasLinearBlending; }
    inline bool hasSRGB() const { return false; }
    inline bool hasSRGBWriteControl() const { return hasSRGB() && false; }
    inline bool hasLinearBlending() const { return hasSRGB() && false; }

    inline int getMajorGlVersion() const { return mVersionMajor; }
    inline int getMinorGlVersion() const { return mVersionMinor; }

private:
    bool mHasNPot;
    bool mHasFramebufferFetch;
    bool mHasDiscardFramebuffer;
    bool mHasDebugMarker;
    bool mHas1BitStencil;
    bool mHas4BitStencil;
    bool mHasUnpackSubImage;
    bool mHasSRGB;
    bool mHasSRGBWriteControl;
    bool mHasLinearBlending;
    bool mHasRenderableFloatTexture;

    int mVersionMajor;
    int mVersionMinor;
    int mVersionMajor = 2;
    int mVersionMinor = 0;
};  // class Extensions

};  // namespace uirenderer
Loading