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