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