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