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