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