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