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