• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #include <inttypes.h>
18 
19 #include <EGL/egl.h>
20 #include <EGL/eglext.h>
21 #include <GLES2/gl2.h>
22 #include <GLES2/gl2ext.h>
23 #include <cutils/compiler.h>
24 #include <gui/BufferItem.h>
25 #include <gui/BufferQueue.h>
26 #include <private/gui/SyncFeatures.h>
27 #include "EGLConsumer.h"
28 #include "SurfaceTexture.h"
29 
30 #include <utils/Log.h>
31 #include <utils/String8.h>
32 #include <utils/Trace.h>
33 
34 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
35 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
36 
37 namespace android {
38 
39 // Macros for including the SurfaceTexture name in log messages
40 #define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__)
41 #define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__)
42 #define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__)
43 #define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
44 
45 static const struct {
46     uint32_t width, height;
47     char const* bits;
48 } kDebugData = {15, 12,
49                 "_______________"
50                 "_______________"
51                 "_____XX_XX_____"
52                 "__X_X_____X_X__"
53                 "__X_XXXXXXX_X__"
54                 "__XXXXXXXXXXX__"
55                 "___XX_XXX_XX___"
56                 "____XXXXXXX____"
57                 "_____X___X_____"
58                 "____X_____X____"
59                 "_______________"
60                 "_______________"};
61 
62 Mutex EGLConsumer::sStaticInitLock;
63 sp<GraphicBuffer> EGLConsumer::sReleasedTexImageBuffer;
64 
hasEglProtectedContentImpl()65 static bool hasEglProtectedContentImpl() {
66     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
67     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
68     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
69     size_t extsLen = strlen(exts);
70     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
71     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
72     bool atEnd = (cropExtLen + 1) < extsLen &&
73                  !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
74     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
75     return equal || atStart || atEnd || inMiddle;
76 }
77 
hasEglProtectedContent()78 static bool hasEglProtectedContent() {
79     // Only compute whether the extension is present once the first time this
80     // function is called.
81     static bool hasIt = hasEglProtectedContentImpl();
82     return hasIt;
83 }
84 
EGLConsumer()85 EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {}
86 
updateTexImage(SurfaceTexture & st)87 status_t EGLConsumer::updateTexImage(SurfaceTexture& st) {
88     // Make sure the EGL state is the same as in previous calls.
89     status_t err = checkAndUpdateEglStateLocked(st);
90     if (err != NO_ERROR) {
91         return err;
92     }
93 
94     BufferItem item;
95 
96     // Acquire the next buffer.
97     // In asynchronous mode the list is guaranteed to be one buffer
98     // deep, while in synchronous mode we use the oldest buffer.
99     err = st.acquireBufferLocked(&item, 0);
100     if (err != NO_ERROR) {
101         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
102             // We always bind the texture even if we don't update its contents.
103             EGC_LOGV("updateTexImage: no buffers were available");
104             glBindTexture(st.mTexTarget, st.mTexName);
105             err = NO_ERROR;
106         } else {
107             EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
108         }
109         return err;
110     }
111 
112     // Release the previous buffer.
113     err = updateAndReleaseLocked(item, nullptr, st);
114     if (err != NO_ERROR) {
115         // We always bind the texture.
116         glBindTexture(st.mTexTarget, st.mTexName);
117         return err;
118     }
119 
120     // Bind the new buffer to the GL texture, and wait until it's ready.
121     return bindTextureImageLocked(st);
122 }
123 
releaseTexImage(SurfaceTexture & st)124 status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) {
125     // Make sure the EGL state is the same as in previous calls.
126     status_t err = NO_ERROR;
127 
128     // if we're detached, no need to validate EGL's state -- we won't use it.
129     if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
130         err = checkAndUpdateEglStateLocked(st, true);
131         if (err != NO_ERROR) {
132             return err;
133         }
134     }
135 
136     // Update the EGLConsumer state.
137     int buf = st.mCurrentTexture;
138     if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
139         EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode);
140 
141         // if we're detached, we just use the fence that was created in detachFromContext()
142         // so... basically, nothing more to do here.
143         if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
144             // Do whatever sync ops we need to do before releasing the slot.
145             err = syncForReleaseLocked(mEglDisplay, st);
146             if (err != NO_ERROR) {
147                 EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
148                 return err;
149             }
150         }
151 
152         err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer, mEglDisplay,
153                                      EGL_NO_SYNC_KHR);
154         if (err < NO_ERROR) {
155             EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err);
156             return err;
157         }
158 
159         if (mReleasedTexImage == nullptr) {
160             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
161         }
162 
163         st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
164         mCurrentTextureImage = mReleasedTexImage;
165         st.mCurrentCrop.makeInvalid();
166         st.mCurrentTransform = 0;
167         st.mCurrentTimestamp = 0;
168         st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
169         st.mCurrentFence = Fence::NO_FENCE;
170         st.mCurrentFenceTime = FenceTime::NO_FENCE;
171 
172         // detached, don't touch the texture (and we may not even have an
173         // EGLDisplay here.
174         if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
175             // This binds a dummy buffer (mReleasedTexImage).
176             status_t result = bindTextureImageLocked(st);
177             if (result != NO_ERROR) {
178                 return result;
179             }
180         }
181     }
182 
183     return NO_ERROR;
184 }
185 
getDebugTexImageBuffer()186 sp<GraphicBuffer> EGLConsumer::getDebugTexImageBuffer() {
187     Mutex::Autolock _l(sStaticInitLock);
188     if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
189         // The first time, create the debug texture in case the application
190         // continues to use it.
191         sp<GraphicBuffer> buffer = new GraphicBuffer(
192                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
193                 GraphicBuffer::USAGE_SW_WRITE_RARELY, "[EGLConsumer debug texture]");
194         uint32_t* bits;
195         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
196         uint32_t stride = buffer->getStride();
197         uint32_t height = buffer->getHeight();
198         memset(bits, 0, stride * height * 4);
199         for (uint32_t y = 0; y < kDebugData.height; y++) {
200             for (uint32_t x = 0; x < kDebugData.width; x++) {
201                 bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000
202                                                                              : 0xFFFFFFFF;
203             }
204             bits += stride;
205         }
206         buffer->unlock();
207         sReleasedTexImageBuffer = buffer;
208     }
209     return sReleasedTexImageBuffer;
210 }
211 
onAcquireBufferLocked(BufferItem * item,SurfaceTexture & st)212 void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) {
213     // If item->mGraphicBuffer is not null, this buffer has not been acquired
214     // before, so any prior EglImage created is using a stale buffer. This
215     // replaces any old EglImage with a new one (using the new buffer).
216     int slot = item->mSlot;
217     if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) {
218         mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
219     }
220 }
221 
onReleaseBufferLocked(int buf)222 void EGLConsumer::onReleaseBufferLocked(int buf) {
223     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
224 }
225 
updateAndReleaseLocked(const BufferItem & item,PendingRelease * pendingRelease,SurfaceTexture & st)226 status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
227                                              SurfaceTexture& st) {
228     status_t err = NO_ERROR;
229 
230     int slot = item.mSlot;
231 
232     if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) {
233         EGC_LOGE(
234                 "updateAndRelease: EGLConsumer is not attached to an OpenGL "
235                 "ES context");
236         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
237         return INVALID_OPERATION;
238     }
239 
240     // Confirm state.
241     err = checkAndUpdateEglStateLocked(st);
242     if (err != NO_ERROR) {
243         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
244         return err;
245     }
246 
247     // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
248     // if nessessary, for the gralloc buffer currently in the slot in
249     // ConsumerBase.
250     // We may have to do this even when item.mGraphicBuffer == NULL (which
251     // means the buffer was previously acquired).
252     err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
253     if (err != NO_ERROR) {
254         EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
255                  slot);
256         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
257         return UNKNOWN_ERROR;
258     }
259 
260     // Do whatever sync ops we need to do before releasing the old slot.
261     if (slot != st.mCurrentTexture) {
262         err = syncForReleaseLocked(mEglDisplay, st);
263         if (err != NO_ERROR) {
264             // Release the buffer we just acquired.  It's not safe to
265             // release the old buffer, so instead we just drop the new frame.
266             // As we are still under lock since acquireBuffer, it is safe to
267             // release by slot.
268             st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay,
269                                    EGL_NO_SYNC_KHR);
270             return err;
271         }
272     }
273 
274     EGC_LOGV(
275             "updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture,
276             mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : nullptr,
277             slot, st.mSlots[slot].mGraphicBuffer->handle);
278 
279     // Hang onto the pointer so that it isn't freed in the call to
280     // releaseBufferLocked() if we're in shared buffer mode and both buffers are
281     // the same.
282     sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
283 
284     // release old buffer
285     if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
286         if (pendingRelease == nullptr) {
287             status_t status = st.releaseBufferLocked(
288                     st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay,
289                     mEglSlots[st.mCurrentTexture].mEglFence);
290             if (status < NO_ERROR) {
291                 EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
292                          status);
293                 err = status;
294                 // keep going, with error raised [?]
295             }
296         } else {
297             pendingRelease->currentTexture = st.mCurrentTexture;
298             pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
299             pendingRelease->display = mEglDisplay;
300             pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence;
301             pendingRelease->isPending = true;
302         }
303     }
304 
305     // Update the EGLConsumer state.
306     st.mCurrentTexture = slot;
307     mCurrentTextureImage = nextTextureImage;
308     st.mCurrentCrop = item.mCrop;
309     st.mCurrentTransform = item.mTransform;
310     st.mCurrentScalingMode = item.mScalingMode;
311     st.mCurrentTimestamp = item.mTimestamp;
312     st.mCurrentDataSpace = item.mDataSpace;
313     st.mCurrentFence = item.mFence;
314     st.mCurrentFenceTime = item.mFenceTime;
315     st.mCurrentFrameNumber = item.mFrameNumber;
316 
317     st.computeCurrentTransformMatrixLocked();
318 
319     return err;
320 }
321 
bindTextureImageLocked(SurfaceTexture & st)322 status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) {
323     if (mEglDisplay == EGL_NO_DISPLAY) {
324         ALOGE("bindTextureImage: invalid display");
325         return INVALID_OPERATION;
326     }
327 
328     GLenum error;
329     while ((error = glGetError()) != GL_NO_ERROR) {
330         EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
331     }
332 
333     glBindTexture(st.mTexTarget, st.mTexName);
334     if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
335         EGC_LOGE("bindTextureImage: no currently-bound texture");
336         return NO_INIT;
337     }
338 
339     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
340     if (err != NO_ERROR) {
341         EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
342                  st.mCurrentTexture);
343         return UNKNOWN_ERROR;
344     }
345     mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
346 
347     // In the rare case that the display is terminated and then initialized
348     // again, we can't detect that the display changed (it didn't), but the
349     // image is invalid. In this case, repeat the exact same steps while
350     // forcing the creation of a new image.
351     if ((error = glGetError()) != GL_NO_ERROR) {
352         glBindTexture(st.mTexTarget, st.mTexName);
353         status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
354         if (result != NO_ERROR) {
355             EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
356                      st.mCurrentTexture);
357             return UNKNOWN_ERROR;
358         }
359         mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
360         if ((error = glGetError()) != GL_NO_ERROR) {
361             EGC_LOGE("bindTextureImage: error binding external image: %#04x", error);
362             return UNKNOWN_ERROR;
363         }
364     }
365 
366     // Wait for the new buffer to be ready.
367     return doGLFenceWaitLocked(st);
368 }
369 
checkAndUpdateEglStateLocked(SurfaceTexture & st,bool contextCheck)370 status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) {
371     EGLDisplay dpy = eglGetCurrentDisplay();
372     EGLContext ctx = eglGetCurrentContext();
373 
374     if (!contextCheck) {
375         // if this is the first time we're called, mEglDisplay/mEglContext have
376         // never been set, so don't error out (below).
377         if (mEglDisplay == EGL_NO_DISPLAY) {
378             mEglDisplay = dpy;
379         }
380         if (mEglContext == EGL_NO_CONTEXT) {
381             mEglContext = ctx;
382         }
383     }
384 
385     if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
386         EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
387         return INVALID_OPERATION;
388     }
389 
390     if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
391         EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
392         return INVALID_OPERATION;
393     }
394 
395     mEglDisplay = dpy;
396     mEglContext = ctx;
397     return NO_ERROR;
398 }
399 
detachFromContext(SurfaceTexture & st)400 status_t EGLConsumer::detachFromContext(SurfaceTexture& st) {
401     EGLDisplay dpy = eglGetCurrentDisplay();
402     EGLContext ctx = eglGetCurrentContext();
403 
404     if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
405         EGC_LOGE("detachFromContext: invalid current EGLDisplay");
406         return INVALID_OPERATION;
407     }
408 
409     if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
410         EGC_LOGE("detachFromContext: invalid current EGLContext");
411         return INVALID_OPERATION;
412     }
413 
414     if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
415         status_t err = syncForReleaseLocked(dpy, st);
416         if (err != OK) {
417             return err;
418         }
419 
420         glDeleteTextures(1, &st.mTexName);
421     }
422 
423     mEglDisplay = EGL_NO_DISPLAY;
424     mEglContext = EGL_NO_CONTEXT;
425 
426     return OK;
427 }
428 
attachToContext(uint32_t tex,SurfaceTexture & st)429 status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) {
430     // Initialize mCurrentTextureImage if there is a current buffer from past attached state.
431     int slot = st.mCurrentTexture;
432     if (slot != BufferItem::INVALID_BUFFER_SLOT) {
433         if (!mEglSlots[slot].mEglImage.get()) {
434             mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
435         }
436         mCurrentTextureImage = mEglSlots[slot].mEglImage;
437     }
438 
439     EGLDisplay dpy = eglGetCurrentDisplay();
440     EGLContext ctx = eglGetCurrentContext();
441 
442     if (dpy == EGL_NO_DISPLAY) {
443         EGC_LOGE("attachToContext: invalid current EGLDisplay");
444         return INVALID_OPERATION;
445     }
446 
447     if (ctx == EGL_NO_CONTEXT) {
448         EGC_LOGE("attachToContext: invalid current EGLContext");
449         return INVALID_OPERATION;
450     }
451 
452     // We need to bind the texture regardless of whether there's a current
453     // buffer.
454     glBindTexture(st.mTexTarget, GLuint(tex));
455 
456     mEglDisplay = dpy;
457     mEglContext = ctx;
458     st.mTexName = tex;
459     st.mOpMode = SurfaceTexture::OpMode::attachedToGL;
460 
461     if (mCurrentTextureImage != nullptr) {
462         // This may wait for a buffer a second time. This is likely required if
463         // this is a different context, since otherwise the wait could be skipped
464         // by bouncing through another context. For the same context the extra
465         // wait is redundant.
466         status_t err = bindTextureImageLocked(st);
467         if (err != NO_ERROR) {
468             return err;
469         }
470     }
471 
472     return OK;
473 }
474 
syncForReleaseLocked(EGLDisplay dpy,SurfaceTexture & st)475 status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) {
476     EGC_LOGV("syncForReleaseLocked");
477 
478     if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
479         if (SyncFeatures::getInstance().useNativeFenceSync()) {
480             EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
481             if (sync == EGL_NO_SYNC_KHR) {
482                 EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
483                 return UNKNOWN_ERROR;
484             }
485             glFlush();
486             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
487             eglDestroySyncKHR(dpy, sync);
488             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
489                 EGC_LOGE(
490                         "syncForReleaseLocked: error dup'ing native fence "
491                         "fd: %#x",
492                         eglGetError());
493                 return UNKNOWN_ERROR;
494             }
495             sp<Fence> fence(new Fence(fenceFd));
496             status_t err = st.addReleaseFenceLocked(st.mCurrentTexture,
497                                                     mCurrentTextureImage->graphicBuffer(), fence);
498             if (err != OK) {
499                 EGC_LOGE(
500                         "syncForReleaseLocked: error adding release fence: "
501                         "%s (%d)",
502                         strerror(-err), err);
503                 return err;
504             }
505         } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
506             EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence;
507             if (fence != EGL_NO_SYNC_KHR) {
508                 // There is already a fence for the current slot.  We need to
509                 // wait on that before replacing it with another fence to
510                 // ensure that all outstanding buffer accesses have completed
511                 // before the producer accesses it.
512                 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
513                 if (result == EGL_FALSE) {
514                     EGC_LOGE(
515                             "syncForReleaseLocked: error waiting for previous "
516                             "fence: %#x",
517                             eglGetError());
518                     return UNKNOWN_ERROR;
519                 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
520                     EGC_LOGE(
521                             "syncForReleaseLocked: timeout waiting for previous "
522                             "fence");
523                     return TIMED_OUT;
524                 }
525                 eglDestroySyncKHR(dpy, fence);
526             }
527 
528             // Create a fence for the outstanding accesses in the current
529             // OpenGL ES context.
530             fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
531             if (fence == EGL_NO_SYNC_KHR) {
532                 EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
533                 return UNKNOWN_ERROR;
534             }
535             glFlush();
536             mEglSlots[st.mCurrentTexture].mEglFence = fence;
537         }
538     }
539 
540     return OK;
541 }
542 
doGLFenceWaitLocked(SurfaceTexture & st) const543 status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const {
544     EGLDisplay dpy = eglGetCurrentDisplay();
545     EGLContext ctx = eglGetCurrentContext();
546 
547     if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
548         EGC_LOGE("doGLFenceWait: invalid current EGLDisplay");
549         return INVALID_OPERATION;
550     }
551 
552     if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
553         EGC_LOGE("doGLFenceWait: invalid current EGLContext");
554         return INVALID_OPERATION;
555     }
556 
557     if (st.mCurrentFence->isValid()) {
558         if (SyncFeatures::getInstance().useWaitSync() &&
559             SyncFeatures::getInstance().useNativeFenceSync()) {
560             // Create an EGLSyncKHR from the current fence.
561             int fenceFd = st.mCurrentFence->dup();
562             if (fenceFd == -1) {
563                 EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
564                 return -errno;
565             }
566             EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
567             EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
568             if (sync == EGL_NO_SYNC_KHR) {
569                 close(fenceFd);
570                 EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
571                 return UNKNOWN_ERROR;
572             }
573 
574             // XXX: The spec draft is inconsistent as to whether this should
575             // return an EGLint or void.  Ignore the return value for now, as
576             // it's not strictly needed.
577             eglWaitSyncKHR(dpy, sync, 0);
578             EGLint eglErr = eglGetError();
579             eglDestroySyncKHR(dpy, sync);
580             if (eglErr != EGL_SUCCESS) {
581                 EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
582                 return UNKNOWN_ERROR;
583             }
584         } else {
585             status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked");
586             if (err != NO_ERROR) {
587                 EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
588                 return err;
589             }
590         }
591     }
592 
593     return NO_ERROR;
594 }
595 
onFreeBufferLocked(int slotIndex)596 void EGLConsumer::onFreeBufferLocked(int slotIndex) {
597     mEglSlots[slotIndex].mEglImage.clear();
598 }
599 
onAbandonLocked()600 void EGLConsumer::onAbandonLocked() {
601     mCurrentTextureImage.clear();
602 }
603 
EglImage(sp<GraphicBuffer> graphicBuffer)604 EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
605         : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {}
606 
~EglImage()607 EGLConsumer::EglImage::~EglImage() {
608     if (mEglImage != EGL_NO_IMAGE_KHR) {
609         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
610             ALOGE("~EglImage: eglDestroyImageKHR failed");
611         }
612         eglTerminate(mEglDisplay);
613     }
614 }
615 
createIfNeeded(EGLDisplay eglDisplay,bool forceCreation)616 status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) {
617     // If there's an image and it's no longer valid, destroy it.
618     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
619     bool displayInvalid = mEglDisplay != eglDisplay;
620     if (haveImage && (displayInvalid || forceCreation)) {
621         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
622             ALOGE("createIfNeeded: eglDestroyImageKHR failed");
623         }
624         eglTerminate(mEglDisplay);
625         mEglImage = EGL_NO_IMAGE_KHR;
626         mEglDisplay = EGL_NO_DISPLAY;
627     }
628 
629     // If there's no image, create one.
630     if (mEglImage == EGL_NO_IMAGE_KHR) {
631         mEglDisplay = eglDisplay;
632         mEglImage = createImage(mEglDisplay, mGraphicBuffer);
633     }
634 
635     // Fail if we can't create a valid image.
636     if (mEglImage == EGL_NO_IMAGE_KHR) {
637         mEglDisplay = EGL_NO_DISPLAY;
638         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
639         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
640               buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
641               buffer->getPixelFormat());
642         return UNKNOWN_ERROR;
643     }
644 
645     return OK;
646 }
647 
bindToTextureTarget(uint32_t texTarget)648 void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
649     glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
650 }
651 
createImage(EGLDisplay dpy,const sp<GraphicBuffer> & graphicBuffer)652 EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy,
653                                                const sp<GraphicBuffer>& graphicBuffer) {
654     EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
655     const bool createProtectedImage =
656             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
657     EGLint attrs[] = {
658             EGL_IMAGE_PRESERVED_KHR,
659             EGL_TRUE,
660             createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
661             createProtectedImage ? EGL_TRUE : EGL_NONE,
662             EGL_NONE,
663     };
664     eglInitialize(dpy, nullptr, nullptr);
665     EGLImageKHR image =
666             eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
667     if (image == EGL_NO_IMAGE_KHR) {
668         EGLint error = eglGetError();
669         ALOGE("error creating EGLImage: %#x", error);
670         eglTerminate(dpy);
671     }
672     return image;
673 }
674 
675 }  // namespace android
676