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

Commit 886b1521 authored by Jamie Gennis's avatar Jamie Gennis Committed by Android Git Automerger
Browse files

am a9c47f32: Merge "GLConsumer: start using EGL_ANDROID_image_crop" into klp-dev

* commit 'a9c47f32':
  GLConsumer: start using EGL_ANDROID_image_crop
parents 9b4b1180 a9c47f32
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -273,7 +273,7 @@ protected:
private:
    // createImage creates a new EGLImage from a GraphicBuffer.
    EGLImageKHR createImage(EGLDisplay dpy,
            const sp<GraphicBuffer>& graphicBuffer);
            const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);

    // freeBufferLocked frees up the given buffer slot.  If the slot has been
    // initialized this will release the reference to the GraphicBuffer in that
@@ -386,6 +386,10 @@ private:
        // mEglImage is the EGLImage created from mGraphicBuffer.
        EGLImageKHR mEglImage;

        // mCropRect is the crop rectangle passed to EGL when mEglImage was
        // created.
        Rect mCropRect;

        // mFence is the EGL sync object that must signal before the buffer
        // associated with this buffer slot may be dequeued. It is initialized
        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+124 −63
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@
#include <utils/String8.h>
#include <utils/Trace.h>

EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define CROP_EXT_STR "EGL_ANDROID_image_crop"

namespace android {

// Macros for including the GLConsumer name in log messages
@@ -89,6 +92,30 @@ static void mtxMul(float out[16], const float a[16], const float b[16]);
Mutex GLConsumer::sStaticInitLock;
sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;

static bool hasEglAndroidImageCropImpl() {
    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
    size_t cropExtLen = strlen(CROP_EXT_STR);
    size_t extsLen = strlen(exts);
    bool equal = !strcmp(CROP_EXT_STR, exts);
    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
    bool atEnd = (cropExtLen+1) < extsLen &&
            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
    return equal || atStart || atEnd || inMiddle;
}

static bool hasEglAndroidImageCrop() {
    // Only compute whether the extension is present once the first time this
    // function is called.
    static bool hasIt = hasEglAndroidImageCropImpl();
    return hasIt;
}

static bool isEglImageCroppable(const Rect& crop) {
    return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
}

GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
        uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
    ConsumerBase(bq, isControlledByApp),
@@ -279,10 +306,22 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
    }

    int slot = item->mBuf;
    bool destroyEglImage = false;

    if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
        if (item->mGraphicBuffer != NULL) {
            // This buffer has not been acquired before, so we must assume
            // that any EGLImage in mEglSlots is stale.
        if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
            destroyEglImage = true;
        } else if (mEglSlots[slot].mCropRect != item->mCrop) {
            // We've already seen this buffer before, but it now has a
            // different crop rect, so we'll need to recreate the EGLImage if
            // we're using the EGL_ANDROID_image_crop extension.
            destroyEglImage = hasEglAndroidImageCrop();
        }
    }

    if (destroyEglImage) {
        if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
            ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
                  slot);
@@ -290,7 +329,6 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
        }
        mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
    }
    }

    return NO_ERROR;
}
@@ -334,13 +372,15 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
    // EGLImage when detaching from a context but the buffer has not been
    // re-allocated.
    if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
        EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer);
        EGLImageKHR image = createImage(mEglDisplay,
                mSlots[buf].mGraphicBuffer, item.mCrop);
        if (image == EGL_NO_IMAGE_KHR) {
            ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
                  mEglDisplay, buf);
            return UNKNOWN_ERROR;
        }
        mEglSlots[buf].mEglImage = image;
        mEglSlots[buf].mCropRect = item.mCrop;
    }

    // Do whatever sync ops we need to do before releasing the old slot.
@@ -581,7 +621,8 @@ status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
            mCurrentTexture, mCurrentTextureBuf.get());

    // Create a temporary EGLImageKHR.
    EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
    Rect crop;
    EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
    if (image == EGL_NO_IMAGE_KHR) {
        return UNKNOWN_ERROR;
    }
