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