GLConsumer.cpp revision 1834f8ea975e9a882b44dc479320fe02e306e630
1/* 2 * Copyright (C) 2010 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 LOG_TAG "GLConsumer" 18#define ATRACE_TAG ATRACE_TAG_GRAPHICS 19//#define LOG_NDEBUG 0 20 21#define GL_GLEXT_PROTOTYPES 22#define EGL_EGLEXT_PROTOTYPES 23 24#include <EGL/egl.h> 25#include <EGL/eglext.h> 26#include <GLES2/gl2.h> 27#include <GLES2/gl2ext.h> 28#include <cutils/compiler.h> 29 30#include <hardware/hardware.h> 31 32#include <gui/GLConsumer.h> 33#include <gui/IGraphicBufferAlloc.h> 34#include <gui/ISurfaceComposer.h> 35#include <gui/SurfaceComposerClient.h> 36 37#include <private/gui/ComposerService.h> 38#include <private/gui/SyncFeatures.h> 39 40#include <utils/Log.h> 41#include <utils/String8.h> 42#include <utils/Trace.h> 43 44EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); 45#define CROP_EXT_STR "EGL_ANDROID_image_crop" 46 47namespace android { 48 49// Macros for including the GLConsumer name in log messages 50#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) 51#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) 52#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) 53#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) 54#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) 55 56static const struct { 57 size_t width, height; 58 char const* bits; 59} kDebugData = { 15, 12, 60 "___________________________________XX_XX_______X_X_____X_X____X_XXXXXXX_X____XXXXXXXXXXX__" 61 "___XX_XXX_XX_______XXXXXXX_________X___X_________X_____X__________________________________" 62}; 63 64// Transform matrices 65static float mtxIdentity[16] = { 66 1, 0, 0, 0, 67 0, 1, 0, 0, 68 0, 0, 1, 0, 69 0, 0, 0, 1, 70}; 71static float mtxFlipH[16] = { 72 -1, 0, 0, 0, 73 0, 1, 0, 0, 74 0, 0, 1, 0, 75 1, 0, 0, 1, 76}; 77static float mtxFlipV[16] = { 78 1, 0, 0, 0, 79 0, -1, 0, 0, 80 0, 0, 1, 0, 81 0, 1, 0, 1, 82}; 83static float mtxRot90[16] = { 84 0, 1, 0, 0, 85 -1, 0, 0, 0, 86 0, 0, 1, 0, 87 1, 0, 0, 1, 88}; 89 90static void mtxMul(float out[16], const float a[16], const float b[16]); 91 92Mutex GLConsumer::sStaticInitLock; 93sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer; 94 95static bool hasEglAndroidImageCropImpl() { 96 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 97 const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); 98 size_t cropExtLen = strlen(CROP_EXT_STR); 99 size_t extsLen = strlen(exts); 100 bool equal = !strcmp(CROP_EXT_STR, exts); 101 bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1); 102 bool atEnd = (cropExtLen+1) < extsLen && 103 !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1)); 104 bool inMiddle = strstr(exts, " " CROP_EXT_STR " "); 105 return equal || atStart || atEnd || inMiddle; 106} 107 108static bool hasEglAndroidImageCrop() { 109 // Only compute whether the extension is present once the first time this 110 // function is called. 111 static bool hasIt = hasEglAndroidImageCropImpl(); 112 return hasIt; 113} 114 115static bool isEglImageCroppable(const Rect& crop) { 116 return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0); 117} 118 119GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, 120 uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : 121 ConsumerBase(bq, isControlledByApp), 122 mCurrentTransform(0), 123 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), 124 mCurrentFence(Fence::NO_FENCE), 125 mCurrentTimestamp(0), 126 mCurrentFrameNumber(0), 127 mDefaultWidth(1), 128 mDefaultHeight(1), 129 mFilteringEnabled(true), 130 mTexName(tex), 131 mUseFenceSync(useFenceSync), 132 mTexTarget(texTarget), 133 mEglDisplay(EGL_NO_DISPLAY), 134 mEglContext(EGL_NO_CONTEXT), 135 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), 136 mAttached(true) 137{ 138 ST_LOGV("GLConsumer"); 139 140 memcpy(mCurrentTransformMatrix, mtxIdentity, 141 sizeof(mCurrentTransformMatrix)); 142 143 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); 144} 145 146GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, 147 bool useFenceSync, bool isControlledByApp) : 148 ConsumerBase(bq, isControlledByApp), 149 mCurrentTransform(0), 150 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), 151 mCurrentFence(Fence::NO_FENCE), 152 mCurrentTimestamp(0), 153 mCurrentFrameNumber(0), 154 mDefaultWidth(1), 155 mDefaultHeight(1), 156 mFilteringEnabled(true), 157 mTexName(-1), 158 mUseFenceSync(useFenceSync), 159 mTexTarget(texTarget), 160 mEglDisplay(EGL_NO_DISPLAY), 161 mEglContext(EGL_NO_CONTEXT), 162 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), 163 mAttached(false) 164{ 165 ST_LOGV("GLConsumer"); 166 167 memcpy(mCurrentTransformMatrix, mtxIdentity, 168 sizeof(mCurrentTransformMatrix)); 169 170 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); 171} 172 173status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) { 174 Mutex::Autolock lock(mMutex); 175 return mConsumer->setDefaultMaxBufferCount(bufferCount); 176} 177 178 179status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) 180{ 181 Mutex::Autolock lock(mMutex); 182 mDefaultWidth = w; 183 mDefaultHeight = h; 184 return mConsumer->setDefaultBufferSize(w, h); 185} 186 187status_t GLConsumer::updateTexImage() { 188 ATRACE_CALL(); 189 ST_LOGV("updateTexImage"); 190 Mutex::Autolock lock(mMutex); 191 192 if (mAbandoned) { 193 ST_LOGE("updateTexImage: GLConsumer is abandoned!"); 194 return NO_INIT; 195 } 196 197 // Make sure the EGL state is the same as in previous calls. 198 status_t err = checkAndUpdateEglStateLocked(); 199 if (err != NO_ERROR) { 200 return err; 201 } 202 203 BufferQueue::BufferItem item; 204 205 // Acquire the next buffer. 206 // In asynchronous mode the list is guaranteed to be one buffer 207 // deep, while in synchronous mode we use the oldest buffer. 208 err = acquireBufferLocked(&item, 0); 209 if (err != NO_ERROR) { 210 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 211 // We always bind the texture even if we don't update its contents. 212 ST_LOGV("updateTexImage: no buffers were available"); 213 glBindTexture(mTexTarget, mTexName); 214 err = NO_ERROR; 215 } else { 216 ST_LOGE("updateTexImage: acquire failed: %s (%d)", 217 strerror(-err), err); 218 } 219 return err; 220 } 221 222 // Release the previous buffer. 223 err = updateAndReleaseLocked(item); 224 if (err != NO_ERROR) { 225 // We always bind the texture. 226 glBindTexture(mTexTarget, mTexName); 227 return err; 228 } 229 230 // Bind the new buffer to the GL texture, and wait until it's ready. 231 return bindTextureImageLocked(); 232} 233 234 235status_t GLConsumer::releaseTexImage() { 236 ATRACE_CALL(); 237 ST_LOGV("releaseTexImage"); 238 Mutex::Autolock lock(mMutex); 239 240 if (mAbandoned) { 241 ST_LOGE("releaseTexImage: GLConsumer is abandoned!"); 242 return NO_INIT; 243 } 244 245 // Make sure the EGL state is the same as in previous calls. 246 status_t err = NO_ERROR; 247 248 if (mAttached) { 249 err = checkAndUpdateEglStateLocked(true); 250 if (err != NO_ERROR) { 251 return err; 252 } 253 } else { 254 // if we're detached, no need to validate EGL's state -- we won't use it. 255 } 256 257 // Update the GLConsumer state. 258 int buf = mCurrentTexture; 259 if (buf != BufferQueue::INVALID_BUFFER_SLOT) { 260 261 ST_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached); 262 263 if (mAttached) { 264 // Do whatever sync ops we need to do before releasing the slot. 265 err = syncForReleaseLocked(mEglDisplay); 266 if (err != NO_ERROR) { 267 ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); 268 return err; 269 } 270 } else { 271 // if we're detached, we just use the fence that was created in detachFromContext() 272 // so... basically, nothing more to do here. 273 } 274 275 err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); 276 if (err < NO_ERROR) { 277 ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)", 278 strerror(-err), err); 279 return err; 280 } 281 282 if (mReleasedTexImage == NULL) { 283 mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); 284 } 285 286 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; 287 mCurrentTextureImage = mReleasedTexImage; 288 mCurrentCrop.makeInvalid(); 289 mCurrentTransform = 0; 290 mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; 291 mCurrentTimestamp = 0; 292 mCurrentFence = Fence::NO_FENCE; 293 294 if (mAttached) { 295 // This binds a dummy buffer (mReleasedTexImage). 296 status_t err = bindTextureImageLocked(); 297 if (err != NO_ERROR) { 298 return err; 299 } 300 } else { 301 // detached, don't touch the texture (and we may not even have an 302 // EGLDisplay here. 303 } 304 } 305 306 return NO_ERROR; 307} 308 309sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { 310 Mutex::Autolock _l(sStaticInitLock); 311 if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) { 312 // The first time, create the debug texture in case the application 313 // continues to use it. 314 sp<GraphicBuffer> buffer = new GraphicBuffer( 315 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888, 316 GraphicBuffer::USAGE_SW_WRITE_RARELY); 317 uint32_t* bits; 318 buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits)); 319 size_t w = buffer->getStride(); 320 size_t h = buffer->getHeight(); 321 memset(bits, 0, w*h*4); 322 for (size_t y=0 ; y<kDebugData.height ; y++) { 323 for (size_t x=0 ; x<kDebugData.width ; x++) { 324 bits[x] = (kDebugData.bits[y*kDebugData.width+x] == 'X') ? 0xFF000000 : 0xFFFFFFFF; 325 } 326 bits += w; 327 } 328 buffer->unlock(); 329 sReleasedTexImageBuffer = buffer; 330 } 331 return sReleasedTexImageBuffer; 332} 333 334status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, 335 nsecs_t presentWhen) { 336 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); 337 if (err != NO_ERROR) { 338 return err; 339 } 340 341 // If item->mGraphicBuffer is not null, this buffer has not been acquired 342 // before, so any prior EglImage created is using a stale buffer. This 343 // replaces any old EglImage with a new one (using the new buffer). 344 if (item->mGraphicBuffer != NULL) { 345 int slot = item->mBuf; 346 mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer); 347 } 348 349 return NO_ERROR; 350} 351 352status_t GLConsumer::releaseBufferLocked(int buf, 353 sp<GraphicBuffer> graphicBuffer, 354 EGLDisplay display, EGLSyncKHR eglFence) { 355 // release the buffer if it hasn't already been discarded by the 356 // BufferQueue. This can happen, for example, when the producer of this 357 // buffer has reallocated the original buffer slot after this buffer 358 // was acquired. 359 status_t err = ConsumerBase::releaseBufferLocked( 360 buf, graphicBuffer, display, eglFence); 361 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; 362 return err; 363} 364 365status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) 366{ 367 status_t err = NO_ERROR; 368 369 int buf = item.mBuf; 370 371 if (!mAttached) { 372 ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " 373 "ES context"); 374 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, 375 mEglDisplay, EGL_NO_SYNC_KHR); 376 return INVALID_OPERATION; 377 } 378 379 // Confirm state. 380 err = checkAndUpdateEglStateLocked(); 381 if (err != NO_ERROR) { 382 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, 383 mEglDisplay, EGL_NO_SYNC_KHR); 384 return err; 385 } 386 387 // Ensure we have a valid EglImageKHR for the slot, creating an EglImage 388 // if nessessary, for the gralloc buffer currently in the slot in 389 // ConsumerBase. 390 // We may have to do this even when item.mGraphicBuffer == NULL (which 391 // means the buffer was previously acquired). 392 err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop); 393 if (err != NO_ERROR) { 394 ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", 395 mEglDisplay, buf); 396 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, 397 mEglDisplay, EGL_NO_SYNC_KHR); 398 return UNKNOWN_ERROR; 399 } 400 401 // Do whatever sync ops we need to do before releasing the old slot. 402 err = syncForReleaseLocked(mEglDisplay); 403 if (err != NO_ERROR) { 404 // Release the buffer we just acquired. It's not safe to 405 // release the old buffer, so instead we just drop the new frame. 406 // As we are still under lock since acquireBuffer, it is safe to 407 // release by slot. 408 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, 409 mEglDisplay, EGL_NO_SYNC_KHR); 410 return err; 411 } 412 413 ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", 414 mCurrentTexture, mCurrentTextureImage != NULL ? 415 mCurrentTextureImage->graphicBufferHandle() : 0, 416 buf, mSlots[buf].mGraphicBuffer->handle); 417 418 // release old buffer 419 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { 420 status_t status = releaseBufferLocked( 421 mCurrentTexture, mCurrentTextureImage->graphicBuffer(), 422 mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); 423 if (status < NO_ERROR) { 424 ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)", 425 strerror(-status), status); 426 err = status; 427 // keep going, with error raised [?] 428 } 429 } 430 431 // Update the GLConsumer state. 432 mCurrentTexture = buf; 433 mCurrentTextureImage = mEglSlots[buf].mEglImage; 434 mCurrentCrop = item.mCrop; 435 mCurrentTransform = item.mTransform; 436 mCurrentScalingMode = item.mScalingMode; 437 mCurrentTimestamp = item.mTimestamp; 438 mCurrentFence = item.mFence; 439 mCurrentFrameNumber = item.mFrameNumber; 440 441 computeCurrentTransformMatrixLocked(); 442 443 return err; 444} 445 446status_t GLConsumer::bindTextureImageLocked() { 447 if (mEglDisplay == EGL_NO_DISPLAY) { 448 ALOGE("bindTextureImage: invalid display"); 449 return INVALID_OPERATION; 450 } 451 452 GLint error; 453 while ((error = glGetError()) != GL_NO_ERROR) { 454 ST_LOGW("bindTextureImage: clearing GL error: %#04x", error); 455 } 456 457 glBindTexture(mTexTarget, mTexName); 458 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && 459 mCurrentTextureImage == NULL) { 460 ST_LOGE("bindTextureImage: no currently-bound texture"); 461 return NO_INIT; 462 } 463 464 status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, 465 mCurrentCrop); 466 if (err != NO_ERROR) { 467 ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", 468 mEglDisplay, mCurrentTexture); 469 return UNKNOWN_ERROR; 470 } 471 mCurrentTextureImage->bindToTextureTarget(mTexTarget); 472 473 // In the rare case that the display is terminated and then initialized 474 // again, we can't detect that the display changed (it didn't), but the 475 // image is invalid. In this case, repeat the exact same steps while 476 // forcing the creation of a new image. 477 if ((error = glGetError()) != GL_NO_ERROR) { 478 glBindTexture(mTexTarget, mTexName); 479 status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, 480 mCurrentCrop, 481 true); 482 if (err != NO_ERROR) { 483 ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", 484 mEglDisplay, mCurrentTexture); 485 return UNKNOWN_ERROR; 486 } 487 mCurrentTextureImage->bindToTextureTarget(mTexTarget); 488 if ((error = glGetError()) != GL_NO_ERROR) { 489 ST_LOGE("bindTextureImage: error binding external image: %#04x", error); 490 return UNKNOWN_ERROR; 491 } 492 } 493 494 // Wait for the new buffer to be ready. 495 return doGLFenceWaitLocked(); 496} 497 498status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) { 499 EGLDisplay dpy = eglGetCurrentDisplay(); 500 EGLContext ctx = eglGetCurrentContext(); 501 502 if (!contextCheck) { 503 // if this is the first time we're called, mEglDisplay/mEglContext have 504 // never been set, so don't error out (below). 505 if (mEglDisplay == EGL_NO_DISPLAY) { 506 mEglDisplay = dpy; 507 } 508 if (mEglContext == EGL_NO_CONTEXT) { 509 mEglContext = ctx; 510 } 511 } 512 513 if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) { 514 ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); 515 return INVALID_OPERATION; 516 } 517 518 if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) { 519 ST_LOGE("checkAndUpdateEglState: invalid current EGLContext"); 520 return INVALID_OPERATION; 521 } 522 523 mEglDisplay = dpy; 524 mEglContext = ctx; 525 return NO_ERROR; 526} 527 528void GLConsumer::setReleaseFence(const sp<Fence>& fence) { 529 if (fence->isValid() && 530 mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { 531 status_t err = addReleaseFence(mCurrentTexture, 532 mCurrentTextureImage->graphicBuffer(), fence); 533 if (err != OK) { 534 ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)", 535 strerror(-err), err); 536 } 537 } 538} 539 540status_t GLConsumer::detachFromContext() { 541 ATRACE_CALL(); 542 ST_LOGV("detachFromContext"); 543 Mutex::Autolock lock(mMutex); 544 545 if (mAbandoned) { 546 ST_LOGE("detachFromContext: abandoned GLConsumer"); 547 return NO_INIT; 548 } 549 550 if (!mAttached) { 551 ST_LOGE("detachFromContext: GLConsumer is not attached to a " 552 "context"); 553 return INVALID_OPERATION; 554 } 555 556 EGLDisplay dpy = eglGetCurrentDisplay(); 557 EGLContext ctx = eglGetCurrentContext(); 558 559 if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { 560 ST_LOGE("detachFromContext: invalid current EGLDisplay"); 561 return INVALID_OPERATION; 562 } 563 564 if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { 565 ST_LOGE("detachFromContext: invalid current EGLContext"); 566 return INVALID_OPERATION; 567 } 568 569 if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) { 570 status_t err = syncForReleaseLocked(dpy); 571 if (err != OK) { 572 return err; 573 } 574 575 glDeleteTextures(1, &mTexName); 576 } 577 578 mEglDisplay = EGL_NO_DISPLAY; 579 mEglContext = EGL_NO_CONTEXT; 580 mAttached = false; 581 582 return OK; 583} 584 585status_t GLConsumer::attachToContext(uint32_t tex) { 586 ATRACE_CALL(); 587 ST_LOGV("attachToContext"); 588 Mutex::Autolock lock(mMutex); 589 590 if (mAbandoned) { 591 ST_LOGE("attachToContext: abandoned GLConsumer"); 592 return NO_INIT; 593 } 594 595 if (mAttached) { 596 ST_LOGE("attachToContext: GLConsumer is already attached to a " 597 "context"); 598 return INVALID_OPERATION; 599 } 600 601 EGLDisplay dpy = eglGetCurrentDisplay(); 602 EGLContext ctx = eglGetCurrentContext(); 603 604 if (dpy == EGL_NO_DISPLAY) { 605 ST_LOGE("attachToContext: invalid current EGLDisplay"); 606 return INVALID_OPERATION; 607 } 608 609 if (ctx == EGL_NO_CONTEXT) { 610 ST_LOGE("attachToContext: invalid current EGLContext"); 611 return INVALID_OPERATION; 612 } 613 614 // We need to bind the texture regardless of whether there's a current 615 // buffer. 616 glBindTexture(mTexTarget, GLuint(tex)); 617 618 mEglDisplay = dpy; 619 mEglContext = ctx; 620 mTexName = tex; 621 mAttached = true; 622 623 if (mCurrentTextureImage != NULL) { 624 // This may wait for a buffer a second time. This is likely required if 625 // this is a different context, since otherwise the wait could be skipped 626 // by bouncing through another context. For the same context the extra 627 // wait is redundant. 628 status_t err = bindTextureImageLocked(); 629 if (err != NO_ERROR) { 630 return err; 631 } 632 } 633 634 return OK; 635} 636 637 638status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { 639 ST_LOGV("syncForReleaseLocked"); 640 641 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { 642 if (SyncFeatures::getInstance().useNativeFenceSync()) { 643 EGLSyncKHR sync = eglCreateSyncKHR(dpy, 644 EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); 645 if (sync == EGL_NO_SYNC_KHR) { 646 ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", 647 eglGetError()); 648 return UNKNOWN_ERROR; 649 } 650 glFlush(); 651 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); 652 eglDestroySyncKHR(dpy, sync); 653 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { 654 ST_LOGE("syncForReleaseLocked: error dup'ing native fence " 655 "fd: %#x", eglGetError()); 656 return UNKNOWN_ERROR; 657 } 658 sp<Fence> fence(new Fence(fenceFd)); 659 status_t err = addReleaseFenceLocked(mCurrentTexture, 660 mCurrentTextureImage->graphicBuffer(), fence); 661 if (err != OK) { 662 ST_LOGE("syncForReleaseLocked: error adding release fence: " 663 "%s (%d)", strerror(-err), err); 664 return err; 665 } 666 } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { 667 EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence; 668 if (fence != EGL_NO_SYNC_KHR) { 669 // There is already a fence for the current slot. We need to 670 // wait on that before replacing it with another fence to 671 // ensure that all outstanding buffer accesses have completed 672 // before the producer accesses it. 673 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); 674 if (result == EGL_FALSE) { 675 ST_LOGE("syncForReleaseLocked: error waiting for previous " 676 "fence: %#x", eglGetError()); 677 return UNKNOWN_ERROR; 678 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { 679 ST_LOGE("syncForReleaseLocked: timeout waiting for previous " 680 "fence"); 681 return TIMED_OUT; 682 } 683 eglDestroySyncKHR(dpy, fence); 684 } 685 686 // Create a fence for the outstanding accesses in the current 687 // OpenGL ES context. 688 fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); 689 if (fence == EGL_NO_SYNC_KHR) { 690 ST_LOGE("syncForReleaseLocked: error creating fence: %#x", 691 eglGetError()); 692 return UNKNOWN_ERROR; 693 } 694 glFlush(); 695 mEglSlots[mCurrentTexture].mEglFence = fence; 696 } 697 } 698 699 return OK; 700} 701 702bool GLConsumer::isExternalFormat(uint32_t format) 703{ 704 switch (format) { 705 // supported YUV formats 706 case HAL_PIXEL_FORMAT_YV12: 707 // Legacy/deprecated YUV formats 708 case HAL_PIXEL_FORMAT_YCbCr_422_SP: 709 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 710 case HAL_PIXEL_FORMAT_YCbCr_422_I: 711 return true; 712 } 713 714 // Any OEM format needs to be considered 715 if (format>=0x100 && format<=0x1FF) 716 return true; 717 718 return false; 719} 720 721uint32_t GLConsumer::getCurrentTextureTarget() const { 722 return mTexTarget; 723} 724 725void GLConsumer::getTransformMatrix(float mtx[16]) { 726 Mutex::Autolock lock(mMutex); 727 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); 728} 729 730void GLConsumer::setFilteringEnabled(bool enabled) { 731 Mutex::Autolock lock(mMutex); 732 if (mAbandoned) { 733 ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); 734 return; 735 } 736 bool needsRecompute = mFilteringEnabled != enabled; 737 mFilteringEnabled = enabled; 738 739 if (needsRecompute && mCurrentTextureImage==NULL) { 740 ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); 741 } 742 743 if (needsRecompute && mCurrentTextureImage != NULL) { 744 computeCurrentTransformMatrixLocked(); 745 } 746} 747 748void GLConsumer::computeCurrentTransformMatrixLocked() { 749 ST_LOGV("computeCurrentTransformMatrixLocked"); 750 751 float xform[16]; 752 for (int i = 0; i < 16; i++) { 753 xform[i] = mtxIdentity[i]; 754 } 755 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { 756 float result[16]; 757 mtxMul(result, xform, mtxFlipH); 758 for (int i = 0; i < 16; i++) { 759 xform[i] = result[i]; 760 } 761 } 762 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { 763 float result[16]; 764 mtxMul(result, xform, mtxFlipV); 765 for (int i = 0; i < 16; i++) { 766 xform[i] = result[i]; 767 } 768 } 769 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { 770 float result[16]; 771 mtxMul(result, xform, mtxRot90); 772 for (int i = 0; i < 16; i++) { 773 xform[i] = result[i]; 774 } 775 } 776 777 sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ? 778 NULL : mCurrentTextureImage->graphicBuffer(); 779 780 if (buf == NULL) { 781 ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL"); 782 } 783 784 float mtxBeforeFlipV[16]; 785 if (!isEglImageCroppable(mCurrentCrop)) { 786 Rect cropRect = mCurrentCrop; 787 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; 788 float bufferWidth = buf->getWidth(); 789 float bufferHeight = buf->getHeight(); 790 if (!cropRect.isEmpty()) { 791 float shrinkAmount = 0.0f; 792 if (mFilteringEnabled) { 793 // In order to prevent bilinear sampling beyond the edge of the 794 // crop rectangle we may need to shrink it by 2 texels in each 795 // dimension. Normally this would just need to take 1/2 a texel 796 // off each end, but because the chroma channels of YUV420 images 797 // are subsampled we may need to shrink the crop region by a whole 798 // texel on each side. 799 switch (buf->getPixelFormat()) { 800 case PIXEL_FORMAT_RGBA_8888: 801 case PIXEL_FORMAT_RGBX_8888: 802 case PIXEL_FORMAT_RGB_888: 803 case PIXEL_FORMAT_RGB_565: 804 case PIXEL_FORMAT_BGRA_8888: 805 // We know there's no subsampling of any channels, so we 806 // only need to shrink by a half a pixel. 807 shrinkAmount = 0.5; 808 break; 809 810 default: 811 // If we don't recognize the format, we must assume the 812 // worst case (that we care about), which is YUV420. 813 shrinkAmount = 1.0; 814 break; 815 } 816 } 817 818 // Only shrink the dimensions that are not the size of the buffer. 819 if (cropRect.width() < bufferWidth) { 820 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; 821 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / 822 bufferWidth; 823 } 824 if (cropRect.height() < bufferHeight) { 825 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / 826 bufferHeight; 827 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / 828 bufferHeight; 829 } 830 } 831 float crop[16] = { 832 sx, 0, 0, 0, 833 0, sy, 0, 0, 834 0, 0, 1, 0, 835 tx, ty, 0, 1, 836 }; 837 838 mtxMul(mtxBeforeFlipV, crop, xform); 839 } else { 840 for (int i = 0; i < 16; i++) { 841 mtxBeforeFlipV[i] = xform[i]; 842 } 843 } 844 845 // SurfaceFlinger expects the top of its window textures to be at a Y 846 // coordinate of 0, so GLConsumer must behave the same way. We don't 847 // want to expose this to applications, however, so we must add an 848 // additional vertical flip to the transform after all the other transforms. 849 mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV); 850} 851 852nsecs_t GLConsumer::getTimestamp() { 853 ST_LOGV("getTimestamp"); 854 Mutex::Autolock lock(mMutex); 855 return mCurrentTimestamp; 856} 857 858nsecs_t GLConsumer::getFrameNumber() { 859 ST_LOGV("getFrameNumber"); 860 Mutex::Autolock lock(mMutex); 861 return mCurrentFrameNumber; 862} 863 864sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const { 865 Mutex::Autolock lock(mMutex); 866 return (mCurrentTextureImage == NULL) ? 867 NULL : mCurrentTextureImage->graphicBuffer(); 868} 869 870Rect GLConsumer::getCurrentCrop() const { 871 Mutex::Autolock lock(mMutex); 872 873 Rect outCrop = mCurrentCrop; 874 if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 875 int32_t newWidth = mCurrentCrop.width(); 876 int32_t newHeight = mCurrentCrop.height(); 877 878 if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { 879 newWidth = newHeight * mDefaultWidth / mDefaultHeight; 880 ST_LOGV("too wide: newWidth = %d", newWidth); 881 } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { 882 newHeight = newWidth * mDefaultHeight / mDefaultWidth; 883 ST_LOGV("too tall: newHeight = %d", newHeight); 884 } 885 886 // The crop is too wide 887 if (newWidth < mCurrentCrop.width()) { 888 int32_t dw = (newWidth - mCurrentCrop.width())/2; 889 outCrop.left -=dw; 890 outCrop.right += dw; 891 // The crop is too tall 892 } else if (newHeight < mCurrentCrop.height()) { 893 int32_t dh = (newHeight - mCurrentCrop.height())/2; 894 outCrop.top -= dh; 895 outCrop.bottom += dh; 896 } 897 898 ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", 899 outCrop.left, outCrop.top, 900 outCrop.right,outCrop.bottom); 901 } 902 903 return outCrop; 904} 905 906uint32_t GLConsumer::getCurrentTransform() const { 907 Mutex::Autolock lock(mMutex); 908 return mCurrentTransform; 909} 910 911uint32_t GLConsumer::getCurrentScalingMode() const { 912 Mutex::Autolock lock(mMutex); 913 return mCurrentScalingMode; 914} 915 916sp<Fence> GLConsumer::getCurrentFence() const { 917 Mutex::Autolock lock(mMutex); 918 return mCurrentFence; 919} 920 921status_t GLConsumer::doGLFenceWait() const { 922 Mutex::Autolock lock(mMutex); 923 return doGLFenceWaitLocked(); 924} 925 926status_t GLConsumer::doGLFenceWaitLocked() const { 927 928 EGLDisplay dpy = eglGetCurrentDisplay(); 929 EGLContext ctx = eglGetCurrentContext(); 930 931 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) { 932 ST_LOGE("doGLFenceWait: invalid current EGLDisplay"); 933 return INVALID_OPERATION; 934 } 935 936 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) { 937 ST_LOGE("doGLFenceWait: invalid current EGLContext"); 938 return INVALID_OPERATION; 939 } 940 941 if (mCurrentFence->isValid()) { 942 if (SyncFeatures::getInstance().useWaitSync()) { 943 // Create an EGLSyncKHR from the current fence. 944 int fenceFd = mCurrentFence->dup(); 945 if (fenceFd == -1) { 946 ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); 947 return -errno; 948 } 949 EGLint attribs[] = { 950 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, 951 EGL_NONE 952 }; 953 EGLSyncKHR sync = eglCreateSyncKHR(dpy, 954 EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); 955 if (sync == EGL_NO_SYNC_KHR) { 956 close(fenceFd); 957 ST_LOGE("doGLFenceWait: error creating EGL fence: %#x", 958 eglGetError()); 959 return UNKNOWN_ERROR; 960 } 961 962 // XXX: The spec draft is inconsistent as to whether this should 963 // return an EGLint or void. Ignore the return value for now, as 964 // it's not strictly needed. 965 eglWaitSyncKHR(dpy, sync, 0); 966 EGLint eglErr = eglGetError(); 967 eglDestroySyncKHR(dpy, sync); 968 if (eglErr != EGL_SUCCESS) { 969 ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", 970 eglErr); 971 return UNKNOWN_ERROR; 972 } 973 } else { 974 status_t err = mCurrentFence->waitForever( 975 "GLConsumer::doGLFenceWaitLocked"); 976 if (err != NO_ERROR) { 977 ST_LOGE("doGLFenceWait: error waiting for fence: %d", err); 978 return err; 979 } 980 } 981 } 982 983 return NO_ERROR; 984} 985 986void GLConsumer::freeBufferLocked(int slotIndex) { 987 ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); 988 if (slotIndex == mCurrentTexture) { 989 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; 990 } 991 mEglSlots[slotIndex].mEglImage.clear(); 992 ConsumerBase::freeBufferLocked(slotIndex); 993} 994 995void GLConsumer::abandonLocked() { 996 ST_LOGV("abandonLocked"); 997 mCurrentTextureImage.clear(); 998 ConsumerBase::abandonLocked(); 999} 1000 1001void GLConsumer::setName(const String8& name) { 1002 Mutex::Autolock _l(mMutex); 1003 mName = name; 1004 mConsumer->setConsumerName(name); 1005} 1006 1007status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { 1008 Mutex::Autolock lock(mMutex); 1009 return mConsumer->setDefaultBufferFormat(defaultFormat); 1010} 1011 1012status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { 1013 Mutex::Autolock lock(mMutex); 1014 usage |= DEFAULT_USAGE_FLAGS; 1015 return mConsumer->setConsumerUsageBits(usage); 1016} 1017 1018status_t GLConsumer::setTransformHint(uint32_t hint) { 1019 Mutex::Autolock lock(mMutex); 1020 return mConsumer->setTransformHint(hint); 1021} 1022 1023void GLConsumer::dumpLocked(String8& result, const char* prefix) const 1024{ 1025 result.appendFormat( 1026 "%smTexName=%d mCurrentTexture=%d\n" 1027 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", 1028 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, 1029 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, 1030 mCurrentTransform); 1031 1032 ConsumerBase::dumpLocked(result, prefix); 1033} 1034 1035static void mtxMul(float out[16], const float a[16], const float b[16]) { 1036 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; 1037 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; 1038 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; 1039 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; 1040 1041 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; 1042 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; 1043 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; 1044 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; 1045 1046 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; 1047 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; 1048 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; 1049 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; 1050 1051 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; 1052 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; 1053 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; 1054 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; 1055} 1056 1057GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) : 1058 mGraphicBuffer(graphicBuffer), 1059 mEglImage(EGL_NO_IMAGE_KHR), 1060 mEglDisplay(EGL_NO_DISPLAY) { 1061} 1062 1063GLConsumer::EglImage::~EglImage() { 1064 if (mEglImage != EGL_NO_IMAGE_KHR) { 1065 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { 1066 ALOGE("~EglImage: eglDestroyImageKHR failed"); 1067 } 1068 eglTerminate(mEglDisplay); 1069 } 1070} 1071 1072status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, 1073 const Rect& cropRect, 1074 bool forceCreation) { 1075 // If there's an image and it's no longer valid, destroy it. 1076 bool haveImage = mEglImage != EGL_NO_IMAGE_KHR; 1077 bool displayInvalid = mEglDisplay != eglDisplay; 1078 bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect; 1079 if (haveImage && (displayInvalid || cropInvalid || forceCreation)) { 1080 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { 1081 ALOGE("createIfNeeded: eglDestroyImageKHR failed"); 1082 } 1083 eglTerminate(mEglDisplay); 1084 mEglImage = EGL_NO_IMAGE_KHR; 1085 mEglDisplay = EGL_NO_DISPLAY; 1086 } 1087 1088 // If there's no image, create one. 1089 if (mEglImage == EGL_NO_IMAGE_KHR) { 1090 mEglDisplay = eglDisplay; 1091 mCropRect = cropRect; 1092 mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect); 1093 } 1094 1095 // Fail if we can't create a valid image. 1096 if (mEglImage == EGL_NO_IMAGE_KHR) { 1097 mEglDisplay = EGL_NO_DISPLAY; 1098 mCropRect.makeInvalid(); 1099 const sp<GraphicBuffer>& buffer = mGraphicBuffer; 1100 ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d", 1101 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), 1102 buffer->getUsage(), buffer->getPixelFormat()); 1103 return UNKNOWN_ERROR; 1104 } 1105 1106 return OK; 1107} 1108 1109void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { 1110 glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage); 1111} 1112 1113EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, 1114 const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) { 1115 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); 1116 EGLint attrs[] = { 1117 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 1118 EGL_IMAGE_CROP_LEFT_ANDROID, crop.left, 1119 EGL_IMAGE_CROP_TOP_ANDROID, crop.top, 1120 EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right, 1121 EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom, 1122 EGL_NONE, 1123 }; 1124 if (!crop.isValid()) { 1125 // No crop rect to set, so terminate the attrib array before the crop. 1126 attrs[2] = EGL_NONE; 1127 } else if (!isEglImageCroppable(crop)) { 1128 // The crop rect is not at the origin, so we can't set the crop on the 1129 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop 1130 // extension. In the future we can add a layered extension that 1131 // removes this restriction if there is hardware that can support it. 1132 attrs[2] = EGL_NONE; 1133 } 1134 eglInitialize(dpy, 0, 0); 1135 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, 1136 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); 1137 if (image == EGL_NO_IMAGE_KHR) { 1138 EGLint error = eglGetError(); 1139 ALOGE("error creating EGLImage: %#x", error); 1140 eglTerminate(dpy); 1141 } 1142 return image; 1143} 1144 1145}; // namespace android 1146