Home | History | Annotate | Download | only in gui
      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 "SurfaceTextureClient"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include <gui/SurfaceTextureClient.h>
     21 #include <surfaceflinger/ISurfaceComposer.h>
     22 #include <surfaceflinger/SurfaceComposerClient.h>
     23 
     24 #include <utils/Log.h>
     25 
     26 namespace android {
     27 
     28 SurfaceTextureClient::SurfaceTextureClient(
     29         const sp<ISurfaceTexture>& surfaceTexture)
     30 {
     31     SurfaceTextureClient::init();
     32     SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
     33 }
     34 
     35 SurfaceTextureClient::SurfaceTextureClient() {
     36     SurfaceTextureClient::init();
     37 }
     38 
     39 SurfaceTextureClient::~SurfaceTextureClient() {
     40     if (mConnectedToCpu) {
     41         SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU);
     42     }
     43 }
     44 
     45 void SurfaceTextureClient::init() {
     46     // Initialize the ANativeWindow function pointers.
     47     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
     48     ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
     49     ANativeWindow::cancelBuffer     = hook_cancelBuffer;
     50     ANativeWindow::lockBuffer       = hook_lockBuffer;
     51     ANativeWindow::queueBuffer      = hook_queueBuffer;
     52     ANativeWindow::query            = hook_query;
     53     ANativeWindow::perform          = hook_perform;
     54 
     55     const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
     56     const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
     57 
     58     mReqWidth = 0;
     59     mReqHeight = 0;
     60     mReqFormat = 0;
     61     mReqUsage = 0;
     62     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
     63     mDefaultWidth = 0;
     64     mDefaultHeight = 0;
     65     mTransformHint = 0;
     66     mConnectedToCpu = false;
     67 }
     68 
     69 void SurfaceTextureClient::setISurfaceTexture(
     70         const sp<ISurfaceTexture>& surfaceTexture)
     71 {
     72     mSurfaceTexture = surfaceTexture;
     73 }
     74 
     75 sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
     76     return mSurfaceTexture;
     77 }
     78 
     79 int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
     80     SurfaceTextureClient* c = getSelf(window);
     81     return c->setSwapInterval(interval);
     82 }
     83 
     84 int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
     85         ANativeWindowBuffer** buffer) {
     86     SurfaceTextureClient* c = getSelf(window);
     87     return c->dequeueBuffer(buffer);
     88 }
     89 
     90 int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
     91         ANativeWindowBuffer* buffer) {
     92     SurfaceTextureClient* c = getSelf(window);
     93     return c->cancelBuffer(buffer);
     94 }
     95 
     96 int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
     97         ANativeWindowBuffer* buffer) {
     98     SurfaceTextureClient* c = getSelf(window);
     99     return c->lockBuffer(buffer);
    100 }
    101 
    102 int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
    103         ANativeWindowBuffer* buffer) {
    104     SurfaceTextureClient* c = getSelf(window);
    105     return c->queueBuffer(buffer);
    106 }
    107 
    108 int SurfaceTextureClient::hook_query(const ANativeWindow* window,
    109                                 int what, int* value) {
    110     const SurfaceTextureClient* c = getSelf(window);
    111     return c->query(what, value);
    112 }
    113 
    114 int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
    115     va_list args;
    116     va_start(args, operation);
    117     SurfaceTextureClient* c = getSelf(window);
    118     return c->perform(operation, args);
    119 }
    120 
    121 int SurfaceTextureClient::setSwapInterval(int interval) {
    122     // EGL specification states:
    123     //  interval is silently clamped to minimum and maximum implementation
    124     //  dependent values before being stored.
    125     // Although we don't have to, we apply the same logic here.
    126 
    127     if (interval < minSwapInterval)
    128         interval = minSwapInterval;
    129 
    130     if (interval > maxSwapInterval)
    131         interval = maxSwapInterval;
    132 
    133     status_t res = mSurfaceTexture->setSynchronousMode(interval ? true : false);
    134 
    135     return res;
    136 }
    137 
    138 int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
    139     LOGV("SurfaceTextureClient::dequeueBuffer");
    140     Mutex::Autolock lock(mMutex);
    141     int buf = -1;
    142     status_t result = mSurfaceTexture->dequeueBuffer(&buf, mReqWidth, mReqHeight,
    143             mReqFormat, mReqUsage);
    144     if (result < 0) {
    145         LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
    146              "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
    147              result);
    148         return result;
    149     }
    150     sp<GraphicBuffer>& gbuf(mSlots[buf]);
    151     if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {
    152         freeAllBuffers();
    153     }
    154 
    155     if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
    156         result = mSurfaceTexture->requestBuffer(buf, &gbuf);
    157         if (result != NO_ERROR) {
    158             LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
    159                     result);
    160             return result;
    161         }
    162     }
    163     *buffer = gbuf.get();
    164     return OK;
    165 }
    166 
    167 int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
    168     LOGV("SurfaceTextureClient::cancelBuffer");
    169     Mutex::Autolock lock(mMutex);
    170     int i = getSlotFromBufferLocked(buffer);
    171     if (i < 0) {
    172         return i;
    173     }
    174     mSurfaceTexture->cancelBuffer(i);
    175     return OK;
    176 }
    177 
    178 int SurfaceTextureClient::getSlotFromBufferLocked(
    179         android_native_buffer_t* buffer) const {
    180     bool dumpedState = false;
    181     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
    182         // XXX: Dump the slots whenever we hit a NULL entry while searching for
    183         // a buffer.
    184         if (mSlots[i] == NULL) {
    185             if (!dumpedState) {
    186                 LOGD("getSlotFromBufferLocked: encountered NULL buffer in slot %d "
    187                         "looking for buffer %p", i, buffer->handle);
    188                 for (int j = 0; j < NUM_BUFFER_SLOTS; j++) {
    189                     if (mSlots[j] == NULL) {
    190                         LOGD("getSlotFromBufferLocked:   %02d: NULL", j);
    191                     } else {
    192                         LOGD("getSlotFromBufferLocked:   %02d: %p", j, mSlots[j]->handle);
    193                     }
    194                 }
    195                 dumpedState = true;
    196             }
    197         }
    198 
    199         if (mSlots[i] != NULL && mSlots[i]->handle == buffer->handle) {
    200             return i;
    201         }
    202     }
    203     LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
    204     return BAD_VALUE;
    205 }
    206 
    207 int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
    208     LOGV("SurfaceTextureClient::lockBuffer");
    209     Mutex::Autolock lock(mMutex);
    210     return OK;
    211 }
    212 
    213 int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
    214     LOGV("SurfaceTextureClient::queueBuffer");
    215     Mutex::Autolock lock(mMutex);
    216     int64_t timestamp;
    217     if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
    218         timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
    219         LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",
    220              timestamp / 1000000.f);
    221     } else {
    222         timestamp = mTimestamp;
    223     }
    224     int i = getSlotFromBufferLocked(buffer);
    225     if (i < 0) {
    226         return i;
    227     }
    228     status_t err = mSurfaceTexture->queueBuffer(i, timestamp,
    229             &mDefaultWidth, &mDefaultHeight, &mTransformHint);
    230     if (err != OK)  {
    231         LOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
    232     }
    233     return err;
    234 }
    235 
    236 int SurfaceTextureClient::query(int what, int* value) const {
    237     LOGV("SurfaceTextureClient::query");
    238     { // scope for the lock
    239         Mutex::Autolock lock(mMutex);
    240         switch (what) {
    241             case NATIVE_WINDOW_FORMAT:
    242                 if (mReqFormat) {
    243                     *value = mReqFormat;
    244                     return NO_ERROR;
    245                 }
    246                 break;
    247             case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
    248                 {
    249                     sp<ISurfaceComposer> composer(
    250                             ComposerService::getComposerService());
    251                     if (composer->authenticateSurfaceTexture(mSurfaceTexture)) {
    252                         *value = 1;
    253                     } else {
    254                         *value = 0;
    255                     }
    256                 }
    257                 return NO_ERROR;
    258             case NATIVE_WINDOW_CONCRETE_TYPE:
    259                 *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
    260                 return NO_ERROR;
    261             case NATIVE_WINDOW_DEFAULT_WIDTH:
    262                 *value = mDefaultWidth;
    263                 return NO_ERROR;
    264             case NATIVE_WINDOW_DEFAULT_HEIGHT:
    265                 *value = mDefaultHeight;
    266                 return NO_ERROR;
    267             case NATIVE_WINDOW_TRANSFORM_HINT:
    268                 *value = mTransformHint;
    269                 return NO_ERROR;
    270         }
    271     }
    272     return mSurfaceTexture->query(what, value);
    273 }
    274 
    275 int SurfaceTextureClient::perform(int operation, va_list args)
    276 {
    277     int res = NO_ERROR;
    278     switch (operation) {
    279     case NATIVE_WINDOW_CONNECT:
    280         // deprecated. must return NO_ERROR.
    281         break;
    282     case NATIVE_WINDOW_DISCONNECT:
    283         // deprecated. must return NO_ERROR.
    284         break;
    285     case NATIVE_WINDOW_SET_USAGE:
    286         res = dispatchSetUsage(args);
    287         break;
    288     case NATIVE_WINDOW_SET_CROP:
    289         res = dispatchSetCrop(args);
    290         break;
    291     case NATIVE_WINDOW_SET_BUFFER_COUNT:
    292         res = dispatchSetBufferCount(args);
    293         break;
    294     case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
    295         res = dispatchSetBuffersGeometry(args);
    296         break;
    297     case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
    298         res = dispatchSetBuffersTransform(args);
    299         break;
    300     case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
    301         res = dispatchSetBuffersTimestamp(args);
    302         break;
    303     case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
    304         res = dispatchSetBuffersDimensions(args);
    305         break;
    306     case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
    307         res = dispatchSetBuffersFormat(args);
    308         break;
    309     case NATIVE_WINDOW_LOCK:
    310         res = dispatchLock(args);
    311         break;
    312     case NATIVE_WINDOW_UNLOCK_AND_POST:
    313         res = dispatchUnlockAndPost(args);
    314         break;
    315     case NATIVE_WINDOW_SET_SCALING_MODE:
    316         res = dispatchSetScalingMode(args);
    317         break;
    318     case NATIVE_WINDOW_API_CONNECT:
    319         res = dispatchConnect(args);
    320         break;
    321     case NATIVE_WINDOW_API_DISCONNECT:
    322         res = dispatchDisconnect(args);
    323         break;
    324     default:
    325         res = NAME_NOT_FOUND;
    326         break;
    327     }
    328     return res;
    329 }
    330 
    331 int SurfaceTextureClient::dispatchConnect(va_list args) {
    332     int api = va_arg(args, int);
    333     return connect(api);
    334 }
    335 
    336 int SurfaceTextureClient::dispatchDisconnect(va_list args) {
    337     int api = va_arg(args, int);
    338     return disconnect(api);
    339 }
    340 
    341 int SurfaceTextureClient::dispatchSetUsage(va_list args) {
    342     int usage = va_arg(args, int);
    343     return setUsage(usage);
    344 }
    345 
    346 int SurfaceTextureClient::dispatchSetCrop(va_list args) {
    347     android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
    348     return setCrop(reinterpret_cast<Rect const*>(rect));
    349 }
    350 
    351 int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
    352     size_t bufferCount = va_arg(args, size_t);
    353     return setBufferCount(bufferCount);
    354 }
    355 
    356 int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
    357     int w = va_arg(args, int);
    358     int h = va_arg(args, int);
    359     int f = va_arg(args, int);
    360     int err = setBuffersDimensions(w, h);
    361     if (err != 0) {
    362         return err;
    363     }
    364     return setBuffersFormat(f);
    365 }
    366 
    367 int SurfaceTextureClient::dispatchSetBuffersDimensions(va_list args) {
    368     int w = va_arg(args, int);
    369     int h = va_arg(args, int);
    370     return setBuffersDimensions(w, h);
    371 }
    372 
    373 int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) {
    374     int f = va_arg(args, int);
    375     return setBuffersFormat(f);
    376 }
    377 
    378 int SurfaceTextureClient::dispatchSetScalingMode(va_list args) {
    379     int m = va_arg(args, int);
    380     return setScalingMode(m);
    381 }
    382 
    383 int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
    384     int transform = va_arg(args, int);
    385     return setBuffersTransform(transform);
    386 }
    387 
    388 int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
    389     int64_t timestamp = va_arg(args, int64_t);
    390     return setBuffersTimestamp(timestamp);
    391 }
    392 
    393 int SurfaceTextureClient::dispatchLock(va_list args) {
    394     ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
    395     ARect* inOutDirtyBounds = va_arg(args, ARect*);
    396     return lock(outBuffer, inOutDirtyBounds);
    397 }
    398 
    399 int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
    400     return unlockAndPost();
    401 }
    402 
    403 
    404 int SurfaceTextureClient::connect(int api) {
    405     LOGV("SurfaceTextureClient::connect");
    406     Mutex::Autolock lock(mMutex);
    407     int err = mSurfaceTexture->connect(api,
    408             &mDefaultWidth, &mDefaultHeight, &mTransformHint);
    409     if (!err && api == NATIVE_WINDOW_API_CPU) {
    410         mConnectedToCpu = true;
    411     }
    412     return err;
    413 }
    414 
    415 int SurfaceTextureClient::disconnect(int api) {
    416     LOGV("SurfaceTextureClient::disconnect");
    417     Mutex::Autolock lock(mMutex);
    418     freeAllBuffers();
    419     int err = mSurfaceTexture->disconnect(api);
    420     if (!err) {
    421         mReqFormat = 0;
    422         mReqWidth = 0;
    423         mReqHeight = 0;
    424         mReqUsage = 0;
    425         if (api == NATIVE_WINDOW_API_CPU) {
    426             mConnectedToCpu = false;
    427         }
    428     }
    429     return err;
    430 }
    431 
    432 int SurfaceTextureClient::setUsage(uint32_t reqUsage)
    433 {
    434     LOGV("SurfaceTextureClient::setUsage");
    435     Mutex::Autolock lock(mMutex);
    436     mReqUsage = reqUsage;
    437     return OK;
    438 }
    439 
    440 int SurfaceTextureClient::setCrop(Rect const* rect)
    441 {
    442     LOGV("SurfaceTextureClient::setCrop");
    443     Mutex::Autolock lock(mMutex);
    444 
    445     Rect realRect;
    446     if (rect == NULL || rect->isEmpty()) {
    447         realRect = Rect(0, 0);
    448     } else {
    449         realRect = *rect;
    450     }
    451 
    452     status_t err = mSurfaceTexture->setCrop(*rect);
    453     LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
    454 
    455     return err;
    456 }
    457 
    458 int SurfaceTextureClient::setBufferCount(int bufferCount)
    459 {
    460     LOGV("SurfaceTextureClient::setBufferCount");
    461     Mutex::Autolock lock(mMutex);
    462 
    463     status_t err = mSurfaceTexture->setBufferCount(bufferCount);
    464     LOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
    465             bufferCount, strerror(-err));
    466 
    467     if (err == NO_ERROR) {
    468         freeAllBuffers();
    469     }
    470 
    471     return err;
    472 }
    473 
    474 int SurfaceTextureClient::setBuffersDimensions(int w, int h)
    475 {
    476     LOGV("SurfaceTextureClient::setBuffersDimensions");
    477     Mutex::Autolock lock(mMutex);
    478 
    479     if (w<0 || h<0)
    480         return BAD_VALUE;
    481 
    482     if ((w && !h) || (!w && h))
    483         return BAD_VALUE;
    484 
    485     mReqWidth = w;
    486     mReqHeight = h;
    487 
    488     status_t err = mSurfaceTexture->setCrop(Rect(0, 0));
    489     LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
    490 
    491     return err;
    492 }
    493 
    494 int SurfaceTextureClient::setBuffersFormat(int format)
    495 {
    496     LOGV("SurfaceTextureClient::setBuffersFormat");
    497     Mutex::Autolock lock(mMutex);
    498 
    499     if (format<0)
    500         return BAD_VALUE;
    501 
    502     mReqFormat = format;
    503 
    504     return NO_ERROR;
    505 }
    506 
    507 int SurfaceTextureClient::setScalingMode(int mode)
    508 {
    509     LOGV("SurfaceTextureClient::setScalingMode(%d)", mode);
    510     Mutex::Autolock lock(mMutex);
    511     // mode is validated on the server
    512     status_t err = mSurfaceTexture->setScalingMode(mode);
    513     LOGE_IF(err, "ISurfaceTexture::setScalingMode(%d) returned %s",
    514             mode, strerror(-err));
    515 
    516     return err;
    517 }
    518 
    519 int SurfaceTextureClient::setBuffersTransform(int transform)
    520 {
    521     LOGV("SurfaceTextureClient::setBuffersTransform");
    522     Mutex::Autolock lock(mMutex);
    523     status_t err = mSurfaceTexture->setTransform(transform);
    524     return err;
    525 }
    526 
    527 int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp)
    528 {
    529     LOGV("SurfaceTextureClient::setBuffersTimestamp");
    530     Mutex::Autolock lock(mMutex);
    531     mTimestamp = timestamp;
    532     return NO_ERROR;
    533 }
    534 
    535 void SurfaceTextureClient::freeAllBuffers() {
    536     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
    537         mSlots[i] = 0;
    538     }
    539 }
    540 
    541 // ----------------------------------------------------------------------
    542 // the lock/unlock APIs must be used from the same thread
    543 
    544 static status_t copyBlt(
    545         const sp<GraphicBuffer>& dst,
    546         const sp<GraphicBuffer>& src,
    547         const Region& reg)
    548 {
    549     // src and dst with, height and format must be identical. no verification
    550     // is done here.
    551     status_t err;
    552     uint8_t const * src_bits = NULL;
    553     err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
    554     LOGE_IF(err, "error locking src buffer %s", strerror(-err));
    555 
    556     uint8_t* dst_bits = NULL;
    557     err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
    558     LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
    559 
    560     Region::const_iterator head(reg.begin());
    561     Region::const_iterator tail(reg.end());
    562     if (head != tail && src_bits && dst_bits) {
    563         const size_t bpp = bytesPerPixel(src->format);
    564         const size_t dbpr = dst->stride * bpp;
    565         const size_t sbpr = src->stride * bpp;
    566 
    567         while (head != tail) {
    568             const Rect& r(*head++);
    569             ssize_t h = r.height();
    570             if (h <= 0) continue;
    571             size_t size = r.width() * bpp;
    572             uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
    573             uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
    574             if (dbpr==sbpr && size==sbpr) {
    575                 size *= h;
    576                 h = 1;
    577             }
    578             do {
    579                 memcpy(d, s, size);
    580                 d += dbpr;
    581                 s += sbpr;
    582             } while (--h > 0);
    583         }
    584     }
    585 
    586     if (src_bits)
    587         src->unlock();
    588 
    589     if (dst_bits)
    590         dst->unlock();
    591 
    592     return err;
    593 }
    594 
    595 // ----------------------------------------------------------------------------
    596 
    597 status_t SurfaceTextureClient::lock(
    598         ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
    599 {
    600     if (mLockedBuffer != 0) {
    601         LOGE("Surface::lock failed, already locked");
    602         return INVALID_OPERATION;
    603     }
    604 
    605     if (!mConnectedToCpu) {
    606         int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
    607         if (err) {
    608             return err;
    609         }
    610         // we're intending to do software rendering from this point
    611         setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
    612     }
    613 
    614     ANativeWindowBuffer* out;
    615     status_t err = dequeueBuffer(&out);
    616     LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
    617     if (err == NO_ERROR) {
    618         sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
    619         err = lockBuffer(backBuffer.get());
    620         LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
    621                 backBuffer->handle, strerror(-err));
    622         if (err == NO_ERROR) {
    623             const Rect bounds(backBuffer->width, backBuffer->height);
    624 
    625             Region newDirtyRegion;
    626             if (inOutDirtyBounds) {
    627                 newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
    628                 newDirtyRegion.andSelf(bounds);
    629             } else {
    630                 newDirtyRegion.set(bounds);
    631             }
    632 
    633             // figure out if we can copy the frontbuffer back
    634             const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
    635             const bool canCopyBack = (frontBuffer != 0 &&
    636                     backBuffer->width  == frontBuffer->width &&
    637                     backBuffer->height == frontBuffer->height &&
    638                     backBuffer->format == frontBuffer->format);
    639 
    640             if (canCopyBack) {
    641                 // copy the area that is invalid and not repainted this round
    642                 const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
    643                 if (!copyback.isEmpty())
    644                     copyBlt(backBuffer, frontBuffer, copyback);
    645             } else {
    646                 // if we can't copy-back anything, modify the user's dirty
    647                 // region to make sure they redraw the whole buffer
    648                 newDirtyRegion.set(bounds);
    649             }
    650 
    651             // keep track of the are of the buffer that is "clean"
    652             // (ie: that will be redrawn)
    653             mOldDirtyRegion = newDirtyRegion;
    654 
    655             if (inOutDirtyBounds) {
    656                 *inOutDirtyBounds = newDirtyRegion.getBounds();
    657             }
    658 
    659             void* vaddr;
    660             status_t res = backBuffer->lock(
    661                     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
    662                     newDirtyRegion.bounds(), &vaddr);
    663 
    664             LOGW_IF(res, "failed locking buffer (handle = %p)",
    665                     backBuffer->handle);
    666 
    667             mLockedBuffer = backBuffer;
    668             outBuffer->width  = backBuffer->width;
    669             outBuffer->height = backBuffer->height;
    670             outBuffer->stride = backBuffer->stride;
    671             outBuffer->format = backBuffer->format;
    672             outBuffer->bits   = vaddr;
    673         }
    674     }
    675     return err;
    676 }
    677 
    678 status_t SurfaceTextureClient::unlockAndPost()
    679 {
    680     if (mLockedBuffer == 0) {
    681         LOGE("Surface::unlockAndPost failed, no locked buffer");
    682         return INVALID_OPERATION;
    683     }
    684 
    685     status_t err = mLockedBuffer->unlock();
    686     LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
    687 
    688     err = queueBuffer(mLockedBuffer.get());
    689     LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
    690             mLockedBuffer->handle, strerror(-err));
    691 
    692     mPostedBuffer = mLockedBuffer;
    693     mLockedBuffer = 0;
    694     return err;
    695 }
    696 
    697 }; // namespace android
    698