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