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