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