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