Loading include/gui/GLConsumer.h +5 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading libs/gui/GLConsumer.cpp +124 −63 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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), Loading Loading @@ -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); Loading @@ -290,7 +329,6 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, } mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR; } } return NO_ERROR; } Loading Loading @@ -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. Loading Loading @@ -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; } Loading Loading @@ -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(); Loading Loading @@ -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 Loading @@ -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) { Loading opengl/include/EGL/eglext.h +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading opengl/libs/EGL/eglApi.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading opengl/specs/README +5 −1 Original line number Diff line number Diff line Loading @@ -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) Loading
include/gui/GLConsumer.h +5 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading
libs/gui/GLConsumer.cpp +124 −63 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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), Loading Loading @@ -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); Loading @@ -290,7 +329,6 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, } mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR; } } return NO_ERROR; } Loading Loading @@ -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. Loading Loading @@ -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; } Loading Loading @@ -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(); Loading Loading @@ -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 Loading @@ -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) { Loading
opengl/include/EGL/eglext.h +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
opengl/libs/EGL/eglApi.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading
opengl/specs/README +5 −1 Original line number Diff line number Diff line Loading @@ -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)