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 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 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 85 EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {} 86 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 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 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 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 222 void EGLConsumer::onReleaseBufferLocked(int buf) { 223 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; 224 } 225 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 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 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 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 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 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 543 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 596 void EGLConsumer::onFreeBufferLocked(int slotIndex) { 597 mEglSlots[slotIndex].mEglImage.clear(); 598 } 599 600 void EGLConsumer::onAbandonLocked() { 601 mCurrentTextureImage.clear(); 602 } 603 604 EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) 605 : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {} 606 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 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 648 void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { 649 glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage)); 650 } 651 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