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