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