1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "GLConsumer"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 //#define LOG_NDEBUG 0
20 
21 #define GL_GLEXT_PROTOTYPES
22 #define EGL_EGLEXT_PROTOTYPES
23 
24 #include <inttypes.h>
25 
26 #include <EGL/egl.h>
27 #include <EGL/eglext.h>
28 #include <GLES2/gl2.h>
29 #include <GLES2/gl2ext.h>
30 #include <cutils/compiler.h>
31 
32 #include <hardware/hardware.h>
33 
34 #include <math/mat4.h>
35 
36 #include <gui/BufferItem.h>
37 #include <gui/GLConsumer.h>
38 #include <gui/ISurfaceComposer.h>
39 #include <gui/SurfaceComposerClient.h>
40 
41 #include <private/gui/ComposerService.h>
42 #include <private/gui/SyncFeatures.h>
43 
44 #include <utils/Log.h>
45 #include <utils/String8.h>
46 #include <utils/Trace.h>
47 
48 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
49 #define CROP_EXT_STR "EGL_ANDROID_image_crop"
50 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
51 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
52 
53 namespace android {
54 
55 // Macros for including the GLConsumer name in log messages
56 #define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
57 #define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
58 //#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
59 #define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
60 #define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
61 
62 static const struct {
63     uint32_t width, height;
64     char const* bits;
65 } kDebugData = { 15, 12,
66     "_______________"
67     "_______________"
68     "_____XX_XX_____"
69     "__X_X_____X_X__"
70     "__X_XXXXXXX_X__"
71     "__XXXXXXXXXXX__"
72     "___XX_XXX_XX___"
73     "____XXXXXXX____"
74     "_____X___X_____"
75     "____X_____X____"
76     "_______________"
77     "_______________"
78 };
79 
80 static const mat4 mtxIdentity;
81 
82 Mutex GLConsumer::sStaticInitLock;
83 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
84 
hasEglAndroidImageCropImpl()85 static bool hasEglAndroidImageCropImpl() {
86     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
87     const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
88     size_t cropExtLen = strlen(CROP_EXT_STR);
89     size_t extsLen = strlen(exts);
90     bool equal = !strcmp(CROP_EXT_STR, exts);
91     bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
92     bool atEnd = (cropExtLen+1) < extsLen &&
93             !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
94     bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
95     return equal || atStart || atEnd || inMiddle;
96 }
97 
hasEglAndroidImageCrop()98 static bool hasEglAndroidImageCrop() {
99     // Only compute whether the extension is present once the first time this
100     // function is called.
101     static bool hasIt = hasEglAndroidImageCropImpl();
102     return hasIt;
103 }
104 
hasEglProtectedContentImpl()105 static bool hasEglProtectedContentImpl() {
106     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
107     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
108     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
109     size_t extsLen = strlen(exts);
110     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
111     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
112     bool atEnd = (cropExtLen+1) < extsLen &&
113             !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen+1));
114     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
115     return equal || atStart || atEnd || inMiddle;
116 }
117 
hasEglProtectedContent()118 static bool hasEglProtectedContent() {
119     // Only compute whether the extension is present once the first time this
120     // function is called.
121     static bool hasIt = hasEglProtectedContentImpl();
122     return hasIt;
123 }
124 
isEglImageCroppable(const Rect & crop)125 static bool isEglImageCroppable(const Rect& crop) {
126     return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
127 }
128 
GLConsumer(const sp<IGraphicBufferConsumer> & bq,uint32_t tex,uint32_t texTarget,bool useFenceSync,bool isControlledByApp)129 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
130         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
131     ConsumerBase(bq, isControlledByApp),
132     mCurrentCrop(Rect::EMPTY_RECT),
133     mCurrentTransform(0),
134     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
135     mCurrentFence(Fence::NO_FENCE),
136     mCurrentTimestamp(0),
137     mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
138     mCurrentFrameNumber(0),
139     mDefaultWidth(1),
140     mDefaultHeight(1),
141     mFilteringEnabled(true),
142     mTexName(tex),
143     mUseFenceSync(useFenceSync),
144     mTexTarget(texTarget),
145     mEglDisplay(EGL_NO_DISPLAY),
146     mEglContext(EGL_NO_CONTEXT),
147     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
148     mAttached(true)
149 {
150     GLC_LOGV("GLConsumer");
151 
152     memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
153             sizeof(mCurrentTransformMatrix));
154 
155     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
156 }
157 
GLConsumer(const sp<IGraphicBufferConsumer> & bq,uint32_t texTarget,bool useFenceSync,bool isControlledByApp)158 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
159         bool useFenceSync, bool isControlledByApp) :
160     ConsumerBase(bq, isControlledByApp),
161     mCurrentCrop(Rect::EMPTY_RECT),
162     mCurrentTransform(0),
163     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
164     mCurrentFence(Fence::NO_FENCE),
165     mCurrentTimestamp(0),
166     mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
167     mCurrentFrameNumber(0),
168     mDefaultWidth(1),
169     mDefaultHeight(1),
170     mFilteringEnabled(true),
171     mTexName(0),
172     mUseFenceSync(useFenceSync),
173     mTexTarget(texTarget),
174     mEglDisplay(EGL_NO_DISPLAY),
175     mEglContext(EGL_NO_CONTEXT),
176     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
177     mAttached(false)
178 {
179     GLC_LOGV("GLConsumer");
180 
181     memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
182             sizeof(mCurrentTransformMatrix));
183 
184     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
185 }
186 
setDefaultBufferSize(uint32_t w,uint32_t h)187 status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
188 {
189     Mutex::Autolock lock(mMutex);
190     if (mAbandoned) {
191         GLC_LOGE("setDefaultBufferSize: GLConsumer is abandoned!");
192         return NO_INIT;
193     }
194     mDefaultWidth = w;
195     mDefaultHeight = h;
196     return mConsumer->setDefaultBufferSize(w, h);
197 }
198 
updateTexImage()199 status_t GLConsumer::updateTexImage() {
200     ATRACE_CALL();
201     GLC_LOGV("updateTexImage");
202     Mutex::Autolock lock(mMutex);
203 
204     if (mAbandoned) {
205         GLC_LOGE("updateTexImage: GLConsumer is abandoned!");
206         return NO_INIT;
207     }
208 
209     // Make sure the EGL state is the same as in previous calls.
210     status_t err = checkAndUpdateEglStateLocked();
211     if (err != NO_ERROR) {
212         return err;
213     }
214 
215     BufferItem item;
216 
217     // Acquire the next buffer.
218     // In asynchronous mode the list is guaranteed to be one buffer
219     // deep, while in synchronous mode we use the oldest buffer.
220     err = acquireBufferLocked(&item, 0);
221     if (err != NO_ERROR) {
222         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
223             // We always bind the texture even if we don't update its contents.
224             GLC_LOGV("updateTexImage: no buffers were available");
225             glBindTexture(mTexTarget, mTexName);
226             err = NO_ERROR;
227         } else {
228             GLC_LOGE("updateTexImage: acquire failed: %s (%d)",
229                 strerror(-err), err);
230         }
231         return err;
232     }
233 
234     // Release the previous buffer.
235     err = updateAndReleaseLocked(item);
236     if (err != NO_ERROR) {
237         // We always bind the texture.
238         glBindTexture(mTexTarget, mTexName);
239         return err;
240     }
241 
242     // Bind the new buffer to the GL texture, and wait until it's ready.
243     return bindTextureImageLocked();
244 }
245 
246 
releaseTexImage()247 status_t GLConsumer::releaseTexImage() {
248     ATRACE_CALL();
249     GLC_LOGV("releaseTexImage");
250     Mutex::Autolock lock(mMutex);
251 
252     if (mAbandoned) {
253         GLC_LOGE("releaseTexImage: GLConsumer is abandoned!");
254         return NO_INIT;
255     }
256 
257     // Make sure the EGL state is the same as in previous calls.
258     status_t err = NO_ERROR;
259 
260     if (mAttached) {
261         err = checkAndUpdateEglStateLocked(true);
262         if (err != NO_ERROR) {
263             return err;
264         }
265     } else {
266         // if we're detached, no need to validate EGL's state -- we won't use it.
267     }
268 
269     // Update the GLConsumer state.
270     int buf = mCurrentTexture;
271     if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
272 
273         GLC_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached);
274 
275         if (mAttached) {
276             // Do whatever sync ops we need to do before releasing the slot.
277             err = syncForReleaseLocked(mEglDisplay);
278             if (err != NO_ERROR) {
279                 GLC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
280                 return err;
281             }
282         } else {
283             // if we're detached, we just use the fence that was created in detachFromContext()
284             // so... basically, nothing more to do here.
285         }
286 
287         err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
288         if (err < NO_ERROR) {
289             GLC_LOGE("releaseTexImage: failed to release buffer: %s (%d)",
290                     strerror(-err), err);
291             return err;
292         }
293 
294         if (mReleasedTexImage == NULL) {
295             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
296         }
297 
298         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
299         mCurrentTextureImage = mReleasedTexImage;
300         mCurrentCrop.makeInvalid();
301         mCurrentTransform = 0;
302         mCurrentTimestamp = 0;
303         mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
304         mCurrentFence = Fence::NO_FENCE;
305         mCurrentFenceTime = FenceTime::NO_FENCE;
306 
307         if (mAttached) {
308             // This binds a dummy buffer (mReleasedTexImage).
309             status_t result = bindTextureImageLocked();
310             if (result != NO_ERROR) {
311                 return result;
312             }
313         } else {
314             // detached, don't touch the texture (and we may not even have an
315             // EGLDisplay here.
316         }
317     }
318 
319     return NO_ERROR;
320 }
321 
getDebugTexImageBuffer()322 sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
323     Mutex::Autolock _l(sStaticInitLock);
324     if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
325         // The first time, create the debug texture in case the application
326         // continues to use it.
327         sp<GraphicBuffer> buffer = new GraphicBuffer(
328                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
329                 GraphicBuffer::USAGE_SW_WRITE_RARELY,
330                 "[GLConsumer debug texture]");
331         uint32_t* bits;
332         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
333         uint32_t stride = buffer->getStride();
334         uint32_t height = buffer->getHeight();
335         memset(bits, 0, stride * height * 4);
336         for (uint32_t y = 0; y < kDebugData.height; y++) {
337             for (uint32_t x = 0; x < kDebugData.width; x++) {
338                 bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ?
339                     0xFF000000 : 0xFFFFFFFF;
340             }
341             bits += stride;
342         }
343         buffer->unlock();
344         sReleasedTexImageBuffer = buffer;
345     }
346     return sReleasedTexImageBuffer;
347 }
348 
acquireBufferLocked(BufferItem * item,nsecs_t presentWhen,uint64_t maxFrameNumber)349 status_t GLConsumer::acquireBufferLocked(BufferItem *item,
350         nsecs_t presentWhen, uint64_t maxFrameNumber) {
351     status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
352             maxFrameNumber);
353     if (err != NO_ERROR) {
354         return err;
355     }
356 
357     // If item->mGraphicBuffer is not null, this buffer has not been acquired
358     // before, so any prior EglImage created is using a stale buffer. This
359     // replaces any old EglImage with a new one (using the new buffer).
360     if (item->mGraphicBuffer != NULL) {
361         int slot = item->mSlot;
362         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
363     }
364 
365     return NO_ERROR;
366 }
367 
releaseBufferLocked(int buf,sp<GraphicBuffer> graphicBuffer,EGLDisplay display,EGLSyncKHR eglFence)368 status_t GLConsumer::releaseBufferLocked(int buf,
369         sp<GraphicBuffer> graphicBuffer,
370         EGLDisplay display, EGLSyncKHR eglFence) {
371     // release the buffer if it hasn't already been discarded by the
372     // BufferQueue. This can happen, for example, when the producer of this
373     // buffer has reallocated the original buffer slot after this buffer
374     // was acquired.
375     status_t err = ConsumerBase::releaseBufferLocked(
376             buf, graphicBuffer, display, eglFence);
377     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
378     return err;
379 }
380 
updateAndReleaseLocked(const BufferItem & item,PendingRelease * pendingRelease)381 status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item,
382         PendingRelease* pendingRelease)
383 {
384     status_t err = NO_ERROR;
385 
386     int slot = item.mSlot;
387 
388     if (!mAttached) {
389         GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
390                 "ES context");
391         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
392                 mEglDisplay, EGL_NO_SYNC_KHR);
393         return INVALID_OPERATION;
394     }
395 
396     // Confirm state.
397     err = checkAndUpdateEglStateLocked();
398     if (err != NO_ERROR) {
399         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
400                 mEglDisplay, EGL_NO_SYNC_KHR);
401         return err;
402     }
403 
404     // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
405     // if nessessary, for the gralloc buffer currently in the slot in
406     // ConsumerBase.
407     // We may have to do this even when item.mGraphicBuffer == NULL (which
408     // means the buffer was previously acquired).
409     err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
410     if (err != NO_ERROR) {
411         GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
412                 mEglDisplay, slot);
413         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
414                 mEglDisplay, EGL_NO_SYNC_KHR);
415         return UNKNOWN_ERROR;
416     }
417 
418     // Do whatever sync ops we need to do before releasing the old slot.
419     if (slot != mCurrentTexture) {
420         err = syncForReleaseLocked(mEglDisplay);
421         if (err != NO_ERROR) {
422             // Release the buffer we just acquired.  It's not safe to
423             // release the old buffer, so instead we just drop the new frame.
424             // As we are still under lock since acquireBuffer, it is safe to
425             // release by slot.
426             releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
427                     mEglDisplay, EGL_NO_SYNC_KHR);
428             return err;
429         }
430     }
431 
432     GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
433             mCurrentTexture, mCurrentTextureImage != NULL ?
434                     mCurrentTextureImage->graphicBufferHandle() : 0,
435             slot, mSlots[slot].mGraphicBuffer->handle);
436 
437     // Hang onto the pointer so that it isn't freed in the call to
438     // releaseBufferLocked() if we're in shared buffer mode and both buffers are
439     // the same.
440     sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
441 
442     // release old buffer
443     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
444         if (pendingRelease == nullptr) {
445             status_t status = releaseBufferLocked(
446                     mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
447                     mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
448             if (status < NO_ERROR) {
449                 GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
450                         strerror(-status), status);
451                 err = status;
452                 // keep going, with error raised [?]
453             }
454         } else {
455             pendingRelease->currentTexture = mCurrentTexture;
456             pendingRelease->graphicBuffer =
457                     mCurrentTextureImage->graphicBuffer();
458             pendingRelease->display = mEglDisplay;
459             pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence;
460             pendingRelease->isPending = true;
461         }
462     }
463 
464     // Update the GLConsumer state.
465     mCurrentTexture = slot;
466     mCurrentTextureImage = nextTextureImage;
467     mCurrentCrop = item.mCrop;
468     mCurrentTransform = item.mTransform;
469     mCurrentScalingMode = item.mScalingMode;
470     mCurrentTimestamp = item.mTimestamp;
471     mCurrentDataSpace = item.mDataSpace;
472     mCurrentFence = item.mFence;
473     mCurrentFenceTime = item.mFenceTime;
474     mCurrentFrameNumber = item.mFrameNumber;
475 
476     computeCurrentTransformMatrixLocked();
477 
478     return err;
479 }
480 
bindTextureImageLocked()481 status_t GLConsumer::bindTextureImageLocked() {
482     if (mEglDisplay == EGL_NO_DISPLAY) {
483         ALOGE("bindTextureImage: invalid display");
484         return INVALID_OPERATION;
485     }
486 
487     GLenum error;
488     while ((error = glGetError()) != GL_NO_ERROR) {
489         GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
490     }
491 
492     glBindTexture(mTexTarget, mTexName);
493     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
494             mCurrentTextureImage == NULL) {
495         GLC_LOGE("bindTextureImage: no currently-bound texture");
496         return NO_INIT;
497     }
498 
499     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
500                                                         mCurrentCrop);
501     if (err != NO_ERROR) {
502         GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
503                 mEglDisplay, mCurrentTexture);
504         return UNKNOWN_ERROR;
505     }
506     mCurrentTextureImage->bindToTextureTarget(mTexTarget);
507 
508     // In the rare case that the display is terminated and then initialized
509     // again, we can't detect that the display changed (it didn't), but the
510     // image is invalid. In this case, repeat the exact same steps while
511     // forcing the creation of a new image.
512     if ((error = glGetError()) != GL_NO_ERROR) {
513         glBindTexture(mTexTarget, mTexName);
514         status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay,
515                                                                mCurrentCrop,
516                                                                true);
517         if (result != NO_ERROR) {
518             GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
519                     mEglDisplay, mCurrentTexture);
520             return UNKNOWN_ERROR;
521         }
522         mCurrentTextureImage->bindToTextureTarget(mTexTarget);
523         if ((error = glGetError()) != GL_NO_ERROR) {
524             GLC_LOGE("bindTextureImage: error binding external image: %#04x", error);
525             return UNKNOWN_ERROR;
526         }
527     }
528 
529     // Wait for the new buffer to be ready.
530     return doGLFenceWaitLocked();
531 }
532 
checkAndUpdateEglStateLocked(bool contextCheck)533 status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
534     EGLDisplay dpy = eglGetCurrentDisplay();
535     EGLContext ctx = eglGetCurrentContext();
536 
537     if (!contextCheck) {
538         // if this is the first time we're called, mEglDisplay/mEglContext have
539         // never been set, so don't error out (below).
540         if (mEglDisplay == EGL_NO_DISPLAY) {
541             mEglDisplay = dpy;
542         }
543         if (mEglContext == EGL_NO_CONTEXT) {
544             mEglContext = ctx;
545         }
546     }
547 
548     if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
549         GLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
550         return INVALID_OPERATION;
551     }
552 
553     if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
554         GLC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
555         return INVALID_OPERATION;
556     }
557 
558     mEglDisplay = dpy;
559     mEglContext = ctx;
560     return NO_ERROR;
561 }
562 
setReleaseFence(const sp<Fence> & fence)563 void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
564     if (fence->isValid() &&
565             mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
566         status_t err = addReleaseFence(mCurrentTexture,
567                 mCurrentTextureImage->graphicBuffer(), fence);
568         if (err != OK) {
569             GLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
570                     strerror(-err), err);
571         }
572     }
573 }
574 
detachFromContext()575 status_t GLConsumer::detachFromContext() {
576     ATRACE_CALL();
577     GLC_LOGV("detachFromContext");
578     Mutex::Autolock lock(mMutex);
579 
580     if (mAbandoned) {
581         GLC_LOGE("detachFromContext: abandoned GLConsumer");
582         return NO_INIT;
583     }
584 
585     if (!mAttached) {
586         GLC_LOGE("detachFromContext: GLConsumer is not attached to a "
587                 "context");
588         return INVALID_OPERATION;
589     }
590 
591     EGLDisplay dpy = eglGetCurrentDisplay();
592     EGLContext ctx = eglGetCurrentContext();
593 
594     if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
595         GLC_LOGE("detachFromContext: invalid current EGLDisplay");
596         return INVALID_OPERATION;
597     }
598 
599     if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
600         GLC_LOGE("detachFromContext: invalid current EGLContext");
601         return INVALID_OPERATION;
602     }
603 
604     if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
605         status_t err = syncForReleaseLocked(dpy);
606         if (err != OK) {
607             return err;
608         }
609 
610         glDeleteTextures(1, &mTexName);
611     }
612 
613     mEglDisplay = EGL_NO_DISPLAY;
614     mEglContext = EGL_NO_CONTEXT;
615     mAttached = false;
616 
617     return OK;
618 }
619 
attachToContext(uint32_t tex)620 status_t GLConsumer::attachToContext(uint32_t tex) {
621     ATRACE_CALL();
622     GLC_LOGV("attachToContext");
623     Mutex::Autolock lock(mMutex);
624 
625     if (mAbandoned) {
626         GLC_LOGE("attachToContext: abandoned GLConsumer");
627         return NO_INIT;
628     }
629 
630     if (mAttached) {
631         GLC_LOGE("attachToContext: GLConsumer is already attached to a "
632                 "context");
633         return INVALID_OPERATION;
634     }
635 
636     EGLDisplay dpy = eglGetCurrentDisplay();
637     EGLContext ctx = eglGetCurrentContext();
638 
639     if (dpy == EGL_NO_DISPLAY) {
640         GLC_LOGE("attachToContext: invalid current EGLDisplay");
641         return INVALID_OPERATION;
642     }
643 
644     if (ctx == EGL_NO_CONTEXT) {
645         GLC_LOGE("attachToContext: invalid current EGLContext");
646         return INVALID_OPERATION;
647     }
648 
649     // We need to bind the texture regardless of whether there's a current
650     // buffer.
651     glBindTexture(mTexTarget, GLuint(tex));
652 
653     mEglDisplay = dpy;
654     mEglContext = ctx;
655     mTexName = tex;
656     mAttached = true;
657 
658     if (mCurrentTextureImage != NULL) {
659         // This may wait for a buffer a second time. This is likely required if
660         // this is a different context, since otherwise the wait could be skipped
661         // by bouncing through another context. For the same context the extra
662         // wait is redundant.
663         status_t err =  bindTextureImageLocked();
664         if (err != NO_ERROR) {
665             return err;
666         }
667     }
668 
669     return OK;
670 }
671 
672 
syncForReleaseLocked(EGLDisplay dpy)673 status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
674     GLC_LOGV("syncForReleaseLocked");
675 
676     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
677         if (SyncFeatures::getInstance().useNativeFenceSync()) {
678             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
679                     EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
680             if (sync == EGL_NO_SYNC_KHR) {
681                 GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
682                         eglGetError());
683                 return UNKNOWN_ERROR;
684             }
685             glFlush();
686             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
687             eglDestroySyncKHR(dpy, sync);
688             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
689                 GLC_LOGE("syncForReleaseLocked: error dup'ing native fence "
690                         "fd: %#x", eglGetError());
691                 return UNKNOWN_ERROR;
692             }
693             sp<Fence> fence(new Fence(fenceFd));
694             status_t err = addReleaseFenceLocked(mCurrentTexture,
695                     mCurrentTextureImage->graphicBuffer(), fence);
696             if (err != OK) {
697                 GLC_LOGE("syncForReleaseLocked: error adding release fence: "
698                         "%s (%d)", strerror(-err), err);
699                 return err;
700             }
701         } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
702             EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
703             if (fence != EGL_NO_SYNC_KHR) {
704                 // There is already a fence for the current slot.  We need to
705                 // wait on that before replacing it with another fence to
706                 // ensure that all outstanding buffer accesses have completed
707                 // before the producer accesses it.
708                 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
709                 if (result == EGL_FALSE) {
710                     GLC_LOGE("syncForReleaseLocked: error waiting for previous "
711                             "fence: %#x", eglGetError());
712                     return UNKNOWN_ERROR;
713                 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
714                     GLC_LOGE("syncForReleaseLocked: timeout waiting for previous "
715                             "fence");
716                     return TIMED_OUT;
717                 }
718                 eglDestroySyncKHR(dpy, fence);
719             }
720 
721             // Create a fence for the outstanding accesses in the current
722             // OpenGL ES context.
723             fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
724             if (fence == EGL_NO_SYNC_KHR) {
725                 GLC_LOGE("syncForReleaseLocked: error creating fence: %#x",
726                         eglGetError());
727                 return UNKNOWN_ERROR;
728             }
729             glFlush();
730             mEglSlots[mCurrentTexture].mEglFence = fence;
731         }
732     }
733 
734     return OK;
735 }
736 
getCurrentTextureTarget() const737 uint32_t GLConsumer::getCurrentTextureTarget() const {
738     return mTexTarget;
739 }
740 
getTransformMatrix(float mtx[16])741 void GLConsumer::getTransformMatrix(float mtx[16]) {
742     Mutex::Autolock lock(mMutex);
743     memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
744 }
745 
setFilteringEnabled(bool enabled)746 void GLConsumer::setFilteringEnabled(bool enabled) {
747     Mutex::Autolock lock(mMutex);
748     if (mAbandoned) {
749         GLC_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
750         return;
751     }
752     bool needsRecompute = mFilteringEnabled != enabled;
753     mFilteringEnabled = enabled;
754 
755     if (needsRecompute && mCurrentTextureImage==NULL) {
756         GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
757     }
758 
759     if (needsRecompute && mCurrentTextureImage != NULL) {
760         computeCurrentTransformMatrixLocked();
761     }
762 }
763 
computeCurrentTransformMatrixLocked()764 void GLConsumer::computeCurrentTransformMatrixLocked() {
765     GLC_LOGV("computeCurrentTransformMatrixLocked");
766     sp<GraphicBuffer> buf = (mCurrentTextureImage == nullptr) ?
767             nullptr : mCurrentTextureImage->graphicBuffer();
768     if (buf == nullptr) {
769         GLC_LOGD("computeCurrentTransformMatrixLocked: "
770                 "mCurrentTextureImage is NULL");
771     }
772     computeTransformMatrix(mCurrentTransformMatrix, buf,
773         isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
774         mCurrentTransform, mFilteringEnabled);
775 }
776 
computeTransformMatrix(float outTransform[16],const sp<GraphicBuffer> & buf,const Rect & cropRect,uint32_t transform,bool filtering)777 void GLConsumer::computeTransformMatrix(float outTransform[16],
778         const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
779         bool filtering) {
780     // Transform matrices
781     static const mat4 mtxFlipH(
782         -1, 0, 0, 0,
783         0, 1, 0, 0,
784         0, 0, 1, 0,
785         1, 0, 0, 1
786     );
787     static const mat4 mtxFlipV(
788         1, 0, 0, 0,
789         0, -1, 0, 0,
790         0, 0, 1, 0,
791         0, 1, 0, 1
792     );
793     static const mat4 mtxRot90(
794         0, 1, 0, 0,
795         -1, 0, 0, 0,
796         0, 0, 1, 0,
797         1, 0, 0, 1
798     );
799 
800     mat4 xform;
801     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
802         xform *= mtxFlipH;
803     }
804     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
805         xform *= mtxFlipV;
806     }
807     if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
808         xform *= mtxRot90;
809     }
810 
811     if (!cropRect.isEmpty()) {
812         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
813         float bufferWidth = buf->getWidth();
814         float bufferHeight = buf->getHeight();
815         float shrinkAmount = 0.0f;
816         if (filtering) {
817             // In order to prevent bilinear sampling beyond the edge of the
818             // crop rectangle we may need to shrink it by 2 texels in each
819             // dimension.  Normally this would just need to take 1/2 a texel
820             // off each end, but because the chroma channels of YUV420 images
821             // are subsampled we may need to shrink the crop region by a whole
822             // texel on each side.
823             switch (buf->getPixelFormat()) {
824                 case PIXEL_FORMAT_RGBA_8888:
825                 case PIXEL_FORMAT_RGBX_8888:
826                 case PIXEL_FORMAT_RGBA_FP16:
827                 case PIXEL_FORMAT_RGBA_1010102:
828                 case PIXEL_FORMAT_RGB_888:
829                 case PIXEL_FORMAT_RGB_565:
830                 case PIXEL_FORMAT_BGRA_8888:
831                     // We know there's no subsampling of any channels, so we
832                     // only need to shrink by a half a pixel.
833                     shrinkAmount = 0.5;
834                     break;
835 
836                 default:
837                     // If we don't recognize the format, we must assume the
838                     // worst case (that we care about), which is YUV420.
839                     shrinkAmount = 1.0;
840                     break;
841             }
842         }
843 
844         // Only shrink the dimensions that are not the size of the buffer.
845         if (cropRect.width() < bufferWidth) {
846             tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
847             sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
848                     bufferWidth;
849         }
850         if (cropRect.height() < bufferHeight) {
851             ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
852                     bufferHeight;
853             sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
854                     bufferHeight;
855         }
856 
857         mat4 crop(
858             sx, 0, 0, 0,
859             0, sy, 0, 0,
860             0, 0, 1, 0,
861             tx, ty, 0, 1
862         );
863         xform = crop * xform;
864     }
865 
866     // SurfaceFlinger expects the top of its window textures to be at a Y
867     // coordinate of 0, so GLConsumer must behave the same way.  We don't
868     // want to expose this to applications, however, so we must add an
869     // additional vertical flip to the transform after all the other transforms.
870     xform = mtxFlipV * xform;
871 
872     memcpy(outTransform, xform.asArray(), sizeof(xform));
873 }
874 
scaleDownCrop(const Rect & crop,uint32_t bufferWidth,uint32_t bufferHeight)875 Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
876     Rect outCrop = crop;
877 
878     uint32_t newWidth = static_cast<uint32_t>(crop.width());
879     uint32_t newHeight = static_cast<uint32_t>(crop.height());
880 
881     if (newWidth * bufferHeight > newHeight * bufferWidth) {
882         newWidth = newHeight * bufferWidth / bufferHeight;
883         ALOGV("too wide: newWidth = %d", newWidth);
884     } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
885         newHeight = newWidth * bufferHeight / bufferWidth;
886         ALOGV("too tall: newHeight = %d", newHeight);
887     }
888 
889     uint32_t currentWidth = static_cast<uint32_t>(crop.width());
890     uint32_t currentHeight = static_cast<uint32_t>(crop.height());
891 
892     // The crop is too wide
893     if (newWidth < currentWidth) {
894         uint32_t dw = currentWidth - newWidth;
895         auto halfdw = dw / 2;
896         outCrop.left += halfdw;
897         // Not halfdw because it would subtract 1 too few when dw is odd
898         outCrop.right -= (dw - halfdw);
899         // The crop is too tall
900     } else if (newHeight < currentHeight) {
901         uint32_t dh = currentHeight - newHeight;
902         auto halfdh = dh / 2;
903         outCrop.top += halfdh;
904         // Not halfdh because it would subtract 1 too few when dh is odd
905         outCrop.bottom -= (dh - halfdh);
906     }
907 
908     ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
909             outCrop.left, outCrop.top,
910             outCrop.right,outCrop.bottom);
911 
912     return outCrop;
913 }
914 
getTimestamp()915 nsecs_t GLConsumer::getTimestamp() {
916     GLC_LOGV("getTimestamp");
917     Mutex::Autolock lock(mMutex);
918     return mCurrentTimestamp;
919 }
920 
getCurrentDataSpace()921 android_dataspace GLConsumer::getCurrentDataSpace() {
922     GLC_LOGV("getCurrentDataSpace");
923     Mutex::Autolock lock(mMutex);
924     return mCurrentDataSpace;
925 }
926 
getFrameNumber()927 uint64_t GLConsumer::getFrameNumber() {
928     GLC_LOGV("getFrameNumber");
929     Mutex::Autolock lock(mMutex);
930     return mCurrentFrameNumber;
931 }
932 
getCurrentBuffer(int * outSlot) const933 sp<GraphicBuffer> GLConsumer::getCurrentBuffer(int* outSlot) const {
934     Mutex::Autolock lock(mMutex);
935 
936     if (outSlot != nullptr) {
937         *outSlot = mCurrentTexture;
938     }
939 
940     return (mCurrentTextureImage == nullptr) ?
941             NULL : mCurrentTextureImage->graphicBuffer();
942 }
943 
getCurrentCrop() const944 Rect GLConsumer::getCurrentCrop() const {
945     Mutex::Autolock lock(mMutex);
946     return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
947         ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
948         : mCurrentCrop;
949 }
950 
getCurrentTransform() const951 uint32_t GLConsumer::getCurrentTransform() const {
952     Mutex::Autolock lock(mMutex);
953     return mCurrentTransform;
954 }
955 
getCurrentScalingMode() const956 uint32_t GLConsumer::getCurrentScalingMode() const {
957     Mutex::Autolock lock(mMutex);
958     return mCurrentScalingMode;
959 }
960 
getCurrentFence() const961 sp<Fence> GLConsumer::getCurrentFence() const {
962     Mutex::Autolock lock(mMutex);
963     return mCurrentFence;
964 }
965 
getCurrentFenceTime() const966 std::shared_ptr<FenceTime> GLConsumer::getCurrentFenceTime() const {
967     Mutex::Autolock lock(mMutex);
968     return mCurrentFenceTime;
969 }
970 
doGLFenceWaitLocked() const971 status_t GLConsumer::doGLFenceWaitLocked() const {
972 
973     EGLDisplay dpy = eglGetCurrentDisplay();
974     EGLContext ctx = eglGetCurrentContext();
975 
976     if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
977         GLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
978         return INVALID_OPERATION;
979     }
980 
981     if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
982         GLC_LOGE("doGLFenceWait: invalid current EGLContext");
983         return INVALID_OPERATION;
984     }
985 
986     if (mCurrentFence->isValid()) {
987         if (SyncFeatures::getInstance().useWaitSync() &&
988             SyncFeatures::getInstance().useNativeFenceSync()) {
989             // Create an EGLSyncKHR from the current fence.
990             int fenceFd = mCurrentFence->dup();
991             if (fenceFd == -1) {
992                 GLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
993                 return -errno;
994             }
995             EGLint attribs[] = {
996                 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
997                 EGL_NONE
998             };
999             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
1000                     EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
1001             if (sync == EGL_NO_SYNC_KHR) {
1002                 close(fenceFd);
1003                 GLC_LOGE("doGLFenceWait: error creating EGL fence: %#x",
1004                         eglGetError());
1005                 return UNKNOWN_ERROR;
1006             }
1007 
1008             // XXX: The spec draft is inconsistent as to whether this should
1009             // return an EGLint or void.  Ignore the return value for now, as
1010             // it's not strictly needed.
1011             eglWaitSyncKHR(dpy, sync, 0);
1012             EGLint eglErr = eglGetError();
1013             eglDestroySyncKHR(dpy, sync);
1014             if (eglErr != EGL_SUCCESS) {
1015                 GLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
1016                         eglErr);
1017                 return UNKNOWN_ERROR;
1018             }
1019         } else {
1020             status_t err = mCurrentFence->waitForever(
1021                     "GLConsumer::doGLFenceWaitLocked");
1022             if (err != NO_ERROR) {
1023                 GLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
1024                 return err;
1025             }
1026         }
1027     }
1028 
1029     return NO_ERROR;
1030 }
1031 
freeBufferLocked(int slotIndex)1032 void GLConsumer::freeBufferLocked(int slotIndex) {
1033     GLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
1034     if (slotIndex == mCurrentTexture) {
1035         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
1036     }
1037     mEglSlots[slotIndex].mEglImage.clear();
1038     ConsumerBase::freeBufferLocked(slotIndex);
1039 }
1040 
abandonLocked()1041 void GLConsumer::abandonLocked() {
1042     GLC_LOGV("abandonLocked");
1043     mCurrentTextureImage.clear();
1044     ConsumerBase::abandonLocked();
1045 }
1046 
setConsumerUsageBits(uint64_t usage)1047 status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
1048     return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
1049 }
1050 
dumpLocked(String8 & result,const char * prefix) const1051 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
1052 {
1053     result.appendFormat(
1054        "%smTexName=%d mCurrentTexture=%d\n"
1055        "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
1056        prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
1057        mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
1058        mCurrentTransform);
1059 
1060     ConsumerBase::dumpLocked(result, prefix);
1061 }
1062 
EglImage(sp<GraphicBuffer> graphicBuffer)1063 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
1064     mGraphicBuffer(graphicBuffer),
1065     mEglImage(EGL_NO_IMAGE_KHR),
1066     mEglDisplay(EGL_NO_DISPLAY),
1067     mCropRect(Rect::EMPTY_RECT) {
1068 }
1069 
~EglImage()1070 GLConsumer::EglImage::~EglImage() {
1071     if (mEglImage != EGL_NO_IMAGE_KHR) {
1072         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
1073            ALOGE("~EglImage: eglDestroyImageKHR failed");
1074         }
1075         eglTerminate(mEglDisplay);
1076     }
1077 }
1078 
createIfNeeded(EGLDisplay eglDisplay,const Rect & cropRect,bool forceCreation)1079 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
1080                                               const Rect& cropRect,
1081                                               bool forceCreation) {
1082     // If there's an image and it's no longer valid, destroy it.
1083     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
1084     bool displayInvalid = mEglDisplay != eglDisplay;
1085     bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
1086     if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
1087         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
1088            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
1089         }
1090         eglTerminate(mEglDisplay);
1091         mEglImage = EGL_NO_IMAGE_KHR;
1092         mEglDisplay = EGL_NO_DISPLAY;
1093     }
1094 
1095     // If there's no image, create one.
1096     if (mEglImage == EGL_NO_IMAGE_KHR) {
1097         mEglDisplay = eglDisplay;
1098         mCropRect = cropRect;
1099         mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
1100     }
1101 
1102     // Fail if we can't create a valid image.
1103     if (mEglImage == EGL_NO_IMAGE_KHR) {
1104         mEglDisplay = EGL_NO_DISPLAY;
1105         mCropRect.makeInvalid();
1106         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
1107         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
1108             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
1109             buffer->getUsage(), buffer->getPixelFormat());
1110         return UNKNOWN_ERROR;
1111     }
1112 
1113     return OK;
1114 }
1115 
bindToTextureTarget(uint32_t texTarget)1116 void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
1117     glEGLImageTargetTexture2DOES(texTarget,
1118             static_cast<GLeglImageOES>(mEglImage));
1119 }
1120 
createImage(EGLDisplay dpy,const sp<GraphicBuffer> & graphicBuffer,const Rect & crop)1121 EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
1122         const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
1123     EGLClientBuffer cbuf =
1124             static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
1125     const bool createProtectedImage =
1126             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) &&
1127             hasEglProtectedContent();
1128     EGLint attrs[] = {
1129         EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
1130         EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
1131         EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
1132         EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
1133         EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
1134         createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
1135         createProtectedImage ? EGL_TRUE : EGL_NONE,
1136         EGL_NONE,
1137     };
1138     if (!crop.isValid()) {
1139         // No crop rect to set, so leave the crop out of the attrib array. Make
1140         // sure to propagate the protected content attrs if they are set.
1141         attrs[2] = attrs[10];
1142         attrs[3] = attrs[11];
1143         attrs[4] = EGL_NONE;
1144     } else if (!isEglImageCroppable(crop)) {
1145         // The crop rect is not at the origin, so we can't set the crop on the
1146         // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
1147         // extension.  In the future we can add a layered extension that
1148         // removes this restriction if there is hardware that can support it.
1149         attrs[2] = attrs[10];
1150         attrs[3] = attrs[11];
1151         attrs[4] = EGL_NONE;
1152     }
1153     eglInitialize(dpy, 0, 0);
1154     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
1155             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
1156     if (image == EGL_NO_IMAGE_KHR) {
1157         EGLint error = eglGetError();
1158         ALOGE("error creating EGLImage: %#x", error);
1159         eglTerminate(dpy);
1160     }
1161     return image;
1162 }
1163 
1164 }; // namespace android
1165