@@ -753,6 +794,8 @@ void GLConsumer::computeCurrentTransformMatrixLocked() {
        ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
    }

    float mtxBeforeFlipV[16];
    if (!isEglImageCroppable(mCurrentCrop)) {
        Rect cropRect = mCurrentCrop;
        float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
        float bufferWidth = buf->getWidth();
@@ -805,8 +848,12 @@ void GLConsumer::computeCurrentTransformMatrixLocked() {
            tx, ty, 0, 1,
        };

    float mtxBeforeFlipV[16];
        mtxMul(mtxBeforeFlipV, crop, xform);
    } else {
        for (int i = 0; i < 16; i++) {
            mtxBeforeFlipV[i] = xform[i];
        }
    }

    // SurfaceFlinger expects the top of its window textures to be at a Y
    // coordinate of 0, so GLConsumer must behave the same way.  We don't
@@ -828,12 +875,26 @@ nsecs_t GLConsumer::getFrameNumber() {
}

EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
        const sp<GraphicBuffer>& graphicBuffer) {
        const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
    EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
    EGLint attrs[] = {
        EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
        EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
        EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
        EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
        EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
        EGL_NONE,
    };
    if (!crop.isValid()) {
        // No crop rect to set, so terminate the attrib array before the crop.
        attrs[2] = EGL_NONE;
    } else if (!isEglImageCroppable(crop)) {
        // The crop rect is not at the origin, so we can't set the crop on the
        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
        // extension.  In the future we can add a layered extension that
        // removes this restriction if there is hardware that can support it.
        attrs[2] = EGL_NONE;
    }
    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
            EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
    if (image == EGL_NO_IMAGE_KHR) {
+8 −0
Original line number Diff line number Diff line
@@ -494,6 +494,14 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC)(EGLDisplay dpy,
#define EGL_FRAMEBUFFER_TARGET_ANDROID		0x3147
#endif

#ifndef EGL_ANDROID_image_crop
#define EGL_ANDROID_image_crop 1
#define EGL_IMAGE_CROP_LEFT_ANDROID   0x3148
#define EGL_IMAGE_CROP_TOP_ANDROID    0x3149
#define EGL_IMAGE_CROP_RIGHT_ANDROID  0x314A
#define EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B
#endif

#ifndef EGL_ANDROID_blob_cache
#define EGL_ANDROID_blob_cache 1
typedef khronos_ssize_t EGLsizeiANDROID;
+2 −2
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ extern char const * const gExtensionString =
        "EGL_NV_system_time "
        "EGL_ANDROID_image_native_buffer "      // mandatory
        "EGL_KHR_wait_sync "                    // strongly recommended
        "EGL_ANDROID_recordable "               // mandatory
        ;

// extensions not exposed to applications but used by the ANDROID system
@@ -106,8 +107,7 @@ extern char const * const gExtensionString =
//      "EGL_IMG_hibernate_process "            // optional
//      "EGL_ANDROID_native_fence_sync "        // strongly recommended
//      "EGL_ANDROID_framebuffer_target "       // mandatory for HWC 1.1
//      "EGL_ANDROID_recordable "               // mandatory

//      "EGL_ANDROID_image_crop "               // optional

/*
 * EGL Extensions entry-points exposed to 3rd party applications
+5 −1
Original line number Diff line number Diff line
@@ -14,4 +14,8 @@ for use by Android extensions.
0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
0x3147               EGL_FRAMEBUFFER_TARGET_ANDROID (EGL_ANDROID_framebuffer_target)
0x3148 - 0x314F      (unused)
0x3148               EGL_IMAGE_CROP_LEFT_ANDROID (EGL_ANDROID_image_crop)
0x3149               EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop)
0x314A               EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
0x314C - 0x314F      (unused)